1 /*
2  * Base64 stream functions
3  *
4  * Copyright (C) 2008-2021, Joachim Metz <joachim.metz@gmail.com>
5  *
6  * Refer to AUTHORS for acknowledgements.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <common.h>
23 #include <byte_stream.h>
24 #include <types.h>
25 
26 #include "libuna_base64_stream.h"
27 #include "libuna_definitions.h"
28 #include "libuna_libcerror.h"
29 #include "libuna_types.h"
30 
31 static uint8_t libuna_base64_sixtet_to_character_table[ 64 ] = {
32 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
33 	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
34 	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
35 	'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
36 
37 static uint8_t libuna_base64url_sixtet_to_character_table[ 64 ] = {
38 	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
39 	'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
40 	'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
41 	'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' };
42 
43 /* Copies a base64 character to a base64 sixtet
44  * Returns 1 if successful, 0 if not a valid base64 character or -1 on error
45  */
libuna_base64_character_copy_to_sixtet(uint32_t base64_character,uint8_t * base64_sixtet,uint32_t base64_variant,libcerror_error_t ** error)46 int libuna_base64_character_copy_to_sixtet(
47      uint32_t base64_character,
48      uint8_t *base64_sixtet,
49      uint32_t base64_variant,
50      libcerror_error_t **error )
51 {
52 	static char *function       = "libuna_base64_character_copy_to_sixtet";
53 	uint32_t safe_base64_sixtet = 0;
54 	uint8_t base64_character_62 = 0;
55 	uint8_t base64_character_63 = 0;
56 
57 	if( base64_sixtet == NULL )
58 	{
59 		libcerror_error_set(
60 		 error,
61 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
62 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
63 		 "%s: invalid base64 sixtet.",
64 		 function );
65 
66 		return( -1 );
67 	}
68 	switch( base64_variant & 0x000f0000UL )
69 	{
70 		case LIBUNA_BASE64_VARIANT_ALPHABET_NORMAL:
71 			base64_character_62 = (uint8_t) '+';
72 			base64_character_63 = (uint8_t) '/';
73 			break;
74 
75 		case LIBUNA_BASE64_VARIANT_ALPHABET_URL:
76 			base64_character_62 = (uint8_t) '-';
77 			base64_character_63 = (uint8_t) '_';
78 			break;
79 
80 		default:
81 			libcerror_error_set(
82 			 error,
83 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
84 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
85 			 "%s: unsupported base64 variant.",
86 			 function );
87 
88 			return( -1 );
89 	}
90 	if( ( base64_character & 0xffffff00UL ) != 0 )
91 	{
92 		return( 0 );
93 	}
94 	/* A-Z is not a continous range on an EBCDIC based system
95 	 * it consists of the ranges: A-I, J-R, S-Z
96 	 */
97 	if( ( base64_character >= (uint32_t) 'A' )
98 	 && ( base64_character <= (uint32_t) 'I' ) )
99 	{
100 		safe_base64_sixtet = base64_character - (uint32_t) 'A';
101 	}
102 	else if( ( base64_character >= (uint32_t) 'J' )
103 	      && ( base64_character <= (uint32_t) 'R' ) )
104 	{
105 		safe_base64_sixtet = base64_character - (uint32_t) 'J' + 9;
106 	}
107 	else if( ( base64_character >= (uint32_t) 'S' )
108 	      && ( base64_character <= (uint32_t) 'Z' ) )
109 	{
110 		safe_base64_sixtet = base64_character - (uint32_t) 'S' + 18;
111 	}
112 	/* a-z is not a continous range on an EBCDIC based system
113 	 * it consists of the ranges: a-i, j-r, s-z
114 	 */
115 	else if( ( base64_character >= (uint32_t) 'a' )
116 	      && ( base64_character <= (uint32_t) 'i' ) )
117 	{
118 		safe_base64_sixtet = base64_character - (uint32_t) 'a' + 26;
119 	}
120 	else if( ( base64_character >= (uint32_t) 'j' )
121 	      && ( base64_character <= (uint32_t) 'r' ) )
122 	{
123 		safe_base64_sixtet = base64_character - (uint32_t) 'j' + 35;
124 	}
125 	else if( ( base64_character >= (uint32_t) 's' )
126 	      && ( base64_character <= (uint32_t) 'z' ) )
127 	{
128 		safe_base64_sixtet = base64_character - (uint32_t) 's' + 44;
129 	}
130 	else if( ( base64_character >= (uint32_t) '0' )
131 	      && ( base64_character <= (uint32_t) '9' ) )
132 	{
133 		safe_base64_sixtet = base64_character - (uint32_t) '0' + 52;
134 	}
135 	else if( base64_character == base64_character_62 )
136 	{
137 		safe_base64_sixtet = 62;
138 	}
139 	else if( base64_character == base64_character_63 )
140 	{
141 		safe_base64_sixtet = 63;
142 	}
143 	else
144 	{
145 		return( 0 );
146 	}
147 	*base64_sixtet = (uint8_t) ( safe_base64_sixtet & 0xff );
148 
149 	return( 1 );
150 }
151 
152 /* Copies a base64 triplet from a base64 stream
153  *
154  * The padding size will still be set to indicate the number of
155  * sixtets in the triplet
156  *
157  * Returns 1 if successful or -1 on error
158  */
libuna_base64_triplet_copy_from_base64_stream(uint32_t * base64_triplet,const uint8_t * base64_stream,size_t base64_stream_size,size_t * base64_stream_index,uint8_t * padding_size,uint32_t base64_variant,libcerror_error_t ** error)159 int libuna_base64_triplet_copy_from_base64_stream(
160      uint32_t *base64_triplet,
161      const uint8_t *base64_stream,
162      size_t base64_stream_size,
163      size_t *base64_stream_index,
164      uint8_t *padding_size,
165      uint32_t base64_variant,
166      libcerror_error_t **error )
167 {
168 	static char *function           = "libuna_base64_triplet_copy_from_base64_stream";
169 	size_t base64_character_size    = 0;
170 	size_t safe_base64_stream_index = 0;
171 	uint32_t base64_character       = 0;
172 	uint32_t safe_base64_triplet    = 0;
173 	uint8_t safe_padding_size       = 0;
174 	uint8_t sixtet1                 = 0;
175 	uint8_t sixtet2                 = 0;
176 	uint8_t sixtet3                 = 0;
177 	uint8_t sixtet4                 = 0;
178 	int result                      = 0;
179 
180 	if( base64_triplet == NULL )
181 	{
182 		libcerror_error_set(
183 		 error,
184 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
185 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
186 		 "%s: invalid base64 triplet.",
187 		 function );
188 
189 		return( -1 );
190 	}
191 	if( base64_stream == NULL )
192 	{
193 		libcerror_error_set(
194 		 error,
195 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
196 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
197 		 "%s: invalid base64 stream.",
198 		 function );
199 
200 		return( -1 );
201 	}
202 	if( base64_stream_size > (size_t) SSIZE_MAX )
203 	{
204 		libcerror_error_set(
205 		 error,
206 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
207 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
208 		 "%s: invalid base64 stream size value exceeds maximum.",
209 		 function );
210 
211 		return( -1 );
212 	}
213 	if( base64_stream_index == NULL )
214 	{
215 		libcerror_error_set(
216 		 error,
217 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
218 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
219 		 "%s: invalid base64 stream index.",
220 		 function );
221 
222 		return( -1 );
223 	}
224 	if( padding_size == NULL )
225 	{
226 		libcerror_error_set(
227 		 error,
228 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
229 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
230 		 "%s: invalid padding size.",
231 		 function );
232 
233 		return( -1 );
234 	}
235 	switch( base64_variant & 0x0f000000UL )
236 	{
237 		case LIBUNA_BASE64_VARIANT_PADDING_NONE:
238 		case LIBUNA_BASE64_VARIANT_PADDING_OPTIONAL:
239 		case LIBUNA_BASE64_VARIANT_PADDING_REQUIRED:
240 		case LIBUNA_BASE64_VARIANT_PADDING_INVALID:
241 			break;
242 
243 		default:
244 			libcerror_error_set(
245 			 error,
246 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
247 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
248 			 "%s: unsupported base64 variant.",
249 			 function );
250 
251 			return( -1 );
252 	}
253 	switch( base64_variant & 0xf0000000UL )
254 	{
255 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
256 			base64_character_size = 1;
257 			break;
258 
259 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
260 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
261 			base64_character_size = 2;
262 			break;
263 
264 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
265 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
266 			base64_character_size = 4;
267 			break;
268 
269 		default:
270 			libcerror_error_set(
271 			 error,
272 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
273 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
274 			 "%s: unsupported base64 variant.",
275 			 function );
276 
277 			return( -1 );
278 	}
279 	safe_base64_stream_index = *base64_stream_index;
280 
281 	if( ( base64_character_size > base64_stream_size )
282 	 || ( safe_base64_stream_index > ( base64_stream_size - base64_character_size ) ) )
283 	{
284 		libcerror_error_set(
285 		 error,
286 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
287 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
288 		 "%s: base64 stream string too small - missing 1st base64 character.",
289 		 function );
290 
291 		return( -1 );
292 	}
293 	switch( base64_variant & 0xf0000000UL )
294 	{
295 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
296 			base64_character = base64_stream[ safe_base64_stream_index ];
297 			break;
298 
299 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
300 			byte_stream_copy_to_uint16_big_endian(
301 			 &( base64_stream[ safe_base64_stream_index ] ),
302 			 base64_character );
303 			break;
304 
305 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
306 			byte_stream_copy_to_uint16_little_endian(
307 			 &( base64_stream[ safe_base64_stream_index ] ),
308 			 base64_character );
309 			break;
310 
311 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
312 			byte_stream_copy_to_uint32_big_endian(
313 			 &( base64_stream[ safe_base64_stream_index ] ),
314 			 base64_character );
315 			break;
316 
317 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
318 			byte_stream_copy_to_uint32_little_endian(
319 			 &( base64_stream[ safe_base64_stream_index ] ),
320 			 base64_character );
321 			break;
322 	}
323 	safe_base64_stream_index += base64_character_size;
324 
325 	result = libuna_base64_character_copy_to_sixtet(
326 	          base64_character,
327 	          &sixtet1,
328 	          base64_variant,
329 	          error );
330 
331 	if( result == -1 )
332 	{
333 		libcerror_error_set(
334 		 error,
335 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
336 		 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
337 		 "%s: unable to copy base64 character to 1st sixtet.",
338 		 function );
339 
340 		return( -1 );
341 	}
342 	else if( result == 0 )
343 	{
344 		libcerror_error_set(
345 		 error,
346 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
347 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
348 		 "%s: invalid 1st base64 character.",
349 		 function );
350 
351 		return( -1 );
352 	}
353 	if( ( base64_character_size > base64_stream_size )
354 	 || ( safe_base64_stream_index > ( base64_stream_size - base64_character_size ) ) )
355 	{
356 		libcerror_error_set(
357 		 error,
358 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
359 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
360 		 "%s: base64 stream string too small - missing 2nd base64 character.",
361 		 function );
362 
363 		return( -1 );
364 	}
365 	switch( base64_variant & 0xf0000000UL )
366 	{
367 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
368 			base64_character = base64_stream[ safe_base64_stream_index ];
369 			break;
370 
371 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
372 			byte_stream_copy_to_uint16_big_endian(
373 			 &( base64_stream[ safe_base64_stream_index ] ),
374 			 base64_character );
375 			break;
376 
377 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
378 			byte_stream_copy_to_uint16_little_endian(
379 			 &( base64_stream[ safe_base64_stream_index ] ),
380 			 base64_character );
381 			break;
382 
383 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
384 			byte_stream_copy_to_uint32_big_endian(
385 			 &( base64_stream[ safe_base64_stream_index ] ),
386 			 base64_character );
387 			break;
388 
389 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
390 			byte_stream_copy_to_uint32_little_endian(
391 			 &( base64_stream[ safe_base64_stream_index ] ),
392 			 base64_character );
393 			break;
394 	}
395 	safe_base64_stream_index += base64_character_size;
396 
397 	result = libuna_base64_character_copy_to_sixtet(
398 	          base64_character,
399 	          &sixtet2,
400 	          base64_variant,
401 	          error );
402 
403 	if( result == -1 )
404 	{
405 		libcerror_error_set(
406 		 error,
407 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
408 		 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
409 		 "%s: unable to copy base64 character to 2nd sixtet.",
410 		 function );
411 
412 		return( -1 );
413 	}
414 	else if( result == 0 )
415 	{
416 		libcerror_error_set(
417 		 error,
418 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
419 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
420 		 "%s: invalid 2nd base64 character.",
421 		 function );
422 
423 		return( -1 );
424 	}
425 	safe_padding_size = 2;
426 
427 	if( ( base64_character_size > base64_stream_size )
428 	 || ( safe_base64_stream_index > ( base64_stream_size - base64_character_size ) ) )
429 	{
430 		if( ( base64_variant & 0x0f000000UL ) == LIBUNA_BASE64_VARIANT_PADDING_REQUIRED )
431 		{
432 			libcerror_error_set(
433 			 error,
434 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
435 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
436 			 "%s: base64 stream string too small - missing 3rd base64 character.",
437 			 function );
438 
439 			return( -1 );
440 		}
441 	}
442 	else
443 	{
444 		switch( base64_variant & 0xf0000000UL )
445 		{
446 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
447 				base64_character = base64_stream[ safe_base64_stream_index ];
448 				break;
449 
450 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
451 				byte_stream_copy_to_uint16_big_endian(
452 				 &( base64_stream[ safe_base64_stream_index ] ),
453 				 base64_character );
454 				break;
455 
456 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
457 				byte_stream_copy_to_uint16_little_endian(
458 				 &( base64_stream[ safe_base64_stream_index ] ),
459 				 base64_character );
460 				break;
461 
462 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
463 				byte_stream_copy_to_uint32_big_endian(
464 				 &( base64_stream[ safe_base64_stream_index ] ),
465 				 base64_character );
466 				break;
467 
468 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
469 				byte_stream_copy_to_uint32_little_endian(
470 				 &( base64_stream[ safe_base64_stream_index ] ),
471 				 base64_character );
472 				break;
473 		}
474 		safe_base64_stream_index += base64_character_size;
475 
476 		if( ( base64_character & 0xffffff00UL ) != 0 )
477 		{
478 			libcerror_error_set(
479 			 error,
480 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
481 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
482 			 "%s: invalid 3rd base64 character.",
483 			 function );
484 
485 			return( -1 );
486 		}
487 		if( base64_character == (uint32_t) '=' )
488 		{
489 			if( ( base64_variant & 0x0f000000UL ) == LIBUNA_BASE64_VARIANT_PADDING_NONE )
490 			{
491 				libcerror_error_set(
492 				 error,
493 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
494 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
495 				 "%s: padding where not supposed to - invalid 3rd base64 character.",
496 				 function );
497 
498 				return( -1 );
499 			}
500 		}
501 		else
502 		{
503 			result = libuna_base64_character_copy_to_sixtet(
504 			          base64_character,
505 			          &sixtet3,
506 			          base64_variant,
507 			          error );
508 
509 			if( result == -1 )
510 			{
511 				libcerror_error_set(
512 				 error,
513 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
514 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
515 				 "%s: unable to copy base64 character to 3rd sixtet.",
516 				 function );
517 
518 				return( -1 );
519 			}
520 			else if( result == 0 )
521 			{
522 				if( ( base64_variant & 0x0f000000UL ) != LIBUNA_BASE64_VARIANT_PADDING_INVALID )
523 				{
524 					libcerror_error_set(
525 					 error,
526 					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
527 					 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
528 					 "%s: invalid 3rd base64 sixtet.",
529 					 function );
530 
531 					return( -1 );
532 				}
533 			}
534 			else
535 			{
536 				safe_padding_size -= 1;
537 			}
538 		}
539 	}
540 	if( ( base64_character_size > base64_stream_size )
541 	 || ( safe_base64_stream_index > ( base64_stream_size - base64_character_size ) ) )
542 	{
543 		if( ( base64_variant & 0x0f000000UL ) == LIBUNA_BASE64_VARIANT_PADDING_REQUIRED )
544 		{
545 			libcerror_error_set(
546 			 error,
547 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
548 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
549 			 "%s: base64 stream string too small - missing 4th base64 character.",
550 			 function );
551 
552 			return( -1 );
553 		}
554 	}
555 	else
556 	{
557 		switch( base64_variant & 0xf0000000UL )
558 		{
559 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
560 				base64_character = base64_stream[ safe_base64_stream_index ];
561 				break;
562 
563 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
564 				byte_stream_copy_to_uint16_big_endian(
565 				 &( base64_stream[ safe_base64_stream_index ] ),
566 				 base64_character );
567 				break;
568 
569 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
570 				byte_stream_copy_to_uint16_little_endian(
571 				 &( base64_stream[ safe_base64_stream_index ] ),
572 				 base64_character );
573 				break;
574 
575 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
576 				byte_stream_copy_to_uint32_big_endian(
577 				 &( base64_stream[ safe_base64_stream_index ] ),
578 				 base64_character );
579 				break;
580 
581 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
582 				byte_stream_copy_to_uint32_little_endian(
583 				 &( base64_stream[ safe_base64_stream_index ] ),
584 				 base64_character );
585 				break;
586 		}
587 		safe_base64_stream_index += base64_character_size;
588 
589 		if( ( base64_character & 0xffffff00UL ) != 0 )
590 		{
591 			libcerror_error_set(
592 			 error,
593 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
594 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
595 			 "%s: invalid 4th base64 character.",
596 			 function );
597 
598 			return( -1 );
599 		}
600 		if( base64_character == (uint32_t) '=' )
601 		{
602 			if( ( base64_variant & 0x0f000000UL ) == LIBUNA_BASE64_VARIANT_PADDING_NONE )
603 			{
604 				libcerror_error_set(
605 				 error,
606 				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
607 				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
608 				 "%s: padding where not supposed to - invalid 4th base64 character.",
609 				 function );
610 
611 				return( -1 );
612 			}
613 		}
614 		else
615 		{
616 			result = libuna_base64_character_copy_to_sixtet(
617 			          base64_character,
618 			          &sixtet4,
619 			          base64_variant,
620 			          error );
621 
622 			if( result == -1 )
623 			{
624 				libcerror_error_set(
625 				 error,
626 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
627 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
628 				 "%s: unable to copy base64 character to 4th sixtet.",
629 				 function );
630 
631 				return( -1 );
632 			}
633 			else if( result == 0 )
634 			{
635 				if( ( base64_variant & 0x0f000000UL ) != LIBUNA_BASE64_VARIANT_PADDING_INVALID )
636 				{
637 					libcerror_error_set(
638 					 error,
639 					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
640 					 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
641 					 "%s: invalid 4th base64 sixtet.",
642 					 function );
643 
644 					return( -1 );
645 				}
646 			}
647 			else
648 			{
649 				if( safe_padding_size > 1 )
650 				{
651 					libcerror_error_set(
652 					 error,
653 					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
654 					 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
655 					 "%s: non-padding where not supposed to - invalid 4th base64 character.",
656 					 function );
657 
658 					return( -1 );
659 				}
660 				safe_padding_size -= 1;
661 			}
662 		}
663 	}
664 	safe_base64_triplet   = sixtet1;
665 	safe_base64_triplet <<= 6;
666 	safe_base64_triplet  |= sixtet2;
667 	safe_base64_triplet <<= 6;
668 	safe_base64_triplet  |= sixtet3;
669 	safe_base64_triplet <<= 6;
670 	safe_base64_triplet  |= sixtet4;
671 
672 	*base64_triplet      = safe_base64_triplet;
673 	*base64_stream_index = safe_base64_stream_index;
674 	*padding_size        = safe_padding_size;
675 
676 	return( 1 );
677 }
678 
679 /* Copies a base64 triplet to a base64 stream
680  * Returns 1 if successful or -1 on error
681  */
libuna_base64_triplet_copy_to_base64_stream(uint32_t base64_triplet,uint8_t * base64_stream,size_t base64_stream_size,size_t * base64_stream_index,uint8_t padding_size,uint32_t base64_variant,libcerror_error_t ** error)682 int libuna_base64_triplet_copy_to_base64_stream(
683      uint32_t base64_triplet,
684      uint8_t *base64_stream,
685      size_t base64_stream_size,
686      size_t *base64_stream_index,
687      uint8_t padding_size,
688      uint32_t base64_variant,
689      libcerror_error_t **error )
690 {
691 	uint8_t *sixtet_to_character_table = NULL;
692 	static char *function              = "libuna_base64_triplet_copy_to_base64_stream";
693 	size_t base64_character_size       = 0;
694 	size_t safe_base64_stream_index    = 0;
695 	uint32_t base64_character          = 0;
696 	uint8_t padding_character          = 0;
697 	uint8_t sixtet1                    = 0;
698 	uint8_t sixtet2                    = 0;
699 	uint8_t sixtet3                    = 0;
700 	uint8_t sixtet4                    = 0;
701 
702 	if( base64_stream == NULL )
703 	{
704 		libcerror_error_set(
705 		 error,
706 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
707 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
708 		 "%s: invalid base64 stream.",
709 		 function );
710 
711 		return( -1 );
712 	}
713 	if( base64_stream_size > (size_t) SSIZE_MAX )
714 	{
715 		libcerror_error_set(
716 		 error,
717 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
718 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
719 		 "%s: invalid base64 stream size value exceeds maximum.",
720 		 function );
721 
722 		return( -1 );
723 	}
724 	if( base64_stream_index == NULL )
725 	{
726 		libcerror_error_set(
727 		 error,
728 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
729 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
730 		 "%s: invalid base64 stream index.",
731 		 function );
732 
733 		return( -1 );
734 	}
735 	if( *base64_stream_index >= base64_stream_size )
736 	{
737 		libcerror_error_set(
738 		 error,
739 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
740 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
741 		 "%s: base64 stream string too small.",
742 		 function );
743 
744 		return( -1 );
745 	}
746 	if( padding_size > 2 )
747 	{
748 		libcerror_error_set(
749 		 error,
750 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
751 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
752 		 "%s: invalid padding size value out of bounds.",
753 		 function );
754 
755 		return( -1 );
756 	}
757 	switch( base64_variant & 0x000f0000UL )
758 	{
759 		case LIBUNA_BASE64_VARIANT_ALPHABET_NORMAL:
760 			sixtet_to_character_table = libuna_base64_sixtet_to_character_table;
761 			break;
762 
763 		case LIBUNA_BASE64_VARIANT_ALPHABET_URL:
764 			sixtet_to_character_table = libuna_base64url_sixtet_to_character_table;
765 			break;
766 
767 		default:
768 			libcerror_error_set(
769 			 error,
770 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
771 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
772 			 "%s: unsupported base64 variant.",
773 			 function );
774 
775 			return( -1 );
776 	}
777 	switch( base64_variant & 0x0f000000UL )
778 	{
779 		case LIBUNA_BASE64_VARIANT_PADDING_NONE:
780 		case LIBUNA_BASE64_VARIANT_PADDING_OPTIONAL:
781 		case LIBUNA_BASE64_VARIANT_PADDING_INVALID:
782 			padding_character = 0;
783 			break;
784 
785 
786 		case LIBUNA_BASE64_VARIANT_PADDING_REQUIRED:
787 			padding_character = (uint8_t) '=';
788 			break;
789 
790 		default:
791 			libcerror_error_set(
792 			 error,
793 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
794 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
795 			 "%s: unsupported base64 variant.",
796 			 function );
797 
798 			return( -1 );
799 	}
800 	switch( base64_variant & 0xf0000000UL )
801 	{
802 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
803 			base64_character_size = 1;
804 			break;
805 
806 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
807 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
808 			base64_character_size = 2;
809 			break;
810 
811 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
812 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
813 			base64_character_size = 4;
814 			break;
815 
816 		default:
817 			libcerror_error_set(
818 			 error,
819 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
820 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
821 			 "%s: unsupported base64 variant.",
822 			 function );
823 
824 			return( -1 );
825 	}
826 	safe_base64_stream_index = *base64_stream_index;
827 
828 	/* Separate the 3 bytes value into 4 x 6 bit values
829 	 */
830 	sixtet4          = (uint8_t) ( base64_triplet & 0x3f );
831 	base64_triplet >>= 6;
832 	sixtet3          = (uint8_t) ( base64_triplet & 0x3f );
833 	base64_triplet >>= 6;
834 	sixtet2          = (uint8_t) ( base64_triplet & 0x3f );
835 	base64_triplet >>= 6;
836 	sixtet1          = (uint8_t) ( base64_triplet & 0x3f );
837 
838 	/* Spread the encoding over 2 characters if 1 byte is available
839 	 */
840 	if( ( safe_base64_stream_index + ( base64_character_size * 2 ) ) > base64_stream_size )
841 	{
842 		libcerror_error_set(
843 		 error,
844 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
845 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
846 		 "%s: base64 stream is too small.",
847 		 function );
848 
849 		return( -1 );
850 	}
851 	base64_character = sixtet_to_character_table[ sixtet1 ];
852 
853 	switch( base64_variant & 0xf0000000UL )
854 	{
855 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
856 			base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
857 			break;
858 
859 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
860 			byte_stream_copy_from_uint16_big_endian(
861 			 &( base64_stream[ safe_base64_stream_index ] ),
862 			 base64_character );
863 			break;
864 
865 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
866 			byte_stream_copy_from_uint16_little_endian(
867 			 &( base64_stream[ safe_base64_stream_index ] ),
868 			 base64_character );
869 			break;
870 
871 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
872 			byte_stream_copy_from_uint32_big_endian(
873 			 &( base64_stream[ safe_base64_stream_index ] ),
874 			 base64_character );
875 			break;
876 
877 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
878 			byte_stream_copy_from_uint32_little_endian(
879 			 &( base64_stream[ safe_base64_stream_index ] ),
880 			 base64_character );
881 			break;
882 	}
883 	safe_base64_stream_index += base64_character_size;
884 
885 	base64_character = sixtet_to_character_table[ sixtet2 ];
886 
887 	switch( base64_variant & 0xf0000000UL )
888 	{
889 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
890 			base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
891 			break;
892 
893 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
894 			byte_stream_copy_from_uint16_big_endian(
895 			 &( base64_stream[ safe_base64_stream_index ] ),
896 			 base64_character );
897 			break;
898 
899 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
900 			byte_stream_copy_from_uint16_little_endian(
901 			 &( base64_stream[ safe_base64_stream_index ] ),
902 			 base64_character );
903 			break;
904 
905 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
906 			byte_stream_copy_from_uint32_big_endian(
907 			 &( base64_stream[ safe_base64_stream_index ] ),
908 			 base64_character );
909 			break;
910 
911 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
912 			byte_stream_copy_from_uint32_little_endian(
913 			 &( base64_stream[ safe_base64_stream_index ] ),
914 			 base64_character );
915 			break;
916 	}
917 	safe_base64_stream_index += base64_character_size;
918 
919 	/* Spread the encoding over 3 characters if 2 bytes are available
920 	 * Otherwise pad the remaining bytes if required
921 	 */
922 	if( ( safe_base64_stream_index + base64_character_size ) > base64_stream_size )
923 	{
924 		libcerror_error_set(
925 		 error,
926 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
927 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
928 		 "%s: base64 stream is too small.",
929 		 function );
930 
931 		return( -1 );
932 	}
933 	if( ( padding_size < 2 )
934 	 || ( padding_character != 0 ) )
935 	{
936 		if( padding_size < 2 )
937 		{
938 			base64_character = sixtet_to_character_table[ sixtet3 ];
939 		}
940 		else if( padding_character != 0 )
941 		{
942 			base64_character = padding_character;
943 		}
944 		switch( base64_variant & 0xf0000000UL )
945 		{
946 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
947 				base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
948 				break;
949 
950 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
951 				byte_stream_copy_from_uint16_big_endian(
952 				 &( base64_stream[ safe_base64_stream_index ] ),
953 				 base64_character );
954 				break;
955 
956 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
957 				byte_stream_copy_from_uint16_little_endian(
958 				 &( base64_stream[ safe_base64_stream_index ] ),
959 				 base64_character );
960 				break;
961 
962 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
963 				byte_stream_copy_from_uint32_big_endian(
964 				 &( base64_stream[ safe_base64_stream_index ] ),
965 				 base64_character );
966 				break;
967 
968 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
969 				byte_stream_copy_from_uint32_little_endian(
970 				 &( base64_stream[ safe_base64_stream_index ] ),
971 				 base64_character );
972 				break;
973 		}
974 		safe_base64_stream_index += base64_character_size;
975 	}
976 	/* Spread the encoding over 4 characters if 3 bytes are available
977 	 * Otherwise pad the remaining bytes if required
978 	 */
979 	if( ( safe_base64_stream_index + base64_character_size ) > base64_stream_size )
980 	{
981 		libcerror_error_set(
982 		 error,
983 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
984 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
985 		 "%s: base64 stream is too small.",
986 		 function );
987 
988 		return( -1 );
989 	}
990 	if( ( padding_size < 1 )
991 	 || ( padding_character != 0 ) )
992 	{
993 		if( padding_size < 1 )
994 		{
995 			base64_character = sixtet_to_character_table[ sixtet4 ];
996 		}
997 		else if( padding_character != 0 )
998 		{
999 			base64_character = padding_character;
1000 		}
1001 		switch( base64_variant & 0xf0000000UL )
1002 		{
1003 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1004 				base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
1005 				break;
1006 
1007 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1008 				byte_stream_copy_from_uint16_big_endian(
1009 				 &( base64_stream[ safe_base64_stream_index ] ),
1010 				 base64_character );
1011 				break;
1012 
1013 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1014 				byte_stream_copy_from_uint16_little_endian(
1015 				 &( base64_stream[ safe_base64_stream_index ] ),
1016 				 base64_character );
1017 				break;
1018 
1019 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1020 				byte_stream_copy_from_uint32_big_endian(
1021 				 &( base64_stream[ safe_base64_stream_index ] ),
1022 				 base64_character );
1023 				break;
1024 
1025 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1026 				byte_stream_copy_from_uint32_little_endian(
1027 				 &( base64_stream[ safe_base64_stream_index ] ),
1028 				 base64_character );
1029 				break;
1030 		}
1031 		safe_base64_stream_index += base64_character_size;
1032 	}
1033 	*base64_stream_index = safe_base64_stream_index;
1034 
1035 	return( 1 );
1036 }
1037 
1038 /* Copies a base64 triplet from a byte stream
1039  * Returns 1 if successful or -1 on error
1040  */
libuna_base64_triplet_copy_from_byte_stream(uint32_t * base64_triplet,const uint8_t * byte_stream,size_t byte_stream_size,size_t * byte_stream_index,uint8_t * padding_size,libcerror_error_t ** error)1041 int libuna_base64_triplet_copy_from_byte_stream(
1042      uint32_t *base64_triplet,
1043      const uint8_t *byte_stream,
1044      size_t byte_stream_size,
1045      size_t *byte_stream_index,
1046      uint8_t *padding_size,
1047      libcerror_error_t **error )
1048 {
1049 	static char *function         = "libuna_base64_triplet_copy_from_byte_stream";
1050 	size_t safe_byte_stream_index = 0;
1051 	uint32_t safe_base64_triplet  = 0;
1052 	uint8_t safe_padding_size     = 0;
1053 
1054 	if( base64_triplet == NULL )
1055 	{
1056 		libcerror_error_set(
1057 		 error,
1058 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1059 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1060 		 "%s: invalid base64 triplet.",
1061 		 function );
1062 
1063 		return( -1 );
1064 	}
1065 	if( byte_stream == NULL )
1066 	{
1067 		libcerror_error_set(
1068 		 error,
1069 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1070 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1071 		 "%s: invalid byte stream.",
1072 		 function );
1073 
1074 		return( -1 );
1075 	}
1076 	if( byte_stream_size > (size_t) SSIZE_MAX )
1077 	{
1078 		libcerror_error_set(
1079 		 error,
1080 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1081 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1082 		 "%s: invalid byte stream size value exceeds maximum.",
1083 		 function );
1084 
1085 		return( -1 );
1086 	}
1087 	if( byte_stream_index == NULL )
1088 	{
1089 		libcerror_error_set(
1090 		 error,
1091 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1092 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1093 		 "%s: invalid byte stream index.",
1094 		 function );
1095 
1096 		return( -1 );
1097 	}
1098 	if( *byte_stream_index >= byte_stream_size )
1099 	{
1100 		libcerror_error_set(
1101 		 error,
1102 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1103 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1104 		 "%s: byte stream string too small.",
1105 		 function );
1106 
1107 		return( -1 );
1108 	}
1109 	if( padding_size == NULL )
1110 	{
1111 		libcerror_error_set(
1112 		 error,
1113 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1114 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1115 		 "%s: invalid padding size.",
1116 		 function );
1117 
1118 		return( -1 );
1119 	}
1120 	safe_byte_stream_index = *byte_stream_index;
1121 
1122 	/* Determine the value of 3 bytes (24 bits)
1123 	 */
1124 	safe_base64_triplet = byte_stream[ safe_byte_stream_index++ ];
1125 	safe_padding_size   = 2;
1126 
1127 	safe_base64_triplet <<= 8;
1128 
1129 	if( safe_byte_stream_index < byte_stream_size )
1130 	{
1131 		safe_base64_triplet |= byte_stream[ safe_byte_stream_index++ ];
1132 		safe_padding_size   -= 1;
1133 	}
1134 	safe_base64_triplet <<= 8;
1135 
1136 	if( safe_byte_stream_index < byte_stream_size )
1137 	{
1138 		safe_base64_triplet |= byte_stream[ safe_byte_stream_index++ ];
1139 		safe_padding_size   -= 1;
1140 	}
1141 	*base64_triplet    = safe_base64_triplet;
1142 	*byte_stream_index = safe_byte_stream_index;
1143 	*padding_size      = safe_padding_size;
1144 
1145 	return( 1 );
1146 }
1147 
1148 /* Copies a base64 triplet to a byte stream
1149  * Returns 1 if successful or -1 on error
1150  */
libuna_base64_triplet_copy_to_byte_stream(uint32_t base64_triplet,uint8_t * byte_stream,size_t byte_stream_size,size_t * byte_stream_index,uint8_t padding_size,libcerror_error_t ** error)1151 int libuna_base64_triplet_copy_to_byte_stream(
1152      uint32_t base64_triplet,
1153      uint8_t *byte_stream,
1154      size_t byte_stream_size,
1155      size_t *byte_stream_index,
1156      uint8_t padding_size,
1157      libcerror_error_t **error )
1158 {
1159 	static char *function         = "libuna_base64_triplet_copy_to_byte_stream";
1160 	size_t safe_byte_stream_index = 0;
1161 
1162 	if( byte_stream == NULL )
1163 	{
1164 		libcerror_error_set(
1165 		 error,
1166 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1167 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1168 		 "%s: invalid byte stream.",
1169 		 function );
1170 
1171 		return( -1 );
1172 	}
1173 	if( byte_stream_size > (size_t) SSIZE_MAX )
1174 	{
1175 		libcerror_error_set(
1176 		 error,
1177 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1178 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1179 		 "%s: invalid byte stream size value exceeds maximum.",
1180 		 function );
1181 
1182 		return( -1 );
1183 	}
1184 	if( byte_stream_index == NULL )
1185 	{
1186 		libcerror_error_set(
1187 		 error,
1188 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1189 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1190 		 "%s: invalid byte stream index.",
1191 		 function );
1192 
1193 		return( -1 );
1194 	}
1195 	if( *byte_stream_index >= byte_stream_size )
1196 	{
1197 		libcerror_error_set(
1198 		 error,
1199 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1200 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1201 		 "%s: byte stream string too small.",
1202 		 function );
1203 
1204 		return( -1 );
1205 	}
1206 	if( padding_size > 2 )
1207 	{
1208 		libcerror_error_set(
1209 		 error,
1210 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1211 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1212 		 "%s: invalid padding size value out of bounds.",
1213 		 function );
1214 
1215 		return( -1 );
1216 	}
1217 	safe_byte_stream_index = *byte_stream_index;
1218 
1219 	byte_stream[ safe_byte_stream_index++ ] = (uint8_t) ( ( base64_triplet >> 16 ) & 0xff );
1220 
1221 	if( padding_size <= 1 )
1222 	{
1223 		if( safe_byte_stream_index >= byte_stream_size )
1224 		{
1225 			libcerror_error_set(
1226 			 error,
1227 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1228 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1229 			 "%s: byte stream string too small.",
1230 			 function );
1231 
1232 			return( -1 );
1233 		}
1234 		byte_stream[ safe_byte_stream_index++ ] = (uint8_t) ( ( base64_triplet >> 8 ) & 0xff );
1235 	}
1236 	if( padding_size == 0 )
1237 	{
1238 		if( safe_byte_stream_index >= byte_stream_size )
1239 		{
1240 			libcerror_error_set(
1241 			 error,
1242 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1243 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1244 			 "%s: byte stream is too small.",
1245 			 function );
1246 
1247 			return( -1 );
1248 		}
1249 		byte_stream[ safe_byte_stream_index++ ] = (uint8_t) ( base64_triplet & 0xff );
1250 	}
1251 	*byte_stream_index = safe_byte_stream_index;
1252 
1253 	return( 1 );
1254 }
1255 
1256 /* Determines the size of a byte stream from a base64 stream
1257  *
1258  * LIBUNA_BASE64_FLAG_STRIP_WHITESPACE removes leading space and tab characters,
1259  * and trailing space, tab and end of line characters
1260  *
1261  * Returns 1 if successful or -1 on error
1262  */
libuna_base64_stream_size_to_byte_stream(const uint8_t * base64_stream,size_t base64_stream_size,size_t * byte_stream_size,uint32_t base64_variant,uint8_t flags,libcerror_error_t ** error)1263 int libuna_base64_stream_size_to_byte_stream(
1264      const uint8_t *base64_stream,
1265      size_t base64_stream_size,
1266      size_t *byte_stream_size,
1267      uint32_t base64_variant,
1268      uint8_t flags,
1269      libcerror_error_t **error )
1270 {
1271 	static char *function        = "libuna_base64_stream_size_to_byte_stream";
1272 	size_t base64_character_size = 0;
1273 	size_t base64_stream_index   = 0;
1274 	size_t number_of_characters  = 0;
1275 	size_t safe_byte_stream_size = 0;
1276 	size_t whitespace_size       = 0;
1277 	uint32_t base64_character1   = 0;
1278 	uint32_t base64_character2   = 0;
1279 	uint8_t base64_character_62  = 0;
1280 	uint8_t base64_character_63  = 0;
1281 	uint8_t character_limit      = 0;
1282 	uint8_t padding_size         = 0;
1283 	uint8_t strip_mode           = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
1284 
1285 	if( base64_stream == NULL )
1286 	{
1287 		libcerror_error_set(
1288 		 error,
1289 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1290 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1291 		 "%s: invalid base64 stream.",
1292 		 function );
1293 
1294 		return( -1 );
1295 	}
1296 	if( ( base64_stream_size == 0 )
1297 	 || ( base64_stream_size > (size_t) SSIZE_MAX ) )
1298 	{
1299 		libcerror_error_set(
1300 		 error,
1301 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1302 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
1303 		 "%s: invalid base64 stream size value out of bounds.",
1304 		 function );
1305 
1306 		return( -1 );
1307 	}
1308 	if( byte_stream_size == NULL )
1309 	{
1310 		libcerror_error_set(
1311 		 error,
1312 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1313 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1314 		 "%s: invalid byte stream size.",
1315 		 function );
1316 
1317 		return( -1 );
1318 	}
1319 	switch( base64_variant & 0x000000ffUL )
1320 	{
1321 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_NONE:
1322 			character_limit = 0;
1323 
1324 			break;
1325 
1326 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_64:
1327 			character_limit = 64;
1328 
1329 			break;
1330 
1331 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_76:
1332 			character_limit = 76;
1333 
1334 			break;
1335 
1336 		default:
1337 			libcerror_error_set(
1338 			 error,
1339 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1340 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1341 			 "%s: unsupported base64 variant.",
1342 			 function );
1343 
1344 			return( -1 );
1345 	}
1346 	switch( base64_variant & 0x000f0000UL )
1347 	{
1348 		case LIBUNA_BASE64_VARIANT_ALPHABET_NORMAL:
1349 			base64_character_62 = (uint8_t) '+';
1350 			base64_character_63 = (uint8_t) '/';
1351 			break;
1352 
1353 		case LIBUNA_BASE64_VARIANT_ALPHABET_URL:
1354 			base64_character_62 = (uint8_t) '-';
1355 			base64_character_63 = (uint8_t) '_';
1356 			break;
1357 
1358 		default:
1359 			libcerror_error_set(
1360 			 error,
1361 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1362 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1363 			 "%s: unsupported base64 variant.",
1364 			 function );
1365 
1366 			return( -1 );
1367 	}
1368 	switch( base64_variant & 0xf0000000UL )
1369 	{
1370 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1371 			base64_character_size = 1;
1372 			break;
1373 
1374 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1375 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1376 			base64_character_size = 2;
1377 			break;
1378 
1379 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1380 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1381 			base64_character_size = 4;
1382 			break;
1383 
1384 		default:
1385 			libcerror_error_set(
1386 			 error,
1387 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1388 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1389 			 "%s: unsupported base64 variant.",
1390 			 function );
1391 
1392 			return( -1 );
1393 	}
1394 	if( base64_stream_size < base64_character_size )
1395 	{
1396 		libcerror_error_set(
1397 		 error,
1398 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1399 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1400 		 "%s: invalid base64 stream value too small.",
1401 		 function );
1402 
1403 		return( -1 );
1404 	}
1405 	if( ( flags & ~( LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) ) != 0 )
1406 	{
1407 		libcerror_error_set(
1408 		 error,
1409 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1410 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1411 		 "%s: unsupported flags.",
1412 		 function );
1413 
1414 		return( -1 );
1415 	}
1416 	base64_stream_index = base64_stream_size - base64_character_size;
1417 	whitespace_size     = 0;
1418 
1419 	while( base64_stream_index > base64_character_size )
1420 	{
1421 		switch( base64_variant & 0xf0000000UL )
1422 		{
1423 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1424 				base64_character1 = base64_stream[ base64_stream_index ];
1425 				break;
1426 
1427 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1428 				byte_stream_copy_to_uint16_big_endian(
1429 				 &( base64_stream[ base64_stream_index ] ),
1430 				 base64_character1 );
1431 				break;
1432 
1433 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1434 				byte_stream_copy_to_uint16_little_endian(
1435 				 &( base64_stream[ base64_stream_index ] ),
1436 				 base64_character1 );
1437 				break;
1438 
1439 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1440 				byte_stream_copy_to_uint32_big_endian(
1441 				 &( base64_stream[ base64_stream_index ] ),
1442 				 base64_character1 );
1443 				break;
1444 
1445 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1446 				byte_stream_copy_to_uint32_little_endian(
1447 				 &( base64_stream[ base64_stream_index ] ),
1448 				 base64_character1 );
1449 				break;
1450 		}
1451 		base64_stream_index -= base64_character_size;
1452 
1453 		if( ( base64_character1 == (uint32_t) '\n' )
1454 		 || ( base64_character1 == (uint32_t) '\r' ) )
1455 		{
1456 			whitespace_size += base64_character_size;
1457 		}
1458 		else if( ( flags & LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) == 0 )
1459 		{
1460 			break;
1461 		}
1462 		else if( ( base64_character1 == (uint32_t) ' ' )
1463 		      || ( base64_character1 == (uint32_t) '\t' )
1464 		      || ( base64_character1 == (uint32_t) '\v' ) )
1465 		{
1466 			whitespace_size += base64_character_size;
1467 		}
1468 		else
1469 		{
1470 			break;
1471 		}
1472 	}
1473 	base64_stream_size -= whitespace_size;
1474 	base64_stream_index = base64_stream_size - base64_character_size;
1475 
1476 	if( base64_stream_size < base64_character_size )
1477 	{
1478 		libcerror_error_set(
1479 		 error,
1480 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1481 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1482 		 "%s: invalid base64 stream value too small.",
1483 		 function );
1484 
1485 		return( -1 );
1486 	}
1487 	if( base64_stream_index > base64_character_size )
1488 	{
1489 		switch( base64_variant & 0xf0000000UL )
1490 		{
1491 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1492 				base64_character1 = base64_stream[ base64_stream_index ];
1493 				break;
1494 
1495 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1496 				byte_stream_copy_to_uint16_big_endian(
1497 				 &( base64_stream[ base64_stream_index ] ),
1498 				 base64_character1 );
1499 				break;
1500 
1501 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1502 				byte_stream_copy_to_uint16_little_endian(
1503 				 &( base64_stream[ base64_stream_index ] ),
1504 				 base64_character1 );
1505 				break;
1506 
1507 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1508 				byte_stream_copy_to_uint32_big_endian(
1509 				 &( base64_stream[ base64_stream_index ] ),
1510 				 base64_character1 );
1511 				break;
1512 
1513 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1514 				byte_stream_copy_to_uint32_little_endian(
1515 				 &( base64_stream[ base64_stream_index ] ),
1516 				 base64_character1 );
1517 				break;
1518 		}
1519 		base64_stream_index -= base64_character_size;
1520 
1521 		if( base64_character1 == (uint32_t) '=' )
1522 		{
1523 			padding_size += 1;
1524 		}
1525 	}
1526 	if( base64_stream_index > base64_character_size )
1527 	{
1528 		switch( base64_variant & 0xf0000000UL )
1529 		{
1530 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1531 				base64_character1 = base64_stream[ base64_stream_index ];
1532 				break;
1533 
1534 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1535 				byte_stream_copy_to_uint16_big_endian(
1536 				 &( base64_stream[ base64_stream_index ] ),
1537 				 base64_character1 );
1538 				break;
1539 
1540 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1541 				byte_stream_copy_to_uint16_little_endian(
1542 				 &( base64_stream[ base64_stream_index ] ),
1543 				 base64_character1 );
1544 				break;
1545 
1546 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1547 				byte_stream_copy_to_uint32_big_endian(
1548 				 &( base64_stream[ base64_stream_index ] ),
1549 				 base64_character1 );
1550 				break;
1551 
1552 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1553 				byte_stream_copy_to_uint32_little_endian(
1554 				 &( base64_stream[ base64_stream_index ] ),
1555 				 base64_character1 );
1556 				break;
1557 		}
1558 		base64_stream_index -= base64_character_size;
1559 
1560 		if( base64_character1 == (uint32_t) '=' )
1561 		{
1562 			padding_size += 1;
1563 		}
1564 	}
1565 	if( base64_stream_index > base64_character_size )
1566 	{
1567 		switch( base64_variant & 0xf0000000UL )
1568 		{
1569 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1570 				base64_character1 = base64_stream[ base64_stream_index ];
1571 				break;
1572 
1573 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1574 				byte_stream_copy_to_uint16_big_endian(
1575 				 &( base64_stream[ base64_stream_index ] ),
1576 				 base64_character1 );
1577 				break;
1578 
1579 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1580 				byte_stream_copy_to_uint16_little_endian(
1581 				 &( base64_stream[ base64_stream_index ] ),
1582 				 base64_character1 );
1583 				break;
1584 
1585 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1586 				byte_stream_copy_to_uint32_big_endian(
1587 				 &( base64_stream[ base64_stream_index ] ),
1588 				 base64_character1 );
1589 				break;
1590 
1591 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1592 				byte_stream_copy_to_uint32_little_endian(
1593 				 &( base64_stream[ base64_stream_index ] ),
1594 				 base64_character1 );
1595 				break;
1596 		}
1597 		if( base64_character1 == (uint32_t) '=' )
1598 		{
1599 			libcerror_error_set(
1600 			 error,
1601 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
1602 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
1603 			 "%s: invalid number of padding bytes.",
1604 			 function );
1605 
1606 			return( -1 );
1607 		}
1608 	}
1609 	base64_stream_index = 0;
1610 	whitespace_size     = 0;
1611 
1612 	while( base64_stream_index < ( base64_stream_size - ( padding_size * base64_character_size ) ) )
1613 	{
1614 		switch( base64_variant & 0xf0000000UL )
1615 		{
1616 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1617 				base64_character1 = base64_stream[ base64_stream_index ];
1618 				break;
1619 
1620 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1621 				byte_stream_copy_to_uint16_big_endian(
1622 				 &( base64_stream[ base64_stream_index ] ),
1623 				 base64_character1 );
1624 				break;
1625 
1626 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1627 				byte_stream_copy_to_uint16_little_endian(
1628 				 &( base64_stream[ base64_stream_index ] ),
1629 				 base64_character1 );
1630 				break;
1631 
1632 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1633 				byte_stream_copy_to_uint32_big_endian(
1634 				 &( base64_stream[ base64_stream_index ] ),
1635 				 base64_character1 );
1636 				break;
1637 
1638 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1639 				byte_stream_copy_to_uint32_little_endian(
1640 				 &( base64_stream[ base64_stream_index ] ),
1641 				 base64_character1 );
1642 				break;
1643 		}
1644 		base64_stream_index += base64_character_size;
1645 
1646 		if( ( base64_character1 == (uint32_t) '\n' )
1647 		 || ( base64_character1 == (uint32_t) '\r' ) )
1648 		{
1649 			if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE )
1650 			 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
1651 			{
1652 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
1653 			}
1654 			else
1655 			{
1656 				if( ( base64_stream_index + base64_character_size ) < base64_stream_size )
1657 				{
1658 					switch( base64_variant & 0xf0000000UL )
1659 					{
1660 						case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1661 							base64_character2 = base64_stream[ base64_stream_index ];
1662 							break;
1663 
1664 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1665 							byte_stream_copy_to_uint16_big_endian(
1666 							 &( base64_stream[ base64_stream_index ] ),
1667 							 base64_character2 );
1668 							break;
1669 
1670 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1671 							byte_stream_copy_to_uint16_little_endian(
1672 							 &( base64_stream[ base64_stream_index ] ),
1673 							 base64_character2 );
1674 							break;
1675 
1676 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1677 							byte_stream_copy_to_uint32_big_endian(
1678 							 &( base64_stream[ base64_stream_index ] ),
1679 							 base64_character2 );
1680 							break;
1681 
1682 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1683 							byte_stream_copy_to_uint32_little_endian(
1684 							 &( base64_stream[ base64_stream_index ] ),
1685 							 base64_character2 );
1686 							break;
1687 					}
1688 					if( ( base64_character2 == (uint32_t) '\n' )
1689 					 || ( base64_character2 == (uint32_t) '\r' ) )
1690 					{
1691 						base64_stream_index += base64_character_size;
1692 
1693 						whitespace_size += base64_character_size;
1694 					}
1695 				}
1696 				strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
1697 			}
1698 			if( ( number_of_characters != 0 )
1699 			 && ( character_limit != 0 ) )
1700 			{
1701 				if( number_of_characters != (size_t) character_limit )
1702 				{
1703 					libcerror_error_set(
1704 					 error,
1705 					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
1706 					 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
1707 					 "%s: number of characters in line does not match character limit.",
1708 					 function );
1709 
1710 					return( -1 );
1711 				}
1712 				number_of_characters = 0;
1713 			}
1714 			whitespace_size += base64_character_size;
1715 		}
1716 		else if( ( base64_character1 == (uint32_t) ' ' )
1717 		      || ( base64_character1 == (uint32_t) '\t' )
1718 		      || ( base64_character1 == (uint32_t) '\v' ) )
1719 		{
1720 			if( ( flags & LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) != 0 )
1721 			{
1722 				if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
1723 				{
1724 					strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE;
1725 				}
1726 				if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
1727 				 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
1728 				{
1729 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
1730 				}
1731 				else
1732 				{
1733 					whitespace_size += base64_character_size;
1734 				}
1735 			}
1736 			else
1737 			{
1738 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
1739 			}
1740 		}
1741 		else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
1742 		{
1743 			strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
1744 		}
1745 		else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE )
1746 		{
1747 			strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
1748 		}
1749 		if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
1750 		{
1751 			/* A-Z is not a continous range on an EBCDIC based system
1752 			 * it consists of the ranges: A-I, J-R, S-Z
1753 			 */
1754 			if( ( base64_character1 >= (uint32_t) 'A' )
1755 			 && ( base64_character1 <= (uint32_t) 'I' ) )
1756 			{
1757 				number_of_characters++;
1758 			}
1759 			else if( ( base64_character1 >= (uint32_t) 'J' )
1760 			      && ( base64_character1 <= (uint32_t) 'R' ) )
1761 			{
1762 				number_of_characters++;
1763 			}
1764 			else if( ( base64_character1 >= (uint32_t) 'S' )
1765 			      && ( base64_character1 <= (uint32_t) 'Z' ) )
1766 			{
1767 				number_of_characters++;
1768 			}
1769 			/* a-z is not a continous range on an EBCDIC based system
1770 			 * it consists of the ranges: a-i, j-r, s-z
1771 			 */
1772 			else if( ( base64_character1 >= (uint32_t) 'a' )
1773 			      && ( base64_character1 <= (uint32_t) 'i' ) )
1774 			{
1775 				number_of_characters++;
1776 			}
1777 			else if( ( base64_character1 >= (uint32_t) 'j' )
1778 			      && ( base64_character1 <= (uint32_t) 'r' ) )
1779 			{
1780 				number_of_characters++;
1781 			}
1782 			else if( ( base64_character1 >= (uint32_t) 's' )
1783 			      && ( base64_character1 <= (uint32_t) 'z' ) )
1784 			{
1785 				number_of_characters++;
1786 			}
1787 			else if( ( base64_character1 >= (uint32_t) '0' )
1788 			      && ( base64_character1 <= (uint32_t) '9' ) )
1789 			{
1790 				number_of_characters++;
1791 			}
1792 			else if( ( base64_character1 == (uint32_t) base64_character_62 )
1793 			      || ( base64_character1 == (uint32_t) base64_character_63 ) )
1794 			{
1795 				number_of_characters++;
1796 			}
1797 			else
1798 			{
1799 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
1800 			}
1801 		}
1802 		if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
1803 		{
1804 			libcerror_error_set(
1805 			 error,
1806 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
1807 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
1808 			 "%s: invalid character in base64 stream at index: %" PRIzd ".",
1809 			 function,
1810 			 base64_stream_index - base64_character_size );
1811 
1812 			return( -1 );
1813 		}
1814 	}
1815 	if( character_limit != 0 )
1816 	{
1817 		if( number_of_characters > (size_t) character_limit )
1818 		{
1819 			libcerror_error_set(
1820 			 error,
1821 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
1822 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
1823 			 "%s: number of characters in last line exceed maximum.",
1824 			 function );
1825 
1826 			return( -1 );
1827 		}
1828 	}
1829 	base64_stream_size -= whitespace_size;
1830 
1831 	/* Make sure the byte stream is able to hold
1832 	 * at least 3 bytes for each 4 base64 characters
1833 	 */
1834 	base64_character_size *= 4;
1835 
1836 	safe_byte_stream_size = base64_stream_size / base64_character_size;
1837 
1838 	if( ( base64_stream_size % base64_character_size ) != 0 )
1839 	{
1840 		safe_byte_stream_size += 1;
1841 	}
1842 	safe_byte_stream_size *= 3;
1843 
1844 	/* The padding size contains the number of bytes to correct
1845 	 */
1846 	*byte_stream_size = safe_byte_stream_size - padding_size;
1847 
1848 	return( 1 );
1849 }
1850 
1851 /* Copies a byte stream from a base64 stream
1852  *
1853  * LIBUNA_BASE64_FLAG_STRIP_WHITESPACE removes leading space and tab characters,
1854  * and trailing space, tab and end of line characters
1855  *
1856  * Returns 1 if successful or -1 on error
1857  */
libuna_base64_stream_copy_to_byte_stream(const uint8_t * base64_stream,size_t base64_stream_size,uint8_t * byte_stream,size_t byte_stream_size,uint32_t base64_variant,uint8_t flags,libcerror_error_t ** error)1858 int libuna_base64_stream_copy_to_byte_stream(
1859      const uint8_t *base64_stream,
1860      size_t base64_stream_size,
1861      uint8_t *byte_stream,
1862      size_t byte_stream_size,
1863      uint32_t base64_variant,
1864      uint8_t flags,
1865      libcerror_error_t **error )
1866 {
1867 	static char *function        = "libuna_base64_stream_copy_to_byte_stream";
1868 	size_t base64_character_size = 0;
1869 	size_t base64_stream_index   = 0;
1870 	size_t byte_stream_index     = 0;
1871 	size_t number_of_characters  = 0;
1872 	size_t whitespace_size       = 0;
1873 	uint32_t base64_character1   = 0;
1874 	uint32_t base64_character2   = 0;
1875 	uint32_t base64_triplet      = 0;
1876 	uint8_t character_limit      = 0;
1877 	uint8_t padding_size         = 0;
1878 	uint8_t strip_mode           = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
1879 
1880 	if( base64_stream == NULL )
1881 	{
1882 		libcerror_error_set(
1883 		 error,
1884 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1885 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1886 		 "%s: invalid base64 stream.",
1887 		 function );
1888 
1889 		return( -1 );
1890 	}
1891 	if( base64_stream_size > (size_t) SSIZE_MAX )
1892 	{
1893 		libcerror_error_set(
1894 		 error,
1895 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1896 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1897 		 "%s: invalid base64 stream size value exceeds maximum.",
1898 		 function );
1899 
1900 		return( -1 );
1901 	}
1902 	if( byte_stream == NULL )
1903 	{
1904 		libcerror_error_set(
1905 		 error,
1906 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1907 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1908 		 "%s: invalid byte stream.",
1909 		 function );
1910 
1911 		return( -1 );
1912 	}
1913 	if( byte_stream_size > (size_t) SSIZE_MAX )
1914 	{
1915 		libcerror_error_set(
1916 		 error,
1917 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1918 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1919 		 "%s: invalid byte stream size value exceeds maximum.",
1920 		 function );
1921 
1922 		return( -1 );
1923 	}
1924 	switch( base64_variant & 0x000000ffUL )
1925 	{
1926 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_NONE:
1927 			character_limit = 0;
1928 
1929 			break;
1930 
1931 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_64:
1932 			character_limit = 64;
1933 
1934 			break;
1935 
1936 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_76:
1937 			character_limit = 76;
1938 
1939 			break;
1940 
1941 		default:
1942 			libcerror_error_set(
1943 			 error,
1944 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1945 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1946 			 "%s: unsupported base64 variant.",
1947 			 function );
1948 
1949 			return( -1 );
1950 	}
1951 	switch( base64_variant & 0xf0000000UL )
1952 	{
1953 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
1954 			base64_character_size = 1;
1955 			break;
1956 
1957 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1958 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1959 			base64_character_size = 2;
1960 			break;
1961 
1962 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1963 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1964 			base64_character_size = 4;
1965 			break;
1966 
1967 		default:
1968 			libcerror_error_set(
1969 			 error,
1970 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1971 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1972 			 "%s: unsupported base64 variant.",
1973 			 function );
1974 
1975 			return( -1 );
1976 	}
1977 	if( base64_stream_size < base64_character_size )
1978 	{
1979 		libcerror_error_set(
1980 		 error,
1981 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1982 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1983 		 "%s: invalid base64 stream value too small.",
1984 		 function );
1985 
1986 		return( -1 );
1987 	}
1988 	if( ( flags & ~( LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) ) != 0 )
1989 	{
1990 		libcerror_error_set(
1991 		 error,
1992 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1993 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1994 		 "%s: unsupported flags.",
1995 		 function );
1996 
1997 		return( -1 );
1998 	}
1999 	base64_stream_index = base64_stream_size - base64_character_size;
2000 	whitespace_size     = 0;
2001 
2002 	while( base64_stream_index > base64_character_size )
2003 	{
2004 		switch( base64_variant & 0xf0000000UL )
2005 		{
2006 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2007 				base64_character1 = base64_stream[ base64_stream_index ];
2008 				break;
2009 
2010 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2011 				byte_stream_copy_to_uint16_big_endian(
2012 				 &( base64_stream[ base64_stream_index ] ),
2013 				 base64_character1 );
2014 				break;
2015 
2016 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2017 				byte_stream_copy_to_uint16_little_endian(
2018 				 &( base64_stream[ base64_stream_index ] ),
2019 				 base64_character1 );
2020 				break;
2021 
2022 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2023 				byte_stream_copy_to_uint32_big_endian(
2024 				 &( base64_stream[ base64_stream_index ] ),
2025 				 base64_character1 );
2026 				break;
2027 
2028 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2029 				byte_stream_copy_to_uint32_little_endian(
2030 				 &( base64_stream[ base64_stream_index ] ),
2031 				 base64_character1 );
2032 				break;
2033 		}
2034 		base64_stream_index -= base64_character_size;
2035 
2036 		if( ( base64_character1 == (uint32_t) '\n' )
2037 		 || ( base64_character1 == (uint32_t) '\r' ) )
2038 		{
2039 			whitespace_size += base64_character_size;
2040 		}
2041 		else if( ( flags & LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) == 0 )
2042 		{
2043 			break;
2044 		}
2045 		else if( ( base64_character1 == (uint32_t) ' ' )
2046 		      || ( base64_character1 == (uint32_t) '\t' )
2047 		      || ( base64_character1 == (uint32_t) '\v' ) )
2048 		{
2049 			whitespace_size += base64_character_size;
2050 		}
2051 		else
2052 		{
2053 			break;
2054 		}
2055 	}
2056 	base64_stream_size -= whitespace_size;
2057 	base64_stream_index = 0;
2058 
2059 	if( ( flags & LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) == 0 )
2060 	{
2061 		strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
2062 	}
2063 	while( base64_stream_index < base64_stream_size )
2064 	{
2065 		switch( base64_variant & 0xf0000000UL )
2066 		{
2067 			case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2068 				base64_character1 = base64_stream[ base64_stream_index ];
2069 				break;
2070 
2071 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2072 				byte_stream_copy_to_uint16_big_endian(
2073 				 &( base64_stream[ base64_stream_index ] ),
2074 				 base64_character1 );
2075 				break;
2076 
2077 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2078 				byte_stream_copy_to_uint16_little_endian(
2079 				 &( base64_stream[ base64_stream_index ] ),
2080 				 base64_character1 );
2081 				break;
2082 
2083 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2084 				byte_stream_copy_to_uint32_big_endian(
2085 				 &( base64_stream[ base64_stream_index ] ),
2086 				 base64_character1 );
2087 				break;
2088 
2089 			case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2090 				byte_stream_copy_to_uint32_little_endian(
2091 				 &( base64_stream[ base64_stream_index ] ),
2092 				 base64_character1 );
2093 				break;
2094 		}
2095 		base64_stream_index += base64_character_size;
2096 
2097 		if( ( base64_character1 == (uint32_t) '\n' )
2098 		 || ( base64_character1 == (uint32_t) '\r' ) )
2099 		{
2100 			if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE )
2101 			 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
2102 			{
2103 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
2104 			}
2105 			else
2106 			{
2107 				if( ( base64_stream_index + base64_character_size ) < base64_stream_size )
2108 				{
2109 					switch( base64_variant & 0xf0000000UL )
2110 					{
2111 						case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2112 							base64_character2 = base64_stream[ base64_stream_index ];
2113 							break;
2114 
2115 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2116 							byte_stream_copy_to_uint16_big_endian(
2117 							 &( base64_stream[ base64_stream_index ] ),
2118 							 base64_character2 );
2119 							break;
2120 
2121 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2122 							byte_stream_copy_to_uint16_little_endian(
2123 							 &( base64_stream[ base64_stream_index ] ),
2124 							 base64_character2 );
2125 							break;
2126 
2127 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2128 							byte_stream_copy_to_uint32_big_endian(
2129 							 &( base64_stream[ base64_stream_index ] ),
2130 							 base64_character2 );
2131 							break;
2132 
2133 						case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2134 							byte_stream_copy_to_uint32_little_endian(
2135 							 &( base64_stream[ base64_stream_index ] ),
2136 							 base64_character2 );
2137 							break;
2138 					}
2139 					if( ( base64_character2 == (uint32_t) '\n' )
2140 					 || ( base64_character2 == (uint32_t) '\r' ) )
2141 					{
2142 						base64_stream_index += base64_character_size;
2143 					}
2144 				}
2145 				strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
2146 			}
2147 			if( character_limit != 0 )
2148 			{
2149 				if( number_of_characters != (size_t) character_limit )
2150 				{
2151 					libcerror_error_set(
2152 					 error,
2153 					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2154 					 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2155 					 "%s: number of characters in line does not match character limit.",
2156 					 function );
2157 
2158 					return( -1 );
2159 				}
2160 				number_of_characters = 0;
2161 			}
2162 		}
2163 		else if( ( base64_character1 == (uint32_t) ' ' )
2164 		      || ( base64_character1 == (uint32_t) '\t' )
2165 		      || ( base64_character1 == (uint32_t) '\v' ) )
2166 		{
2167 			if( ( flags & LIBUNA_BASE64_FLAG_STRIP_WHITESPACE ) != 0 )
2168 			{
2169 				if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
2170 				{
2171 					strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE;
2172 				}
2173 				if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
2174 				 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
2175 				{
2176 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
2177 				}
2178 			}
2179 			else
2180 			{
2181 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
2182 			}
2183 		}
2184 		else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
2185 		{
2186 			strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
2187 		}
2188 		else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE )
2189 		{
2190 			strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
2191 		}
2192 		if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
2193 		{
2194 			libcerror_error_set(
2195 			 error,
2196 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2197 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2198 			 "%s: invalid character in base64 stream at index: %" PRIzd ".",
2199 			 function,
2200 			 base64_stream_index - base64_character_size );
2201 
2202 			return( -1 );
2203 		}
2204 		if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
2205 		{
2206 			if( padding_size > 0 )
2207 			{
2208 				libcerror_error_set(
2209 				 error,
2210 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2211 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2212 				 "%s: invalid 1st base64 sixtet.",
2213 				 function );
2214 
2215 				return( -1 );
2216 			}
2217 			base64_stream_index -= base64_character_size;
2218 
2219 			/* Convert the base64 stream into a base64 triplet
2220 			 */
2221 			if( libuna_base64_triplet_copy_from_base64_stream(
2222 			     &base64_triplet,
2223 			     base64_stream,
2224 			     base64_stream_size,
2225 			     &base64_stream_index,
2226 			     &padding_size,
2227 			     base64_variant,
2228 			     error ) != 1 )
2229 			{
2230 				libcerror_error_set(
2231 				 error,
2232 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2233 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2234 				 "%s: unable to copy base64 triplet from base64 stream.",
2235 				 function );
2236 
2237 				return( -1 );
2238 			}
2239 			/* Convert the base64 triplet into a byte stream
2240 			 */
2241 			if( libuna_base64_triplet_copy_to_byte_stream(
2242 			     base64_triplet,
2243 			     byte_stream,
2244 			     byte_stream_size,
2245 			     &byte_stream_index,
2246 			     padding_size,
2247 			     error ) != 1 )
2248 			{
2249 				libcerror_error_set(
2250 				 error,
2251 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2252 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2253 				 "%s: unable to copy base64 triplet to byte stream.",
2254 				 function );
2255 
2256 				return( -1 );
2257 			}
2258 			number_of_characters += 4 - padding_size;
2259 		}
2260 	}
2261 	if( character_limit != 0 )
2262 	{
2263 		if( number_of_characters > (size_t) character_limit )
2264 		{
2265 			libcerror_error_set(
2266 			 error,
2267 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2268 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2269 			 "%s: number of characters in last line exceed maximum.",
2270 			 function );
2271 
2272 			return( -1 );
2273 		}
2274 	}
2275 	return( 1 );
2276 }
2277 
2278 /* Determines the size of a base64 stream from a byte stream
2279  * Returns 1 if successful or -1 on error
2280  */
libuna_base64_stream_size_from_byte_stream(const uint8_t * byte_stream,size_t byte_stream_size,size_t * base64_stream_size,uint32_t base64_variant,libcerror_error_t ** error)2281 int libuna_base64_stream_size_from_byte_stream(
2282      const uint8_t *byte_stream,
2283      size_t byte_stream_size,
2284      size_t *base64_stream_size,
2285      uint32_t base64_variant,
2286      libcerror_error_t **error )
2287 {
2288 	static char *function                = "libuna_base64_stream_size_from_byte_stream";
2289 	size_t base64_character_size         = 0;
2290 	size_t calculated_base64_stream_size = 0;
2291 	size_t remaining_size                = 0;
2292 	size_t whitespace_size               = 0;
2293 	uint8_t character_limit              = 0;
2294 	uint8_t padding_character            = 0;
2295 
2296 	if( byte_stream == NULL )
2297 	{
2298 		libcerror_error_set(
2299 		 error,
2300 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2301 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2302 		 "%s: invalid byte stream.",
2303 		 function );
2304 
2305 		return( -1 );
2306 	}
2307 	if( byte_stream_size > (size_t) SSIZE_MAX )
2308 	{
2309 		libcerror_error_set(
2310 		 error,
2311 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2312 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2313 		 "%s: invalid byte stream size value exceeds maximum.",
2314 		 function );
2315 
2316 		return( -1 );
2317 	}
2318 	if( base64_stream_size == NULL )
2319 	{
2320 		libcerror_error_set(
2321 		 error,
2322 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2323 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2324 		 "%s: invalid base64 stream size.",
2325 		 function );
2326 
2327 		return( -1 );
2328 	}
2329 	switch( base64_variant & 0x000000ffUL )
2330 	{
2331 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_NONE:
2332 			character_limit = 0;
2333 
2334 			break;
2335 
2336 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_64:
2337 			character_limit = 64;
2338 
2339 			break;
2340 
2341 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_76:
2342 			character_limit = 76;
2343 
2344 			break;
2345 
2346 		default:
2347 			libcerror_error_set(
2348 			 error,
2349 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2350 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2351 			 "%s: unsupported base64 variant.",
2352 			 function );
2353 
2354 			return( -1 );
2355 	}
2356 	switch( base64_variant & 0x0f000000UL )
2357 	{
2358 		case LIBUNA_BASE64_VARIANT_PADDING_NONE:
2359 			padding_character = 0;
2360 			break;
2361 
2362 		case LIBUNA_BASE64_VARIANT_PADDING_OPTIONAL:
2363 			padding_character = (uint8_t) '=';
2364 			break;
2365 
2366 		case LIBUNA_BASE64_VARIANT_PADDING_REQUIRED:
2367 			padding_character = (uint8_t) '=';
2368 			break;
2369 
2370 		default:
2371 			libcerror_error_set(
2372 			 error,
2373 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2374 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2375 			 "%s: unsupported base64 variant.",
2376 			 function );
2377 
2378 			return( -1 );
2379 	}
2380 	switch( base64_variant & 0xf0000000UL )
2381 	{
2382 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2383 			base64_character_size = 1;
2384 			break;
2385 
2386 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2387 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2388 			base64_character_size = 2;
2389 			break;
2390 
2391 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2392 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2393 			base64_character_size = 4;
2394 			break;
2395 
2396 		default:
2397 			libcerror_error_set(
2398 			 error,
2399 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2400 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2401 			 "%s: unsupported base64 variant.",
2402 			 function );
2403 
2404 			return( -1 );
2405 	}
2406 	/* Make sure the base64 stream is able to hold
2407 	 * at least 4 base64 characters for each 3 bytes
2408 	 */
2409 	calculated_base64_stream_size = ( byte_stream_size / 3 ) * 4;
2410 
2411 	remaining_size = byte_stream_size % 3;
2412 
2413 	if( remaining_size != 0 )
2414 	{
2415 		if( padding_character != 0 )
2416 		{
2417 			calculated_base64_stream_size += 4;
2418 		}
2419 		else if( remaining_size == 1 )
2420 		{
2421 			calculated_base64_stream_size += 2;
2422 		}
2423 		else if( remaining_size == 2 )
2424 		{
2425 			calculated_base64_stream_size += 3;
2426 		}
2427 	}
2428 	if( character_limit != 0 )
2429 	{
2430 		if( calculated_base64_stream_size > character_limit )
2431 		{
2432 			whitespace_size = calculated_base64_stream_size / character_limit;
2433 
2434 			if( ( calculated_base64_stream_size % character_limit ) != 0 )
2435 			{
2436 				whitespace_size += 1;
2437 			}
2438 			calculated_base64_stream_size += whitespace_size;
2439 		}
2440 		calculated_base64_stream_size += 1;
2441 	}
2442 	calculated_base64_stream_size *= base64_character_size;
2443 
2444 	*base64_stream_size = calculated_base64_stream_size;
2445 
2446 	return( 1 );
2447 }
2448 
2449 /* Copies a base64 stream from a byte stream
2450  * Returns 1 if successful or -1 on error
2451  */
libuna_base64_stream_copy_from_byte_stream(uint8_t * base64_stream,size_t base64_stream_size,const uint8_t * byte_stream,size_t byte_stream_size,uint32_t base64_variant,libcerror_error_t ** error)2452 int libuna_base64_stream_copy_from_byte_stream(
2453      uint8_t *base64_stream,
2454      size_t base64_stream_size,
2455      const uint8_t *byte_stream,
2456      size_t byte_stream_size,
2457      uint32_t base64_variant,
2458      libcerror_error_t **error )
2459 {
2460 	static char *function      = "libuna_base64_stream_copy_from_byte_stream";
2461 	size_t base64_stream_index = 0;
2462 
2463 	if( libuna_base64_stream_with_index_copy_from_byte_stream(
2464 	     base64_stream,
2465 	     base64_stream_size,
2466 	     &base64_stream_index,
2467 	     byte_stream,
2468 	     byte_stream_size,
2469 	     base64_variant,
2470 	     error ) != 1 )
2471 	{
2472 		libcerror_error_set(
2473 		 error,
2474 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
2475 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
2476 		 "%s: unable to copy base64 stream from byte stream.",
2477 		 function );
2478 
2479 		return( -1 );
2480 	}
2481 	return( 1 );
2482 }
2483 
2484 /* Copies a base64 stream from a byte stream
2485  * Returns 1 if successful or -1 on error
2486  */
libuna_base64_stream_with_index_copy_from_byte_stream(uint8_t * base64_stream,size_t base64_stream_size,size_t * base64_stream_index,const uint8_t * byte_stream,size_t byte_stream_size,uint32_t base64_variant,libcerror_error_t ** error)2487 int libuna_base64_stream_with_index_copy_from_byte_stream(
2488      uint8_t *base64_stream,
2489      size_t base64_stream_size,
2490      size_t *base64_stream_index,
2491      const uint8_t *byte_stream,
2492      size_t byte_stream_size,
2493      uint32_t base64_variant,
2494      libcerror_error_t **error )
2495 {
2496 	static char *function                = "libuna_base64_stream_with_index_copy_from_byte_stream";
2497 	size_t base64_character_size         = 0;
2498 	size_t calculated_base64_stream_size = 0;
2499 	size_t byte_stream_index             = 0;
2500 	size_t number_of_characters          = 0;
2501 	size_t remaining_size                = 0;
2502 	size_t safe_base64_stream_index      = 0;
2503 	size_t whitespace_size               = 0;
2504 	uint32_t base64_character            = 0;
2505 	uint32_t base64_triplet              = 0;
2506 	uint8_t character_limit              = 0;
2507 	uint8_t padding_character            = 0;
2508 	uint8_t padding_size                 = 0;
2509 
2510 	if( base64_stream == NULL )
2511 	{
2512 		libcerror_error_set(
2513 		 error,
2514 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2515 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2516 		 "%s: invalid base64 stream.",
2517 		 function );
2518 
2519 		return( -1 );
2520 	}
2521 	if( base64_stream_size > (size_t) SSIZE_MAX )
2522 	{
2523 		libcerror_error_set(
2524 		 error,
2525 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2526 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2527 		 "%s: invalid base64 stream size value exceeds maximum.",
2528 		 function );
2529 
2530 		return( -1 );
2531 	}
2532 	if( base64_stream_index == NULL )
2533 	{
2534 		libcerror_error_set(
2535 		 error,
2536 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2537 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2538 		 "%s: invalid base64 stream index.",
2539 		 function );
2540 
2541 		return( -1 );
2542 	}
2543 	if( *base64_stream_index >= base64_stream_size )
2544 	{
2545 		libcerror_error_set(
2546 		 error,
2547 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2548 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
2549 		 "%s: base64 stream string too small.",
2550 		 function );
2551 
2552 		return( -1 );
2553 	}
2554 	if( byte_stream == NULL )
2555 	{
2556 		libcerror_error_set(
2557 		 error,
2558 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2559 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
2560 		 "%s: invalid byte stream.",
2561 		 function );
2562 
2563 		return( -1 );
2564 	}
2565 	if( byte_stream_size > (size_t) SSIZE_MAX )
2566 	{
2567 		libcerror_error_set(
2568 		 error,
2569 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2570 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
2571 		 "%s: invalid byte stream size value exceeds maximum.",
2572 		 function );
2573 
2574 		return( -1 );
2575 	}
2576 	switch( base64_variant & 0x000000ffUL )
2577 	{
2578 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_NONE:
2579 			character_limit = 0;
2580 
2581 			break;
2582 
2583 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_64:
2584 			character_limit = 64;
2585 
2586 			break;
2587 
2588 		case LIBUNA_BASE64_VARIANT_CHARACTER_LIMIT_76:
2589 			character_limit = 76;
2590 
2591 			break;
2592 
2593 		default:
2594 			libcerror_error_set(
2595 			 error,
2596 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2597 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2598 			 "%s: unsupported base64 variant.",
2599 			 function );
2600 
2601 			return( -1 );
2602 	}
2603 	switch( base64_variant & 0x0f000000UL )
2604 	{
2605 		case LIBUNA_BASE64_VARIANT_PADDING_NONE:
2606 			padding_character = 0;
2607 			break;
2608 
2609 		case LIBUNA_BASE64_VARIANT_PADDING_OPTIONAL:
2610 			padding_character = (uint8_t) '=';
2611 			break;
2612 
2613 		case LIBUNA_BASE64_VARIANT_PADDING_REQUIRED:
2614 			padding_character = (uint8_t) '=';
2615 			break;
2616 
2617 		default:
2618 			libcerror_error_set(
2619 			 error,
2620 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2621 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2622 			 "%s: unsupported base64 variant.",
2623 			 function );
2624 
2625 			return( -1 );
2626 	}
2627 	switch( base64_variant & 0xf0000000UL )
2628 	{
2629 		case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2630 			base64_character_size = 1;
2631 			break;
2632 
2633 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2634 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2635 			base64_character_size = 2;
2636 			break;
2637 
2638 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2639 		case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2640 			base64_character_size = 4;
2641 			break;
2642 
2643 		default:
2644 			libcerror_error_set(
2645 			 error,
2646 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2647 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
2648 			 "%s: unsupported base64 variant.",
2649 			 function );
2650 
2651 			return( -1 );
2652 	}
2653 	safe_base64_stream_index = *base64_stream_index;
2654 
2655 	/* Make sure the base64 stream is able to hold
2656 	 * at least 4 base64 characters for each 3 bytes
2657 	 */
2658 	calculated_base64_stream_size = ( byte_stream_size / 3 ) * 4;
2659 
2660 	remaining_size = byte_stream_size % 3;
2661 
2662 	if( remaining_size != 0 )
2663 	{
2664 		if( padding_character != 0 )
2665 		{
2666 			calculated_base64_stream_size += 4;
2667 		}
2668 		else if( remaining_size == 1 )
2669 		{
2670 			calculated_base64_stream_size += 2;
2671 		}
2672 		else if( remaining_size == 2 )
2673 		{
2674 			calculated_base64_stream_size += 3;
2675 		}
2676 	}
2677 	if( character_limit != 0 )
2678 	{
2679 		if( calculated_base64_stream_size > character_limit )
2680 		{
2681 			whitespace_size = calculated_base64_stream_size / character_limit;
2682 
2683 			if( ( calculated_base64_stream_size % character_limit ) != 0 )
2684 			{
2685 				whitespace_size += 1;
2686 			}
2687 			calculated_base64_stream_size += whitespace_size;
2688 		}
2689 		calculated_base64_stream_size += 1;
2690 	}
2691 	calculated_base64_stream_size *= base64_character_size;
2692 
2693 	if( base64_stream_size < calculated_base64_stream_size )
2694 	{
2695 		libcerror_error_set(
2696 		 error,
2697 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
2698 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
2699 		 "%s: base64 stream is too small.",
2700 		 function );
2701 
2702 		return( -1 );
2703 	}
2704 	while( byte_stream_index < byte_stream_size )
2705 	{
2706 		/* Convert the byte stream into a base64 triplet
2707 		 */
2708 		if( libuna_base64_triplet_copy_from_byte_stream(
2709 		     &base64_triplet,
2710 		     byte_stream,
2711 		     byte_stream_size,
2712 		     &byte_stream_index,
2713 		     &padding_size,
2714 		     error ) != 1 )
2715 		{
2716 			libcerror_error_set(
2717 			 error,
2718 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2719 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2720 			 "%s: unable to copy base64 triplet from byte stream.",
2721 			 function );
2722 
2723 			return( -1 );
2724 		}
2725 		/* Convert the base64 triplet into a base64 stream
2726 		 */
2727 		if( libuna_base64_triplet_copy_to_base64_stream(
2728 		     base64_triplet,
2729 		     base64_stream,
2730 		     base64_stream_size,
2731 		     &safe_base64_stream_index,
2732 		     padding_size,
2733 		     base64_variant,
2734 		     error ) != 1 )
2735 		{
2736 			libcerror_error_set(
2737 			 error,
2738 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
2739 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
2740 			 "%s: unable to copy base64 triplet to base64 stream.",
2741 			 function );
2742 
2743 			return( -1 );
2744 		}
2745 		if( character_limit != 0 )
2746 		{
2747 			number_of_characters += 4;
2748 
2749 			if( number_of_characters >= (size_t) character_limit )
2750 			{
2751 				base64_character = (uint32_t) '\n';
2752 
2753 				switch( base64_variant & 0xf0000000UL )
2754 				{
2755 					case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2756 						base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
2757 						break;
2758 
2759 					case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2760 						byte_stream_copy_from_uint16_big_endian(
2761 						 &( base64_stream[ safe_base64_stream_index ] ),
2762 						 base64_character );
2763 						break;
2764 
2765 					case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2766 						byte_stream_copy_from_uint16_little_endian(
2767 						 &( base64_stream[ safe_base64_stream_index ] ),
2768 						 base64_character );
2769 						break;
2770 
2771 					case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2772 						byte_stream_copy_from_uint32_big_endian(
2773 						 &( base64_stream[ safe_base64_stream_index ] ),
2774 						 base64_character );
2775 						break;
2776 
2777 					case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2778 						byte_stream_copy_from_uint32_little_endian(
2779 						 &( base64_stream[ safe_base64_stream_index ] ),
2780 						 base64_character );
2781 						break;
2782 				}
2783 				safe_base64_stream_index += base64_character_size;
2784 
2785 				number_of_characters = 0;
2786 			}
2787 		}
2788 	}
2789 	if( character_limit != 0 )
2790 	{
2791 		if( number_of_characters != 0 )
2792 		{
2793 			base64_character = (uint32_t) '\n';
2794 
2795 			switch( base64_variant & 0xf0000000UL )
2796 			{
2797 				case LIBUNA_BASE64_VARIANT_ENCODING_BYTE_STREAM:
2798 					base64_stream[ safe_base64_stream_index ] = (uint8_t) base64_character;
2799 					break;
2800 
2801 				case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
2802 					byte_stream_copy_from_uint16_big_endian(
2803 					 &( base64_stream[ safe_base64_stream_index ] ),
2804 					 base64_character );
2805 					break;
2806 
2807 				case LIBUNA_BASE64_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
2808 					byte_stream_copy_from_uint16_little_endian(
2809 					 &( base64_stream[ safe_base64_stream_index ] ),
2810 					 base64_character );
2811 					break;
2812 
2813 				case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
2814 					byte_stream_copy_from_uint32_big_endian(
2815 					 &( base64_stream[ safe_base64_stream_index ] ),
2816 					 base64_character );
2817 					break;
2818 
2819 				case LIBUNA_BASE64_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
2820 					byte_stream_copy_from_uint32_little_endian(
2821 					 &( base64_stream[ safe_base64_stream_index ] ),
2822 					 base64_character );
2823 					break;
2824 			}
2825 			safe_base64_stream_index += base64_character_size;
2826 		}
2827 	}
2828 	*base64_stream_index = safe_base64_stream_index;
2829 
2830 	return( 1 );
2831 }
2832 
2833