Coverage Report

Created: 2024-02-25 07:20

/src/libwrc/libwrc/libwrc_version_values.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Version (resource) values functions
3
 *
4
 * Copyright (C) 2011-2024, 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 <memory.h>
25
#include <types.h>
26
27
#include "libwrc_data_descriptor.h"
28
#include "libwrc_definitions.h"
29
#include "libwrc_io_handle.h"
30
#include "libwrc_language_entry.h"
31
#include "libwrc_libbfio.h"
32
#include "libwrc_libcerror.h"
33
#include "libwrc_libcnotify.h"
34
#include "libwrc_libfvalue.h"
35
#include "libwrc_version_values.h"
36
37
#include "wrc_version_information_resource.h"
38
39
uint8_t libwrc_version_information_value_identifier[ 32 ] = \
40
  { 'V', 0, 'S', 0, '_', 0, 'V', 0, 'E', 0, 'R', 0, 'S', 0, 'I', 0, 'O', 0, 'N', 0, '_', 0, 'I', 0, 'N', 0, 'F', 0, 'O', 0, 0, 0 };
41
42
uint8_t libwrc_version_fixed_file_information_signature[ 4 ] = \
43
  { 0xbd, 0x04, 0xef, 0xfe };
44
45
/* Creates version values
46
 * Make sure the value version_values is referencing, is set to NULL
47
 * Returns 1 if successful or -1 on error
48
 */
49
int libwrc_version_values_initialize(
50
     libwrc_version_values_t **version_values,
51
     libcerror_error_t **error )
52
0
{
53
0
  static char *function = "libwrc_version_values_initialize";
54
55
0
  if( version_values == NULL )
56
0
  {
57
0
    libcerror_error_set(
58
0
     error,
59
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
60
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
61
0
     "%s: invalid version values.",
62
0
     function );
63
64
0
    return( -1 );
65
0
  }
66
0
  if( *version_values != NULL )
67
0
  {
68
0
    libcerror_error_set(
69
0
     error,
70
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
71
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
72
0
     "%s: invalid version values value already set.",
73
0
     function );
74
75
0
    return( -1 );
76
0
  }
77
0
  *version_values = memory_allocate_structure(
78
0
                     libwrc_version_values_t );
79
80
0
  if( *version_values == NULL )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
85
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
86
0
     "%s: unable to create version values.",
87
0
     function );
88
89
0
    goto on_error;
90
0
  }
91
0
  if( memory_set(
92
0
       *version_values,
93
0
       0,
94
0
       sizeof( libwrc_version_values_t ) ) == NULL )
95
0
  {
96
0
    libcerror_error_set(
97
0
     error,
98
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
99
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
100
0
     "%s: unable to clear version values.",
101
0
     function );
102
103
0
    goto on_error;
104
0
  }
105
0
  return( 1 );
106
107
0
on_error:
108
0
  if( *version_values != NULL )
109
0
  {
110
0
    memory_free(
111
0
     *version_values );
112
113
0
    *version_values = NULL;
114
0
  }
115
0
  return( -1 );
116
0
}
117
118
/* Frees version values
119
 * Returns 1 if successful or -1 on error
120
 */
121
int libwrc_version_values_free(
122
     libwrc_version_values_t **version_values,
123
     libcerror_error_t **error )
124
0
{
125
0
  static char *function = "libwrc_version_values_free";
126
127
0
  if( version_values == NULL )
128
0
  {
129
0
    libcerror_error_set(
130
0
     error,
131
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
132
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
133
0
     "%s: invalid version values.",
134
0
     function );
135
136
0
    return( -1 );
137
0
  }
138
0
  if( *version_values != NULL )
139
0
  {
140
0
    memory_free(
141
0
     *version_values );
142
143
0
    *version_values = NULL;
144
0
  }
145
0
  return( 1 );
146
0
}
147
148
/* Reads the version (resource) values
149
 * Returns 1 if successful or -1 on error
150
 */
151
int libwrc_version_values_read(
152
     libwrc_language_entry_t *language_entry,
153
     libwrc_io_handle_t *io_handle,
154
     libbfio_handle_t *file_io_handle,
155
     libwrc_data_descriptor_t *data_descriptor,
156
     libcerror_error_t **error )
157
0
{
158
0
  libwrc_version_values_t *version_values = NULL;
159
0
  libfvalue_value_t *value_identifier     = NULL;
160
0
  uint8_t *resource_data                  = NULL;
161
0
  uint8_t *version_resource_data          = NULL;
162
0
  static char *function                   = "libwrc_version_values_read";
163
0
  off64_t file_offset                     = 0;
164
0
  size_t alignment_padding_size           = 0;
165
0
  size_t resource_data_offset             = 0;
166
0
  size_t resource_data_size               = 0;
167
0
  ssize_t read_count                      = 0;
168
0
  uint32_t value_32bit                    = 0;
169
0
  uint16_t value_data_size                = 0;
170
0
  uint16_t value_data_type                = 0;
171
0
  uint16_t version_resource_data_size     = 0;
172
0
  int value_index                         = 0;
173
174
0
  if( language_entry == NULL )
175
0
  {
176
0
    libcerror_error_set(
177
0
     error,
178
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
179
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
180
0
     "%s: invalid language entry.",
181
0
     function );
182
183
0
    return( -1 );
184
0
  }
185
0
  if( io_handle == NULL )
186
0
  {
187
0
    libcerror_error_set(
188
0
     error,
189
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
190
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
191
0
     "%s: invalid IO handle.",
192
0
     function );
193
194
0
    return( -1 );
195
0
  }
196
0
  if( data_descriptor == NULL )
197
0
  {
198
0
    libcerror_error_set(
199
0
     error,
200
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
201
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
202
0
     "%s: invalid data descriptor.",
203
0
     function );
204
205
0
    return( -1 );
206
0
  }
207
0
  if( libwrc_version_values_initialize(
208
0
       &version_values,
209
0
       error ) != 1 )
210
0
  {
211
0
    libcerror_error_set(
212
0
     error,
213
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
214
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
215
0
     "%s: unable to create version values.",
216
0
     function );
217
218
0
    goto on_error;
219
0
  }
220
0
  resource_data_size = (size_t) data_descriptor->size;
221
222
0
  if( ( resource_data_size == 0 )
223
0
   || ( resource_data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
224
0
  {
225
0
    libcerror_error_set(
226
0
     error,
227
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
228
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
229
0
     "%s: invalid resource data size value out of bounds.",
230
0
     function );
231
232
0
    goto on_error;
233
0
  }
234
0
  resource_data = (uint8_t *) memory_allocate(
235
0
                               sizeof( uint8_t ) * resource_data_size );
236
237
0
  if( resource_data == NULL )
238
0
  {
239
0
    libcerror_error_set(
240
0
     error,
241
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
242
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
243
0
     "%s: unable to create resource data.",
244
0
     function );
245
246
0
    goto on_error;
247
0
  }
248
0
  file_offset = data_descriptor->virtual_address - io_handle->virtual_address;
249
250
0
  read_count = libbfio_handle_read_buffer_at_offset(
251
0
                file_io_handle,
252
0
                resource_data,
253
0
                resource_data_size,
254
0
                file_offset,
255
0
                error );
256
257
0
  if( read_count != (ssize_t) resource_data_size )
258
0
  {
259
0
    libcerror_error_set(
260
0
     error,
261
0
     LIBCERROR_ERROR_DOMAIN_IO,
262
0
     LIBCERROR_IO_ERROR_READ_FAILED,
263
0
     "%s: unable to read resource data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
264
0
     function,
265
0
     file_offset,
266
0
     file_offset );
267
268
0
    goto on_error;
269
0
  }
270
0
  version_resource_data = resource_data;
271
272
#if defined( HAVE_DEBUG_OUTPUT )
273
  if( libcnotify_verbose != 0 )
274
  {
275
    libcnotify_printf(
276
     "%s: resource data:\n",
277
     function );
278
    libcnotify_print_data(
279
     version_resource_data,
280
     resource_data_size,
281
     0 );
282
  }
283
#endif
284
0
  byte_stream_copy_to_uint16_little_endian(
285
0
   ( (wrc_version_value_header_t *) version_resource_data )->size,
286
0
   version_resource_data_size );
287
288
0
  byte_stream_copy_to_uint16_little_endian(
289
0
   ( (wrc_version_value_header_t *) version_resource_data )->value_data_size,
290
0
   value_data_size );
291
292
0
  byte_stream_copy_to_uint16_little_endian(
293
0
   ( (wrc_version_value_header_t *) version_resource_data )->value_data_type,
294
0
   value_data_type );
295
296
#if defined( HAVE_DEBUG_OUTPUT )
297
  if( libcnotify_verbose != 0 )
298
  {
299
    libcnotify_printf(
300
     "%s: size\t\t\t\t\t: %" PRIu16 "\n",
301
     function,
302
     version_resource_data_size );
303
304
    libcnotify_printf(
305
     "%s: value data size\t\t\t\t: %" PRIu16 "\n",
306
     function,
307
     value_data_size );
308
309
    libcnotify_printf(
310
     "%s: value data type\t\t\t\t: %" PRIu16 "\n",
311
     function,
312
     value_data_type );
313
314
    libcnotify_printf(
315
     "\n" );
316
  }
317
#endif
318
0
  resource_data_offset += sizeof( wrc_version_value_header_t );
319
320
0
  if( libfvalue_value_type_initialize(
321
0
       &value_identifier,
322
0
       LIBFVALUE_VALUE_TYPE_STRING_UTF16,
323
0
       error ) != 1 )
324
0
  {
325
0
    libcerror_error_set(
326
0
     error,
327
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
328
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
329
0
     "%s: unable to create value identifier value.",
330
0
     function );
331
332
0
    goto on_error;
333
0
  }
334
0
  read_count = libfvalue_value_type_set_data_string(
335
0
                value_identifier,
336
0
                &( version_resource_data[ resource_data_offset ] ),
337
0
                resource_data_size,
338
0
                LIBFVALUE_CODEPAGE_UTF16_LITTLE_ENDIAN,
339
0
                LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
340
0
                error );
341
342
0
  if( read_count == -1 )
343
0
  {
344
0
    libcerror_error_set(
345
0
     error,
346
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
347
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
348
0
     "%s: unable to set data of value identifier value.",
349
0
     function );
350
351
0
    goto on_error;
352
0
  }
353
#if defined( HAVE_DEBUG_OUTPUT )
354
  if( libcnotify_verbose != 0 )
355
  {
356
    libcnotify_printf(
357
     "%s: value identifier\t\t\t\t: ",
358
     function );
359
360
    if( libfvalue_value_print(
361
         value_identifier,
362
         0,
363
         0,
364
         error ) != 1 )
365
    {
366
      libcerror_error_set(
367
       error,
368
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
369
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
370
       "%s: unable to print value identifier value.",
371
       function );
372
373
      goto on_error;
374
    }
375
    libcnotify_printf(
376
     "\n" );
377
  }
378
#endif
379
0
  if( ( read_count != 32 )
380
0
   || ( memory_compare(
381
0
         &( version_resource_data[ resource_data_offset ] ),
382
0
         libwrc_version_information_value_identifier,
383
0
         32 ) != 0 ) )
384
0
  {
385
0
    libcerror_error_set(
386
0
     error,
387
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
388
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
389
0
     "%s: unsupported version resource value signature.",
390
0
     function );
391
392
0
    goto on_error;
393
0
  }
394
0
  if( libfvalue_value_free(
395
0
       &value_identifier,
396
0
       error ) != 1 )
397
0
  {
398
0
    libcerror_error_set(
399
0
     error,
400
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
401
0
     LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
402
0
     "%s: unable to free value identifier value.",
403
0
     function );
404
405
0
    goto on_error;
406
0
  }
407
0
  resource_data_offset += read_count;
408
409
0
  if( ( resource_data_offset % 4 ) != 0 )
410
0
  {
411
0
    alignment_padding_size = 4 - ( resource_data_offset % 4 );
412
413
#if defined( HAVE_DEBUG_OUTPUT )
414
    if( libcnotify_verbose != 0 )
415
    {
416
      libcnotify_printf(
417
       "%s: alignment padding:\n",
418
       function );
419
      libcnotify_print_data(
420
       &( version_resource_data[ resource_data_offset ] ),
421
       alignment_padding_size,
422
       0 );
423
    }
424
#endif
425
0
    resource_data_offset += alignment_padding_size;
426
0
  }
427
/* TODO refactor to separate function? */
428
0
  if( value_data_size > 0 )
429
0
  {
430
0
    if( value_data_size > resource_data_size )
431
0
    {
432
0
      libcerror_error_set(
433
0
       error,
434
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
435
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
436
0
       "%s: value data size value out of bounds.",
437
0
       function );
438
439
0
      goto on_error;
440
0
    }
441
#if defined( HAVE_DEBUG_OUTPUT )
442
    if( libcnotify_verbose != 0 )
443
    {
444
      libcnotify_printf(
445
       "%s: value data:\n",
446
       function );
447
      libcnotify_print_data(
448
       &( version_resource_data[ resource_data_offset ] ),
449
       value_data_size,
450
       0 );
451
    }
452
#endif
453
0
    byte_stream_copy_to_uint32_little_endian(
454
0
     &( version_resource_data[ resource_data_offset + 8 ] ),
455
0
     version_values->file_version );
456
457
0
    byte_stream_copy_to_uint32_little_endian(
458
0
     &( version_resource_data[ resource_data_offset + 12 ] ),
459
0
     value_32bit );
460
461
0
    version_values->file_version <<= 32;
462
0
    version_values->file_version  |= value_32bit;
463
464
0
    byte_stream_copy_to_uint32_little_endian(
465
0
     &( version_resource_data[ resource_data_offset + 16 ] ),
466
0
     version_values->product_version );
467
468
0
    byte_stream_copy_to_uint32_little_endian(
469
0
     &( version_resource_data[ resource_data_offset + 20 ] ),
470
0
     value_32bit );
471
472
0
    version_values->product_version <<= 32;
473
0
    version_values->product_version  |= value_32bit;
474
475
#if defined( HAVE_DEBUG_OUTPUT )
476
    if( libcnotify_verbose != 0 )
477
    {
478
      byte_stream_copy_to_uint32_little_endian(
479
       &( version_resource_data[ resource_data_offset ] ),
480
       value_32bit );
481
      libcnotify_printf(
482
       "%s: signature\t\t\t\t\t: 0x%08" PRIx32 "\n",
483
       function,
484
       value_32bit );
485
486
      byte_stream_copy_to_uint32_little_endian(
487
       &( version_resource_data[ resource_data_offset + 4 ] ),
488
       value_32bit );
489
      libcnotify_printf(
490
       "%s: version\t\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
491
       function,
492
       value_32bit >> 16,
493
       value_32bit & 0x0000ffffUL );
494
495
      byte_stream_copy_to_uint32_little_endian(
496
       &( version_resource_data[ resource_data_offset + 8 ] ),
497
       value_32bit );
498
      libcnotify_printf(
499
       "%s: file version upper\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
500
       function,
501
       value_32bit >> 16,
502
       value_32bit & 0x0000ffffUL );
503
504
      byte_stream_copy_to_uint32_little_endian(
505
       &( version_resource_data[ resource_data_offset + 12 ] ),
506
       value_32bit );
507
      libcnotify_printf(
508
       "%s: file version lower\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
509
       function,
510
       value_32bit >> 16,
511
       value_32bit & 0x0000ffffUL );
512
513
      byte_stream_copy_to_uint32_little_endian(
514
       &( version_resource_data[ resource_data_offset + 16 ] ),
515
       value_32bit );
516
      libcnotify_printf(
517
       "%s: product version upper\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
518
       function,
519
       value_32bit >> 16,
520
       value_32bit & 0x0000ffffUL );
521
522
      byte_stream_copy_to_uint32_little_endian(
523
       &( version_resource_data[ resource_data_offset + 20 ] ),
524
       value_32bit );
525
      libcnotify_printf(
526
       "%s: product version lower\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
527
       function,
528
       value_32bit >> 16,
529
       value_32bit & 0x0000ffffUL );
530
531
      byte_stream_copy_to_uint32_little_endian(
532
       &( version_resource_data[ resource_data_offset + 24 ] ),
533
       value_32bit );
534
      libcnotify_printf(
535
       "%s: file flags bitmask\t\t\t\t: 0x%08" PRIx32 "\n",
536
       function,
537
       value_32bit );
538
539
      byte_stream_copy_to_uint32_little_endian(
540
       &( version_resource_data[ resource_data_offset + 28 ] ),
541
       value_32bit );
542
      libcnotify_printf(
543
       "%s: file flags\t\t\t\t\t: 0x%08" PRIx32 "\n",
544
       function,
545
       value_32bit );
546
547
      byte_stream_copy_to_uint32_little_endian(
548
       &( version_resource_data[ resource_data_offset + 32 ] ),
549
       value_32bit );
550
      libcnotify_printf(
551
       "%s: file operating system\t\t\t: 0x%08" PRIx32 "\n",
552
       function,
553
       value_32bit );
554
555
      byte_stream_copy_to_uint32_little_endian(
556
       &( version_resource_data[ resource_data_offset + 36 ] ),
557
       value_32bit );
558
      libcnotify_printf(
559
       "%s: file type\t\t\t\t\t: 0x%08" PRIx32 "\n",
560
       function,
561
       value_32bit );
562
563
      byte_stream_copy_to_uint32_little_endian(
564
       &( version_resource_data[ resource_data_offset + 40 ] ),
565
       value_32bit );
566
      libcnotify_printf(
567
       "%s: file sub type\t\t\t\t: 0x%08" PRIx32 "\n",
568
       function,
569
       value_32bit );
570
571
      byte_stream_copy_to_uint32_little_endian(
572
       &( version_resource_data[ resource_data_offset + 44 ] ),
573
       value_32bit );
574
      libcnotify_printf(
575
       "%s: file time upper\t\t\t\t: 0x%08" PRIx32 "\n",
576
       function,
577
       value_32bit );
578
579
      byte_stream_copy_to_uint32_little_endian(
580
       &( version_resource_data[ resource_data_offset + 48 ] ),
581
       value_32bit );
582
      libcnotify_printf(
583
       "%s: file time lower\t\t\t\t: 0x%08" PRIx32 "\n",
584
       function,
585
       value_32bit );
586
587
      libcnotify_printf(
588
       "\n" );
589
    }
590
#endif
591
0
    resource_data_offset += value_data_size;
592
0
  }
593
0
  if( ( resource_data_offset % 4 ) != 0 )
594
0
  {
595
0
    alignment_padding_size = 4 - ( resource_data_offset % 4 );
596
597
#if defined( HAVE_DEBUG_OUTPUT )
598
    if( libcnotify_verbose != 0 )
599
    {
600
      libcnotify_printf(
601
       "%s: alignment padding:\n",
602
       function );
603
      libcnotify_print_data(
604
       &( version_resource_data[ resource_data_offset ] ),
605
       alignment_padding_size,
606
       0 );
607
    }
608
#endif
609
0
    resource_data_offset += alignment_padding_size;
610
0
  }
611
0
  read_count = libwrc_version_values_read_string_file_information(
612
0
                language_entry,
613
0
                version_resource_data,
614
0
                resource_data_size,
615
0
                resource_data_offset,
616
0
                error );
617
618
0
  if( read_count == -1 )
619
0
  {
620
0
    libcerror_error_set(
621
0
     error,
622
0
     LIBCERROR_ERROR_DOMAIN_IO,
623
0
     LIBCERROR_IO_ERROR_READ_FAILED,
624
0
     "%s: unable to read string file information.",
625
0
     function );
626
627
0
    goto on_error;
628
0
  }
629
0
  resource_data_offset += read_count;
630
631
0
  read_count = libwrc_version_values_read_variable_file_information(
632
0
                language_entry,
633
0
                version_resource_data,
634
0
                resource_data_size,
635
0
                resource_data_offset,
636
0
                error );
637
638
0
  if( read_count == -1 )
639
0
  {
640
0
    libcerror_error_set(
641
0
     error,
642
0
     LIBCERROR_ERROR_DOMAIN_IO,
643
0
     LIBCERROR_IO_ERROR_READ_FAILED,
644
0
     "%s: unable to read variable file information.",
645
0
     function );
646
647
0
    goto on_error;
648
0
  }
649
#if defined( HAVE_DEBUG_OUTPUT )
650
  resource_data_offset += read_count;
651
#endif
652
653
/* TODO */
654
0
  if( libwrc_language_entry_append_value(
655
0
       language_entry,
656
0
       &value_index,
657
0
       (intptr_t *) version_values,
658
0
       error ) != 1 )
659
0
  {
660
0
    libcerror_error_set(
661
0
     error,
662
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
663
0
     LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
664
0
     "%s: unable to append version values.",
665
0
     function );
666
667
0
    goto on_error;
668
0
  }
669
0
  version_values = NULL;
670
671
0
  memory_free(
672
0
   resource_data );
673
674
0
  return( 1 );
675
676
0
on_error:
677
0
  if( value_identifier != NULL )
678
0
  {
679
0
    libfvalue_value_free(
680
0
     &value_identifier,
681
0
     NULL );
682
0
  }
683
0
  if( resource_data != NULL )
684
0
  {
685
0
    memory_free(
686
0
     resource_data );
687
0
  }
688
0
  if( version_values != NULL )
689
0
  {
690
0
    libwrc_version_values_free(
691
0
     &version_values,
692
0
     NULL );
693
0
  }
694
0
  return( -1 );
695
0
}
696
697
/* Reads the version (resource) string file information
698
 * Returns number of bytes read if successful or -1 on error
699
 */
700
ssize_t libwrc_version_values_read_string_file_information(
701
         libwrc_language_entry_t *language_entry,
702
         const uint8_t *resource_data,
703
         size_t resource_data_size,
704
         size_t resource_data_offset,
705
         libcerror_error_t **error )
706
0
{
707
0
  uint8_t *value_identifier_string    = NULL;
708
0
  static char *function               = "libwrc_version_values_read_string_file_information";
709
0
  size_t alignment_padding_size       = 0;
710
0
  size_t calculated_value_data_size   = 0;
711
0
  size_t resource_data_start_offset   = 0;
712
0
  size_t trailing_data_size           = 0;
713
0
  size_t value_identifier_string_size = 0;
714
0
  ssize_t read_count                  = 0;
715
0
  uint16_t data_size                  = 0;
716
0
  uint16_t value_data_size            = 0;
717
0
  uint16_t value_data_type            = 0;
718
719
0
  if( language_entry == NULL )
720
0
  {
721
0
    libcerror_error_set(
722
0
     error,
723
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
724
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
725
0
     "%s: invalid language entry.",
726
0
     function );
727
728
0
    return( -1 );
729
0
  }
730
0
  if( resource_data == NULL )
731
0
  {
732
0
    libcerror_error_set(
733
0
     error,
734
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
735
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
736
0
     "%s: invalid resource data.",
737
0
     function );
738
739
0
    return( -1 );
740
0
  }
741
0
  if( resource_data_size > (size_t) SSIZE_MAX )
742
0
  {
743
0
    libcerror_error_set(
744
0
     error,
745
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
746
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
747
0
     "%s: invalid resource data size value exceeds maximum.",
748
0
     function );
749
750
0
    return( -1 );
751
0
  }
752
0
  if( resource_data_offset >= resource_data_size )
753
0
  {
754
0
    libcerror_error_set(
755
0
     error,
756
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
757
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
758
0
     "%s: invalid resource data offset value out of bounds.",
759
0
     function );
760
761
0
    return( -1 );
762
0
  }
763
0
  if( ( resource_data_offset + 2 ) > resource_data_size )
764
0
  {
765
0
    libcerror_error_set(
766
0
     error,
767
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
768
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
769
0
     "%s: invalid resource data value too small.",
770
0
     function );
771
772
0
    return( -1 );
773
0
  }
774
0
  resource_data_start_offset = resource_data_offset;
775
776
0
  byte_stream_copy_to_uint16_little_endian(
777
0
   &( resource_data[ resource_data_offset ] ),
778
0
   data_size );
779
780
0
  resource_data_offset += 2;
781
782
#if defined( HAVE_DEBUG_OUTPUT )
783
  if( libcnotify_verbose != 0 )
784
  {
785
    libcnotify_printf(
786
     "%s: data size\t\t: %" PRIu16 "\n",
787
     function,
788
     data_size );
789
  }
790
#endif
791
0
  if( data_size != 0 )
792
0
  {
793
0
    if( ( data_size < 8 )
794
0
     || ( data_size > ( resource_data_size - ( resource_data_offset - 2 ) ) ) )
795
0
    {
796
0
      libcerror_error_set(
797
0
       error,
798
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
799
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
800
0
       "%s: data size value out of bounds.",
801
0
       function );
802
803
0
      return( -1 );
804
0
    }
805
0
    byte_stream_copy_to_uint16_little_endian(
806
0
     &( resource_data[ resource_data_offset ] ),
807
0
     value_data_size );
808
809
0
    resource_data_offset += 2;
810
811
0
    byte_stream_copy_to_uint16_little_endian(
812
0
     &( resource_data[ resource_data_offset ] ),
813
0
     value_data_type );
814
815
0
    resource_data_offset += 2;
816
817
#if defined( HAVE_DEBUG_OUTPUT )
818
    if( libcnotify_verbose != 0 )
819
    {
820
      libcnotify_printf(
821
       "%s: value data size\t: %" PRIu16 "\n",
822
       function,
823
       value_data_size );
824
825
      libcnotify_printf(
826
       "%s: value data type\t: %" PRIu16 "\n",
827
       function,
828
       value_data_type );
829
    }
830
#endif
831
0
    value_identifier_string      = (uint8_t *) &( resource_data[ resource_data_offset ] );
832
0
    value_identifier_string_size = 0;
833
834
0
    while( ( resource_data_offset + 2 ) < resource_data_size )
835
0
    {
836
0
      value_identifier_string_size += 2;
837
838
0
      if( ( resource_data[ resource_data_offset ] == 0 )
839
0
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
840
0
      {
841
0
        resource_data_offset += 2;
842
843
0
        break;
844
0
      }
845
0
      resource_data_offset += 2;
846
0
    }
847
#if defined( HAVE_DEBUG_OUTPUT )
848
    if( libcnotify_verbose != 0 )
849
    {
850
      libcnotify_printf(
851
       "%s: value identifier string data:\n",
852
       function );
853
      libcnotify_print_data(
854
       value_identifier_string,
855
       value_identifier_string_size,
856
       0 );
857
    }
858
#endif
859
/* TODO convert string */
860
0
    if( ( resource_data_offset % 4 ) != 0 )
861
0
    {
862
0
      alignment_padding_size = 4 - ( resource_data_offset % 4 );
863
864
#if defined( HAVE_DEBUG_OUTPUT )
865
      if( libcnotify_verbose != 0 )
866
      {
867
        libcnotify_printf(
868
         "%s: alignment padding:\n",
869
         function );
870
        libcnotify_print_data(
871
         &( resource_data[ resource_data_offset ] ),
872
         alignment_padding_size,
873
         0 );
874
      }
875
#endif
876
0
      resource_data_offset += alignment_padding_size;
877
0
    }
878
0
    if( value_data_type == 1 )
879
0
    {
880
/* TODO check value_data_size == 0 ? */
881
0
      read_count = libwrc_version_values_read_string_table(
882
0
              language_entry,
883
0
              resource_data,
884
0
              resource_data_size,
885
0
              resource_data_offset,
886
0
              error );
887
888
0
      if( read_count == -1 )
889
0
      {
890
0
        libcerror_error_set(
891
0
         error,
892
0
         LIBCERROR_ERROR_DOMAIN_IO,
893
0
         LIBCERROR_IO_ERROR_READ_FAILED,
894
0
         "%s: unable to read string table.",
895
0
         function );
896
897
0
        return( -1 );
898
0
      }
899
0
      resource_data_offset += read_count;
900
0
    }
901
/* TODO print unsupported type warning */
902
0
    calculated_value_data_size = resource_data_offset - resource_data_start_offset;
903
904
0
    if( calculated_value_data_size < data_size )
905
0
    {
906
0
      trailing_data_size = data_size - trailing_data_size;
907
908
#if defined( HAVE_DEBUG_OUTPUT )
909
      if( libcnotify_verbose != 0 )
910
      {
911
        libcnotify_printf(
912
         "%s: trailing data:\n",
913
         function );
914
        libcnotify_print_data(
915
         &( resource_data[ resource_data_offset ] ),
916
         trailing_data_size,
917
         0 );
918
      }
919
#endif
920
0
      resource_data_offset += trailing_data_size;
921
0
    }
922
0
  }
923
0
  return( (ssize_t) data_size );
924
0
}
925
926
/* Reads the version (resource) string table
927
 * Returns number of bytes read if successful or -1 on error
928
 */
929
ssize_t libwrc_version_values_read_string_table(
930
         libwrc_language_entry_t *language_entry,
931
         const uint8_t *resource_data,
932
         size_t resource_data_size,
933
         size_t resource_data_offset,
934
         libcerror_error_t **error )
935
0
{
936
0
  uint8_t *value_identifier_string    = NULL;
937
0
  static char *function               = "libwrc_version_values_read_string_table";
938
0
  size_t alignment_padding_size       = 0;
939
0
  size_t calculated_value_data_size   = 0;
940
0
  size_t resource_data_start_offset   = 0;
941
0
  size_t trailing_data_size           = 0;
942
0
  size_t value_identifier_string_size = 0;
943
0
  ssize_t read_count                  = 0;
944
0
  uint16_t data_size                  = 0;
945
0
  uint16_t value_data_size            = 0;
946
0
  uint16_t value_data_type            = 0;
947
948
0
  if( language_entry == NULL )
949
0
  {
950
0
    libcerror_error_set(
951
0
     error,
952
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
953
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
954
0
     "%s: invalid language entry.",
955
0
     function );
956
957
0
    return( -1 );
958
0
  }
959
0
  if( resource_data == NULL )
960
0
  {
961
0
    libcerror_error_set(
962
0
     error,
963
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
964
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
965
0
     "%s: invalid resource data.",
966
0
     function );
967
968
0
    return( -1 );
969
0
  }
970
0
  if( resource_data_size > (size_t) SSIZE_MAX )
971
0
  {
972
0
    libcerror_error_set(
973
0
     error,
974
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
975
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
976
0
     "%s: invalid resource data size value exceeds maximum.",
977
0
     function );
978
979
0
    return( -1 );
980
0
  }
981
0
  if( resource_data_offset >= resource_data_size )
982
0
  {
983
0
    libcerror_error_set(
984
0
     error,
985
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
986
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
987
0
     "%s: invalid resource data offset value out of bounds.",
988
0
     function );
989
990
0
    return( -1 );
991
0
  }
992
0
  if( ( resource_data_offset + 2 ) > resource_data_size )
993
0
  {
994
0
    libcerror_error_set(
995
0
     error,
996
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
997
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
998
0
     "%s: invalid resource data value too small.",
999
0
     function );
1000
1001
0
    return( -1 );
1002
0
  }
1003
0
  resource_data_start_offset = resource_data_offset;
1004
1005
0
  byte_stream_copy_to_uint16_little_endian(
1006
0
   &( resource_data[ resource_data_offset ] ),
1007
0
   data_size );
1008
1009
0
  resource_data_offset += 2;
1010
1011
#if defined( HAVE_DEBUG_OUTPUT )
1012
  if( libcnotify_verbose != 0 )
1013
  {
1014
    libcnotify_printf(
1015
     "%s: data size\t\t\t: %" PRIu16 "\n",
1016
     function,
1017
     data_size );
1018
  }
1019
#endif
1020
0
  if( data_size != 0 )
1021
0
  {
1022
0
    if( ( data_size < 8 )
1023
0
     || ( data_size > ( resource_data_size - ( resource_data_offset - 2 ) ) ) )
1024
0
    {
1025
0
      libcerror_error_set(
1026
0
       error,
1027
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1028
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1029
0
       "%s: data size value out of bounds.",
1030
0
       function );
1031
1032
0
      return( -1 );
1033
0
    }
1034
0
    byte_stream_copy_to_uint16_little_endian(
1035
0
     &( resource_data[ resource_data_offset ] ),
1036
0
     value_data_size );
1037
1038
0
    resource_data_offset += 2;
1039
1040
0
    byte_stream_copy_to_uint16_little_endian(
1041
0
     &( resource_data[ resource_data_offset ] ),
1042
0
     value_data_type );
1043
1044
0
    resource_data_offset += 2;
1045
1046
#if defined( HAVE_DEBUG_OUTPUT )
1047
    if( libcnotify_verbose != 0 )
1048
    {
1049
      libcnotify_printf(
1050
       "%s: value data size\t\t: %" PRIu16 "\n",
1051
       function,
1052
       value_data_size );
1053
1054
      libcnotify_printf(
1055
       "%s: value data type\t\t: %" PRIu16 "\n",
1056
       function,
1057
       value_data_type );
1058
    }
1059
#endif
1060
0
    value_identifier_string      = (uint8_t *) &( resource_data[ resource_data_offset ] );
1061
0
    value_identifier_string_size = 0;
1062
1063
0
    while( ( resource_data_offset + 2 ) < resource_data_size )
1064
0
    {
1065
0
      value_identifier_string_size += 2;
1066
1067
0
      if( ( resource_data[ resource_data_offset ] == 0 )
1068
0
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
1069
0
      {
1070
0
        resource_data_offset += 2;
1071
1072
0
        break;
1073
0
      }
1074
0
      resource_data_offset += 2;
1075
0
    }
1076
#if defined( HAVE_DEBUG_OUTPUT )
1077
    if( libcnotify_verbose != 0 )
1078
    {
1079
      libcnotify_printf(
1080
       "%s: value identifier string data:\n",
1081
       function );
1082
      libcnotify_print_data(
1083
       value_identifier_string,
1084
       value_identifier_string_size,
1085
       0 );
1086
    }
1087
#endif
1088
/* TODO convert string */
1089
0
    if( ( resource_data_offset % 4 ) != 0 )
1090
0
    {
1091
0
      alignment_padding_size = 4 - ( resource_data_offset % 4 );
1092
1093
#if defined( HAVE_DEBUG_OUTPUT )
1094
      if( libcnotify_verbose != 0 )
1095
      {
1096
        libcnotify_printf(
1097
         "%s: alignment padding:\n",
1098
         function );
1099
        libcnotify_print_data(
1100
         &( resource_data[ resource_data_offset ] ),
1101
         alignment_padding_size,
1102
         0 );
1103
      }
1104
#endif
1105
0
      resource_data_offset += alignment_padding_size;
1106
0
    }
1107
0
    if( value_data_type == 0 )
1108
0
    {
1109
/* TODO check value data size is in bounds */
1110
#if defined( HAVE_DEBUG_OUTPUT )
1111
      if( libcnotify_verbose != 0 )
1112
      {
1113
        libcnotify_printf(
1114
         "%s: value data:\n",
1115
         function );
1116
        libcnotify_print_data(
1117
         &( resource_data[ resource_data_offset ] ),
1118
         value_data_size,
1119
         0 );
1120
      }
1121
#endif
1122
0
      resource_data_offset += value_data_size;
1123
0
    }
1124
0
    else if( value_data_type == 1 )
1125
0
    {
1126
/* TODO check value_data_size == 0 ? */
1127
0
      while( ( resource_data_offset + 2 ) < ( resource_data_start_offset + data_size ) )
1128
0
      {
1129
0
        read_count = libwrc_version_values_read_string(
1130
0
                language_entry,
1131
0
                resource_data,
1132
0
                resource_data_size,
1133
0
                resource_data_offset,
1134
0
                error );
1135
1136
0
        if( read_count == -1 )
1137
0
        {
1138
0
          libcerror_error_set(
1139
0
           error,
1140
0
           LIBCERROR_ERROR_DOMAIN_IO,
1141
0
           LIBCERROR_IO_ERROR_READ_FAILED,
1142
0
           "%s: unable to read string.",
1143
0
           function );
1144
1145
0
          return( -1 );
1146
0
        }
1147
0
        else if( read_count == 0 )
1148
0
        {
1149
0
          break;
1150
0
        }
1151
0
        resource_data_offset += read_count;
1152
1153
0
        if( ( resource_data_offset % 4 ) != 0 )
1154
0
        {
1155
0
          alignment_padding_size = 4 - ( resource_data_offset % 4 );
1156
1157
0
          if( ( resource_data_offset + alignment_padding_size ) < ( resource_data_start_offset + data_size ) )
1158
0
          {
1159
#if defined( HAVE_DEBUG_OUTPUT )
1160
            if( libcnotify_verbose != 0 )
1161
            {
1162
              libcnotify_printf(
1163
               "%s: alignment padding:\n",
1164
               function );
1165
              libcnotify_print_data(
1166
               &( resource_data[ resource_data_offset ] ),
1167
               alignment_padding_size,
1168
               0 );
1169
            }
1170
#endif
1171
0
            resource_data_offset += alignment_padding_size;
1172
0
          }
1173
0
        }
1174
0
      }
1175
0
    }
1176
/* TODO print unsupported type warning */
1177
0
    calculated_value_data_size = resource_data_offset - resource_data_start_offset;
1178
1179
0
    if( calculated_value_data_size < data_size )
1180
0
    {
1181
0
      trailing_data_size = data_size - calculated_value_data_size;
1182
1183
#if defined( HAVE_DEBUG_OUTPUT )
1184
      if( libcnotify_verbose != 0 )
1185
      {
1186
        libcnotify_printf(
1187
         "%s: trailing data:\n",
1188
         function );
1189
        libcnotify_print_data(
1190
         &( resource_data[ resource_data_offset ] ),
1191
         trailing_data_size,
1192
         0 );
1193
      }
1194
#endif
1195
0
      resource_data_offset += trailing_data_size;
1196
0
    }
1197
0
  }
1198
0
  return( (ssize_t) data_size );
1199
0
}
1200
1201
/* Reads the version (resource) string
1202
 * Returns number of bytes read if successful or -1 on error
1203
 */
1204
ssize_t libwrc_version_values_read_string(
1205
         libwrc_language_entry_t *language_entry,
1206
         const uint8_t *resource_data,
1207
         size_t resource_data_size,
1208
         size_t resource_data_offset,
1209
         libcerror_error_t **error )
1210
0
{
1211
0
  static char *function             = "libwrc_version_values_read_string";
1212
0
  size_t alignment_padding_size     = 0;
1213
0
  size_t value_string_size          = 0;
1214
0
  uint16_t data_size                = 0;
1215
0
  uint16_t value_data_size          = 0;
1216
0
  uint16_t value_data_type          = 0;
1217
1218
#if defined( HAVE_DEBUG_OUTPUT )
1219
  size_t resource_data_start_offset = 0;
1220
  size_t trailing_data_size         = 0;
1221
  size_t value_string_offset        = 0;
1222
#endif
1223
1224
0
  if( language_entry == NULL )
1225
0
  {
1226
0
    libcerror_error_set(
1227
0
     error,
1228
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1229
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1230
0
     "%s: invalid language entry.",
1231
0
     function );
1232
1233
0
    return( -1 );
1234
0
  }
1235
0
  if( resource_data == NULL )
1236
0
  {
1237
0
    libcerror_error_set(
1238
0
     error,
1239
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1240
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1241
0
     "%s: invalid resource data.",
1242
0
     function );
1243
1244
0
    return( -1 );
1245
0
  }
1246
0
  if( resource_data_size > (size_t) SSIZE_MAX )
1247
0
  {
1248
0
    libcerror_error_set(
1249
0
     error,
1250
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1251
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1252
0
     "%s: invalid resource data size value exceeds maximum.",
1253
0
     function );
1254
1255
0
    return( -1 );
1256
0
  }
1257
0
  if( resource_data_offset >= resource_data_size )
1258
0
  {
1259
0
    libcerror_error_set(
1260
0
     error,
1261
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1262
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1263
0
     "%s: invalid resource data offset value out of bounds.",
1264
0
     function );
1265
1266
0
    return( -1 );
1267
0
  }
1268
0
  if( ( resource_data_offset + 2 ) > resource_data_size )
1269
0
  {
1270
0
    libcerror_error_set(
1271
0
     error,
1272
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1273
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1274
0
     "%s: invalid resource data value too small.",
1275
0
     function );
1276
1277
0
    return( -1 );
1278
0
  }
1279
#if defined( HAVE_DEBUG_OUTPUT )
1280
  resource_data_start_offset = resource_data_offset;
1281
#endif
1282
1283
0
  byte_stream_copy_to_uint16_little_endian(
1284
0
   &( resource_data[ resource_data_offset ] ),
1285
0
   data_size );
1286
1287
0
  resource_data_offset += 2;
1288
1289
#if defined( HAVE_DEBUG_OUTPUT )
1290
  if( libcnotify_verbose != 0 )
1291
  {
1292
    libcnotify_printf(
1293
     "%s: data size\t\t\t\t: %" PRIu16 "\n",
1294
     function,
1295
     data_size );
1296
  }
1297
#endif
1298
0
  if( data_size != 0 )
1299
0
  {
1300
0
    if( ( data_size < 8 )
1301
0
     || ( data_size > ( resource_data_size - ( resource_data_offset - 2 ) ) ) )
1302
0
    {
1303
0
      libcerror_error_set(
1304
0
       error,
1305
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1306
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1307
0
       "%s: data size value out of bounds.",
1308
0
       function );
1309
1310
0
      return( -1 );
1311
0
    }
1312
0
    byte_stream_copy_to_uint16_little_endian(
1313
0
     &( resource_data[ resource_data_offset ] ),
1314
0
     value_data_size );
1315
1316
0
    resource_data_offset += 2;
1317
1318
0
    byte_stream_copy_to_uint16_little_endian(
1319
0
     &( resource_data[ resource_data_offset ] ),
1320
0
     value_data_type );
1321
1322
0
    resource_data_offset += 2;
1323
1324
#if defined( HAVE_DEBUG_OUTPUT )
1325
    if( libcnotify_verbose != 0 )
1326
    {
1327
      libcnotify_printf(
1328
       "%s: value data size\t\t\t: %" PRIu16 "\n",
1329
       function,
1330
       value_data_size );
1331
1332
      libcnotify_printf(
1333
       "%s: value data type\t\t\t: %" PRIu16 "\n",
1334
       function,
1335
       value_data_type );
1336
    }
1337
#endif
1338
/* TODO check value_data_size == 0 ? */
1339
/* TODO handle value_data_type != 1 */
1340
#if defined( HAVE_DEBUG_OUTPUT )
1341
    value_string_offset = resource_data_offset;
1342
#endif
1343
1344
0
    value_string_size = 0;
1345
1346
0
    while( ( resource_data_offset + 2 ) < resource_data_size )
1347
0
    {
1348
0
      value_string_size += 2;
1349
1350
0
      if( ( resource_data[ resource_data_offset ] == 0 )
1351
0
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
1352
0
      {
1353
0
        resource_data_offset += 2;
1354
1355
0
        break;
1356
0
      }
1357
0
      resource_data_offset += 2;
1358
0
    }
1359
#if defined( HAVE_DEBUG_OUTPUT )
1360
    if( libcnotify_verbose != 0 )
1361
    {
1362
      libcnotify_printf(
1363
       "%s: value identifier string data:\n",
1364
       function );
1365
      libcnotify_print_data(
1366
       &( resource_data[ value_string_offset ] ),
1367
       value_string_size,
1368
       0 );
1369
    }
1370
#endif
1371
/* TODO convert string */
1372
0
    if( ( resource_data_offset % 4 ) != 0 )
1373
0
    {
1374
0
      alignment_padding_size = 4 - ( resource_data_offset % 4 );
1375
1376
#if defined( HAVE_DEBUG_OUTPUT )
1377
      if( libcnotify_verbose != 0 )
1378
      {
1379
        libcnotify_printf(
1380
         "%s: alignment padding:\n",
1381
         function );
1382
        libcnotify_print_data(
1383
         &( resource_data[ resource_data_offset ] ),
1384
         alignment_padding_size,
1385
         0 );
1386
      }
1387
#endif
1388
0
      resource_data_offset += alignment_padding_size;
1389
0
    }
1390
#if defined( HAVE_DEBUG_OUTPUT )
1391
    value_string_offset = resource_data_offset;
1392
    value_string_size   = 0;
1393
1394
    while( ( resource_data_offset + 2 ) < resource_data_size )
1395
    {
1396
      value_string_size += 2;
1397
1398
      if( ( resource_data[ resource_data_offset ] == 0 )
1399
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
1400
      {
1401
        resource_data_offset += 2;
1402
1403
        break;
1404
      }
1405
      resource_data_offset += 2;
1406
    }
1407
#endif
1408
#if defined( HAVE_DEBUG_OUTPUT )
1409
    if( libcnotify_verbose != 0 )
1410
    {
1411
      libcnotify_printf(
1412
       "%s: value string data:\n",
1413
       function );
1414
      libcnotify_print_data(
1415
       &( resource_data[ value_string_offset ] ),
1416
       value_string_size,
1417
       0 );
1418
    }
1419
#endif
1420
#if defined( HAVE_DEBUG_OUTPUT )
1421
    if( libcnotify_verbose != 0 )
1422
    {
1423
      trailing_data_size = resource_data_offset - resource_data_start_offset;
1424
1425
      if( trailing_data_size < data_size )
1426
      {
1427
        trailing_data_size = data_size - trailing_data_size;
1428
1429
        libcnotify_printf(
1430
         "%s: trailing data:\n",
1431
         function );
1432
        libcnotify_print_data(
1433
         &( resource_data[ resource_data_offset ] ),
1434
         trailing_data_size,
1435
         0 );
1436
      }
1437
    }
1438
#endif
1439
0
  }
1440
0
  return( (ssize_t) data_size );
1441
0
}
1442
1443
/* Reads the version (resource) variable file information
1444
 * Returns number of bytes read if successful or -1 on error
1445
 */
1446
ssize_t libwrc_version_values_read_variable_file_information(
1447
         libwrc_language_entry_t *language_entry,
1448
         const uint8_t *resource_data,
1449
         size_t resource_data_size,
1450
         size_t resource_data_offset,
1451
         libcerror_error_t **error )
1452
0
{
1453
0
  static char *function             = "libwrc_version_values_read_variable_file_information";
1454
0
  size_t alignment_padding_size     = 0;
1455
0
  size_t resource_data_start_offset = 0;
1456
0
  size_t value_string_size          = 0;
1457
0
  ssize_t read_count                = 0;
1458
0
  uint16_t data_size                = 0;
1459
0
  uint16_t value_data_size          = 0;
1460
0
  uint16_t value_data_type          = 0;
1461
1462
#if defined( HAVE_DEBUG_OUTPUT )
1463
  size_t trailing_data_size         = 0;
1464
  size_t value_string_offset        = 0;
1465
#endif
1466
1467
0
  if( language_entry == NULL )
1468
0
  {
1469
0
    libcerror_error_set(
1470
0
     error,
1471
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1472
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1473
0
     "%s: invalid language entry.",
1474
0
     function );
1475
1476
0
    return( -1 );
1477
0
  }
1478
0
  if( resource_data == NULL )
1479
0
  {
1480
0
    libcerror_error_set(
1481
0
     error,
1482
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1483
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1484
0
     "%s: invalid resource data.",
1485
0
     function );
1486
1487
0
    return( -1 );
1488
0
  }
1489
0
  if( resource_data_size > (size_t) SSIZE_MAX )
1490
0
  {
1491
0
    libcerror_error_set(
1492
0
     error,
1493
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1494
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1495
0
     "%s: invalid resource data size value exceeds maximum.",
1496
0
     function );
1497
1498
0
    return( -1 );
1499
0
  }
1500
0
  if( resource_data_offset >= resource_data_size )
1501
0
  {
1502
0
    libcerror_error_set(
1503
0
     error,
1504
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1505
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1506
0
     "%s: invalid resource data offset value out of bounds.",
1507
0
     function );
1508
1509
0
    return( -1 );
1510
0
  }
1511
0
  if( ( resource_data_offset + 2 ) > resource_data_size )
1512
0
  {
1513
0
    libcerror_error_set(
1514
0
     error,
1515
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1516
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1517
0
     "%s: invalid resource data value too small.",
1518
0
     function );
1519
1520
0
    return( -1 );
1521
0
  }
1522
0
  resource_data_start_offset = resource_data_offset;
1523
1524
0
  byte_stream_copy_to_uint16_little_endian(
1525
0
   &( resource_data[ resource_data_offset ] ),
1526
0
   data_size );
1527
1528
0
  resource_data_offset += 2;
1529
1530
#if defined( HAVE_DEBUG_OUTPUT )
1531
  if( libcnotify_verbose != 0 )
1532
  {
1533
    libcnotify_printf(
1534
     "%s: data size\t\t: %" PRIu16 "\n",
1535
     function,
1536
     data_size );
1537
  }
1538
#endif
1539
0
  if( data_size != 0 )
1540
0
  {
1541
0
    if( ( data_size < 8 )
1542
0
     || ( data_size > ( resource_data_size - ( resource_data_offset - 2 ) ) ) )
1543
0
    {
1544
0
      libcerror_error_set(
1545
0
       error,
1546
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1547
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1548
0
       "%s: data size value out of bounds.",
1549
0
       function );
1550
1551
0
      return( -1 );
1552
0
    }
1553
0
    byte_stream_copy_to_uint16_little_endian(
1554
0
     &( resource_data[ resource_data_offset ] ),
1555
0
     value_data_size );
1556
1557
0
    resource_data_offset += 2;
1558
1559
0
    byte_stream_copy_to_uint16_little_endian(
1560
0
     &( resource_data[ resource_data_offset ] ),
1561
0
     value_data_type );
1562
1563
0
    resource_data_offset += 2;
1564
1565
#if defined( HAVE_DEBUG_OUTPUT )
1566
    if( libcnotify_verbose != 0 )
1567
    {
1568
      libcnotify_printf(
1569
       "%s: value data size\t: %" PRIu16 "\n",
1570
       function,
1571
       value_data_size );
1572
1573
      libcnotify_printf(
1574
       "%s: value data type\t: %" PRIu16 "\n",
1575
       function,
1576
       value_data_type );
1577
    }
1578
#endif
1579
/* TODO check value_data_size == 0 ? */
1580
/* TODO handle value_data_type != 1 */
1581
#if defined( HAVE_DEBUG_OUTPUT )
1582
    value_string_offset = resource_data_offset;
1583
#endif
1584
1585
0
    value_string_size  = 0;
1586
1587
0
    while( ( resource_data_offset + 2 ) < resource_data_size )
1588
0
    {
1589
0
      value_string_size += 2;
1590
1591
0
      if( ( resource_data[ resource_data_offset ] == 0 )
1592
0
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
1593
0
      {
1594
0
        resource_data_offset += 2;
1595
1596
0
        break;
1597
0
      }
1598
0
      resource_data_offset += 2;
1599
0
    }
1600
#if defined( HAVE_DEBUG_OUTPUT )
1601
    if( libcnotify_verbose != 0 )
1602
    {
1603
      libcnotify_printf(
1604
       "%s: value identifier string data:\n",
1605
       function );
1606
      libcnotify_print_data(
1607
       &( resource_data[ value_string_offset ] ),
1608
       value_string_size,
1609
       0 );
1610
    }
1611
#endif
1612
/* TODO convert string */
1613
0
    if( ( resource_data_offset % 4 ) != 0 )
1614
0
    {
1615
0
      alignment_padding_size = 4 - ( resource_data_offset % 4 );
1616
1617
#if defined( HAVE_DEBUG_OUTPUT )
1618
      if( libcnotify_verbose != 0 )
1619
      {
1620
        libcnotify_printf(
1621
         "%s: alignment padding:\n",
1622
         function );
1623
        libcnotify_print_data(
1624
         &( resource_data[ resource_data_offset ] ),
1625
         alignment_padding_size,
1626
         0 );
1627
      }
1628
#endif
1629
0
      resource_data_offset += alignment_padding_size;
1630
0
    }
1631
0
    while( ( resource_data_offset + 2 ) < ( resource_data_start_offset + data_size ) )
1632
0
    {
1633
0
      read_count = libwrc_version_values_read_variable(
1634
0
              language_entry,
1635
0
              resource_data,
1636
0
              resource_data_size,
1637
0
              resource_data_offset,
1638
0
              error );
1639
1640
0
      if( read_count == -1 )
1641
0
      {
1642
0
        libcerror_error_set(
1643
0
         error,
1644
0
         LIBCERROR_ERROR_DOMAIN_IO,
1645
0
         LIBCERROR_IO_ERROR_READ_FAILED,
1646
0
         "%s: unable to read variable.",
1647
0
         function );
1648
1649
0
        return( -1 );
1650
0
      }
1651
0
      else if( read_count == 0 )
1652
0
      {
1653
0
        break;
1654
0
      }
1655
0
      resource_data_offset += read_count;
1656
0
    }
1657
#if defined( HAVE_DEBUG_OUTPUT )
1658
    if( libcnotify_verbose != 0 )
1659
    {
1660
      trailing_data_size = resource_data_offset - resource_data_start_offset;
1661
1662
      if( trailing_data_size < data_size )
1663
      {
1664
        trailing_data_size = data_size - trailing_data_size;
1665
1666
        libcnotify_printf(
1667
         "%s: trailing data:\n",
1668
         function );
1669
        libcnotify_print_data(
1670
         &( resource_data[ resource_data_offset ] ),
1671
         trailing_data_size,
1672
         0 );
1673
      }
1674
    }
1675
#endif
1676
0
  }
1677
0
  return( (ssize_t) data_size );
1678
0
}
1679
1680
/* Reads the version (resource) variable
1681
 * Returns number of bytes read if successful or -1 on error
1682
 */
1683
ssize_t libwrc_version_values_read_variable(
1684
         libwrc_language_entry_t *language_entry,
1685
         const uint8_t *resource_data,
1686
         size_t resource_data_size,
1687
         size_t resource_data_offset,
1688
         libcerror_error_t **error )
1689
0
{
1690
0
  static char *function             = "libwrc_version_values_read_variable";
1691
0
  size_t alignment_padding_size     = 0;
1692
0
  size_t value_string_size          = 0;
1693
0
  uint16_t data_size                = 0;
1694
0
  uint16_t value_data_size          = 0;
1695
0
  uint16_t value_data_type          = 0;
1696
1697
#if defined( HAVE_DEBUG_OUTPUT )
1698
  size_t resource_data_start_offset = 0;
1699
  size_t trailing_data_size         = 0;
1700
  size_t value_string_offset        = 0;
1701
#endif
1702
1703
0
  if( language_entry == NULL )
1704
0
  {
1705
0
    libcerror_error_set(
1706
0
     error,
1707
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1708
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1709
0
     "%s: invalid language entry.",
1710
0
     function );
1711
1712
0
    return( -1 );
1713
0
  }
1714
0
  if( resource_data == NULL )
1715
0
  {
1716
0
    libcerror_error_set(
1717
0
     error,
1718
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1719
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1720
0
     "%s: invalid resource data.",
1721
0
     function );
1722
1723
0
    return( -1 );
1724
0
  }
1725
0
  if( resource_data_size > (size_t) SSIZE_MAX )
1726
0
  {
1727
0
    libcerror_error_set(
1728
0
     error,
1729
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1730
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
1731
0
     "%s: invalid resource data size value exceeds maximum.",
1732
0
     function );
1733
1734
0
    return( -1 );
1735
0
  }
1736
0
  if( resource_data_offset >= resource_data_size )
1737
0
  {
1738
0
    libcerror_error_set(
1739
0
     error,
1740
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1741
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1742
0
     "%s: invalid resource data offset value out of bounds.",
1743
0
     function );
1744
1745
0
    return( -1 );
1746
0
  }
1747
0
  if( ( resource_data_offset + 2 ) > resource_data_size )
1748
0
  {
1749
0
    libcerror_error_set(
1750
0
     error,
1751
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1752
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
1753
0
     "%s: invalid resource data value too small.",
1754
0
     function );
1755
1756
0
    return( -1 );
1757
0
  }
1758
#if defined( HAVE_DEBUG_OUTPUT )
1759
  resource_data_start_offset = resource_data_offset;
1760
#endif
1761
1762
0
  byte_stream_copy_to_uint16_little_endian(
1763
0
   &( resource_data[ resource_data_offset ] ),
1764
0
   data_size );
1765
1766
0
  resource_data_offset += 2;
1767
1768
#if defined( HAVE_DEBUG_OUTPUT )
1769
  if( libcnotify_verbose != 0 )
1770
  {
1771
    libcnotify_printf(
1772
     "%s: data size\t\t\t\t: %" PRIu16 "\n",
1773
     function,
1774
     data_size );
1775
  }
1776
#endif
1777
0
  if( data_size != 0 )
1778
0
  {
1779
0
    if( ( data_size < 8 )
1780
0
     || ( data_size > ( resource_data_size - ( resource_data_offset - 2 ) ) ) )
1781
0
    {
1782
0
      libcerror_error_set(
1783
0
       error,
1784
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
1785
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1786
0
       "%s: data size value out of bounds.",
1787
0
       function );
1788
1789
0
      return( -1 );
1790
0
    }
1791
0
    byte_stream_copy_to_uint16_little_endian(
1792
0
     &( resource_data[ resource_data_offset ] ),
1793
0
     value_data_size );
1794
1795
0
    resource_data_offset += 2;
1796
1797
0
    byte_stream_copy_to_uint16_little_endian(
1798
0
     &( resource_data[ resource_data_offset ] ),
1799
0
     value_data_type );
1800
1801
0
    resource_data_offset += 2;
1802
1803
#if defined( HAVE_DEBUG_OUTPUT )
1804
    if( libcnotify_verbose != 0 )
1805
    {
1806
      libcnotify_printf(
1807
       "%s: value data size\t\t\t: %" PRIu16 "\n",
1808
       function,
1809
       value_data_size );
1810
1811
      libcnotify_printf(
1812
       "%s: value data type\t\t\t: %" PRIu16 "\n",
1813
       function,
1814
       value_data_type );
1815
    }
1816
#endif
1817
/* TODO check value_data_size == 0 ? */
1818
/* TODO handle value_data_type != 1 */
1819
#if defined( HAVE_DEBUG_OUTPUT )
1820
    value_string_offset = resource_data_offset;
1821
#endif
1822
1823
0
    value_string_size = 0;
1824
1825
0
    while( ( resource_data_offset + 2 ) < resource_data_size )
1826
0
    {
1827
0
      value_string_size += 2;
1828
1829
0
      if( ( resource_data[ resource_data_offset ] == 0 )
1830
0
       && ( resource_data[ resource_data_offset + 1 ] == 0 ) )
1831
0
      {
1832
0
        resource_data_offset += 2;
1833
1834
0
        break;
1835
0
      }
1836
0
      resource_data_offset += 2;
1837
0
    }
1838
#if defined( HAVE_DEBUG_OUTPUT )
1839
    if( libcnotify_verbose != 0 )
1840
    {
1841
      libcnotify_printf(
1842
       "%s: value identifier string data:\n",
1843
       function );
1844
      libcnotify_print_data(
1845
       &( resource_data[ value_string_offset ] ),
1846
       value_string_size,
1847
       0 );
1848
    }
1849
#endif
1850
/* TODO convert string */
1851
0
    if( ( resource_data_offset % 4 ) != 0 )
1852
0
    {
1853
0
      alignment_padding_size = 4 - ( resource_data_offset % 4 );
1854
1855
#if defined( HAVE_DEBUG_OUTPUT )
1856
      if( libcnotify_verbose != 0 )
1857
      {
1858
        libcnotify_printf(
1859
         "%s: alignment padding:\n",
1860
         function );
1861
        libcnotify_print_data(
1862
         &( resource_data[ resource_data_offset ] ),
1863
         alignment_padding_size,
1864
         0 );
1865
      }
1866
#endif
1867
0
      resource_data_offset += alignment_padding_size;
1868
0
    }
1869
/* TODO */
1870
1871
#if defined( HAVE_DEBUG_OUTPUT )
1872
    if( libcnotify_verbose != 0 )
1873
    {
1874
      trailing_data_size = resource_data_offset - resource_data_start_offset;
1875
1876
      if( trailing_data_size < data_size )
1877
      {
1878
        trailing_data_size = data_size - trailing_data_size;
1879
1880
        libcnotify_printf(
1881
         "%s: trailing data:\n",
1882
         function );
1883
        libcnotify_print_data(
1884
         &( resource_data[ resource_data_offset ] ),
1885
         trailing_data_size,
1886
         0 );
1887
      }
1888
    }
1889
#endif
1890
0
  }
1891
0
  return( (ssize_t) data_size );
1892
0
}
1893
1894
/* Retrieves the file version
1895
 * Returns 1 if successful or -1 on error
1896
 */
1897
int libwrc_version_values_get_file_version(
1898
     libwrc_version_values_t *version_values,
1899
     uint64_t *file_version,
1900
     libcerror_error_t **error )
1901
0
{
1902
0
  static char *function = "libwrc_version_values_get_file_version";
1903
1904
0
  if( version_values == NULL )
1905
0
  {
1906
0
    libcerror_error_set(
1907
0
     error,
1908
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1909
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1910
0
     "%s: invalid version values.",
1911
0
     function );
1912
1913
0
    return( -1 );
1914
0
  }
1915
0
  if( file_version == NULL )
1916
0
  {
1917
0
    libcerror_error_set(
1918
0
     error,
1919
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1920
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1921
0
     "%s: invalid file version.",
1922
0
     function );
1923
1924
0
    return( -1 );
1925
0
  }
1926
0
  *file_version = version_values->file_version;
1927
1928
0
  return( 1 );
1929
0
}
1930
1931
/* Retrieves the product version
1932
 * Returns 1 if successful or -1 on error
1933
 */
1934
int libwrc_version_values_get_product_version(
1935
     libwrc_version_values_t *version_values,
1936
     uint64_t *product_version,
1937
     libcerror_error_t **error )
1938
0
{
1939
0
  static char *function = "libwrc_version_values_get_product_version";
1940
1941
0
  if( version_values == NULL )
1942
0
  {
1943
0
    libcerror_error_set(
1944
0
     error,
1945
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1946
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1947
0
     "%s: invalid version values.",
1948
0
     function );
1949
1950
0
    return( -1 );
1951
0
  }
1952
0
  if( product_version == NULL )
1953
0
  {
1954
0
    libcerror_error_set(
1955
0
     error,
1956
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1957
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1958
0
     "%s: invalid product version.",
1959
0
     function );
1960
1961
0
    return( -1 );
1962
0
  }
1963
0
  *product_version = version_values->product_version;
1964
1965
0
  return( 1 );
1966
0
}
1967