Line data Source code
1 : /*
2 : * datatypes.c
3 : *
4 : * data types for finite fields and functions for input, output, and
5 : * manipulation
6 : *
7 : * David A. McGrew
8 : * Cisco Systems, Inc.
9 : */
10 : /*
11 : *
12 : * Copyright (c) 2001-2006 Cisco Systems, Inc.
13 : * All rights reserved.
14 : *
15 : * Redistribution and use in source and binary forms, with or without
16 : * modification, are permitted provided that the following conditions
17 : * are met:
18 : *
19 : * Redistributions of source code must retain the above copyright
20 : * notice, this list of conditions and the following disclaimer.
21 : *
22 : * Redistributions in binary form must reproduce the above
23 : * copyright notice, this list of conditions and the following
24 : * disclaimer in the documentation and/or other materials provided
25 : * with the distribution.
26 : *
27 : * Neither the name of the Cisco Systems, Inc. nor the names of its
28 : * contributors may be used to endorse or promote products derived
29 : * from this software without specific prior written permission.
30 : *
31 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 : * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
35 : * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
36 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
38 : * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
42 : * OF THE POSSIBILITY OF SUCH DAMAGE.
43 : *
44 : */
45 :
46 : #include "datatypes.h"
47 :
48 : // MOZILLA: upstream code lacks |static const| and uses |int| elements, which
49 : // means it isn't read-only and so cannot be shared between processes, and is
50 : // four times bigger than necessary. Please preserve these changes until they
51 : // are upstreamed.
52 : static const int8_t
53 : octet_weight[256] = {
54 : 0, 1, 1, 2, 1, 2, 2, 3,
55 : 1, 2, 2, 3, 2, 3, 3, 4,
56 : 1, 2, 2, 3, 2, 3, 3, 4,
57 : 2, 3, 3, 4, 3, 4, 4, 5,
58 : 1, 2, 2, 3, 2, 3, 3, 4,
59 : 2, 3, 3, 4, 3, 4, 4, 5,
60 : 2, 3, 3, 4, 3, 4, 4, 5,
61 : 3, 4, 4, 5, 4, 5, 5, 6,
62 : 1, 2, 2, 3, 2, 3, 3, 4,
63 : 2, 3, 3, 4, 3, 4, 4, 5,
64 : 2, 3, 3, 4, 3, 4, 4, 5,
65 : 3, 4, 4, 5, 4, 5, 5, 6,
66 : 2, 3, 3, 4, 3, 4, 4, 5,
67 : 3, 4, 4, 5, 4, 5, 5, 6,
68 : 3, 4, 4, 5, 4, 5, 5, 6,
69 : 4, 5, 5, 6, 5, 6, 6, 7,
70 : 1, 2, 2, 3, 2, 3, 3, 4,
71 : 2, 3, 3, 4, 3, 4, 4, 5,
72 : 2, 3, 3, 4, 3, 4, 4, 5,
73 : 3, 4, 4, 5, 4, 5, 5, 6,
74 : 2, 3, 3, 4, 3, 4, 4, 5,
75 : 3, 4, 4, 5, 4, 5, 5, 6,
76 : 3, 4, 4, 5, 4, 5, 5, 6,
77 : 4, 5, 5, 6, 5, 6, 6, 7,
78 : 2, 3, 3, 4, 3, 4, 4, 5,
79 : 3, 4, 4, 5, 4, 5, 5, 6,
80 : 3, 4, 4, 5, 4, 5, 5, 6,
81 : 4, 5, 5, 6, 5, 6, 6, 7,
82 : 3, 4, 4, 5, 4, 5, 5, 6,
83 : 4, 5, 5, 6, 5, 6, 6, 7,
84 : 4, 5, 5, 6, 5, 6, 6, 7,
85 : 5, 6, 6, 7, 6, 7, 7, 8
86 : };
87 :
88 : int
89 0 : octet_get_weight(uint8_t octet) {
90 : // MOZILLA: upstream code here is slightly different due to the changes we've
91 : // made to octet_weight's declaration above
92 0 : return (int)octet_weight[octet];
93 : }
94 :
95 : /*
96 : * bit_string is a buffer that is used to hold output strings, e.g.
97 : * for printing.
98 : */
99 :
100 : /* the value MAX_PRINT_STRING_LEN is defined in datatypes.h */
101 :
102 : char bit_string[MAX_PRINT_STRING_LEN];
103 :
104 : uint8_t
105 0 : nibble_to_hex_char(uint8_t nibble) {
106 0 : char buf[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
107 : '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
108 0 : return buf[nibble & 0xF];
109 : }
110 :
111 : char *
112 0 : octet_string_hex_string(const void *s, int length) {
113 0 : const uint8_t *str = (const uint8_t *)s;
114 : int i;
115 :
116 : /* double length, since one octet takes two hex characters */
117 0 : length *= 2;
118 :
119 : /* truncate string if it would be too long */
120 0 : if (length > MAX_PRINT_STRING_LEN)
121 0 : length = MAX_PRINT_STRING_LEN-1;
122 :
123 0 : for (i=0; i < length; i+=2) {
124 0 : bit_string[i] = nibble_to_hex_char(*str >> 4);
125 0 : bit_string[i+1] = nibble_to_hex_char(*str++ & 0xF);
126 : }
127 0 : bit_string[i] = 0; /* null terminate string */
128 0 : return bit_string;
129 : }
130 :
131 : static inline int
132 0 : hex_char_to_nibble(uint8_t c) {
133 0 : switch(c) {
134 0 : case ('0'): return 0x0;
135 0 : case ('1'): return 0x1;
136 0 : case ('2'): return 0x2;
137 0 : case ('3'): return 0x3;
138 0 : case ('4'): return 0x4;
139 0 : case ('5'): return 0x5;
140 0 : case ('6'): return 0x6;
141 0 : case ('7'): return 0x7;
142 0 : case ('8'): return 0x8;
143 0 : case ('9'): return 0x9;
144 0 : case ('a'): return 0xa;
145 0 : case ('A'): return 0xa;
146 0 : case ('b'): return 0xb;
147 0 : case ('B'): return 0xb;
148 0 : case ('c'): return 0xc;
149 0 : case ('C'): return 0xc;
150 0 : case ('d'): return 0xd;
151 0 : case ('D'): return 0xd;
152 0 : case ('e'): return 0xe;
153 0 : case ('E'): return 0xe;
154 0 : case ('f'): return 0xf;
155 0 : case ('F'): return 0xf;
156 0 : default: return -1; /* this flags an error */
157 : }
158 : /* NOTREACHED */
159 : return -1; /* this keeps compilers from complaining */
160 : }
161 :
162 : int
163 0 : is_hex_string(char *s) {
164 0 : while(*s != 0)
165 0 : if (hex_char_to_nibble(*s++) == -1)
166 0 : return 0;
167 0 : return 1;
168 : }
169 :
170 : /*
171 : * hex_string_to_octet_string converts a hexadecimal string
172 : * of length 2 * len to a raw octet string of length len
173 : */
174 :
175 : int
176 0 : hex_string_to_octet_string(char *raw, char *hex, int len) {
177 : uint8_t x;
178 : int tmp;
179 : int hex_len;
180 :
181 0 : hex_len = 0;
182 0 : while (hex_len < len) {
183 0 : tmp = hex_char_to_nibble(hex[0]);
184 0 : if (tmp == -1)
185 0 : return hex_len;
186 0 : x = (tmp << 4);
187 0 : hex_len++;
188 0 : tmp = hex_char_to_nibble(hex[1]);
189 0 : if (tmp == -1)
190 0 : return hex_len;
191 0 : x |= (tmp & 0xff);
192 0 : hex_len++;
193 0 : *raw++ = x;
194 0 : hex += 2;
195 : }
196 0 : return hex_len;
197 : }
198 :
199 : char *
200 0 : v128_hex_string(v128_t *x) {
201 : int i, j;
202 :
203 0 : for (i=j=0; i < 16; i++) {
204 0 : bit_string[j++] = nibble_to_hex_char(x->v8[i] >> 4);
205 0 : bit_string[j++] = nibble_to_hex_char(x->v8[i] & 0xF);
206 : }
207 :
208 0 : bit_string[j] = 0; /* null terminate string */
209 0 : return bit_string;
210 : }
211 :
212 : char *
213 0 : v128_bit_string(v128_t *x) {
214 : int j, i;
215 : uint32_t mask;
216 :
217 0 : for (j=i=0; j < 4; j++) {
218 0 : for (mask=0x80000000; mask > 0; mask >>= 1) {
219 0 : if (x->v32[j] & mask)
220 0 : bit_string[i] = '1';
221 : else
222 0 : bit_string[i] = '0';
223 0 : ++i;
224 : }
225 : }
226 0 : bit_string[128] = 0; /* null terminate string */
227 :
228 0 : return bit_string;
229 : }
230 :
231 : void
232 0 : v128_copy_octet_string(v128_t *x, const uint8_t s[16]) {
233 : #ifdef ALIGNMENT_32BIT_REQUIRED
234 : if ((((uint32_t) &s[0]) & 0x3) != 0)
235 : #endif
236 : {
237 0 : x->v8[0] = s[0];
238 0 : x->v8[1] = s[1];
239 0 : x->v8[2] = s[2];
240 0 : x->v8[3] = s[3];
241 0 : x->v8[4] = s[4];
242 0 : x->v8[5] = s[5];
243 0 : x->v8[6] = s[6];
244 0 : x->v8[7] = s[7];
245 0 : x->v8[8] = s[8];
246 0 : x->v8[9] = s[9];
247 0 : x->v8[10] = s[10];
248 0 : x->v8[11] = s[11];
249 0 : x->v8[12] = s[12];
250 0 : x->v8[13] = s[13];
251 0 : x->v8[14] = s[14];
252 0 : x->v8[15] = s[15];
253 : }
254 : #ifdef ALIGNMENT_32BIT_REQUIRED
255 : else
256 : {
257 : v128_t *v = (v128_t *) &s[0];
258 :
259 : v128_copy(x,v);
260 : }
261 : #endif
262 0 : }
263 :
264 : #ifndef DATATYPES_USE_MACROS /* little functions are not macros */
265 :
266 : void
267 : v128_set_to_zero(v128_t *x) {
268 : _v128_set_to_zero(x);
269 : }
270 :
271 : void
272 : v128_copy(v128_t *x, const v128_t *y) {
273 : _v128_copy(x, y);
274 : }
275 :
276 : void
277 : v128_xor(v128_t *z, v128_t *x, v128_t *y) {
278 : _v128_xor(z, x, y);
279 : }
280 :
281 : void
282 : v128_and(v128_t *z, v128_t *x, v128_t *y) {
283 : _v128_and(z, x, y);
284 : }
285 :
286 : void
287 : v128_or(v128_t *z, v128_t *x, v128_t *y) {
288 : _v128_or(z, x, y);
289 : }
290 :
291 : void
292 : v128_complement(v128_t *x) {
293 : _v128_complement(x);
294 : }
295 :
296 : int
297 : v128_is_eq(const v128_t *x, const v128_t *y) {
298 : return _v128_is_eq(x, y);
299 : }
300 :
301 : int
302 : v128_xor_eq(v128_t *x, const v128_t *y) {
303 : return _v128_xor_eq(x, y);
304 : }
305 :
306 : int
307 : v128_get_bit(const v128_t *x, int i) {
308 : return _v128_get_bit(x, i);
309 : }
310 :
311 : void
312 : v128_set_bit(v128_t *x, int i) {
313 : _v128_set_bit(x, i);
314 : }
315 :
316 : void
317 : v128_clear_bit(v128_t *x, int i){
318 : _v128_clear_bit(x, i);
319 : }
320 :
321 : void
322 : v128_set_bit_to(v128_t *x, int i, int y){
323 : _v128_set_bit_to(x, i, y);
324 : }
325 :
326 :
327 : #endif /* DATATYPES_USE_MACROS */
328 :
329 : void
330 0 : v128_right_shift(v128_t *x, int shift) {
331 0 : const int base_index = shift >> 5;
332 0 : const int bit_index = shift & 31;
333 : int i, from;
334 : uint32_t b;
335 :
336 0 : if (shift > 127) {
337 0 : v128_set_to_zero(x);
338 0 : return;
339 : }
340 :
341 0 : if (bit_index == 0) {
342 :
343 : /* copy each word from left size to right side */
344 0 : x->v32[4-1] = x->v32[4-1-base_index];
345 0 : for (i=4-1; i > base_index; i--)
346 0 : x->v32[i-1] = x->v32[i-1-base_index];
347 :
348 : } else {
349 :
350 : /* set each word to the "or" of the two bit-shifted words */
351 0 : for (i = 4; i > base_index; i--) {
352 0 : from = i-1 - base_index;
353 0 : b = x->v32[from] << bit_index;
354 0 : if (from > 0)
355 0 : b |= x->v32[from-1] >> (32-bit_index);
356 0 : x->v32[i-1] = b;
357 : }
358 :
359 : }
360 :
361 : /* now wrap up the final portion */
362 0 : for (i=0; i < base_index; i++)
363 0 : x->v32[i] = 0;
364 :
365 : }
366 :
367 : void
368 0 : v128_left_shift(v128_t *x, int shift) {
369 : int i;
370 0 : const int base_index = shift >> 5;
371 0 : const int bit_index = shift & 31;
372 :
373 0 : if (shift > 127) {
374 0 : v128_set_to_zero(x);
375 0 : return;
376 : }
377 :
378 0 : if (bit_index == 0) {
379 0 : for (i=0; i < 4 - base_index; i++)
380 0 : x->v32[i] = x->v32[i+base_index];
381 : } else {
382 0 : for (i=0; i < 4 - base_index - 1; i++)
383 0 : x->v32[i] = (x->v32[i+base_index] >> bit_index) ^
384 0 : (x->v32[i+base_index+1] << (32 - bit_index));
385 0 : x->v32[4 - base_index-1] = x->v32[4-1] >> bit_index;
386 : }
387 :
388 : /* now wrap up the final portion */
389 0 : for (i = 4 - base_index; i < 4; i++)
390 0 : x->v32[i] = 0;
391 :
392 : }
393 :
394 : /* functions manipulating bitvector_t */
395 :
396 : #ifndef DATATYPES_USE_MACROS /* little functions are not macros */
397 :
398 : int
399 : bitvector_get_bit(const bitvector_t *v, int bit_index)
400 : {
401 : return _bitvector_get_bit(v, bit_index);
402 : }
403 :
404 : void
405 : bitvector_set_bit(bitvector_t *v, int bit_index)
406 : {
407 : _bitvector_set_bit(v, bit_index);
408 : }
409 :
410 : void
411 : bitvector_clear_bit(bitvector_t *v, int bit_index)
412 : {
413 : _bitvector_clear_bit(v, bit_index);
414 : }
415 :
416 :
417 : #endif /* DATATYPES_USE_MACROS */
418 :
419 : int
420 0 : bitvector_alloc(bitvector_t *v, unsigned long length) {
421 : unsigned long l;
422 :
423 : /* Round length up to a multiple of bits_per_word */
424 0 : length = (length + bits_per_word - 1) & ~(unsigned long)((bits_per_word - 1));
425 :
426 0 : l = length / bits_per_word * bytes_per_word;
427 :
428 : /* allocate memory, then set parameters */
429 0 : if (l == 0)
430 0 : v->word = NULL;
431 : else {
432 0 : v->word = (uint32_t*)crypto_alloc(l);
433 0 : if (v->word == NULL) {
434 0 : v->word = NULL;
435 0 : v->length = 0;
436 0 : return -1;
437 : }
438 : }
439 0 : v->length = length;
440 :
441 : /* initialize bitvector to zero */
442 0 : bitvector_set_to_zero(v);
443 :
444 0 : return 0;
445 : }
446 :
447 :
448 : void
449 0 : bitvector_dealloc(bitvector_t *v) {
450 0 : if (v->word != NULL)
451 0 : crypto_free(v->word);
452 0 : v->word = NULL;
453 0 : v->length = 0;
454 0 : }
455 :
456 : void
457 0 : bitvector_set_to_zero(bitvector_t *x)
458 : {
459 : /* C99 guarantees that memset(0) will set the value 0 for uint32_t */
460 0 : memset(x->word, 0, x->length >> 3);
461 0 : }
462 :
463 : char *
464 0 : bitvector_bit_string(bitvector_t *x, char* buf, int len) {
465 : int j, i;
466 : uint32_t mask;
467 :
468 0 : for (j=i=0; j < (int)(x->length>>5) && i < len-1; j++) {
469 0 : for (mask=0x80000000; mask > 0; mask >>= 1) {
470 0 : if (x->word[j] & mask)
471 0 : buf[i] = '1';
472 : else
473 0 : buf[i] = '0';
474 0 : ++i;
475 0 : if (i >= len-1)
476 0 : break;
477 : }
478 : }
479 0 : buf[i] = 0; /* null terminate string */
480 :
481 0 : return buf;
482 : }
483 :
484 : void
485 0 : bitvector_left_shift(bitvector_t *x, int shift) {
486 : int i;
487 0 : const int base_index = shift >> 5;
488 0 : const int bit_index = shift & 31;
489 0 : const int word_length = x->length >> 5;
490 :
491 0 : if (shift >= (int)x->length) {
492 0 : bitvector_set_to_zero(x);
493 0 : return;
494 : }
495 :
496 0 : if (bit_index == 0) {
497 0 : for (i=0; i < word_length - base_index; i++)
498 0 : x->word[i] = x->word[i+base_index];
499 : } else {
500 0 : for (i=0; i < word_length - base_index - 1; i++)
501 0 : x->word[i] = (x->word[i+base_index] >> bit_index) ^
502 0 : (x->word[i+base_index+1] << (32 - bit_index));
503 0 : x->word[word_length - base_index-1] = x->word[word_length-1] >> bit_index;
504 : }
505 :
506 : /* now wrap up the final portion */
507 0 : for (i = word_length - base_index; i < word_length; i++)
508 0 : x->word[i] = 0;
509 :
510 : }
511 :
512 :
513 : int
514 0 : octet_string_is_eq(uint8_t *a, uint8_t *b, int len) {
515 0 : uint8_t *end = b + len;
516 0 : while (b < end)
517 0 : if (*a++ != *b++)
518 0 : return 1;
519 0 : return 0;
520 : }
521 :
522 : void
523 0 : octet_string_set_to_zero(uint8_t *s, int len) {
524 0 : uint8_t *end = s + len;
525 :
526 : do {
527 0 : *s = 0;
528 0 : } while (++s < end);
529 :
530 0 : }
531 :
532 :
533 : /*
534 : * From RFC 1521: The Base64 Alphabet
535 : *
536 : * Value Encoding Value Encoding Value Encoding Value Encoding
537 : * 0 A 17 R 34 i 51 z
538 : * 1 B 18 S 35 j 52 0
539 : * 2 C 19 T 36 k 53 1
540 : * 3 D 20 U 37 l 54 2
541 : * 4 E 21 V 38 m 55 3
542 : * 5 F 22 W 39 n 56 4
543 : * 6 G 23 X 40 o 57 5
544 : * 7 H 24 Y 41 p 58 6
545 : * 8 I 25 Z 42 q 59 7
546 : * 9 J 26 a 43 r 60 8
547 : * 10 K 27 b 44 s 61 9
548 : * 11 L 28 c 45 t 62 +
549 : * 12 M 29 d 46 u 63 /
550 : * 13 N 30 e 47 v
551 : * 14 O 31 f 48 w (pad) =
552 : * 15 P 32 g 49 x
553 : * 16 Q 33 h 50 y
554 : */
555 :
556 : int
557 0 : base64_char_to_sextet(uint8_t c) {
558 0 : switch(c) {
559 : case 'A':
560 0 : return 0;
561 : case 'B':
562 0 : return 1;
563 : case 'C':
564 0 : return 2;
565 : case 'D':
566 0 : return 3;
567 : case 'E':
568 0 : return 4;
569 : case 'F':
570 0 : return 5;
571 : case 'G':
572 0 : return 6;
573 : case 'H':
574 0 : return 7;
575 : case 'I':
576 0 : return 8;
577 : case 'J':
578 0 : return 9;
579 : case 'K':
580 0 : return 10;
581 : case 'L':
582 0 : return 11;
583 : case 'M':
584 0 : return 12;
585 : case 'N':
586 0 : return 13;
587 : case 'O':
588 0 : return 14;
589 : case 'P':
590 0 : return 15;
591 : case 'Q':
592 0 : return 16;
593 : case 'R':
594 0 : return 17;
595 : case 'S':
596 0 : return 18;
597 : case 'T':
598 0 : return 19;
599 : case 'U':
600 0 : return 20;
601 : case 'V':
602 0 : return 21;
603 : case 'W':
604 0 : return 22;
605 : case 'X':
606 0 : return 23;
607 : case 'Y':
608 0 : return 24;
609 : case 'Z':
610 0 : return 25;
611 : case 'a':
612 0 : return 26;
613 : case 'b':
614 0 : return 27;
615 : case 'c':
616 0 : return 28;
617 : case 'd':
618 0 : return 29;
619 : case 'e':
620 0 : return 30;
621 : case 'f':
622 0 : return 31;
623 : case 'g':
624 0 : return 32;
625 : case 'h':
626 0 : return 33;
627 : case 'i':
628 0 : return 34;
629 : case 'j':
630 0 : return 35;
631 : case 'k':
632 0 : return 36;
633 : case 'l':
634 0 : return 37;
635 : case 'm':
636 0 : return 38;
637 : case 'n':
638 0 : return 39;
639 : case 'o':
640 0 : return 40;
641 : case 'p':
642 0 : return 41;
643 : case 'q':
644 0 : return 42;
645 : case 'r':
646 0 : return 43;
647 : case 's':
648 0 : return 44;
649 : case 't':
650 0 : return 45;
651 : case 'u':
652 0 : return 46;
653 : case 'v':
654 0 : return 47;
655 : case 'w':
656 0 : return 48;
657 : case 'x':
658 0 : return 49;
659 : case 'y':
660 0 : return 50;
661 : case 'z':
662 0 : return 51;
663 : case '0':
664 0 : return 52;
665 : case '1':
666 0 : return 53;
667 : case '2':
668 0 : return 54;
669 : case '3':
670 0 : return 55;
671 : case '4':
672 0 : return 56;
673 : case '5':
674 0 : return 57;
675 : case '6':
676 0 : return 58;
677 : case '7':
678 0 : return 59;
679 : case '8':
680 0 : return 60;
681 : case '9':
682 0 : return 61;
683 : case '+':
684 0 : return 62;
685 : case '/':
686 0 : return 63;
687 : case '=':
688 0 : return 64;
689 : default:
690 0 : break;
691 : }
692 0 : return -1;
693 : }
694 :
695 : /*
696 : * base64_string_to_octet_string converts a hexadecimal string
697 : * of length 2 * len to a raw octet string of length len
698 : */
699 :
700 : int
701 0 : base64_string_to_octet_string(char *raw, char *base64, int len) {
702 : uint8_t x;
703 : int tmp;
704 : int base64_len;
705 :
706 0 : base64_len = 0;
707 0 : while (base64_len < len) {
708 0 : tmp = base64_char_to_sextet(base64[0]);
709 0 : if (tmp == -1)
710 0 : return base64_len;
711 0 : x = (tmp << 6);
712 0 : base64_len++;
713 0 : tmp = base64_char_to_sextet(base64[1]);
714 0 : if (tmp == -1)
715 0 : return base64_len;
716 0 : x |= (tmp & 0xffff);
717 0 : base64_len++;
718 0 : *raw++ = x;
719 0 : base64 += 2;
720 : }
721 0 : return base64_len;
722 : }
|