1 /*
2  * Percent or URL encoded 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 <types.h>
24 
25 #include "libuna_definitions.h"
26 #include "libuna_libcerror.h"
27 #include "libuna_types.h"
28 #include "libuna_url_stream.h"
29 
30 /* Determines the size of a url stream from a byte stream
31  * Returns 1 if successful or -1 on error
32  */
libuna_url_stream_size_from_byte_stream(uint8_t * byte_stream,size_t byte_stream_size,size_t * url_stream_size,libcerror_error_t ** error)33 int libuna_url_stream_size_from_byte_stream(
34      uint8_t *byte_stream,
35      size_t byte_stream_size,
36      size_t *url_stream_size,
37      libcerror_error_t **error )
38 {
39 	static char *function    = "libuna_url_stream_size_from_byte_stream";
40 	size_t byte_stream_index = 0;
41 
42 	if( byte_stream == NULL )
43 	{
44 		libcerror_error_set(
45 		 error,
46 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
47 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
48 		 "%s: invalid byte stream.",
49 		 function );
50 
51 		return( -1 );
52 	}
53 	if( byte_stream_size > (size_t) SSIZE_MAX )
54 	{
55 		libcerror_error_set(
56 		 error,
57 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
59 		 "%s: invalid byte stream size value exceeds maximum.",
60 		 function );
61 
62 		return( -1 );
63 	}
64 	if( url_stream_size == NULL )
65 	{
66 		libcerror_error_set(
67 		 error,
68 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
69 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
70 		 "%s: invalid url stream size.",
71 		 function );
72 
73 		return( -1 );
74 	}
75 	/* TODO what about end of string character */
76 
77 	*url_stream_size = 0;
78 
79 	/* Check if the byte stream contains
80 	 * reserved or non-allowed characters that need to be decoded
81 	 */
82 	while( byte_stream_index < byte_stream_size )
83 	{
84 		/* A-Z is not a continous range on an EBCDIC based system
85 		 * it consists of the ranges: A-I, J-R, S-Z
86 		 */
87 		if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'A' )
88 		 && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'I' ) )
89 		{
90 			*url_stream_size += 1;
91 		}
92 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'J' )
93 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'R' ) )
94 		{
95 			*url_stream_size += 1;
96 		}
97 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'S' )
98 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'Z' ) )
99 		{
100 			*url_stream_size += 1;
101 		}
102 		/* a-z is not a continous range on an EBCDIC based system
103 		 * it consists of the ranges: a-i, j-r, s-z
104 		 */
105 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'a' )
106 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'i' ) )
107 		{
108 			*url_stream_size += 1;
109 		}
110 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'j' )
111 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'r' ) )
112 		{
113 			*url_stream_size += 1;
114 		}
115 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 's' )
116 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'z' ) )
117 		{
118 			*url_stream_size += 1;
119 		}
120 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) '0' )
121 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) '9' ) )
122 		{
123 			*url_stream_size += 1;
124 		}
125 		else if( ( byte_stream[ byte_stream_index ] == (uint8_t) '-' )
126 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '_' )
127 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '.' )
128 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '`' ) )
129 		{
130 			*url_stream_size += 1;
131 		}
132 		else
133 		{
134 			*url_stream_size += 3;
135 		}
136 		byte_stream_index++;
137 	}
138 	return( 1 );
139 }
140 
141 /* Copies a url stream from a byte stream
142  * Returns 1 if successful or -1 on error
143  */
libuna_url_stream_copy_from_byte_stream(uint8_t * url_stream,size_t url_stream_size,uint8_t * byte_stream,size_t byte_stream_size,libcerror_error_t ** error)144 int libuna_url_stream_copy_from_byte_stream(
145      uint8_t *url_stream,
146      size_t url_stream_size,
147      uint8_t *byte_stream,
148      size_t byte_stream_size,
149      libcerror_error_t **error )
150 {
151 	static char *function    = "libuna_url_stream_copy_from_byte_stream";
152 	size_t url_stream_index  = 0;
153 	size_t byte_stream_index = 0;
154 	uint8_t byte_value       = 0;
155 
156 	if( url_stream == NULL )
157 	{
158 		libcerror_error_set(
159 		 error,
160 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
161 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
162 		 "%s: invalid url stream.",
163 		 function );
164 
165 		return( -1 );
166 	}
167 	if( url_stream_size > (size_t) SSIZE_MAX )
168 	{
169 		libcerror_error_set(
170 		 error,
171 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
172 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
173 		 "%s: invalid url stream size value exceeds maximum.",
174 		 function );
175 
176 		return( -1 );
177 	}
178 	if( byte_stream == NULL )
179 	{
180 		libcerror_error_set(
181 		 error,
182 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
183 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
184 		 "%s: invalid byte stream.",
185 		 function );
186 
187 		return( -1 );
188 	}
189 	if( byte_stream_size > (size_t) SSIZE_MAX )
190 	{
191 		libcerror_error_set(
192 		 error,
193 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
194 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
195 		 "%s: invalid byte stream size value exceeds maximum.",
196 		 function );
197 
198 		return( -1 );
199 	}
200 	/* TODO what about end of string character */
201 
202 	/* Check if the byte stream contains
203 	 * reserved or non-allowed characters that need to be decoded
204 	 */
205 	while( byte_stream_index < byte_stream_size )
206 	{
207 		if( url_stream_index >= url_stream_size )
208 		{
209 			libcerror_error_set(
210 			 error,
211 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
212 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
213 			 "%s: url stream is too small.",
214 			 function );
215 
216 			return( -1 );
217 		}
218 		/* A-Z is not a continous range on an EBCDIC based system
219 		 * it consists of the ranges: A-I, J-R, S-Z
220 		 */
221 		if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'A' )
222 		 && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'I' ) )
223 		{
224 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
225 		}
226 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'J' )
227 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'R' ) )
228 		{
229 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
230 		}
231 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'S' )
232 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'Z' ) )
233 		{
234 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
235 		}
236 		/* a-z is not a continous range on an EBCDIC based system
237 		 * it consists of the ranges: a-i, j-r, s-z
238 		 */
239 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'a' )
240 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'i' ) )
241 		{
242 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
243 		}
244 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 'j' )
245 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'r' ) )
246 		{
247 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
248 		}
249 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) 's' )
250 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) 'z' ) )
251 		{
252 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
253 		}
254 		else if( ( byte_stream[ byte_stream_index ] >= (uint8_t) '0' )
255 		      && ( byte_stream[ byte_stream_index ] <= (uint8_t) '9' ) )
256 		{
257 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
258 		}
259 		else if( ( byte_stream[ byte_stream_index ] == (uint8_t) '-' )
260 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '_' )
261 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '.' )
262 		      || ( byte_stream[ byte_stream_index ] == (uint8_t) '`' ) )
263 		{
264 			url_stream[ url_stream_index++ ] = byte_stream[ byte_stream_index ];
265 		}
266 		else
267 		{
268 			if( ( url_stream_index + 3 ) > url_stream_size )
269 			{
270 				libcerror_error_set(
271 				 error,
272 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
273 				 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
274 				 "%s: url stream is too small.",
275 				 function );
276 
277 				return( -1 );
278 			}
279 			url_stream[ url_stream_index++ ] = (uint8_t) '%';
280 
281 			byte_value = byte_stream[ byte_stream_index ] >> 4;
282 
283 			if( byte_value <= 9 )
284 			{
285 				url_stream[ url_stream_index++ ] = (uint8_t) '0' + byte_value;
286 			}
287 			else
288 			{
289 				url_stream[ url_stream_index++ ] = (uint8_t) 'A' + byte_value;
290 			}
291 			byte_value = byte_stream[ byte_stream_index ] & 0x0f;
292 
293 			if( byte_value < 9 )
294 			{
295 				url_stream[ url_stream_index++ ] = (uint8_t) '0' + byte_value;
296 			}
297 			else
298 			{
299 				url_stream[ url_stream_index++ ] = (uint8_t) 'A' + byte_value;
300 			}
301 		}
302 		byte_stream_index++;
303 	}
304 	return( 1 );
305 }
306 
307 /* Determines the size of a byte stream from a url stream
308  * Returns 1 if successful or -1 on error
309  */
libuna_url_stream_size_to_byte_stream(uint8_t * url_stream,size_t url_stream_size,size_t * byte_stream_size,libcerror_error_t ** error)310 int libuna_url_stream_size_to_byte_stream(
311      uint8_t *url_stream,
312      size_t url_stream_size,
313      size_t *byte_stream_size,
314      libcerror_error_t **error )
315 {
316 	static char *function   = "libuna_url_stream_size_to_byte_stream";
317 	size_t url_stream_index = 0;
318 
319 	if( url_stream == NULL )
320 	{
321 		libcerror_error_set(
322 		 error,
323 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
324 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
325 		 "%s: invalid url stream.",
326 		 function );
327 
328 		return( -1 );
329 	}
330 	if( url_stream_size > (size_t) SSIZE_MAX )
331 	{
332 		libcerror_error_set(
333 		 error,
334 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
335 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
336 		 "%s: invalid url stream size value exceeds maximum.",
337 		 function );
338 
339 		return( -1 );
340 	}
341 	if( byte_stream_size == NULL )
342 	{
343 		libcerror_error_set(
344 		 error,
345 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
346 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
347 		 "%s: invalid byte stream size.",
348 		 function );
349 
350 		return( -1 );
351 	}
352 	*byte_stream_size = 0;
353 
354 	while( url_stream_index < url_stream_size )
355 	{
356 		if( url_stream[ url_stream_index ] == (uint8_t) '%' )
357 		{
358 			url_stream_index++;
359 
360 			if( ( url_stream_index + 2 ) > url_stream_size )
361 			{
362 				libcerror_error_set(
363 				 error,
364 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
365 				 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
366 				 "%s: url stream is too small.",
367 				 function );
368 
369 				return( -1 );
370 			}
371 			if( ( url_stream[ url_stream_index ] >= (uint8_t) 'A' )
372 			 && ( url_stream[ url_stream_index ] <= (uint8_t) 'F' ) )
373 			{
374 			}
375 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) 'a' )
376 			      && ( url_stream[ url_stream_index ] <= (uint8_t) 'f' ) )
377 			{
378 			}
379 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) '0' )
380 			      && ( url_stream[ url_stream_index ] <= (uint8_t) '9' ) )
381 			{
382 			}
383 			else
384 			{
385 				libcerror_error_set(
386 				 error,
387 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
388 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
389 				 "%s: invalid URL encoded character.",
390 				 function );
391 
392 				return( -1 );
393 			}
394 			url_stream_index++;
395 
396 			if( ( url_stream[ url_stream_index ] >= (uint8_t) 'A' )
397 			 && ( url_stream[ url_stream_index ] <= (uint8_t) 'F' ) )
398 			{
399 			}
400 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) 'a' )
401 			      && ( url_stream[ url_stream_index ] <= (uint8_t) 'f' ) )
402 			{
403 			}
404 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) '0' )
405 			      && ( url_stream[ url_stream_index ] <= (uint8_t) '9' ) )
406 			{
407 			}
408 			else
409 			{
410 				libcerror_error_set(
411 				 error,
412 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
413 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
414 				 "%s: invalid URL encoded character.",
415 				 function );
416 
417 				return( -1 );
418 			}
419 			url_stream_index++;
420 		}
421 		else
422 		{
423 			url_stream_index++;
424 		}
425 		*byte_stream_size += 1;
426 	}
427 	return( 1 );
428 }
429 
430 /* Copies a byte stream from a url stream
431  * Returns 1 if successful or -1 on error
432  */
libuna_url_stream_copy_to_byte_stream(uint8_t * url_stream,size_t url_stream_size,uint8_t * byte_stream,size_t byte_stream_size,libcerror_error_t ** error)433 int libuna_url_stream_copy_to_byte_stream(
434      uint8_t *url_stream,
435      size_t url_stream_size,
436      uint8_t *byte_stream,
437      size_t byte_stream_size,
438      libcerror_error_t **error )
439 {
440 	static char *function    = "libuna_url_stream_copy_to_byte_stream";
441 	size_t url_stream_index  = 0;
442 	size_t byte_stream_index = 0;
443 	uint8_t byte_value       = 0;
444 
445 	if( url_stream == NULL )
446 	{
447 		libcerror_error_set(
448 		 error,
449 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451 		 "%s: invalid url stream.",
452 		 function );
453 
454 		return( -1 );
455 	}
456 	if( url_stream_size > (size_t) SSIZE_MAX )
457 	{
458 		libcerror_error_set(
459 		 error,
460 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
461 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
462 		 "%s: invalid url stream size value exceeds maximum.",
463 		 function );
464 
465 		return( -1 );
466 	}
467 	if( byte_stream == NULL )
468 	{
469 		libcerror_error_set(
470 		 error,
471 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
472 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
473 		 "%s: invalid byte stream.",
474 		 function );
475 
476 		return( -1 );
477 	}
478 	if( byte_stream_size > (size_t) SSIZE_MAX )
479 	{
480 		libcerror_error_set(
481 		 error,
482 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
483 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
484 		 "%s: invalid byte stream size value exceeds maximum.",
485 		 function );
486 
487 		return( -1 );
488 	}
489 	while( url_stream_index < url_stream_size )
490 	{
491 		if( byte_stream_index >= byte_stream_size )
492 		{
493 			libcerror_error_set(
494 			 error,
495 			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
496 			 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
497 			 "%s: byte stream is too small.",
498 			 function );
499 
500 			return( -1 );
501 		}
502 		if( url_stream[ url_stream_index ] == (uint8_t) '%' )
503 		{
504 			url_stream_index++;
505 
506 			if( ( url_stream_index + 2 ) > url_stream_size )
507 			{
508 				libcerror_error_set(
509 				 error,
510 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
511 				 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
512 				 "%s: url stream is too small.",
513 				 function );
514 
515 				return( -1 );
516 			}
517 			if( ( url_stream[ url_stream_index ] >= (uint8_t) 'A' )
518 			 && ( url_stream[ url_stream_index ] <= (uint8_t) 'F' ) )
519 			{
520 				byte_value = url_stream[ url_stream_index ] - (uint8_t) 'A';
521 			}
522 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) 'a' )
523 			      && ( url_stream[ url_stream_index ] <= (uint8_t) 'f' ) )
524 			{
525 				byte_value = url_stream[ url_stream_index ] - (uint8_t) 'a';
526 			}
527 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) '0' )
528 			      && ( url_stream[ url_stream_index ] <= (uint8_t) '9' ) )
529 			{
530 				byte_value = url_stream[ url_stream_index ] - (uint8_t) '0';
531 			}
532 			else
533 			{
534 				libcerror_error_set(
535 				 error,
536 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
537 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
538 				 "%s: invalid URL encoded character.",
539 				 function );
540 
541 				return( -1 );
542 			}
543 			byte_value <<= 4;
544 
545 			url_stream_index++;
546 
547 			if( ( url_stream[ url_stream_index ] >= (uint8_t) 'A' )
548 			 && ( url_stream[ url_stream_index ] <= (uint8_t) 'F' ) )
549 			{
550 				byte_value += url_stream[ url_stream_index ] - (uint8_t) 'A';
551 			}
552 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) 'a' )
553 			      && ( url_stream[ url_stream_index ] <= (uint8_t) 'f' ) )
554 			{
555 				byte_value += url_stream[ url_stream_index ] - (uint8_t) 'a';
556 			}
557 			else if( ( url_stream[ url_stream_index ] >= (uint8_t) '0' )
558 			      && ( url_stream[ url_stream_index ] <= (uint8_t) '9' ) )
559 			{
560 				byte_value += url_stream[ url_stream_index ] - (uint8_t) '0';
561 			}
562 			else
563 			{
564 				libcerror_error_set(
565 				 error,
566 				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
567 				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
568 				 "%s: invalid URL encoded character.",
569 				 function );
570 
571 				return( -1 );
572 			}
573 			url_stream_index++;
574 
575 			byte_stream[ byte_stream_index++ ] = byte_value;
576 		}
577 		else
578 		{
579 			byte_stream[ byte_stream_index++ ] = url_stream[ url_stream_index++ ];
580 		}
581 	}
582 	return( 1 );
583 }
584 
585