Coverage Report

Created: 2025-06-22 07:35

/src/libscca/libscca/libscca_file_header.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * File header 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 "libscca_debug.h"
28
#include "libscca_file_header.h"
29
#include "libscca_io_handle.h"
30
#include "libscca_libbfio.h"
31
#include "libscca_libcerror.h"
32
#include "libscca_libcnotify.h"
33
#include "libscca_libfdata.h"
34
#include "libscca_libuna.h"
35
36
#include "scca_file_header.h"
37
38
/* Creates file header
39
 * Make sure the value file_header is referencing, is set to NULL
40
 * Returns 1 if successful or -1 on error
41
 */
42
int libscca_file_header_initialize(
43
     libscca_file_header_t **file_header,
44
     libcerror_error_t **error )
45
1.64k
{
46
1.64k
  static char *function = "libscca_file_header_initialize";
47
48
1.64k
  if( file_header == NULL )
49
0
  {
50
0
    libcerror_error_set(
51
0
     error,
52
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54
0
     "%s: invalid file header.",
55
0
     function );
56
57
0
    return( -1 );
58
0
  }
59
1.64k
  if( *file_header != NULL )
60
0
  {
61
0
    libcerror_error_set(
62
0
     error,
63
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
64
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65
0
     "%s: invalid file header value already set.",
66
0
     function );
67
68
0
    return( -1 );
69
0
  }
70
1.64k
  *file_header = memory_allocate_structure(
71
1.64k
                  libscca_file_header_t );
72
73
1.64k
  if( *file_header == NULL )
74
0
  {
75
0
    libcerror_error_set(
76
0
     error,
77
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
78
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
79
0
     "%s: unable to create file header.",
80
0
     function );
81
82
0
    goto on_error;
83
0
  }
84
1.64k
  if( memory_set(
85
1.64k
       *file_header,
86
1.64k
       0,
87
1.64k
       sizeof( libscca_file_header_t ) ) == NULL )
88
0
  {
89
0
    libcerror_error_set(
90
0
     error,
91
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
92
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
93
0
     "%s: unable to clear file header.",
94
0
     function );
95
96
0
    goto on_error;
97
0
  }
98
1.64k
  return( 1 );
99
100
0
on_error:
101
0
  if( *file_header != NULL )
102
0
  {
103
0
    memory_free(
104
0
     *file_header );
105
106
0
    *file_header = NULL;
107
0
  }
108
0
  return( -1 );
109
1.64k
}
110
111
/* Frees file header
112
 * Returns 1 if successful or -1 on error
113
 */
114
int libscca_file_header_free(
115
     libscca_file_header_t **file_header,
116
     libcerror_error_t **error )
117
1.64k
{
118
1.64k
  static char *function = "libscca_file_header_free";
119
120
1.64k
  if( file_header == NULL )
121
0
  {
122
0
    libcerror_error_set(
123
0
     error,
124
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
125
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
126
0
     "%s: invalid file header.",
127
0
     function );
128
129
0
    return( -1 );
130
0
  }
131
1.64k
  if( *file_header != NULL )
132
1.64k
  {
133
1.64k
    memory_free(
134
1.64k
     *file_header );
135
136
1.64k
    *file_header = NULL;
137
1.64k
  }
138
1.64k
  return( 1 );
139
1.64k
}
140
141
/* Reads the file header data
142
 * Returns 1 if successful or -1 on error
143
 */
144
int libscca_file_header_read_data(
145
     libscca_file_header_t *file_header,
146
     const uint8_t *data,
147
     size_t data_size,
148
     libcerror_error_t **error )
149
1.62k
{
150
1.62k
  static char *function = "libscca_file_header_read_data";
151
152
#if defined( HAVE_DEBUG_OUTPUT )
153
  uint32_t value_32bit  = 0;
154
#endif
155
156
1.62k
  if( file_header == NULL )
157
0
  {
158
0
    libcerror_error_set(
159
0
     error,
160
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
161
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
162
0
     "%s: invalid file header.",
163
0
     function );
164
165
0
    return( -1 );
166
0
  }
167
1.62k
  if( data == NULL )
168
0
  {
169
0
    libcerror_error_set(
170
0
     error,
171
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
172
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
173
0
     "%s: invalid data.",
174
0
     function );
175
176
0
    return( -1 );
177
0
  }
178
1.62k
  if( ( data_size < sizeof( scca_file_header_t ) )
179
1.62k
   || ( data_size > (size_t) SSIZE_MAX ) )
180
0
  {
181
0
    libcerror_error_set(
182
0
     error,
183
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
184
0
     LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
185
0
     "%s: invalid data size value out of bounds.",
186
0
     function );
187
188
0
    return( -1 );
189
0
  }
190
#if defined( HAVE_DEBUG_OUTPUT )
191
  if( libcnotify_verbose != 0 )
192
  {
193
    libcnotify_printf(
194
     "%s: file header data:\n",
195
     function );
196
    libcnotify_print_data(
197
     data,
198
     sizeof( scca_file_header_t ),
199
     0 );
200
  }
201
#endif
202
1.62k
  if( memory_compare(
203
1.62k
       ( (scca_file_header_t *) data )->signature,
204
1.62k
       scca_file_signature,
205
1.62k
       4 ) != 0 )
206
138
  {
207
138
    libcerror_error_set(
208
138
     error,
209
138
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
210
138
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
211
138
     "%s: invalid signature.",
212
138
     function );
213
214
138
    return( -1 );
215
138
  }
216
1.48k
  byte_stream_copy_to_uint32_little_endian(
217
1.48k
   ( (scca_file_header_t *) data )->format_version,
218
1.48k
   file_header->format_version );
219
220
1.48k
  byte_stream_copy_to_uint32_little_endian(
221
1.48k
   ( (scca_file_header_t *) data )->file_size,
222
1.48k
   file_header->file_size );
223
224
1.48k
  byte_stream_copy_to_uint32_little_endian(
225
1.48k
   ( (scca_file_header_t *) data )->prefetch_hash,
226
1.48k
   file_header->prefetch_hash );
227
228
1.48k
  if( memory_copy(
229
1.48k
       file_header->executable_filename,
230
1.48k
       ( (scca_file_header_t *) data )->executable_filename,
231
1.48k
       60 ) == NULL )
232
0
  {
233
0
    libcerror_error_set(
234
0
     error,
235
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
236
0
     LIBCERROR_MEMORY_ERROR_COPY_FAILED,
237
0
     "%s: unable to copy executable filename.",
238
0
     function );
239
240
0
    return( -1 );
241
0
  }
242
1.48k
  for( file_header->executable_filename_size = 0;
243
15.0k
       ( file_header->executable_filename_size + 1 ) < 60;
244
13.5k
       file_header->executable_filename_size += 2 )
245
14.9k
  {
246
14.9k
    if( ( file_header->executable_filename[ file_header->executable_filename_size ] == 0 )
247
14.9k
     && ( file_header->executable_filename[ file_header->executable_filename_size + 1 ] == 0 ) )
248
1.37k
    {
249
1.37k
      break;
250
1.37k
    }
251
14.9k
  }
252
#if defined( HAVE_DEBUG_OUTPUT )
253
  if( libcnotify_verbose != 0 )
254
  {
255
    libcnotify_printf(
256
     "%s: format version\t\t\t\t: %" PRIu32 "\n",
257
     function,
258
     file_header->format_version );
259
260
    libcnotify_printf(
261
     "%s: signature\t\t\t\t: %c%c%c%c\n",
262
     function,
263
     ( (scca_file_header_t *) data )->signature[ 0 ],
264
     ( (scca_file_header_t *) data )->signature[ 1 ],
265
     ( (scca_file_header_t *) data )->signature[ 2 ],
266
     ( (scca_file_header_t *) data )->signature[ 3 ] );
267
268
    byte_stream_copy_to_uint32_little_endian(
269
     ( (scca_file_header_t *) data )->unknown1,
270
     value_32bit );
271
    libcnotify_printf(
272
     "%s: unknown1\t\t\t\t\t: 0x%08" PRIx32 "\n",
273
     function,
274
     value_32bit );
275
276
    libcnotify_printf(
277
     "%s: file size\t\t\t\t: %" PRIu32 "\n",
278
     function,
279
     file_header->file_size );
280
281
    if( libscca_debug_print_utf16_string_value(
282
         function,
283
         "executable filename\t\t\t",
284
         file_header->executable_filename,
285
         file_header->executable_filename_size,
286
         LIBUNA_ENDIAN_LITTLE | LIBUNA_UTF16_STREAM_ALLOW_UNPAIRED_SURROGATE,
287
         error ) != 1 )
288
    {
289
      libcerror_error_set(
290
       error,
291
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
292
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
293
       "%s: unable to print UTF-16 string value.",
294
       function );
295
296
      return( -1 );
297
    }
298
    libcnotify_printf(
299
     "%s: prefetch hash\t\t\t\t: 0x%08" PRIx32 "\n",
300
     function,
301
     file_header->prefetch_hash );
302
303
    byte_stream_copy_to_uint32_little_endian(
304
     ( (scca_file_header_t *) data )->unknown2,
305
     value_32bit );
306
    libcnotify_printf(
307
     "%s: unknown2\t\t\t\t\t: 0x%08" PRIx32 "\n",
308
     function,
309
     value_32bit );
310
311
    libcnotify_printf(
312
     "\n" );
313
  }
314
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
315
316
1.48k
  return( 1 );
317
1.48k
}
318
319
/* Reads the file header data
320
 * Returns 1 if successful or -1 on error
321
 */
322
int libscca_file_header_read_data_stream(
323
     libscca_file_header_t *file_header,
324
     libfdata_stream_t *data_stream,
325
     libbfio_handle_t *file_io_handle,
326
     libcerror_error_t **error )
327
1.64k
{
328
1.64k
  uint8_t file_header_data[ sizeof( scca_file_header_t ) ];
329
330
1.64k
  static char *function = "libscca_file_header_read_data_stream";
331
1.64k
  ssize_t read_count    = 0;
332
333
1.64k
  if( file_header == NULL )
334
0
  {
335
0
    libcerror_error_set(
336
0
     error,
337
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
338
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
339
0
     "%s: invalid file header.",
340
0
     function );
341
342
0
    return( -1 );
343
0
  }
344
#if defined( HAVE_DEBUG_OUTPUT )
345
  if( libcnotify_verbose != 0 )
346
  {
347
    libcnotify_printf(
348
     "%s: reading (uncompressed) file header at offset: 0 (0x00000000)\n",
349
     function );
350
  }
351
#endif
352
1.64k
  read_count = libfdata_stream_read_buffer_at_offset(
353
1.64k
                data_stream,
354
1.64k
                (intptr_t *) file_io_handle,
355
1.64k
                file_header_data,
356
1.64k
                sizeof( scca_file_header_t ),
357
1.64k
                0,
358
1.64k
                0,
359
1.64k
                error );
360
361
1.64k
  if( read_count != (ssize_t) sizeof( scca_file_header_t ) )
362
21
  {
363
21
    libcerror_error_set(
364
21
     error,
365
21
     LIBCERROR_ERROR_DOMAIN_IO,
366
21
     LIBCERROR_IO_ERROR_READ_FAILED,
367
21
     "%s: unable to read file header data at offset: 0 (0x00000000).",
368
21
     function );
369
370
21
    return( -1 );
371
21
  }
372
1.62k
  if( libscca_file_header_read_data(
373
1.62k
       file_header,
374
1.62k
       file_header_data,
375
1.62k
       sizeof( scca_file_header_t ),
376
1.62k
       error ) != 1 )
377
138
  {
378
138
    libcerror_error_set(
379
138
     error,
380
138
     LIBCERROR_ERROR_DOMAIN_IO,
381
138
     LIBCERROR_IO_ERROR_READ_FAILED,
382
138
     "%s: unable to read file header.",
383
138
     function );
384
385
138
    return( -1 );
386
138
  }
387
1.48k
  return( 1 );
388
1.62k
}
389
390
/* Retrieves the size of a specific UTF-8 encoded executable filename
391
 * This function uses UTF-8 RFC 2279 (or 6-byte UTF-8) to support characters outside Unicode
392
 * The returned size includes the end of string character
393
 * Returns 1 if successful or -1 on error
394
 */
395
int libscca_file_header_get_utf8_executable_filename_size(
396
     libscca_file_header_t *file_header,
397
     size_t *utf8_string_size,
398
     libcerror_error_t **error )
399
0
{
400
0
  static char *function = "libscca_file_header_get_utf8_executable_filename_size";
401
402
0
  if( file_header == NULL )
403
0
  {
404
0
    libcerror_error_set(
405
0
     error,
406
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
407
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
408
0
     "%s: invalid file header.",
409
0
     function );
410
411
0
    return( -1 );
412
0
  }
413
0
  if( libuna_utf8_string_size_from_utf16_stream(
414
0
       file_header->executable_filename,
415
0
       file_header->executable_filename_size,
416
0
       LIBUNA_ENDIAN_LITTLE | LIBUNA_UTF16_STREAM_ALLOW_UNPAIRED_SURROGATE,
417
0
       utf8_string_size,
418
0
       error ) != 1 )
419
0
  {
420
0
    libcerror_error_set(
421
0
     error,
422
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
423
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
424
0
     "%s: unable to determine size of UTF-8 executable filename string.",
425
0
     function );
426
427
0
    return( -1 );
428
0
  }
429
0
  return( 1 );
430
0
}
431
432
/* Retrieves a specific UTF-8 encoded executable filename
433
 * This function uses UTF-8 RFC 2279 (or 6-byte UTF-8) to support characters outside Unicode
434
 * The size should include the end of string character
435
 * Returns 1 if successful or -1 on error
436
 */
437
int libscca_file_header_get_utf8_executable_filename(
438
     libscca_file_header_t *file_header,
439
     uint8_t *utf8_string,
440
     size_t utf8_string_size,
441
     libcerror_error_t **error )
442
0
{
443
0
  static char *function = "libscca_file_header_get_utf8_executable_filename";
444
445
0
  if( file_header == NULL )
446
0
  {
447
0
    libcerror_error_set(
448
0
     error,
449
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
450
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
451
0
     "%s: invalid file header.",
452
0
     function );
453
454
0
    return( -1 );
455
0
  }
456
0
  if( libuna_utf8_string_copy_from_utf16_stream(
457
0
       (libuna_utf8_character_t *) utf8_string,
458
0
       utf8_string_size,
459
0
       file_header->executable_filename,
460
0
       file_header->executable_filename_size,
461
0
       LIBUNA_ENDIAN_LITTLE | LIBUNA_UTF16_STREAM_ALLOW_UNPAIRED_SURROGATE,
462
0
       error ) != 1 )
463
0
  {
464
0
    libcerror_error_set(
465
0
     error,
466
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
467
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
468
0
     "%s: unable to set UTF-8 executable filename string.",
469
0
     function );
470
471
0
    return( -1 );
472
0
  }
473
0
  return( 1 );
474
0
}
475
476
/* Retrieves the size of a specific UTF-16 encoded executable filename
477
 * This function uses UCS-2 (with surrogates) to support characters outside Unicode
478
 * The returned size includes the end of string character
479
 * Returns 1 if successful or -1 on error
480
 */
481
int libscca_file_header_get_utf16_executable_filename_size(
482
     libscca_file_header_t *file_header,
483
     size_t *utf16_string_size,
484
     libcerror_error_t **error )
485
0
{
486
0
  static char *function = "libscca_file_header_get_utf16_executable_filename_size";
487
488
0
  if( file_header == NULL )
489
0
  {
490
0
    libcerror_error_set(
491
0
     error,
492
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
493
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
494
0
     "%s: invalid file header.",
495
0
     function );
496
497
0
    return( -1 );
498
0
  }
499
0
  if( libuna_utf16_string_size_from_utf16_stream(
500
0
       file_header->executable_filename,
501
0
       file_header->executable_filename_size,
502
0
       LIBUNA_ENDIAN_LITTLE | LIBUNA_UTF16_STREAM_ALLOW_UNPAIRED_SURROGATE,
503
0
       utf16_string_size,
504
0
       error ) != 1 )
505
0
  {
506
0
    libcerror_error_set(
507
0
     error,
508
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
509
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
510
0
     "%s: unable to determine size of UTF-16 executable filename string.",
511
0
     function );
512
513
0
    return( -1 );
514
0
  }
515
0
  return( 1 );
516
0
}
517
518
/* Retrieves a specific UTF-16 encoded executable filename
519
 * This function uses UCS-2 (with surrogates) to support characters outside Unicode
520
 * The size should include the end of string character
521
 * Returns 1 if successful or -1 on error
522
 */
523
int libscca_file_header_get_utf16_executable_filename(
524
     libscca_file_header_t *file_header,
525
     uint16_t *utf16_string,
526
     size_t utf16_string_size,
527
     libcerror_error_t **error )
528
0
{
529
0
  static char *function = "libscca_file_header_get_utf16_executable_filename";
530
531
0
  if( file_header == NULL )
532
0
  {
533
0
    libcerror_error_set(
534
0
     error,
535
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
536
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
537
0
     "%s: invalid file header.",
538
0
     function );
539
540
0
    return( -1 );
541
0
  }
542
0
  if( libuna_utf16_string_copy_from_utf16_stream(
543
0
       (libuna_utf16_character_t *) utf16_string,
544
0
       utf16_string_size,
545
0
       file_header->executable_filename,
546
0
       file_header->executable_filename_size,
547
0
       LIBUNA_ENDIAN_LITTLE | LIBUNA_UTF16_STREAM_ALLOW_UNPAIRED_SURROGATE,
548
0
       error ) != 1 )
549
0
  {
550
0
    libcerror_error_set(
551
0
     error,
552
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
553
0
     LIBCERROR_RUNTIME_ERROR_SET_FAILED,
554
0
     "%s: unable to set UTF-16 executable filename string.",
555
0
     function );
556
557
0
    return( -1 );
558
0
  }
559
0
  return( 1 );
560
0
}
561