1 /*
2  * Base16 stream functions
3  *
4  * Copyright (C) 2008-2020, 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_base16_stream.h"
27 #include "libuna_definitions.h"
28 #include "libuna_libcerror.h"
29 #include "libuna_types.h"
30 
31 /* Copies a base16 character from a base16 stream
32  * Returns 1 if successful or -1 on error
33  */
libuna_base16_character_copy_from_base16_stream(uint32_t * base16_character,const uint8_t * base16_stream,uint32_t base16_variant,libcerror_error_t ** error)34 int libuna_base16_character_copy_from_base16_stream(
35      uint32_t *base16_character,
36      const uint8_t *base16_stream,
37      uint32_t base16_variant,
38      libcerror_error_t **error )
39 {
40 	static char *function          = "libuna_base16_character_copy_from_base16_stream";
41 	uint32_t safe_base16_character = 0;
42 
43 	if( base16_character == NULL )
44 	{
45 		libcerror_error_set(
46 		 error,
47 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
48 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
49 		 "%s: invalid base16 character.",
50 		 function );
51 
52 		return( -1 );
53 	}
54 	if( base16_stream == NULL )
55 	{
56 		libcerror_error_set(
57 		 error,
58 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
59 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
60 		 "%s: invalid base16 stream.",
61 		 function );
62 
63 		return( -1 );
64 	}
65 	switch( base16_variant & 0xf0000000UL )
66 	{
67 		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
68 			safe_base16_character = *base16_stream;
69 			break;
70 
71 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
72 			byte_stream_copy_to_uint16_big_endian(
73 			 base16_stream,
74 			 safe_base16_character );
75 			break;
76 
77 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
78 			byte_stream_copy_to_uint16_little_endian(
79 			 base16_stream,
80 			 safe_base16_character );
81 			break;
82 
83 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
84 			byte_stream_copy_to_uint32_big_endian(
85 			 base16_stream,
86 			 safe_base16_character );
87 			break;
88 
89 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
90 			byte_stream_copy_to_uint32_little_endian(
91 			 base16_stream,
92 			 safe_base16_character );
93 			break;
94 
95 		default:
96 			libcerror_error_set(
97 			 error,
98 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
99 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
100 			 "%s: unsupported base16 variant.",
101 			 function );
102 
103 			return( -1 );
104 	}
105 	if( ( safe_base16_character & 0xffffff00UL ) != 0 )
106 	{
107 		libcerror_error_set(
108 		 error,
109 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
110 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
111 		 "%s: invalid base16 character.",
112 		 function );
113 
114 		return( -1 );
115 	}
116 	*base16_character = safe_base16_character;
117 
118 	return( 1 );
119 }
120 
121 /* Determines the size of a byte stream from a base16 stream
122  *
123  * LIBUNA_BASE16_FLAG_STRIP_WHITESPACE removes leading space and tab characters,
124  * and trailing space, tab and end of line characters
125  *
126  * Returns 1 if successful or -1 on error
127  */
libuna_base16_stream_size_to_byte_stream(const uint8_t * base16_stream,size_t base16_stream_size,size_t * byte_stream_size,uint32_t base16_variant,uint8_t flags,libcerror_error_t ** error)128 int libuna_base16_stream_size_to_byte_stream(
129      const uint8_t *base16_stream,
130      size_t base16_stream_size,
131      size_t *byte_stream_size,
132      uint32_t base16_variant,
133      uint8_t flags,
134      libcerror_error_t **error )
135 {
136 	static char *function        = "libuna_base16_stream_size_to_byte_stream";
137 	size_t base16_character_size = 0;
138 	size_t base16_stream_index   = 0;
139 	size_t number_of_characters  = 0;
140 	size_t whitespace_size       = 0;
141 	uint32_t base16_character1   = 0;
142 	uint32_t base16_character2   = 0;
143 	uint8_t character_case       = 0;
144 	uint8_t character_limit      = 0;
145 	uint8_t strip_mode           = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
146 
147 	if( base16_stream == NULL )
148 	{
149 		libcerror_error_set(
150 		 error,
151 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
152 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
153 		 "%s: invalid base16 stream.",
154 		 function );
155 
156 		return( -1 );
157 	}
158 	if( base16_stream_size > (size_t) SSIZE_MAX )
159 	{
160 		libcerror_error_set(
161 		 error,
162 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
163 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
164 		 "%s: invalid base16 stream size value exceeds maximum.",
165 		 function );
166 
167 		return( -1 );
168 	}
169 	if( byte_stream_size == NULL )
170 	{
171 		libcerror_error_set(
172 		 error,
173 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
174 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
175 		 "%s: invalid byte stream size.",
176 		 function );
177 
178 		return( -1 );
179 	}
180 	switch( base16_variant & 0x000000ffUL )
181 	{
182 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE:
183 			character_limit = 0;
184 			break;
185 
186 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
187 			character_limit = 64;
188 			break;
189 
190 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
191 			character_limit = 76;
192 			break;
193 
194 		default:
195 			libcerror_error_set(
196 			 error,
197 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
198 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
199 			 "%s: unsupported base16 variant.",
200 			 function );
201 
202 			return( -1 );
203 	}
204 	switch( base16_variant & 0x000f0000UL )
205 	{
206 		case LIBUNA_BASE16_VARIANT_CASE_LOWER:
207 			character_case = LIBUNA_CASE_LOWER;
208 			break;
209 
210 		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
211 			character_case = LIBUNA_CASE_MIXED;
212 			break;
213 
214 		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
215 			character_case = LIBUNA_CASE_UPPER;
216 			break;
217 
218 		default:
219 			libcerror_error_set(
220 			 error,
221 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
222 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
223 			 "%s: unsupported base16 variant.",
224 			 function );
225 
226 			return( -1 );
227 	}
228 	switch( base16_variant & 0xf0000000UL )
229 	{
230 		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
231 			base16_character_size = 1;
232 			break;
233 
234 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
235 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
236 			base16_character_size = 2;
237 			break;
238 
239 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
240 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
241 			base16_character_size = 4;
242 			break;
243 
244 		default:
245 			libcerror_error_set(
246 			 error,
247 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
248 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
249 			 "%s: unsupported base16 variant.",
250 			 function );
251 
252 			return( -1 );
253 	}
254 	if( ( flags & ~( LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) ) != 0 )
255 	{
256 		libcerror_error_set(
257 		 error,
258 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
259 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
260 		 "%s: unsupported flags.",
261 		 function );
262 
263 		return( -1 );
264 	}
265 	/* Ignore trailing whitespace
266 	 */
267 	if( base16_stream_size > base16_character_size )
268 	{
269 		base16_stream_index = base16_stream_size - base16_character_size;
270 		whitespace_size     = 0;
271 
272 		while( base16_stream_index > base16_character_size )
273 		{
274 			if( libuna_base16_character_copy_from_base16_stream(
275 			     &base16_character1,
276 			     &( base16_stream[ base16_stream_index ] ),
277 			     base16_variant,
278 			     error ) != 1 )
279 			{
280 				libcerror_error_set(
281 				 error,
282 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
283 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
284 				 "%s: unable to copy base16 character at index: %" PRIzd ".",
285 				 function,
286 				 base16_stream_index );
287 
288 				return( -1 );
289 			}
290 			base16_stream_index -= base16_character_size;
291 
292 			if( ( base16_character1 == (uint32_t) '\n' )
293 			 || ( base16_character1 == (uint32_t) '\r' ) )
294 			{
295 				whitespace_size += base16_character_size;
296 			}
297 			else if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 )
298 			{
299 				break;
300 			}
301 			else if( ( base16_character1 == (uint32_t) ' ' )
302 			      || ( base16_character1 == (uint32_t) '\t' )
303 			      || ( base16_character1 == (uint32_t) '\v' ) )
304 			{
305 				whitespace_size += base16_character_size;
306 			}
307 			else
308 			{
309 				break;
310 			}
311 		}
312 		base16_stream_size -= whitespace_size;
313 	}
314 	base16_stream_index = 0;
315 	whitespace_size     = 0;
316 
317 	while( base16_stream_index < base16_stream_size )
318 	{
319 		if( libuna_base16_character_copy_from_base16_stream(
320 		     &base16_character1,
321 		     &( base16_stream[ base16_stream_index ] ),
322 		     base16_variant,
323 		     error ) != 1 )
324 		{
325 			libcerror_error_set(
326 			 error,
327 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
328 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
329 			 "%s: unable to copy base16 character at index: %" PRIzd ".",
330 			 function,
331 			 base16_stream_index );
332 
333 			return( -1 );
334 		}
335 		base16_stream_index += base16_character_size;
336 
337 		if( ( base16_character1 == (uint32_t) '\n' )
338 		 || ( base16_character1 == (uint32_t) '\r' ) )
339 		{
340 			if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE )
341 			 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
342 			{
343 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
344 			}
345 			else
346 			{
347 				/* Handle multi-character end-of-line
348 				 */
349 				if( ( base16_stream_index + base16_character_size ) < base16_stream_size )
350 				{
351 					if( libuna_base16_character_copy_from_base16_stream(
352 					     &base16_character2,
353 					     &( base16_stream[ base16_stream_index + base16_character_size ] ),
354 					     base16_variant,
355 					     error ) != 1 )
356 					{
357 						libcerror_error_set(
358 						 error,
359 						 LIBCERROR_ERROR_DOMAIN_CONVERSION,
360 						 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
361 						 "%s: unable to copy base16 character at index: %" PRIzd ".",
362 						 function,
363 						 base16_stream_index );
364 
365 						return( -1 );
366 					}
367 					if( ( base16_character2 == (uint32_t) '\n' )
368 					 || ( base16_character2 == (uint32_t) '\r' ) )
369 					{
370 						base16_stream_index += base16_character_size;
371 						whitespace_size     += base16_character_size;
372 					}
373 				}
374 				strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
375 			}
376 			if( character_limit != 0 )
377 			{
378 				if( number_of_characters != (size_t) character_limit )
379 				{
380 					libcerror_error_set(
381 					 error,
382 					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
383 					 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
384 					 "%s: number of characters in line does not match character limit.",
385 					 function );
386 
387 					return( -1 );
388 				}
389 				number_of_characters = 0;
390 			}
391 			whitespace_size += base16_character_size;
392 		}
393 		else if( ( base16_character1 == (uint32_t) ' ' )
394 		      || ( base16_character1 == (uint32_t) '\t' )
395 		      || ( base16_character1 == (uint32_t) '\v' ) )
396 		{
397 			if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) != 0 )
398 			{
399 				if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
400 				{
401 					strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE;
402 				}
403 				if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
404 				 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
405 				{
406 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
407 				}
408 				else
409 				{
410 					whitespace_size += base16_character_size;
411 				}
412 			}
413 			else
414 			{
415 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
416 			}
417 		}
418 		else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
419 		{
420 			strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
421 		}
422 		else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE )
423 		{
424 			strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
425 		}
426 		if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
427 		{
428 			if( ( base16_character1 >= (uint32_t) 'A' )
429 			 && ( base16_character1 <= (uint32_t) 'F' ) )
430 			{
431 				if( ( character_case != LIBUNA_CASE_MIXED )
432 				 && ( character_case != LIBUNA_CASE_UPPER ) )
433 				{
434 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
435 				}
436 				number_of_characters++;
437 			}
438 			else if( ( base16_character1 >= (uint32_t) 'a' )
439 			      && ( base16_character1 <= (uint32_t) 'f' ) )
440 			{
441 				if( ( character_case != LIBUNA_CASE_MIXED )
442 				 && ( character_case != LIBUNA_CASE_LOWER ) )
443 				{
444 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
445 				}
446 				number_of_characters++;
447 			}
448 			else if( ( base16_character1 >= (uint32_t) '0' )
449 			      && ( base16_character1 <= (uint32_t) '9' ) )
450 			{
451 				number_of_characters++;
452 			}
453 			else
454 			{
455 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
456 			}
457 		}
458 		if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
459 		{
460 			libcerror_error_set(
461 			 error,
462 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
463 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
464 			 "%s: invalid character in base16 stream at index: %" PRIzd ".",
465 			 function,
466 			 base16_stream_index - base16_character_size );
467 
468 			return( -1 );
469 		}
470 	}
471 	if( character_limit != 0 )
472 	{
473 		if( number_of_characters > (size_t) character_limit )
474 		{
475 			libcerror_error_set(
476 			 error,
477 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
478 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
479 			 "%s: number of characters in last line exceed maximum.",
480 			 function );
481 
482 			return( -1 );
483 		}
484 	}
485 	base16_stream_size -= whitespace_size;
486 
487 	/* Make sure the byte stream is able to hold
488 	 * at least 1 byte for each 2 base16 characters
489 	 */
490 	base16_character_size *= 2;
491 
492 	if( ( base16_stream_size % base16_character_size ) != 0 )
493 	{
494 		libcerror_error_set(
495 		 error,
496 		 LIBCERROR_ERROR_DOMAIN_CONVERSION,
497 		 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
498 		 "%s: invalid base16 stream size.",
499 		 function );
500 
501 		return( -1 );
502 	}
503 	base16_stream_size /= base16_character_size;
504 
505 	*byte_stream_size = base16_stream_size;
506 
507 	return( 1 );
508 }
509 
510 /* Copies a byte stream from a base16 stream
511  *
512  * LIBUNA_BASE16_FLAG_STRIP_WHITESPACE removes leading space and tab characters,
513  * and trailing space, tab and end of line characters
514  *
515  * Returns 1 if successful or -1 on error
516  */
libuna_base16_stream_copy_to_byte_stream(const uint8_t * base16_stream,size_t base16_stream_size,uint8_t * byte_stream,size_t byte_stream_size,uint32_t base16_variant,uint8_t flags,libcerror_error_t ** error)517 int libuna_base16_stream_copy_to_byte_stream(
518      const uint8_t *base16_stream,
519      size_t base16_stream_size,
520      uint8_t *byte_stream,
521      size_t byte_stream_size,
522      uint32_t base16_variant,
523      uint8_t flags,
524      libcerror_error_t **error )
525 {
526 	static char *function        = "libuna_base16_stream_copy_to_byte_stream";
527 	size_t base16_character_size = 0;
528 	size_t base16_stream_index   = 0;
529 	size_t byte_stream_index     = 0;
530 	size_t number_of_characters  = 0;
531 	size_t whitespace_size       = 0;
532 	uint32_t base16_character1   = 0;
533 	uint32_t base16_character2   = 0;
534 	uint8_t byte_value           = 0;
535 	uint8_t character_case       = 0;
536 	uint8_t character_limit      = 0;
537 	uint8_t strip_mode           = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
538 
539 	if( base16_stream == NULL )
540 	{
541 		libcerror_error_set(
542 		 error,
543 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
544 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
545 		 "%s: invalid base16 stream.",
546 		 function );
547 
548 		return( -1 );
549 	}
550 	if( base16_stream_size > (size_t) SSIZE_MAX )
551 	{
552 		libcerror_error_set(
553 		 error,
554 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
555 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
556 		 "%s: invalid base16 stream size value exceeds maximum.",
557 		 function );
558 
559 		return( -1 );
560 	}
561 	if( byte_stream == NULL )
562 	{
563 		libcerror_error_set(
564 		 error,
565 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
566 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
567 		 "%s: invalid byte stream.",
568 		 function );
569 
570 		return( -1 );
571 	}
572 	if( byte_stream_size > (size_t) SSIZE_MAX )
573 	{
574 		libcerror_error_set(
575 		 error,
576 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
577 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
578 		 "%s: invalid byte stream size value exceeds maximum.",
579 		 function );
580 
581 		return( -1 );
582 	}
583 	switch( base16_variant & 0x000000ffUL )
584 	{
585 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE:
586 			character_limit = 0;
587 			break;
588 
589 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
590 			character_limit = 64;
591 			break;
592 
593 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
594 			character_limit = 76;
595 			break;
596 
597 		default:
598 			libcerror_error_set(
599 			 error,
600 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
601 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
602 			 "%s: unsupported base16 variant.",
603 			 function );
604 
605 			return( -1 );
606 	}
607 	switch( base16_variant & 0x000f0000UL )
608 	{
609 		case LIBUNA_BASE16_VARIANT_CASE_LOWER:
610 			character_case = LIBUNA_CASE_LOWER;
611 			break;
612 
613 		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
614 			character_case = LIBUNA_CASE_MIXED;
615 			break;
616 
617 		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
618 			character_case = LIBUNA_CASE_UPPER;
619 			break;
620 
621 		default:
622 			libcerror_error_set(
623 			 error,
624 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
625 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
626 			 "%s: unsupported base16 variant.",
627 			 function );
628 
629 			return( -1 );
630 	}
631 	switch( base16_variant & 0xf0000000UL )
632 	{
633 		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
634 			base16_character_size = 1;
635 			break;
636 
637 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
638 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
639 			base16_character_size = 2;
640 			break;
641 
642 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
643 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
644 			base16_character_size = 4;
645 			break;
646 
647 		default:
648 			libcerror_error_set(
649 			 error,
650 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
651 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
652 			 "%s: unsupported base16 variant.",
653 			 function );
654 
655 			return( -1 );
656 	}
657 	if( ( flags & ~( LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) ) != 0 )
658 	{
659 		libcerror_error_set(
660 		 error,
661 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
662 		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
663 		 "%s: unsupported flags.",
664 		 function );
665 
666 		return( -1 );
667 	}
668 	/* Ignore trailing whitespace
669 	 */
670 	if( base16_stream_size > base16_character_size )
671 	{
672 		base16_stream_index = base16_stream_size - base16_character_size;
673 		whitespace_size     = 0;
674 
675 		while( base16_stream_index > base16_character_size )
676 		{
677 			if( libuna_base16_character_copy_from_base16_stream(
678 			     &base16_character1,
679 			     &( base16_stream[ base16_stream_index ] ),
680 			     base16_variant,
681 			     error ) != 1 )
682 			{
683 				libcerror_error_set(
684 				 error,
685 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
686 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
687 				 "%s: unable to copy base16 character at index: %" PRIzd ".",
688 				 function,
689 				 base16_stream_index );
690 
691 				return( -1 );
692 			}
693 			base16_stream_index -= base16_character_size;
694 
695 			if( ( base16_character1 == (uint32_t) '\n' )
696 			 || ( base16_character1 == (uint32_t) '\r' ) )
697 			{
698 				whitespace_size += base16_character_size;
699 			}
700 			else if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 )
701 			{
702 				break;
703 			}
704 			else if( ( base16_character1 == (uint32_t) ' ' )
705 			      || ( base16_character1 == (uint32_t) '\t' )
706 			      || ( base16_character1 == (uint32_t) '\v' ) )
707 			{
708 				whitespace_size += base16_character_size;
709 			}
710 			else
711 			{
712 				break;
713 			}
714 		}
715 		base16_stream_size -= whitespace_size;
716 	}
717 	if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 )
718 	{
719 		strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
720 	}
721 	base16_stream_index = 0;
722 
723 	while( base16_stream_index < base16_stream_size )
724 	{
725 		if( libuna_base16_character_copy_from_base16_stream(
726 		     &base16_character1,
727 		     &( base16_stream[ base16_stream_index ] ),
728 		     base16_variant,
729 		     error ) != 1 )
730 		{
731 			libcerror_error_set(
732 			 error,
733 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
734 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
735 			 "%s: unable to copy base16 character at index: %" PRIzd ".",
736 			 function,
737 			 base16_stream_index );
738 
739 			return( -1 );
740 		}
741 		base16_stream_index += base16_character_size;
742 
743 		if( ( base16_character1 == (uint32_t) '\n' )
744 		 || ( base16_character1 == (uint32_t) '\r' ) )
745 		{
746 			if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE )
747 			 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
748 			{
749 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
750 			}
751 			else
752 			{
753 				/* Handle multi-character end-of-line
754 				 */
755 				if( ( base16_stream_index + base16_character_size ) < base16_stream_size )
756 				{
757 					if( libuna_base16_character_copy_from_base16_stream(
758 					     &base16_character2,
759 					     &( base16_stream[ base16_stream_index + base16_character_size ] ),
760 					     base16_variant,
761 					     error ) != 1 )
762 					{
763 						libcerror_error_set(
764 						 error,
765 						 LIBCERROR_ERROR_DOMAIN_CONVERSION,
766 						 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
767 						 "%s: unable to copy base16 character at index: %" PRIzd ".",
768 						 function,
769 						 base16_stream_index );
770 
771 						return( -1 );
772 					}
773 					if( ( base16_character2 == (uint32_t) '\n' )
774 					 || ( base16_character2 == (uint32_t) '\r' ) )
775 					{
776 						base16_stream_index += base16_character_size;
777 					}
778 				}
779 				strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
780 			}
781 			if( character_limit != 0 )
782 			{
783 				if( number_of_characters != (size_t) character_limit )
784 				{
785 					libcerror_error_set(
786 					 error,
787 					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
788 					 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
789 					 "%s: number of characters in line does not match character limit.",
790 					 function );
791 
792 					return( -1 );
793 				}
794 				number_of_characters = 0;
795 			}
796 		}
797 		else if( ( base16_character1 == (uint32_t) ' ' )
798 		      || ( base16_character1 == (uint32_t) '\t' )
799 		      || ( base16_character1 == (uint32_t) '\v' ) )
800 		{
801 			if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) != 0 )
802 			{
803 				if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
804 				{
805 					strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE;
806 				}
807 				if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
808 				 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
809 				{
810 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
811 				}
812 			}
813 			else
814 			{
815 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
816 			}
817 		}
818 		else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
819 		{
820 			strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
821 		}
822 		else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE )
823 		{
824 			strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
825 		}
826 		if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
827 		{
828 			libcerror_error_set(
829 			 error,
830 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
831 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
832 			 "%s: invalid character in base16 stream at index: %" PRIzd ".",
833 			 function,
834 			 base16_stream_index - base16_character_size );
835 
836 			return( -1 );
837 		}
838 		if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
839 		{
840 			byte_value = 0;
841 
842 			if( ( base16_character1 >= (uint32_t) 'A' )
843 			 && ( base16_character1 <= (uint32_t) 'F' ) )
844 			{
845 				if( ( character_case != LIBUNA_CASE_MIXED )
846 				 && ( character_case != LIBUNA_CASE_UPPER ) )
847 				{
848 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
849 				}
850 				byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 );
851 			}
852 			else if( ( base16_character1 >= (uint32_t) 'a' )
853 			      && ( base16_character1 <= (uint32_t) 'f' ) )
854 			{
855 				if( ( character_case != LIBUNA_CASE_MIXED )
856 				 && ( character_case != LIBUNA_CASE_LOWER ) )
857 				{
858 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
859 				}
860 				byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 );
861 			}
862 			else if( ( base16_character1 >= (uint32_t) '0' )
863 			      && ( base16_character1 <= (uint32_t) '9' ) )
864 			{
865 				byte_value = (uint8_t) ( base16_character1 - (uint32_t) '0' );
866 			}
867 			else
868 			{
869 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
870 			}
871 			if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
872 			{
873 				libcerror_error_set(
874 				 error,
875 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
876 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
877 				 "%s: invalid base16 character stream at index: %" PRIzd ".",
878 				 function,
879 				 base16_stream_index - base16_character_size );
880 
881 				return( -1 );
882 			}
883 			byte_value <<= 4;
884 
885 			if( libuna_base16_character_copy_from_base16_stream(
886 			     &base16_character1,
887 			     &( base16_stream[ base16_stream_index ] ),
888 			     base16_variant,
889 			     error ) != 1 )
890 			{
891 				libcerror_error_set(
892 				 error,
893 				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
894 				 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
895 				 "%s: unable to copy base16 character at index: %" PRIzd ".",
896 				 function,
897 				 base16_stream_index );
898 
899 				return( -1 );
900 			}
901 			base16_stream_index += base16_character_size;
902 
903 			if( ( base16_character1 >= (uint32_t) 'A' )
904 			 && ( base16_character1 <= (uint32_t) 'F' ) )
905 			{
906 				if( ( character_case != LIBUNA_CASE_MIXED )
907 				 && ( character_case != LIBUNA_CASE_UPPER ) )
908 				{
909 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
910 				}
911 				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 );
912 			}
913 			else if( ( base16_character1 >= (uint32_t) 'a' )
914 			      && ( base16_character1 <= (uint32_t) 'f' ) )
915 			{
916 				if( ( character_case != LIBUNA_CASE_MIXED )
917 				 && ( character_case != LIBUNA_CASE_LOWER ) )
918 				{
919 					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
920 				}
921 				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 );
922 			}
923 			else if( ( base16_character1 >= (uint32_t) '0' )
924 			      && ( base16_character1 <= (uint32_t) '9' ) )
925 			{
926 				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) '0' );
927 			}
928 			else
929 			{
930 				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
931 			}
932 			if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
933 			{
934 				libcerror_error_set(
935 				 error,
936 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
937 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
938 				 "%s: invalid base16 character stream at index: %" PRIzd ".",
939 				 function,
940 				 base16_stream_index - base16_character_size );
941 
942 				return( -1 );
943 			}
944 			if( byte_stream_index >= byte_stream_size )
945 			{
946 				libcerror_error_set(
947 				 error,
948 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
949 				 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
950 				 "%s: byte stream is too small.",
951 				 function );
952 
953 				return( -1 );
954 			}
955 			byte_stream[ byte_stream_index++ ] = byte_value;
956 
957 			number_of_characters += 2;
958 		}
959 	}
960 	if( character_limit != 0 )
961 	{
962 		if( number_of_characters > (size_t) character_limit )
963 		{
964 			libcerror_error_set(
965 			 error,
966 			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
967 			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
968 			 "%s: number of characters in last line exceed maximum.",
969 			 function );
970 
971 			return( -1 );
972 		}
973 	}
974 	return( 1 );
975 }
976 
977 /* Determines the size of a base16 stream from a byte stream
978  * Returns 1 if successful or -1 on error
979  */
libuna_base16_stream_size_from_byte_stream(const uint8_t * byte_stream,size_t byte_stream_size,size_t * base16_stream_size,uint32_t base16_variant,libcerror_error_t ** error)980 int libuna_base16_stream_size_from_byte_stream(
981      const uint8_t *byte_stream,
982      size_t byte_stream_size,
983      size_t *base16_stream_size,
984      uint32_t base16_variant,
985      libcerror_error_t **error )
986 {
987 	static char *function          = "libuna_base16_stream_size_from_byte_stream";
988 	size_t base16_character_size   = 0;
989 	size_t safe_base16_stream_size = 0;
990 	size_t whitespace_size         = 0;
991 	uint8_t character_limit        = 0;
992 
993 	if( byte_stream == NULL )
994 	{
995 		libcerror_error_set(
996 		 error,
997 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
998 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
999 		 "%s: invalid byte stream.",
1000 		 function );
1001 
1002 		return( -1 );
1003 	}
1004 	if( byte_stream_size > (size_t) SSIZE_MAX )
1005 	{
1006 		libcerror_error_set(
1007 		 error,
1008 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1009 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1010 		 "%s: invalid byte stream size value exceeds maximum.",
1011 		 function );
1012 
1013 		return( -1 );
1014 	}
1015 	if( base16_stream_size == NULL )
1016 	{
1017 		libcerror_error_set(
1018 		 error,
1019 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1020 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1021 		 "%s: invalid base16 stream size.",
1022 		 function );
1023 
1024 		return( -1 );
1025 	}
1026 	switch( base16_variant & 0x000000ffUL )
1027 	{
1028 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE:
1029 			character_limit = 0;
1030 			break;
1031 
1032 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
1033 			character_limit = 64;
1034 			break;
1035 
1036 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
1037 			character_limit = 76;
1038 			break;
1039 
1040 		default:
1041 			libcerror_error_set(
1042 			 error,
1043 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1044 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1045 			 "%s: unsupported base16 variant.",
1046 			 function );
1047 
1048 			return( -1 );
1049 	}
1050 	switch( base16_variant & 0x000f0000UL )
1051 	{
1052 		case LIBUNA_BASE16_VARIANT_CASE_LOWER:
1053 		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
1054 		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
1055 			break;
1056 
1057 		default:
1058 			libcerror_error_set(
1059 			 error,
1060 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1061 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1062 			 "%s: unsupported base16 variant.",
1063 			 function );
1064 
1065 			return( -1 );
1066 	}
1067 	switch( base16_variant & 0xf0000000UL )
1068 	{
1069 		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1070 			base16_character_size = 1;
1071 			break;
1072 
1073 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1074 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1075 			base16_character_size = 2;
1076 			break;
1077 
1078 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1079 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1080 			base16_character_size = 4;
1081 			break;
1082 
1083 		default:
1084 			libcerror_error_set(
1085 			 error,
1086 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1087 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1088 			 "%s: unsupported base16 variant.",
1089 			 function );
1090 
1091 			return( -1 );
1092 	}
1093 	/* The base16 stream contains 2 characters for every byte
1094 	 */
1095 	safe_base16_stream_size = byte_stream_size * 2;
1096 
1097 	if( character_limit != 0 )
1098 	{
1099 		whitespace_size = safe_base16_stream_size / character_limit;
1100 
1101 		if( ( safe_base16_stream_size % character_limit ) != 0 )
1102 		{
1103 			whitespace_size += 1;
1104 		}
1105 		safe_base16_stream_size += whitespace_size;
1106 	}
1107 	*base16_stream_size = safe_base16_stream_size * base16_character_size;
1108 
1109 	return( 1 );
1110 }
1111 
1112 /* Copies a base16 stream from a byte stream
1113  * Returns 1 if successful or -1 on error
1114  */
libuna_base16_stream_copy_from_byte_stream(uint8_t * base16_stream,size_t base16_stream_size,const uint8_t * byte_stream,size_t byte_stream_size,uint32_t base16_variant,libcerror_error_t ** error)1115 int libuna_base16_stream_copy_from_byte_stream(
1116      uint8_t *base16_stream,
1117      size_t base16_stream_size,
1118      const uint8_t *byte_stream,
1119      size_t byte_stream_size,
1120      uint32_t base16_variant,
1121      libcerror_error_t **error )
1122 {
1123 	static char *function      = "libuna_base16_stream_copy_from_byte_stream";
1124 	size_t base16_stream_index = 0;
1125 
1126 	if( libuna_base16_stream_with_index_copy_from_byte_stream(
1127 	     base16_stream,
1128 	     base16_stream_size,
1129 	     &base16_stream_index,
1130 	     byte_stream,
1131 	     byte_stream_size,
1132 	     base16_variant,
1133 	     error ) != 1 )
1134 	{
1135 		libcerror_error_set(
1136 		 error,
1137 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
1138 		 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
1139 		 "%s: unable to copy base16 stream from byte stream.",
1140 		 function );
1141 
1142 		return( -1 );
1143 	}
1144 	return( 1 );
1145 }
1146 
1147 /* Copies a base16 stream from a byte stream
1148  * Returns 1 if successful or -1 on error
1149  */
libuna_base16_stream_with_index_copy_from_byte_stream(uint8_t * base16_stream,size_t base16_stream_size,size_t * base16_stream_index,const uint8_t * byte_stream,size_t byte_stream_size,uint32_t base16_variant,libcerror_error_t ** error)1150 int libuna_base16_stream_with_index_copy_from_byte_stream(
1151      uint8_t *base16_stream,
1152      size_t base16_stream_size,
1153      size_t *base16_stream_index,
1154      const uint8_t *byte_stream,
1155      size_t byte_stream_size,
1156      uint32_t base16_variant,
1157      libcerror_error_t **error )
1158 {
1159 	static char *function                = "libuna_base16_stream_with_index_copy_from_byte_stream";
1160 	size_t base16_character_size         = 0;
1161 	size_t byte_stream_index             = 0;
1162 	size_t calculated_base16_stream_size = 0;
1163 	size_t number_of_characters          = 0;
1164 	size_t safe_base16_stream_index      = 0;
1165 	size_t whitespace_size               = 0;
1166 	uint32_t a_character_value           = 0;
1167 	uint32_t base16_character            = 0;
1168 	uint8_t character_limit              = 0;
1169 
1170 	if( base16_stream == NULL )
1171 	{
1172 		libcerror_error_set(
1173 		 error,
1174 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1175 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1176 		 "%s: invalid base16 stream.",
1177 		 function );
1178 
1179 		return( -1 );
1180 	}
1181 	if( base16_stream_size > (size_t) SSIZE_MAX )
1182 	{
1183 		libcerror_error_set(
1184 		 error,
1185 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1186 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1187 		 "%s: invalid base16 stream size value exceeds maximum.",
1188 		 function );
1189 
1190 		return( -1 );
1191 	}
1192 	if( base16_stream_index == NULL )
1193 	{
1194 		libcerror_error_set(
1195 		 error,
1196 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1197 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1198 		 "%s: invalid base16 stream index.",
1199 		 function );
1200 
1201 		return( -1 );
1202 	}
1203 	if( *base16_stream_index >= base16_stream_size )
1204 	{
1205 		libcerror_error_set(
1206 		 error,
1207 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1208 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1209 		 "%s: base16 stream string too small.",
1210 		 function );
1211 
1212 		return( -1 );
1213 	}
1214 	if( byte_stream == NULL )
1215 	{
1216 		libcerror_error_set(
1217 		 error,
1218 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1219 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1220 		 "%s: invalid byte stream.",
1221 		 function );
1222 
1223 		return( -1 );
1224 	}
1225 	if( byte_stream_size > (size_t) SSIZE_MAX )
1226 	{
1227 		libcerror_error_set(
1228 		 error,
1229 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1230 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1231 		 "%s: invalid byte stream size value exceeds maximum.",
1232 		 function );
1233 
1234 		return( -1 );
1235 	}
1236 	switch( base16_variant & 0x000000ffUL )
1237 	{
1238 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE:
1239 			character_limit = 0;
1240 			break;
1241 
1242 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
1243 			character_limit = 64;
1244 			break;
1245 
1246 		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
1247 			character_limit = 76;
1248 			break;
1249 
1250 		default:
1251 			libcerror_error_set(
1252 			 error,
1253 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1254 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1255 			 "%s: unsupported base16 variant.",
1256 			 function );
1257 
1258 			return( -1 );
1259 	}
1260 	switch( base16_variant & 0x000f0000UL )
1261 	{
1262 		case LIBUNA_BASE16_VARIANT_CASE_LOWER:
1263 			a_character_value = (uint32_t) 'a' - 10;
1264 			break;
1265 
1266 		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
1267 		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
1268 			a_character_value = (uint32_t) 'A' - 10;
1269 			break;
1270 
1271 		default:
1272 			libcerror_error_set(
1273 			 error,
1274 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1275 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1276 			 "%s: unsupported base16 variant.",
1277 			 function );
1278 
1279 			return( -1 );
1280 	}
1281 	switch( base16_variant & 0xf0000000UL )
1282 	{
1283 		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1284 			base16_character_size = 1;
1285 			break;
1286 
1287 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1288 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1289 			base16_character_size = 2;
1290 			break;
1291 
1292 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1293 		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1294 			base16_character_size = 4;
1295 			break;
1296 
1297 		default:
1298 			libcerror_error_set(
1299 			 error,
1300 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1301 			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
1302 			 "%s: unsupported base16 variant.",
1303 			 function );
1304 
1305 			return( -1 );
1306 	}
1307 	safe_base16_stream_index = *base16_stream_index;
1308 
1309 	/* Make sure the base16 stream is able to hold
1310 	 * at least 2 bytes for each byte
1311 	 */
1312 	calculated_base16_stream_size = byte_stream_size * 2;
1313 
1314 	if( character_limit != 0 )
1315 	{
1316 		whitespace_size = calculated_base16_stream_size / character_limit;
1317 
1318 		if( ( calculated_base16_stream_size % character_limit ) != 0 )
1319 		{
1320 			whitespace_size += 1;
1321 		}
1322 		calculated_base16_stream_size += whitespace_size;
1323 	}
1324 	calculated_base16_stream_size *= base16_character_size;
1325 
1326 	if( base16_stream_size < calculated_base16_stream_size )
1327 	{
1328 		libcerror_error_set(
1329 		 error,
1330 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1331 		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1332 		 "%s: base16 stream is too small.",
1333 		 function );
1334 
1335 		return( -1 );
1336 	}
1337 	while( byte_stream_index < byte_stream_size )
1338 	{
1339 		base16_character = byte_stream[ byte_stream_index ] >> 4;
1340 
1341 		if( base16_character <= 9 )
1342 		{
1343 			base16_character += (uint32_t) '0';
1344 		}
1345 		else
1346 		{
1347 			base16_character += a_character_value;
1348 		}
1349 		switch( base16_variant & 0xf0000000UL )
1350 		{
1351 			case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1352 				base16_stream[ safe_base16_stream_index ] = (uint8_t) base16_character;
1353 				break;
1354 
1355 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1356 				byte_stream_copy_from_uint16_big_endian(
1357 				 &( base16_stream[ safe_base16_stream_index ] ),
1358 				 base16_character );
1359 				break;
1360 
1361 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1362 				byte_stream_copy_from_uint16_little_endian(
1363 				 &( base16_stream[ safe_base16_stream_index ] ),
1364 				 base16_character );
1365 				break;
1366 
1367 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1368 				byte_stream_copy_from_uint32_big_endian(
1369 				 &( base16_stream[ safe_base16_stream_index ] ),
1370 				 base16_character );
1371 				break;
1372 
1373 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1374 				byte_stream_copy_from_uint32_little_endian(
1375 				 &( base16_stream[ safe_base16_stream_index ] ),
1376 				 base16_character );
1377 				break;
1378 		}
1379 		safe_base16_stream_index += base16_character_size;
1380 
1381 		base16_character = byte_stream[ byte_stream_index ] & 0x0f;
1382 
1383 		if( base16_character <= 9 )
1384 		{
1385 			base16_character += (uint32_t) '0';
1386 		}
1387 		else
1388 		{
1389 			base16_character += a_character_value;
1390 		}
1391 		switch( base16_variant & 0xf0000000UL )
1392 		{
1393 			case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1394 				base16_stream[ safe_base16_stream_index ] = (uint8_t) base16_character;
1395 				break;
1396 
1397 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1398 				byte_stream_copy_from_uint16_big_endian(
1399 				 &( base16_stream[ safe_base16_stream_index ] ),
1400 				 base16_character );
1401 				break;
1402 
1403 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1404 				byte_stream_copy_from_uint16_little_endian(
1405 				 &( base16_stream[ safe_base16_stream_index ] ),
1406 				 base16_character );
1407 				break;
1408 
1409 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1410 				byte_stream_copy_from_uint32_big_endian(
1411 				 &( base16_stream[ safe_base16_stream_index ] ),
1412 				 base16_character );
1413 				break;
1414 
1415 			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1416 				byte_stream_copy_from_uint32_little_endian(
1417 				 &( base16_stream[ safe_base16_stream_index ] ),
1418 				 base16_character );
1419 				break;
1420 		}
1421 		safe_base16_stream_index += base16_character_size;
1422 
1423 		if( character_limit != 0 )
1424 		{
1425 			number_of_characters += 2;
1426 
1427 			if( number_of_characters >= (size_t) character_limit )
1428 			{
1429 				base16_character = (uint32_t) '\n';
1430 
1431 				switch( base16_variant & 0xf0000000UL )
1432 				{
1433 					case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1434 						base16_stream[ safe_base16_stream_index ] = (uint8_t) base16_character;
1435 						break;
1436 
1437 					case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1438 						byte_stream_copy_from_uint16_big_endian(
1439 						 &( base16_stream[ safe_base16_stream_index ] ),
1440 						 base16_character );
1441 						break;
1442 
1443 					case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1444 						byte_stream_copy_from_uint16_little_endian(
1445 						 &( base16_stream[ safe_base16_stream_index ] ),
1446 						 base16_character );
1447 						break;
1448 
1449 					case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1450 						byte_stream_copy_from_uint32_big_endian(
1451 						 &( base16_stream[ safe_base16_stream_index ] ),
1452 						 base16_character );
1453 						break;
1454 
1455 					case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1456 						byte_stream_copy_from_uint32_little_endian(
1457 						 &( base16_stream[ safe_base16_stream_index ] ),
1458 						 base16_character );
1459 						break;
1460 				}
1461 				safe_base16_stream_index += base16_character_size;
1462 
1463 				number_of_characters = 0;
1464 			}
1465 		}
1466 		byte_stream_index++;
1467 	}
1468 	if( character_limit != 0 )
1469 	{
1470 		if( number_of_characters != 0 )
1471 		{
1472 			base16_character = (uint32_t) '\n';
1473 
1474 			switch( base16_variant & 0xf0000000UL )
1475 			{
1476 				case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
1477 					base16_stream[ safe_base16_stream_index ] = (uint8_t) base16_character;
1478 					break;
1479 
1480 				case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
1481 					byte_stream_copy_from_uint16_big_endian(
1482 					 &( base16_stream[ safe_base16_stream_index ] ),
1483 					 base16_character );
1484 					break;
1485 
1486 				case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
1487 					byte_stream_copy_from_uint16_little_endian(
1488 					 &( base16_stream[ safe_base16_stream_index ] ),
1489 					 base16_character );
1490 					break;
1491 
1492 				case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
1493 					byte_stream_copy_from_uint32_big_endian(
1494 					 &( base16_stream[ safe_base16_stream_index ] ),
1495 					 base16_character );
1496 					break;
1497 
1498 				case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
1499 					byte_stream_copy_from_uint32_little_endian(
1500 					 &( base16_stream[ safe_base16_stream_index ] ),
1501 					 base16_character );
1502 					break;
1503 			}
1504 			safe_base16_stream_index += base16_character_size;
1505 		}
1506 	}
1507 	*base16_stream_index = safe_base16_stream_index;
1508 
1509 	return( 1 );
1510 }
1511 
1512