1 /*
2  * Strings array functions
3  *
4  * Copyright (C) 2011-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 <memory.h>
24 #include <types.h>
25 
26 #include "libevt_libcerror.h"
27 #include "libevt_libcnotify.h"
28 #include "libevt_libuna.h"
29 #include "libevt_strings_array.h"
30 
31 /* Creates a strings array
32  * Make sure the value strings_array is referencing, is set to NULL
33  * Returns 1 if successful or -1 on error
34  */
libevt_strings_array_initialize(libevt_strings_array_t ** strings_array,libcerror_error_t ** error)35 int libevt_strings_array_initialize(
36      libevt_strings_array_t **strings_array,
37      libcerror_error_t **error )
38 {
39 	static char *function = "libevt_strings_array_initialize";
40 
41 	if( strings_array == NULL )
42 	{
43 		libcerror_error_set(
44 		 error,
45 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
46 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
47 		 "%s: invalid strings array.",
48 		 function );
49 
50 		return( -1 );
51 	}
52 	if( *strings_array != NULL )
53 	{
54 		libcerror_error_set(
55 		 error,
56 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
57 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
58 		 "%s: invalid strings array value already set.",
59 		 function );
60 
61 		return( -1 );
62 	}
63 	*strings_array = memory_allocate_structure(
64 	                  libevt_strings_array_t );
65 
66 	if( *strings_array == NULL )
67 	{
68 		libcerror_error_set(
69 		 error,
70 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
71 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
72 		 "%s: unable to create strings array.",
73 		 function );
74 
75 		goto on_error;
76 	}
77 	if( memory_set(
78 	     *strings_array,
79 	     0,
80 	     sizeof( libevt_strings_array_t ) ) == NULL )
81 	{
82 		libcerror_error_set(
83 		 error,
84 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
85 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
86 		 "%s: unable to clear strings array.",
87 		 function );
88 
89 		goto on_error;
90 	}
91 	return( 1 );
92 
93 on_error:
94 	if( *strings_array != NULL )
95 	{
96 		memory_free(
97 		 *strings_array );
98 
99 		*strings_array = NULL;
100 	}
101 	return( -1 );
102 }
103 
104 /* Frees a strings array
105  * Returns 1 if successful or -1 on error
106  */
libevt_strings_array_free(libevt_strings_array_t ** strings_array,libcerror_error_t ** error)107 int libevt_strings_array_free(
108      libevt_strings_array_t **strings_array,
109      libcerror_error_t **error )
110 {
111 	static char *function = "libevt_strings_array_free";
112 
113 	if( strings_array == NULL )
114 	{
115 		libcerror_error_set(
116 		 error,
117 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
118 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
119 		 "%s: invalid strings array.",
120 		 function );
121 
122 		return( -1 );
123 	}
124 	if( *strings_array != NULL )
125 	{
126 		if( ( *strings_array )->string_sizes != NULL )
127 		{
128 			memory_free(
129 			 ( *strings_array )->string_sizes );
130 		}
131 		if( ( *strings_array )->strings != NULL )
132 		{
133 			memory_free(
134 			 ( *strings_array )->strings );
135 		}
136 		if( ( *strings_array )->strings_data != NULL )
137 		{
138 			memory_free(
139 			 ( *strings_array )->strings_data );
140 		}
141 		memory_free(
142 		 *strings_array );
143 
144 		*strings_array = NULL;
145 	}
146 	return( 1 );
147 }
148 
149 /* Reads the strings array data
150  * Returns 1 if successful or -1 on error
151  */
libevt_strings_array_read_data(libevt_strings_array_t * strings_array,const uint8_t * data,size_t data_size,libcerror_error_t ** error)152 int libevt_strings_array_read_data(
153      libevt_strings_array_t *strings_array,
154      const uint8_t *data,
155      size_t data_size,
156      libcerror_error_t **error )
157 {
158 	static char *function = "libevt_strings_array_read_data";
159 	size_t data_offset    = 0;
160 	size_t string_offset  = 0;
161 	int number_of_strings = 0;
162 	int string_index      = 0;
163 
164 	if( strings_array == NULL )
165 	{
166 		libcerror_error_set(
167 		 error,
168 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
169 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
170 		 "%s: invalid strings array.",
171 		 function );
172 
173 		return( -1 );
174 	}
175 	if( strings_array->strings_data != NULL )
176 	{
177 		libcerror_error_set(
178 		 error,
179 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
180 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
181 		 "%s: invalid strings array - strings data value already set.",
182 		 function );
183 
184 		return( -1 );
185 	}
186 	if( data == NULL )
187 	{
188 		libcerror_error_set(
189 		 error,
190 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
191 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
192 		 "%s: invalid data.",
193 		 function );
194 
195 		return( -1 );
196 	}
197 	if( ( data_size < 2 )
198 	 || ( data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
199 	{
200 		libcerror_error_set(
201 		 error,
202 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
203 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
204 		 "%s: invalid data size value out of bounds.",
205 		 function );
206 
207 		return( -1 );
208 	}
209 	if( ( data_size % 2 ) != 0 )
210 	{
211 		libcerror_error_set(
212 		 error,
213 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
214 		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
215 		 "%s: invalid data size - value must be a multitude of 2.",
216 		 function );
217 
218 		return( -1 );
219 	}
220 #if defined( HAVE_DEBUG_OUTPUT )
221 	if( libcnotify_verbose != 0 )
222 	{
223 		libcnotify_printf(
224 		 "%s: strings array data:\n",
225 		 function );
226 		libcnotify_print_data(
227 		 data,
228 		 data_size,
229 		 0 );
230 	}
231 #endif
232 	for( data_offset = 0;
233 	     data_offset < data_size;
234 	     data_offset += 2 )
235 	{
236 		if( ( data[ data_offset ] == 0 )
237 		 && ( data[ data_offset + 1 ] == 0 ) )
238 		{
239 			number_of_strings++;
240 		}
241 	}
242 #if defined( HAVE_DEBUG_OUTPUT )
243 	if( libcnotify_verbose != 0 )
244 	{
245 		libcnotify_printf(
246 		 "%s: number of strings\t\t\t: %d\n",
247 		 function,
248 		 number_of_strings );
249 
250 		libcnotify_printf(
251 		 "\n" );
252 	}
253 #endif
254 	strings_array->strings_data = (uint8_t *) memory_allocate(
255 	                                           sizeof( uint8_t ) * data_size );
256 
257 	if( strings_array->strings_data == NULL )
258 	{
259 		libcerror_error_set(
260 		 error,
261 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
262 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
263 		 "%s: unable to create strings data.",
264 		 function );
265 
266 		goto on_error;
267 	}
268 	if( memory_copy(
269 	     strings_array->strings_data,
270 	     data,
271 	     sizeof( uint8_t ) * data_size ) == NULL )
272 	{
273 		libcerror_error_set(
274 		 error,
275 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
276 		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
277 		 "%s: unable to copy strings data.",
278 		 function );
279 
280 		goto on_error;
281 	}
282 	strings_array->strings_data_size = data_size;
283 
284 	strings_array->strings = (uint8_t **) memory_allocate(
285 	                                       sizeof( uint8_t* ) * number_of_strings );
286 
287 	if( strings_array->strings == NULL )
288 	{
289 		libcerror_error_set(
290 		 error,
291 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
292 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
293 		 "%s: unable to create strings.",
294 		 function );
295 
296 		goto on_error;
297 	}
298 	if( memory_set(
299 	     strings_array->strings,
300 	     0,
301 	     sizeof( uint8_t* ) * number_of_strings ) == NULL )
302 	{
303 		libcerror_error_set(
304 		 error,
305 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
306 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
307 		 "%s: unable to clear strings.",
308 		 function );
309 
310 		goto on_error;
311 	}
312 	strings_array->string_sizes = (size_t *) memory_allocate(
313 	                                          sizeof( size_t ) * number_of_strings );
314 
315 	if( strings_array->string_sizes == NULL )
316 	{
317 		libcerror_error_set(
318 		 error,
319 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
320 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
321 		 "%s: unable to create string sizes.",
322 		 function );
323 
324 		goto on_error;
325 	}
326 	if( memory_set(
327 	     strings_array->string_sizes,
328 	     0,
329 	     sizeof( uint8_t* ) * number_of_strings ) == NULL )
330 	{
331 		libcerror_error_set(
332 		 error,
333 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
334 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
335 		 "%s: unable to clear string sizes.",
336 		 function );
337 
338 		goto on_error;
339 	}
340 	for( data_offset = 0;
341 	     data_offset < strings_array->strings_data_size;
342 	     data_offset += 2 )
343 	{
344 		if( ( strings_array->strings_data[ data_offset ] == 0 )
345 		 && ( strings_array->strings_data[ data_offset + 1 ] == 0 ) )
346 		{
347 			strings_array->strings[ string_index ]      = &( strings_array->strings_data[ string_offset ] );
348 			strings_array->string_sizes[ string_index ] = ( data_offset + 2 ) - string_offset;
349 
350 #if defined( HAVE_DEBUG_OUTPUT )
351 			if( libcnotify_verbose != 0 )
352 			{
353 				libcnotify_printf(
354 				 "%s: string: %d data:\n",
355 				 function,
356 				 string_index );
357 				libcnotify_print_data(
358 				 strings_array->strings[ string_index ],
359 				 strings_array->string_sizes[ string_index ],
360 				 0 );
361 			}
362 #endif
363 			string_offset = data_offset + 2;
364 
365 			string_index++;
366 		}
367 	}
368 	strings_array->number_of_strings = number_of_strings;
369 
370 	return( 1 );
371 
372 on_error:
373 	if( strings_array->string_sizes != NULL )
374 	{
375 		memory_free(
376 		 strings_array->string_sizes );
377 
378 		strings_array->string_sizes = NULL;
379 	}
380 	if( strings_array->strings != NULL )
381 	{
382 		memory_free(
383 		 strings_array->strings );
384 
385 		strings_array->strings = NULL;
386 	}
387 	if( strings_array->strings_data != NULL )
388 	{
389 		memory_free(
390 		 strings_array->strings_data );
391 
392 		strings_array->strings_data = NULL;
393 	}
394 	strings_array->strings_data_size = 0;
395 
396 	return( -1 );
397 }
398 
399 /* Retrieves the number of strings
400  * Returns 1 if successful or -1 on error
401  */
libevt_strings_array_get_number_of_strings(libevt_strings_array_t * strings_array,int * number_of_strings,libcerror_error_t ** error)402 int libevt_strings_array_get_number_of_strings(
403      libevt_strings_array_t *strings_array,
404      int *number_of_strings,
405      libcerror_error_t **error )
406 {
407 	static char *function = "libevt_strings_array_get_number_of_strings";
408 
409 	if( strings_array == NULL )
410 	{
411 		libcerror_error_set(
412 		 error,
413 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
414 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
415 		 "%s: invalid strings array.",
416 		 function );
417 
418 		return( -1 );
419 	}
420 	if( number_of_strings == NULL )
421 	{
422 		libcerror_error_set(
423 		 error,
424 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
425 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
426 		 "%s: invalid number of strings.",
427 		 function );
428 
429 		return( -1 );
430 	}
431 	*number_of_strings = strings_array->number_of_strings;
432 
433 	return( 1 );
434 }
435 
436 /* Retrieves the size of a specific UTF-8 encoded string
437  * The returned size includes the end of string character
438  * Returns 1 if successful or -1 on error
439  */
libevt_strings_array_get_utf8_string_size(libevt_strings_array_t * strings_array,int string_index,size_t * utf8_string_size,libcerror_error_t ** error)440 int libevt_strings_array_get_utf8_string_size(
441      libevt_strings_array_t *strings_array,
442      int string_index,
443      size_t *utf8_string_size,
444      libcerror_error_t **error )
445 {
446 	static char *function = "libevt_strings_array_get_utf8_string_size";
447 
448 	if( strings_array == NULL )
449 	{
450 		libcerror_error_set(
451 		 error,
452 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
453 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
454 		 "%s: invalid record values.",
455 		 function );
456 
457 		return( -1 );
458 	}
459 	if( strings_array->strings == NULL )
460 	{
461 		libcerror_error_set(
462 		 error,
463 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
464 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
465 		 "%s: invalid string index value out of bounds.",
466 		 function );
467 
468 		return( -1 );
469 	}
470 	if( ( string_index < 0 )
471 	 || ( string_index >= strings_array->number_of_strings ) )
472 	{
473 		libcerror_error_set(
474 		 error,
475 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
476 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
477 		 "%s: invalid strings index value out of bounds.",
478 		 function );
479 
480 		return( -1 );
481 	}
482 	if( libuna_utf8_string_size_from_utf16_stream(
483 	     strings_array->strings[ string_index ],
484 	     strings_array->string_sizes[ string_index ],
485 	     LIBUNA_ENDIAN_LITTLE,
486 	     utf8_string_size,
487 	     error ) != 1 )
488 	{
489 		libcerror_error_set(
490 		 error,
491 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
492 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
493 		 "%s: unable to determine size of UTF-8 string: %d.",
494 		 function,
495 		 string_index );
496 
497 		return( -1 );
498 	}
499 	return( 1 );
500 }
501 
502 /* Retrieves a specific UTF-8 encoded string
503  * The size should include the end of string character
504  * Returns 1 if successful or -1 on error
505  */
libevt_strings_array_get_utf8_string(libevt_strings_array_t * strings_array,int string_index,uint8_t * utf8_string,size_t utf8_string_size,libcerror_error_t ** error)506 int libevt_strings_array_get_utf8_string(
507      libevt_strings_array_t *strings_array,
508      int string_index,
509      uint8_t *utf8_string,
510      size_t utf8_string_size,
511      libcerror_error_t **error )
512 {
513 	static char *function = "libevt_values_record_get_utf8_string";
514 
515 	if( strings_array == NULL )
516 	{
517 		libcerror_error_set(
518 		 error,
519 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
520 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
521 		 "%s: invalid record values.",
522 		 function );
523 
524 		return( -1 );
525 	}
526 	if( strings_array->strings == NULL )
527 	{
528 		libcerror_error_set(
529 		 error,
530 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
531 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
532 		 "%s: invalid string index value out of bounds.",
533 		 function );
534 
535 		return( -1 );
536 	}
537 	if( ( string_index < 0 )
538 	 || ( string_index >= strings_array->number_of_strings ) )
539 	{
540 		libcerror_error_set(
541 		 error,
542 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
543 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
544 		 "%s: invalid strings index value out of bounds.",
545 		 function );
546 
547 		return( -1 );
548 	}
549 	if( libuna_utf8_string_copy_from_utf16_stream(
550 	     (libuna_utf8_character_t *) utf8_string,
551 	     utf8_string_size,
552 	     strings_array->strings[ string_index ],
553 	     strings_array->string_sizes[ string_index ],
554 	     LIBUNA_ENDIAN_LITTLE,
555 	     error ) != 1 )
556 	{
557 		libcerror_error_set(
558 		 error,
559 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
560 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
561 		 "%s: unable to set UTF-8 string: %d.",
562 		 function,
563 		 string_index );
564 
565 		return( -1 );
566 	}
567 	return( 1 );
568 }
569 
570 /* Retrieves the size of a specific UTF-16 encoded string
571  * The returned size includes the end of string character
572  * Returns 1 if successful or -1 on error
573  */
libevt_strings_array_get_utf16_string_size(libevt_strings_array_t * strings_array,int string_index,size_t * utf16_string_size,libcerror_error_t ** error)574 int libevt_strings_array_get_utf16_string_size(
575      libevt_strings_array_t *strings_array,
576      int string_index,
577      size_t *utf16_string_size,
578      libcerror_error_t **error )
579 {
580 	static char *function = "libevt_strings_array_get_utf16_string_size";
581 
582 	if( strings_array == NULL )
583 	{
584 		libcerror_error_set(
585 		 error,
586 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
587 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
588 		 "%s: invalid record values.",
589 		 function );
590 
591 		return( -1 );
592 	}
593 	if( strings_array->strings == NULL )
594 	{
595 		libcerror_error_set(
596 		 error,
597 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
598 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
599 		 "%s: invalid string index value out of bounds.",
600 		 function );
601 
602 		return( -1 );
603 	}
604 	if( ( string_index < 0 )
605 	 || ( string_index >= strings_array->number_of_strings ) )
606 	{
607 		libcerror_error_set(
608 		 error,
609 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
610 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
611 		 "%s: invalid strings index value out of bounds.",
612 		 function );
613 
614 		return( -1 );
615 	}
616 	if( libuna_utf16_string_size_from_utf16_stream(
617 	     strings_array->strings[ string_index ],
618 	     strings_array->string_sizes[ string_index ],
619 	     LIBUNA_ENDIAN_LITTLE,
620 	     utf16_string_size,
621 	     error ) != 1 )
622 	{
623 		libcerror_error_set(
624 		 error,
625 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
626 		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
627 		 "%s: unable to determine size of UTF-16 string: %d.",
628 		 function,
629 		 string_index );
630 
631 		return( -1 );
632 	}
633 	return( 1 );
634 }
635 
636 /* Retrieves a specific UTF-16 encoded string
637  * The size should include the end of string character
638  * Returns 1 if successful or -1 on error
639  */
libevt_strings_array_get_utf16_string(libevt_strings_array_t * strings_array,int string_index,uint16_t * utf16_string,size_t utf16_string_size,libcerror_error_t ** error)640 int libevt_strings_array_get_utf16_string(
641      libevt_strings_array_t *strings_array,
642      int string_index,
643      uint16_t *utf16_string,
644      size_t utf16_string_size,
645      libcerror_error_t **error )
646 {
647 	static char *function = "libevt_values_record_get_utf16_string";
648 
649 	if( strings_array == NULL )
650 	{
651 		libcerror_error_set(
652 		 error,
653 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
654 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
655 		 "%s: invalid record values.",
656 		 function );
657 
658 		return( -1 );
659 	}
660 	if( strings_array->strings == NULL )
661 	{
662 		libcerror_error_set(
663 		 error,
664 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
665 		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
666 		 "%s: invalid string index value out of bounds.",
667 		 function );
668 
669 		return( -1 );
670 	}
671 	if( ( string_index < 0 )
672 	 || ( string_index >= strings_array->number_of_strings ) )
673 	{
674 		libcerror_error_set(
675 		 error,
676 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
677 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
678 		 "%s: invalid strings index value out of bounds.",
679 		 function );
680 
681 		return( -1 );
682 	}
683 	if( libuna_utf16_string_copy_from_utf16_stream(
684 	     (libuna_utf16_character_t *) utf16_string,
685 	     utf16_string_size,
686 	     strings_array->strings[ string_index ],
687 	     strings_array->string_sizes[ string_index ],
688 	     LIBUNA_ENDIAN_LITTLE,
689 	     error ) != 1 )
690 	{
691 		libcerror_error_set(
692 		 error,
693 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
694 		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
695 		 "%s: unable to set UTF-16 string: %d.",
696 		 function,
697 		 string_index );
698 
699 		return( -1 );
700 	}
701 	return( 1 );
702 }
703 
704