Coverage Report

Created: 2025-10-14 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwrc/libwrc/libwrc_message_table_values.c
Line
Count
Source
1
/*
2
 * Message table 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 <memory.h>
24
#include <types.h>
25
26
#include "libwrc_data_descriptor.h"
27
#include "libwrc_definitions.h"
28
#include "libwrc_io_handle.h"
29
#include "libwrc_libbfio.h"
30
#include "libwrc_libcerror.h"
31
#include "libwrc_libcnotify.h"
32
#include "libwrc_libfvalue.h"
33
#include "libwrc_language_entry.h"
34
#include "libwrc_message_table_values.h"
35
36
#include "wrc_message_table_resource.h"
37
38
/* Reads message table values
39
 * Returns 1 if successful or -1 on error
40
 */
41
int libwrc_message_table_values_read(
42
     libwrc_language_entry_t *language_entry,
43
     libwrc_io_handle_t *io_handle,
44
     libbfio_handle_t *file_io_handle,
45
     libwrc_data_descriptor_t *data_descriptor,
46
     libcerror_error_t **error )
47
0
{
48
0
  libfvalue_value_t *message_table_value       = NULL;
49
0
  uint8_t *resource_data                       = NULL;
50
0
  uint8_t *message_table_resource_data         = NULL;
51
0
  uint8_t *message_table_string_resource_data  = NULL;
52
0
  static char *function                        = "libwrc_message_table_values_read";
53
0
  off64_t file_offset                          = 0;
54
0
  size_t message_entry_descriptors_size        = 0;
55
0
  size_t resource_data_size                    = 0;
56
0
  ssize_t read_count                           = 0;
57
0
  uint32_t first_message_identifier            = 0;
58
0
  uint32_t last_message_identifier             = 0;
59
0
  uint16_t message_entry_descriptor_index      = 0;
60
0
  uint16_t message_table_string_flags          = 0;
61
0
  uint32_t message_table_string_offset         = 0;
62
0
  uint16_t message_table_string_size           = 0;
63
0
  uint16_t number_of_message_entry_descriptors = 0;
64
0
  uint16_t string_size                         = 0;
65
0
  int result                                   = 0;
66
0
  int value_encoding                           = 0;
67
0
  int value_index                              = 0;
68
69
0
  if( language_entry == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
74
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
75
0
     "%s: invalid language entry.",
76
0
     function );
77
78
0
    return( -1 );
79
0
  }
80
0
  if( io_handle == NULL )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
85
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
86
0
     "%s: invalid IO handle.",
87
0
     function );
88
89
0
    return( -1 );
90
0
  }
91
0
  if( data_descriptor == NULL )
92
0
  {
93
0
    libcerror_error_set(
94
0
     error,
95
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
96
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
97
0
     "%s: invalid data descriptor.",
98
0
     function );
99
100
0
    return( -1 );
101
0
  }
102
0
  resource_data_size = (size_t) data_descriptor->size;
103
104
0
  if( ( resource_data_size == 0 )
105
0
   || ( resource_data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
106
0
  {
107
0
    libcerror_error_set(
108
0
     error,
109
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
110
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
111
0
     "%s: invalid resource data size value out of bounds.",
112
0
     function );
113
114
0
    goto on_error;
115
0
  }
116
0
  resource_data = (uint8_t *) memory_allocate(
117
0
                               sizeof( uint8_t ) * resource_data_size );
118
119
0
  if( resource_data == NULL )
120
0
  {
121
0
    libcerror_error_set(
122
0
     error,
123
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
124
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
125
0
     "%s: unable to create resource data.",
126
0
     function );
127
128
0
    goto on_error;
129
0
  }
130
0
  file_offset = data_descriptor->virtual_address - io_handle->virtual_address;
131
132
0
  read_count = libbfio_handle_read_buffer_at_offset(
133
0
                file_io_handle,
134
0
                resource_data,
135
0
                resource_data_size,
136
0
                file_offset,
137
0
                error );
138
139
0
  if( read_count != (ssize_t) resource_data_size )
140
0
  {
141
0
    libcerror_error_set(
142
0
     error,
143
0
     LIBCERROR_ERROR_DOMAIN_IO,
144
0
     LIBCERROR_IO_ERROR_READ_FAILED,
145
0
     "%s: unable to read resource data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
146
0
     function,
147
0
     file_offset,
148
0
     file_offset );
149
150
0
    goto on_error;
151
0
  }
152
0
  message_table_resource_data = resource_data;
153
154
#if defined( HAVE_DEBUG_OUTPUT )
155
  if( libcnotify_verbose != 0 )
156
  {
157
    libcnotify_printf(
158
     "%s: resource data:\n",
159
     function );
160
    libcnotify_print_data(
161
     message_table_resource_data,
162
     resource_data_size,
163
     0 );
164
  }
165
#endif
166
0
  byte_stream_copy_to_uint32_little_endian(
167
0
   message_table_resource_data,
168
0
   number_of_message_entry_descriptors );
169
170
#if defined( HAVE_DEBUG_OUTPUT )
171
  if( libcnotify_verbose != 0 )
172
  {
173
    libcnotify_printf(
174
     "%s: number of message entry descriptors\t: %" PRIu32 "\n",
175
     function,
176
     number_of_message_entry_descriptors );
177
178
    libcnotify_printf(
179
     "\n" );
180
  }
181
#endif
182
0
  message_table_resource_data += sizeof( uint32_t );
183
0
  resource_data_size          -= sizeof( uint32_t );
184
185
0
  message_entry_descriptors_size = number_of_message_entry_descriptors
186
0
                                 * sizeof( wrc_message_table_entry_descriptor_t );
187
188
0
  if( message_entry_descriptors_size > resource_data_size )
189
0
  {
190
0
    libcerror_error_set(
191
0
     error,
192
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
193
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
194
0
     "%s: number of message entry descriptors value out of bound.",
195
0
     function );
196
197
0
    goto on_error;
198
0
  }
199
0
  for( message_entry_descriptor_index = 0;
200
0
       message_entry_descriptor_index < number_of_message_entry_descriptors;
201
0
       message_entry_descriptor_index++ )
202
0
  {
203
#if defined( HAVE_DEBUG_OUTPUT )
204
    if( libcnotify_verbose != 0 )
205
    {
206
      libcnotify_printf(
207
       "%s: message entry descriptor: %03d\n",
208
       function,
209
       message_entry_descriptor_index );
210
      libcnotify_print_data(
211
       message_table_resource_data,
212
       sizeof( wrc_message_table_entry_descriptor_t ),
213
       0 );
214
    }
215
#endif
216
0
    byte_stream_copy_to_uint32_little_endian(
217
0
     ( (wrc_message_table_entry_descriptor_t *) message_table_resource_data )->first_identifier,
218
0
     first_message_identifier );
219
220
0
    byte_stream_copy_to_uint32_little_endian(
221
0
     ( (wrc_message_table_entry_descriptor_t *) message_table_resource_data )->last_identifier,
222
0
     last_message_identifier );
223
224
0
    byte_stream_copy_to_uint32_little_endian(
225
0
     ( (wrc_message_table_entry_descriptor_t *) message_table_resource_data )->offset,
226
0
     message_table_string_offset );
227
228
#if defined( HAVE_DEBUG_OUTPUT )
229
    if( libcnotify_verbose != 0 )
230
    {
231
      libcnotify_printf(
232
       "%s: first message identifier\t\t\t: 0x%08" PRIx32 "\n",
233
       function,
234
       first_message_identifier );
235
236
      libcnotify_printf(
237
       "%s: last message identifier\t\t\t: 0x%08" PRIx32 "\n",
238
       function,
239
       last_message_identifier );
240
241
      libcnotify_printf(
242
       "%s: first message string offset\t\t\t: 0x%08" PRIx32 "\n",
243
       function,
244
       message_table_string_offset );
245
246
      libcnotify_printf(
247
       "\n" );
248
    }
249
#endif
250
0
    message_table_resource_data += sizeof( wrc_message_table_entry_descriptor_t );
251
0
    resource_data_size          -= sizeof( wrc_message_table_entry_descriptor_t );
252
253
0
    if( first_message_identifier > last_message_identifier )
254
0
    {
255
0
      libcerror_error_set(
256
0
       error,
257
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
258
0
       LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
259
0
       "%s: first message identifier exceeds last.",
260
0
       function );
261
262
0
      goto on_error;
263
0
    }
264
0
    while( first_message_identifier <= last_message_identifier )
265
0
    {
266
0
      if( message_table_string_offset >= (size_t) data_descriptor->size )
267
0
      {
268
0
        libcerror_error_set(
269
0
         error,
270
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
271
0
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
272
0
         "%s: number of message string offset value out of bound.",
273
0
         function );
274
275
0
        goto on_error;
276
0
      }
277
0
      message_table_string_resource_data = &( resource_data[ message_table_string_offset ] );
278
279
#if defined( HAVE_DEBUG_OUTPUT )
280
      if( libcnotify_verbose != 0 )
281
      {
282
        libcnotify_printf(
283
         "%s: message string: 0x%08" PRIx32 "\n",
284
         function,
285
         first_message_identifier );
286
        libcnotify_print_data(
287
         message_table_string_resource_data,
288
         sizeof( wrc_message_table_string_t ),
289
         0 );
290
      }
291
#endif
292
0
      byte_stream_copy_to_uint16_little_endian(
293
0
       ( (wrc_message_table_string_t *) message_table_string_resource_data )->size,
294
0
       message_table_string_size );
295
296
0
      byte_stream_copy_to_uint16_little_endian(
297
0
       ( (wrc_message_table_string_t *) message_table_string_resource_data )->flags,
298
0
       message_table_string_flags );
299
300
#if defined( HAVE_DEBUG_OUTPUT )
301
      if( libcnotify_verbose != 0 )
302
      {
303
        libcnotify_printf(
304
         "%s: message string: 0x%08" PRIx32 " size\t\t: %" PRIu16 "\n",
305
         function,
306
         first_message_identifier,
307
         message_table_string_size );
308
309
        libcnotify_printf(
310
         "%s: message string: 0x%08" PRIx32 " flags\t\t: 0x%04" PRIx16 "\n",
311
         function,
312
         first_message_identifier,
313
         message_table_string_flags );
314
      }
315
#endif
316
0
      if( message_table_string_size > sizeof( wrc_message_table_string_t ) )
317
0
      {
318
0
        message_table_string_resource_data += sizeof( wrc_message_table_string_t );
319
0
        message_table_string_offset        += sizeof( wrc_message_table_string_t );
320
0
        message_table_string_size          -= sizeof( wrc_message_table_string_t );
321
322
0
        if( ( message_table_string_flags & 0x0001 ) == 0 )
323
0
        {
324
0
          result = libfvalue_value_type_initialize(
325
0
                    &( message_table_value ),
326
0
                    LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
327
0
                    error );
328
0
        }
329
0
        else
330
0
        {
331
0
          result = libfvalue_value_type_initialize(
332
0
                    &( message_table_value ),
333
0
                    LIBFVALUE_VALUE_TYPE_STRING_UTF16,
334
0
                    error );
335
0
        }
336
0
        if( result != 1 )
337
0
        {
338
0
          libcerror_error_set(
339
0
           error,
340
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
341
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
342
0
           "%s: unable to create string value.",
343
0
           function );
344
345
0
          goto on_error;
346
0
        }
347
0
        if( libfvalue_value_set_identifier(
348
0
             message_table_value,
349
0
             (uint8_t *) &first_message_identifier,
350
0
             4,
351
0
             LIBFVALUE_VALUE_IDENTIFIER_FLAG_MANAGED,
352
0
             error ) != 1 )
353
0
        {
354
0
          libcerror_error_set(
355
0
           error,
356
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
357
0
           LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
358
0
           "%s: unable to set identifier of message table value.",
359
0
           function );
360
361
0
          goto on_error;
362
0
        }
363
0
        if( ( message_table_string_flags & 0x0001 ) == 0 )
364
0
        {
365
0
          value_encoding = io_handle->ascii_codepage;
366
0
        }
367
0
        else
368
0
        {
369
0
          value_encoding = LIBFVALUE_CODEPAGE_UTF16_LITTLE_ENDIAN;
370
0
        }
371
/* TODO data bounds check */
372
#if defined( HAVE_DEBUG_OUTPUT )
373
        if( libcnotify_verbose != 0 )
374
        {
375
          libcnotify_printf(
376
           "%s: message string: 0x%08" PRIx32 " data:\n",
377
           function,
378
           first_message_identifier );
379
          libcnotify_print_data(
380
           message_table_string_resource_data,
381
           (size_t) message_table_string_size,
382
           0 );
383
        }
384
#endif
385
        /* Strip off trailing 0-byte values
386
         */
387
0
        string_size = message_table_string_size;
388
389
0
        if( ( message_table_string_flags & 0x0001 ) == 0 )
390
0
        {
391
0
          while( string_size > 0 )
392
0
          {
393
0
            string_size -= 1;
394
395
0
            if( message_table_string_resource_data[ string_size ] != 0 )
396
0
            {
397
0
              break;
398
0
            }
399
0
          }
400
0
          string_size += 1;
401
0
        }
402
0
        else
403
0
        {
404
0
          while( string_size > 1 )
405
0
          {
406
0
            string_size -= 2;
407
408
0
            if( ( message_table_string_resource_data[ string_size ] != 0 )
409
0
             || ( message_table_string_resource_data[ string_size + 1 ] != 0 ) )
410
0
            {
411
0
              break;
412
0
            }
413
0
          }
414
0
          string_size += 2;
415
0
        }
416
0
        if( libfvalue_value_set_data(
417
0
             message_table_value,
418
0
             message_table_string_resource_data,
419
0
             (size_t) string_size,
420
0
             value_encoding,
421
0
             LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
422
0
             error ) != 1 )
423
0
        {
424
0
          libcerror_error_set(
425
0
           error,
426
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
427
0
           LIBCERROR_RUNTIME_ERROR_SET_FAILED,
428
0
           "%s: unable to set data of string value.",
429
0
           function );
430
431
0
          goto on_error;
432
0
        }
433
#if defined( HAVE_DEBUG_OUTPUT )
434
        if( libcnotify_verbose != 0 )
435
        {
436
          libcnotify_printf(
437
           "%s: message string: 0x%08" PRIx32 " value\t\t: ",
438
           function,
439
           first_message_identifier );
440
441
          if( libfvalue_value_print(
442
               message_table_value,
443
               0,
444
               0,
445
               error ) != 1 )
446
          {
447
            libcerror_error_set(
448
             error,
449
             LIBCERROR_ERROR_DOMAIN_RUNTIME,
450
             LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
451
             "%s: unable to print string value.",
452
             function );
453
454
            goto on_error;
455
          }
456
          libcnotify_printf(
457
           "\n" );
458
        }
459
#endif
460
0
      }
461
#if defined( HAVE_DEBUG_OUTPUT )
462
      else if( libcnotify_verbose != 0 )
463
      {
464
        libcnotify_printf(
465
         "\n" );
466
      }
467
#endif
468
0
      message_table_string_resource_data += message_table_string_size;
469
0
      message_table_string_offset        += message_table_string_size;
470
471
0
      if( libwrc_language_entry_append_value(
472
0
           language_entry,
473
0
           &value_index,
474
0
           (intptr_t *) message_table_value,
475
0
           error ) != 1 )
476
0
      {
477
0
        libcerror_error_set(
478
0
         error,
479
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
480
0
         LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
481
0
         "%s: unable to append message table values.",
482
0
         function );
483
484
0
        goto on_error;
485
0
      }
486
0
      message_table_value = NULL;
487
488
0
      first_message_identifier++;
489
0
    }
490
0
  }
491
0
  memory_free(
492
0
   resource_data );
493
494
0
  return( 1 );
495
496
0
on_error:
497
0
  if( message_table_value != NULL )
498
0
  {
499
0
    libfvalue_value_free(
500
0
     &message_table_value,
501
0
     NULL );
502
0
  }
503
0
  if( resource_data != NULL )
504
0
  {
505
0
    memory_free(
506
0
     resource_data );
507
0
  }
508
0
  return( -1 );
509
0
}
510