Coverage Report

Created: 2024-02-25 07:19

/src/libnk2/libnk2/libnk2_item.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Item functions
3
 *
4
 * Copyright (C) 2009-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 "libnk2_debug.h"
27
#include "libnk2_definitions.h"
28
#include "libnk2_io_handle.h"
29
#include "libnk2_item.h"
30
#include "libnk2_libbfio.h"
31
#include "libnk2_libcdata.h"
32
#include "libnk2_libcerror.h"
33
#include "libnk2_libcnotify.h"
34
#include "libnk2_record_entry.h"
35
#include "libnk2_unused.h"
36
37
#include "nk2_item.h"
38
39
/* Creates an item
40
 * Make sure the value item is referencing, is set to NULL
41
 * Returns 1 if successful or -1 on error
42
 */
43
int libnk2_item_initialize(
44
     libnk2_item_t **item,
45
     libcerror_error_t **error )
46
1.96k
{
47
1.96k
  libnk2_internal_item_t *internal_item = NULL;
48
1.96k
  static char *function                 = "libnk2_item_initialize";
49
50
1.96k
  if( item == NULL )
51
0
  {
52
0
    libcerror_error_set(
53
0
     error,
54
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
55
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
56
0
     "%s: invalid item.",
57
0
     function );
58
59
0
    return( -1 );
60
0
  }
61
1.96k
  if( *item != NULL )
62
0
  {
63
0
    libcerror_error_set(
64
0
     error,
65
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
66
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
67
0
     "%s: invalid item value already set.",
68
0
     function );
69
70
0
    return( -1 );
71
0
  }
72
1.96k
  internal_item = memory_allocate_structure(
73
1.96k
                   libnk2_internal_item_t );
74
75
1.96k
  if( internal_item == NULL )
76
0
  {
77
0
    libcerror_error_set(
78
0
     error,
79
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
80
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
81
0
     "%s: unable to create item.",
82
0
     function );
83
84
0
    goto on_error;
85
0
  }
86
1.96k
  if( memory_set(
87
1.96k
       internal_item,
88
1.96k
       0,
89
1.96k
       sizeof( libnk2_internal_item_t ) ) == NULL )
90
0
  {
91
0
    libcerror_error_set(
92
0
     error,
93
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
94
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
95
0
     "%s: unable to clear item.",
96
0
     function );
97
98
0
    memory_free(
99
0
     internal_item );
100
101
0
    return( -1 );
102
0
  }
103
1.96k
  if( libcdata_array_initialize(
104
1.96k
       &( internal_item->entries_array ),
105
1.96k
       0,
106
1.96k
       error ) != 1 )
107
0
  {
108
0
    libcerror_error_set(
109
0
     error,
110
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
111
0
     LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
112
0
     "%s: unable to create entries array.",
113
0
     function );
114
115
0
    goto on_error;
116
0
  }
117
1.96k
  *item = (libnk2_item_t *) internal_item;
118
119
1.96k
  return( 1 );
120
121
0
on_error:
122
0
  if( internal_item != NULL )
123
0
  {
124
0
    memory_free(
125
0
     internal_item );
126
0
  }
127
0
  return( -1 );
128
1.96k
}
129
130
/* Frees an item
131
 * Returns 1 if successful or -1 on error
132
 */
133
int libnk2_item_free(
134
     libnk2_item_t **item,
135
     libcerror_error_t **error )
136
0
{
137
0
  static char *function = "libnk2_item_free";
138
139
0
  if( item == NULL )
140
0
  {
141
0
    libcerror_error_set(
142
0
     error,
143
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
144
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
145
0
     "%s: invalid item.",
146
0
     function );
147
148
0
    return( -1 );
149
0
  }
150
0
  if( *item != NULL )
151
0
  {
152
0
    *item = NULL;
153
0
  }
154
0
  return( 1 );
155
0
}
156
157
/* Frees an item
158
 * Returns 1 if successful or -1 on error
159
 */
160
int libnk2_internal_item_free(
161
     libnk2_internal_item_t **internal_item,
162
     libcerror_error_t **error )
163
1.96k
{
164
1.96k
  static char *function = "libnk2_internal_item_free";
165
1.96k
  int result            = 1;
166
167
1.96k
  if( internal_item == 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 item.",
174
0
     function );
175
176
0
    return( -1 );
177
0
  }
178
1.96k
  if( *internal_item != NULL )
179
1.96k
  {
180
1.96k
    if( libcdata_array_free(
181
1.96k
         &( ( *internal_item )->entries_array ),
182
1.96k
         (int (*)(intptr_t **, libcerror_error_t **)) &libnk2_internal_record_entry_free,
183
1.96k
         error ) != 1 )
184
0
    {
185
0
      libcerror_error_set(
186
0
       error,
187
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
188
0
       LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
189
0
       "%s: unable to free entries array.",
190
0
       function );
191
192
0
      result = -1;
193
0
    }
194
1.96k
    memory_free(
195
1.96k
     *internal_item );
196
197
1.96k
    *internal_item = NULL;
198
1.96k
  }
199
1.96k
  return( result );
200
1.96k
}
201
202
/* Reads the record entries
203
 * Returns 1 if successful or -1 on error
204
 */
205
int libnk2_item_read_record_entries(
206
     libnk2_internal_item_t *internal_item,
207
     libnk2_io_handle_t *io_handle,
208
     libbfio_handle_t *file_io_handle,
209
     uint32_t item_index LIBNK2_ATTRIBUTE_UNUSED,
210
     uint32_t number_of_record_entries,
211
     libcerror_error_t **error )
212
1.96k
{
213
1.96k
  libnk2_record_entry_t *record_entry = NULL;
214
1.96k
  static char *function               = "libnk2_item_read_record_entries";
215
1.96k
  uint32_t record_entry_index         = 0;
216
1.96k
  int entry_index                     = 0;
217
218
1.96k
  LIBNK2_UNREFERENCED_PARAMETER( item_index )
219
220
1.96k
  if( internal_item == NULL )
221
0
  {
222
0
    libcerror_error_set(
223
0
     error,
224
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
225
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
226
0
     "%s: invalid item.",
227
0
     function );
228
229
0
    return( -1 );
230
0
  }
231
1.96k
  if( io_handle == NULL )
232
0
  {
233
0
    libcerror_error_set(
234
0
     error,
235
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
236
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
237
0
     "%s: invalid IO handle.",
238
0
     function );
239
240
0
    return( -1 );
241
0
  }
242
1.96k
  for( record_entry_index = 0;
243
686k
       record_entry_index < number_of_record_entries;
244
684k
       record_entry_index++ )
245
684k
  {
246
#if defined( HAVE_DEBUG_OUTPUT )
247
    if( libcnotify_verbose != 0 )
248
    {
249
      libcnotify_printf(
250
       "%s: reading item: %03" PRIu32 " value: %03" PRIu32 "\n",
251
       function,
252
       item_index,
253
       record_entry_index );
254
    }
255
#endif
256
684k
    if( libnk2_record_entry_initialize(
257
684k
         &record_entry,
258
684k
         io_handle->ascii_codepage,
259
684k
         error ) != 1 )
260
0
    {
261
0
      libcerror_error_set(
262
0
       error,
263
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
264
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
265
0
       "%s: unable to create record entry.",
266
0
       function );
267
268
0
      goto on_error;
269
0
    }
270
684k
    if( libnk2_record_entry_read_file_io_handle(
271
684k
         record_entry,
272
684k
         file_io_handle,
273
684k
         error ) != 1 )
274
434
    {
275
434
      libcerror_error_set(
276
434
       error,
277
434
       LIBCERROR_ERROR_DOMAIN_IO,
278
434
       LIBCERROR_IO_ERROR_READ_FAILED,
279
434
       "%s: unable to read record entry.",
280
434
       function );
281
282
434
      goto on_error;
283
434
    }
284
/* TODO refactor */
285
#if defined( HAVE_DEBUG_OUTPUT )
286
    if( libcnotify_verbose != 0 )
287
    {
288
      libcnotify_printf(
289
       "%s: item: %03" PRIu32 " value: %03" PRIu32 " value data:\n",
290
       function,
291
       item_index,
292
       record_entry_index );
293
294
      if( libnk2_debug_print_mapi_value(
295
           ( (libnk2_internal_record_entry_t *) record_entry )->entry_type,
296
           ( (libnk2_internal_record_entry_t *) record_entry )->value_type,
297
           ( (libnk2_internal_record_entry_t *) record_entry )->value_data,
298
           ( (libnk2_internal_record_entry_t *) record_entry )->value_data_size,
299
           io_handle->ascii_codepage,
300
           error ) != 1 )
301
      {
302
        libcerror_error_set(
303
         error,
304
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
305
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
306
         "%s: unable to print MAPI value.",
307
         function );
308
309
        goto on_error;
310
      }
311
    }
312
#endif
313
684k
    if( libcdata_array_append_entry(
314
684k
         internal_item->entries_array,
315
684k
         &entry_index,
316
684k
         (intptr_t *) record_entry,
317
684k
         error ) != 1 )
318
0
    {
319
0
      libcerror_error_set(
320
0
       error,
321
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
322
0
       LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
323
0
       "%s: unable to append record entry to array.",
324
0
       function );
325
326
0
      goto on_error;
327
0
    }
328
684k
    record_entry = NULL;
329
330
684k
    if( io_handle->abort != 0 )
331
0
    {
332
0
      libcerror_error_set(
333
0
       error,
334
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
335
0
       LIBCERROR_RUNTIME_ERROR_ABORT_REQUESTED,
336
0
       "%s: abort requested.",
337
0
       function );
338
339
0
      goto on_error;
340
0
    }
341
684k
  }
342
1.52k
  return( 1 );
343
344
434
on_error:
345
434
  if( record_entry != NULL )
346
434
  {
347
434
    libnk2_internal_record_entry_free(
348
434
     (libnk2_internal_record_entry_t **) &record_entry,
349
434
     NULL );
350
434
  }
351
434
  libcdata_array_empty(
352
434
   internal_item->entries_array,
353
434
   (int (*)(intptr_t **, libcerror_error_t **)) &libnk2_internal_record_entry_free,
354
434
   NULL );
355
356
434
  return( -1 );
357
1.96k
}
358
359
/* Retrieves the number of entries
360
 * All sets in an item contain the same number of entries
361
 * Returns 1 if successful or -1 on error
362
 */
363
int libnk2_item_get_number_of_entries(
364
     libnk2_item_t *item,
365
     int *number_of_entries,
366
     libcerror_error_t **error )
367
0
{
368
0
  libnk2_internal_item_t *internal_item = NULL;
369
0
  static char *function                 = "libnk2_item_get_number_of_entries";
370
371
0
  if( item == NULL )
372
0
  {
373
0
    libcerror_error_set(
374
0
     error,
375
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
376
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
377
0
     "%s: invalid item.",
378
0
     function );
379
380
0
    return( -1 );
381
0
  }
382
0
  internal_item = (libnk2_internal_item_t *) item;
383
384
0
  if( libcdata_array_get_number_of_entries(
385
0
       internal_item->entries_array,
386
0
       number_of_entries,
387
0
       error ) != 1 )
388
0
  {
389
0
    libcerror_error_set(
390
0
     error,
391
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
392
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
393
0
     "%s: unable to retrieve number of entries.",
394
0
     function );
395
396
0
    return( -1 );
397
0
  }
398
0
  return( 1 );
399
0
}
400
401
/* Retrieves a specific entry from the item
402
 * Returns 1 if successful or -1 on error
403
 */
404
int libnk2_item_get_entry_by_index(
405
     libnk2_item_t *item,
406
     int entry_index,
407
     libnk2_record_entry_t **record_entry,
408
     libcerror_error_t **error )
409
0
{
410
0
  libnk2_internal_item_t *internal_item = NULL;
411
0
  static char *function                 = "libnk2_item_get_entry_by_index";
412
413
0
  if( item == NULL )
414
0
  {
415
0
    libcerror_error_set(
416
0
     error,
417
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
418
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
419
0
     "%s: invalid item.",
420
0
     function );
421
422
0
    return( -1 );
423
0
  }
424
0
  internal_item = (libnk2_internal_item_t *) item;
425
426
0
  if( record_entry == NULL )
427
0
  {
428
0
    libcerror_error_set(
429
0
     error,
430
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
431
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
432
0
     "%s: invalid record entry.",
433
0
     function );
434
435
0
    return( -1 );
436
0
  }
437
0
  if( *record_entry != NULL )
438
0
  {
439
0
    libcerror_error_set(
440
0
     error,
441
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
442
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
443
0
     "%s: invalid record entry value already set.",
444
0
     function );
445
446
0
    return( -1 );
447
0
  }
448
0
  if( libcdata_array_get_entry_by_index(
449
0
       internal_item->entries_array,
450
0
       entry_index,
451
0
       (intptr_t **) record_entry,
452
0
       error ) != 1 )
453
0
  {
454
0
    libcerror_error_set(
455
0
     error,
456
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
457
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
458
0
     "%s: unable to retrieve record entry: %d.",
459
0
     function,
460
0
     entry_index );
461
462
0
    return( -1 );
463
0
  }
464
0
  return( 1 );
465
0
}
466
467
/* Retrieves the record entry matching the entry and value type pair from the item
468
 *
469
 * When the LIBNK2_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE is set
470
 * the value type is ignored and set. The default behavior is a strict
471
 * matching of the value type. In this case the value type must be filled
472
 * with the corresponding value type
473
 *
474
 * Returns 1 if successful, 0 if no such value or -1 on error
475
 */
476
int libnk2_item_get_entry_by_type(
477
     libnk2_item_t *item,
478
     uint32_t entry_type,
479
     uint32_t value_type,
480
     libnk2_record_entry_t **record_entry,
481
     uint8_t flags,
482
     libcerror_error_t **error )
483
0
{
484
0
  libnk2_internal_item_t *internal_item                 = NULL;
485
0
  libnk2_internal_record_entry_t *internal_record_entry = NULL;
486
0
  static char *function                                 = "libnk2_item_get_entry_by_type";
487
0
  int entry_index                                       = 0;
488
0
  int number_of_entries                                 = 0;
489
0
  int result                                            = 0;
490
491
0
  if( item == NULL )
492
0
  {
493
0
    libcerror_error_set(
494
0
     error,
495
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
496
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
497
0
     "%s: invalid item.",
498
0
     function );
499
500
0
    return( -1 );
501
0
  }
502
0
  internal_item = (libnk2_internal_item_t *) item;
503
504
0
  if( record_entry == NULL )
505
0
  {
506
0
    libcerror_error_set(
507
0
     error,
508
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
509
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
510
0
     "%s: invalid record entry.",
511
0
     function );
512
513
0
    return( -1 );
514
0
  }
515
0
  if( *record_entry != NULL )
516
0
  {
517
0
    libcerror_error_set(
518
0
     error,
519
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
520
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
521
0
     "%s: invalid record entry value already set.",
522
0
     function );
523
524
0
    return( -1 );
525
0
  }
526
0
  if( ( flags & ~( LIBNK2_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE ) ) != 0 )
527
0
  {
528
0
    libcerror_error_set(
529
0
     error,
530
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
531
0
     LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
532
0
     "%s: unsupported flags: 0x%02" PRIx8 ".",
533
0
     function,
534
0
     flags );
535
536
0
    return( -1 );
537
0
  }
538
0
  if( libcdata_array_get_number_of_entries(
539
0
       internal_item->entries_array,
540
0
       &number_of_entries,
541
0
       error ) != 1 )
542
0
  {
543
0
    libcerror_error_set(
544
0
     error,
545
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
546
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
547
0
     "%s: unable to retrieve number of entries.",
548
0
     function );
549
550
0
    return( -1 );
551
0
  }
552
0
  for( entry_index = 0;
553
0
       entry_index < number_of_entries;
554
0
       entry_index++ )
555
0
  {
556
0
    if( libcdata_array_get_entry_by_index(
557
0
         internal_item->entries_array,
558
0
         entry_index,
559
0
         (intptr_t **) &internal_record_entry,
560
0
         error ) != 1 )
561
0
    {
562
0
      libcerror_error_set(
563
0
       error,
564
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
565
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
566
0
       "%s: unable to retrieve record entry: %d.",
567
0
       function,
568
0
       entry_index );
569
570
0
      return( -1 );
571
0
    }
572
0
    if( internal_record_entry == NULL )
573
0
    {
574
0
      libcerror_error_set(
575
0
       error,
576
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
577
0
       LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
578
0
       "%s: missing data record entry: %d.",
579
0
       function,
580
0
       entry_index );
581
582
0
      return( -1 );
583
0
    }
584
0
    result = 0;
585
586
0
    if( internal_record_entry->entry_type == entry_type )
587
0
    {
588
0
      result = 1;
589
0
    }
590
0
    if( result != 0 )
591
0
    {
592
0
      if( ( ( flags & LIBNK2_ENTRY_VALUE_FLAG_MATCH_ANY_VALUE_TYPE ) != 0 )
593
0
       || ( internal_record_entry->value_type == value_type ) )
594
0
      {
595
0
        *record_entry = (libnk2_record_entry_t *) internal_record_entry;
596
597
0
        return( 1 );
598
0
      }
599
0
    }
600
0
  }
601
0
  *record_entry = NULL;
602
603
0
  return( 0 );
604
0
}