Coverage Report

Created: 2026-10-22 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcreg/libcreg/libcreg_key_tree.c
Line
Count
Source
1
/*
2
 * Key tree functions
3
 *
4
 * Copyright (C) 2013-2026, 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 <types.h>
24
25
#if defined( HAVE_WCTYPE_H ) || defined( HAVE_WINAPI )
26
#include <wctype.h>
27
#endif
28
29
#include "libcreg_definitions.h"
30
#include "libcreg_key.h"
31
#include "libcreg_key_descriptor.h"
32
#include "libcreg_key_item.h"
33
#include "libcreg_key_navigation.h"
34
#include "libcreg_key_tree.h"
35
#include "libcreg_libcerror.h"
36
#include "libcreg_libcnotify.h"
37
#include "libcreg_libuna.h"
38
#include "libcreg_types.h"
39
40
/* Retrieves the key for the specific UTF-8 encoded path
41
 * The path separator is the \ character
42
 * Creates a new key
43
 * Returns 1 if successful, 0 if no such key or -1 on error
44
 */
45
int libcreg_key_tree_get_sub_key_by_utf8_path(
46
     libcreg_io_handle_t *io_handle,
47
     libbfio_handle_t *file_io_handle,
48
     libcreg_key_navigation_t *key_navigation,
49
     uint32_t key_offset,
50
     const uint8_t *utf8_string,
51
     size_t utf8_string_length,
52
     int ascii_codepage,
53
     libcreg_key_t **sub_key,
54
     libcerror_error_t **error )
55
0
{
56
0
  libcreg_key_descriptor_t *sub_key_descriptor = NULL;
57
0
  libcreg_key_item_t *sub_key_item             = NULL;
58
0
  uint8_t *utf8_string_segment                 = NULL;
59
0
  static char *function                        = "libcreg_key_tree_get_sub_key_by_utf8_path";
60
0
  libuna_unicode_character_t unicode_character = 0;
61
0
  size_t utf8_string_index                     = 0;
62
0
  size_t utf8_string_segment_length            = 0;
63
0
  uint32_t sub_key_offset                      = 0;
64
0
  int result                                   = 0;
65
66
#if defined( HAVE_DEBUG_OUTPUT )
67
  uint32_t name_hash                           = 0;
68
#endif
69
70
0
  if( utf8_string == NULL )
71
0
  {
72
0
    libcerror_error_set(
73
0
     error,
74
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
76
0
     "%s: invalid UTF-8 string.",
77
0
     function );
78
79
0
    return( -1 );
80
0
  }
81
0
  if( utf8_string_length > (size_t) SSIZE_MAX )
82
0
  {
83
0
    libcerror_error_set(
84
0
     error,
85
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
86
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
87
0
     "%s: invalid UTF-8 string length value exceeds maximum.",
88
0
     function );
89
90
0
    return( -1 );
91
0
  }
92
0
  if( sub_key == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
97
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
98
0
     "%s: invalid sub key.",
99
0
     function );
100
101
0
    return( -1 );
102
0
  }
103
0
  if( *sub_key != NULL )
104
0
  {
105
0
    libcerror_error_set(
106
0
     error,
107
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
108
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
109
0
     "%s: sub key already set.",
110
0
     function );
111
112
0
    return( -1 );
113
0
  }
114
0
  sub_key_offset = key_offset;
115
116
0
  if( utf8_string_length > 0 )
117
0
  {
118
    /* Ignore a leading separator
119
     */
120
0
    if( utf8_string[ utf8_string_index ] == (uint8_t) LIBCREG_SEPARATOR )
121
0
    {
122
0
      utf8_string_index++;
123
0
    }
124
0
  }
125
  /* If the string is empty return the current key
126
   */
127
0
  if( utf8_string_length == utf8_string_index )
128
0
  {
129
0
    result = 1;
130
0
  }
131
0
  else while( utf8_string_index < utf8_string_length )
132
0
  {
133
0
    utf8_string_segment        = (uint8_t *) &( utf8_string[ utf8_string_index ] );
134
0
    utf8_string_segment_length = utf8_string_index;
135
136
#if defined( HAVE_DEBUG_OUTPUT )
137
    name_hash = 0;
138
#endif
139
0
    while( utf8_string_index < utf8_string_length )
140
0
    {
141
0
      if( libuna_unicode_character_copy_from_utf8(
142
0
           &unicode_character,
143
0
           utf8_string,
144
0
           utf8_string_length,
145
0
           &utf8_string_index,
146
0
           error ) != 1 )
147
0
      {
148
0
        libcerror_error_set(
149
0
         error,
150
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
151
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
152
0
         "%s: unable to copy UTF-8 string to Unicode character.",
153
0
         function );
154
155
0
        goto on_error;
156
0
      }
157
0
      if( ( unicode_character == (libuna_unicode_character_t) LIBCREG_SEPARATOR )
158
0
       || ( unicode_character == 0 ) )
159
0
      {
160
0
        utf8_string_segment_length += 1;
161
162
0
        break;
163
0
      }
164
#if defined( HAVE_DEBUG_OUTPUT )
165
      name_hash *= 37;
166
      name_hash += (uint32_t) towupper( (wint_t) unicode_character );
167
#endif
168
0
    }
169
#if defined( HAVE_DEBUG_OUTPUT )
170
    if( libcnotify_verbose != 0 )
171
    {
172
      libcnotify_printf(
173
       "%s: name hash\t\t: 0x%08" PRIx32 "\n",
174
       function,
175
       name_hash );
176
    }
177
#endif
178
0
    utf8_string_segment_length = utf8_string_index - utf8_string_segment_length;
179
180
0
    if( utf8_string_segment_length == 0 )
181
0
    {
182
0
      result = 0;
183
0
    }
184
0
    else
185
0
    {
186
/* TODO: instead of key item directory read key descriptors ? */
187
0
      if( libcreg_key_item_initialize(
188
0
           &sub_key_item,
189
0
           error ) != 1 )
190
0
      {
191
0
        libcerror_error_set(
192
0
         error,
193
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
194
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
195
0
         "%s: unable to create sub key item.",
196
0
         function );
197
198
0
        goto on_error;
199
0
      }
200
0
      if( libcreg_key_item_read(
201
0
           sub_key_item,
202
0
           file_io_handle,
203
0
           key_navigation,
204
0
           sub_key_offset,
205
0
           error ) != 1 )
206
0
      {
207
0
        libcerror_error_set(
208
0
         error,
209
0
         LIBCERROR_ERROR_DOMAIN_IO,
210
0
         LIBCERROR_IO_ERROR_READ_FAILED,
211
0
         "%s: unable to read sub key item at offset: %" PRIu32 " (0x%08" PRIx32 ").",
212
0
         function,
213
0
         sub_key_offset,
214
0
         sub_key_offset );
215
216
0
        goto on_error;
217
0
      }
218
0
      result = libcreg_key_item_get_sub_key_descriptor_by_utf8_name(
219
0
                sub_key_item,
220
0
                file_io_handle,
221
0
                key_navigation,
222
0
          utf8_string_segment,
223
0
          utf8_string_segment_length,
224
0
          ascii_codepage,
225
0
                &sub_key_descriptor,
226
0
                error );
227
228
0
      if( result == 1 )
229
0
      {
230
0
        sub_key_offset = sub_key_descriptor->key_offset;
231
0
      }
232
0
      if( libcreg_key_item_free(
233
0
           &sub_key_item,
234
0
           error ) != 1 )
235
0
      {
236
0
        libcerror_error_set(
237
0
         error,
238
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
239
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
240
0
         "%s: unable to free sub key item.",
241
0
         function );
242
243
0
        goto on_error;
244
0
      }
245
0
    }
246
0
    if( result == -1 )
247
0
    {
248
0
      libcerror_error_set(
249
0
       error,
250
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
251
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
252
0
       "%s: unable to retrieve sub key values by name.",
253
0
       function );
254
255
0
      goto on_error;
256
0
    }
257
0
    else if( result == 0 )
258
0
    {
259
0
      break;
260
0
    }
261
0
  }
262
0
  if( result != 0 )
263
0
  {
264
0
    if( libcreg_key_initialize(
265
0
         sub_key,
266
0
         io_handle,
267
0
         file_io_handle,
268
0
         key_navigation,
269
0
         sub_key_offset,
270
0
         error ) != 1 )
271
0
    {
272
0
      libcerror_error_set(
273
0
       error,
274
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
275
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
276
0
       "%s: unable to create sub key.",
277
0
       function );
278
279
0
      goto on_error;
280
0
    }
281
0
  }
282
0
  return( result );
283
284
0
on_error:
285
0
  if( sub_key_item != NULL )
286
0
  {
287
0
    libcreg_key_item_free(
288
0
     &sub_key_item,
289
0
     NULL );
290
0
  }
291
0
  return( -1 );
292
0
}
293
294
/* Retrieves the key for the specific UTF-16 encoded path
295
 * The path separator is the \ character
296
 * Creates a new key
297
 * Returns 1 if successful, 0 if no such key or -1 on error
298
 */
299
int libcreg_key_tree_get_sub_key_by_utf16_path(
300
     libcreg_io_handle_t *io_handle,
301
     libbfio_handle_t *file_io_handle,
302
     libcreg_key_navigation_t *key_navigation,
303
     uint32_t key_offset,
304
     const uint16_t *utf16_string,
305
     size_t utf16_string_length,
306
     int ascii_codepage,
307
     libcreg_key_t **sub_key,
308
     libcerror_error_t **error )
309
0
{
310
0
  libcreg_key_descriptor_t *sub_key_descriptor = NULL;
311
0
  libcreg_key_item_t *sub_key_item             = NULL;
312
0
  uint16_t *utf16_string_segment               = NULL;
313
0
  static char *function                        = "libcreg_key_tree_get_sub_key_by_utf16_path";
314
0
  libuna_unicode_character_t unicode_character = 0;
315
0
  size_t utf16_string_index                    = 0;
316
0
  size_t utf16_string_segment_length           = 0;
317
0
  uint32_t sub_key_offset                      = 0;
318
0
  int result                                   = 0;
319
320
#if defined( HAVE_DEBUG_OUTPUT )
321
  uint32_t name_hash                           = 0;
322
#endif
323
324
0
  if( utf16_string == NULL )
325
0
  {
326
0
    libcerror_error_set(
327
0
     error,
328
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
329
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
330
0
     "%s: invalid UTF-16 string.",
331
0
     function );
332
333
0
    return( -1 );
334
0
  }
335
0
  if( utf16_string_length > (size_t) SSIZE_MAX )
336
0
  {
337
0
    libcerror_error_set(
338
0
     error,
339
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
340
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
341
0
     "%s: invalid UTF-16 string length value exceeds maximum.",
342
0
     function );
343
344
0
    return( -1 );
345
0
  }
346
0
  if( sub_key == NULL )
347
0
  {
348
0
    libcerror_error_set(
349
0
     error,
350
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
351
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
352
0
     "%s: invalid sub key.",
353
0
     function );
354
355
0
    return( -1 );
356
0
  }
357
0
  if( *sub_key != NULL )
358
0
  {
359
0
    libcerror_error_set(
360
0
     error,
361
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
362
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
363
0
     "%s: sub key already set.",
364
0
     function );
365
366
0
    return( -1 );
367
0
  }
368
0
  sub_key_offset = key_offset;
369
370
0
  if( utf16_string_length > 0 )
371
0
  {
372
    /* Ignore a leading separator
373
     */
374
0
    if( utf16_string[ utf16_string_index ] == (uint16_t) LIBCREG_SEPARATOR )
375
0
    {
376
0
      utf16_string_index++;
377
0
    }
378
0
  }
379
  /* If the string is empty return the current key
380
   */
381
0
  if( utf16_string_length == utf16_string_index )
382
0
  {
383
0
    result = 1;
384
0
  }
385
0
  else while( utf16_string_index < utf16_string_length )
386
0
  {
387
0
    utf16_string_segment        = (uint16_t *) &( utf16_string[ utf16_string_index ] );
388
0
    utf16_string_segment_length = utf16_string_index;
389
390
#if defined( HAVE_DEBUG_OUTPUT )
391
    name_hash = 0;
392
#endif
393
0
    while( utf16_string_index < utf16_string_length )
394
0
    {
395
0
      if( libuna_unicode_character_copy_from_utf16(
396
0
           &unicode_character,
397
0
           utf16_string,
398
0
           utf16_string_length,
399
0
           &utf16_string_index,
400
0
           error ) != 1 )
401
0
      {
402
0
        libcerror_error_set(
403
0
         error,
404
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
405
0
         LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
406
0
         "%s: unable to copy UTF-16 string to Unicode character.",
407
0
         function );
408
409
0
        goto on_error;
410
0
      }
411
0
      if( ( unicode_character == (libuna_unicode_character_t) LIBCREG_SEPARATOR )
412
0
       || ( unicode_character == 0 ) )
413
0
      {
414
0
        utf16_string_segment_length += 1;
415
416
0
        break;
417
0
      }
418
#if defined( HAVE_DEBUG_OUTPUT )
419
      name_hash *= 37;
420
      name_hash += (uint32_t) towupper( (wint_t) unicode_character );
421
#endif
422
0
    }
423
#if defined( HAVE_DEBUG_OUTPUT )
424
    if( libcnotify_verbose != 0 )
425
    {
426
      libcnotify_printf(
427
       "%s: name hash\t\t: 0x%08" PRIx32 "\n",
428
       function,
429
       name_hash );
430
    }
431
#endif
432
0
    utf16_string_segment_length = utf16_string_index - utf16_string_segment_length;
433
434
0
    if( utf16_string_segment_length == 0 )
435
0
    {
436
0
      result = 0;
437
0
    }
438
0
    else
439
0
    {
440
/* TODO: instead of key item directory read key descriptors ? */
441
0
      if( libcreg_key_item_initialize(
442
0
           &sub_key_item,
443
0
           error ) != 1 )
444
0
      {
445
0
        libcerror_error_set(
446
0
         error,
447
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
448
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
449
0
         "%s: unable to create sub key item.",
450
0
         function );
451
452
0
        goto on_error;
453
0
      }
454
0
      if( libcreg_key_item_read(
455
0
           sub_key_item,
456
0
           file_io_handle,
457
0
           key_navigation,
458
0
           sub_key_offset,
459
0
           error ) != 1 )
460
0
      {
461
0
        libcerror_error_set(
462
0
         error,
463
0
         LIBCERROR_ERROR_DOMAIN_IO,
464
0
         LIBCERROR_IO_ERROR_READ_FAILED,
465
0
         "%s: unable to read sub key item at offset: %" PRIu32 " (0x%08" PRIx32 ").",
466
0
         function,
467
0
         sub_key_offset,
468
0
         sub_key_offset );
469
470
0
        goto on_error;
471
0
      }
472
0
      result = libcreg_key_item_get_sub_key_descriptor_by_utf16_name(
473
0
                sub_key_item,
474
0
                file_io_handle,
475
0
                key_navigation,
476
0
          utf16_string_segment,
477
0
          utf16_string_segment_length,
478
0
          ascii_codepage,
479
0
                &sub_key_descriptor,
480
0
                error );
481
482
0
      if( result == 1 )
483
0
      {
484
0
        sub_key_offset = sub_key_descriptor->key_offset;
485
0
      }
486
0
      if( libcreg_key_item_free(
487
0
           &sub_key_item,
488
0
           error ) != 1 )
489
0
      {
490
0
        libcerror_error_set(
491
0
         error,
492
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
493
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
494
0
         "%s: unable to free sub key item.",
495
0
         function );
496
497
0
        goto on_error;
498
0
      }
499
0
    }
500
0
    if( result == -1 )
501
0
    {
502
0
      libcerror_error_set(
503
0
       error,
504
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
505
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
506
0
       "%s: unable to retrieve sub key values by name.",
507
0
       function );
508
509
0
      goto on_error;
510
0
    }
511
0
    else if( result == 0 )
512
0
    {
513
0
      break;
514
0
    }
515
0
  }
516
0
  if( result != 0 )
517
0
  {
518
0
    if( libcreg_key_initialize(
519
0
         sub_key,
520
0
         io_handle,
521
0
         file_io_handle,
522
0
         key_navigation,
523
0
         sub_key_offset,
524
0
         error ) != 1 )
525
0
    {
526
0
      libcerror_error_set(
527
0
       error,
528
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
529
0
       LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
530
0
       "%s: unable to create sub key.",
531
0
       function );
532
533
0
      goto on_error;
534
0
    }
535
0
  }
536
0
  return( result );
537
538
0
on_error:
539
0
  if( sub_key_item != NULL )
540
0
  {
541
0
    libcreg_key_item_free(
542
0
     &sub_key_item,
543
     NULL );
544
0
  }
545
0
  return( -1 );
546
0
}
547