Coverage Report

Created: 2026-05-24 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmsiecf/libmsiecf/libmsiecf_url_values.c
Line
Count
Source
1
/*
2
 * URL values functions
3
 *
4
 * Copyright (C) 2009-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 <byte_stream.h>
24
#include <memory.h>
25
#include <system_string.h>
26
#include <types.h>
27
28
#include "libmsiecf_debug.h"
29
#include "libmsiecf_definitions.h"
30
#include "libmsiecf_hash.h"
31
#include "libmsiecf_io_handle.h"
32
#include "libmsiecf_libbfio.h"
33
#include "libmsiecf_libcerror.h"
34
#include "libmsiecf_libcnotify.h"
35
#include "libmsiecf_libfdatetime.h"
36
#include "libmsiecf_libfole.h"
37
#include "libmsiecf_libfvalue.h"
38
#include "libmsiecf_property_type.h"
39
#include "libmsiecf_url_values.h"
40
41
#include "msiecf_url_record.h"
42
43
/* Creates URL values
44
 * Make sure the value url_values is referencing, is set to NULL
45
 * Returns 1 if successful or -1 on error
46
 */
47
int libmsiecf_url_values_initialize(
48
     libmsiecf_url_values_t **url_values,
49
     libcerror_error_t **error )
50
667
{
51
667
  static char *function = "libmsiecf_url_values_initialize";
52
53
667
  if( url_values == NULL )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
59
0
     "%s: invalid url values.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
667
  if( *url_values != NULL )
65
0
  {
66
0
    libcerror_error_set(
67
0
     error,
68
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
69
0
     LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
70
0
     "%s: invalid url values value already set.",
71
0
     function );
72
73
0
    return( -1 );
74
0
  }
75
667
  *url_values = memory_allocate_structure(
76
667
                 libmsiecf_url_values_t );
77
78
667
  if( *url_values == NULL )
79
0
  {
80
0
    libcerror_error_set(
81
0
     error,
82
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
83
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
84
0
     "%s: unable to create URL values.",
85
0
     function );
86
87
0
    goto on_error;
88
0
  }
89
667
  if( memory_set(
90
667
       *url_values,
91
667
       0,
92
667
       sizeof( libmsiecf_url_values_t ) ) == NULL )
93
0
  {
94
0
    libcerror_error_set(
95
0
     error,
96
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
97
0
     LIBCERROR_MEMORY_ERROR_SET_FAILED,
98
0
     "%s: unable to clear URL values.",
99
0
     function );
100
101
0
    goto on_error;
102
0
  }
103
667
  return( 1 );
104
105
0
on_error:
106
0
  if( *url_values != NULL )
107
0
  {
108
0
    memory_free(
109
0
     *url_values );
110
111
0
    *url_values = NULL;
112
0
  }
113
0
  return( -1 );
114
667
}
115
116
/* Frees URL values
117
 * Returns 1 if successful or -1 on error
118
 */
119
int libmsiecf_url_values_free(
120
     libmsiecf_url_values_t **url_values,
121
     libcerror_error_t **error )
122
667
{
123
667
  static char *function = "libmsiecf_url_values_free";
124
667
  int result            = 1;
125
126
667
  if( url_values == NULL )
127
0
  {
128
0
    libcerror_error_set(
129
0
     error,
130
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
131
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
132
0
     "%s: invalid URL values.",
133
0
     function );
134
135
0
    return( -1 );
136
0
  }
137
667
  if( *url_values != NULL )
138
667
  {
139
667
    if( ( *url_values )->location != NULL )
140
525
    {
141
525
      if( libfvalue_value_free(
142
525
           &( ( *url_values )->location ),
143
525
           error ) != 1 )
144
0
      {
145
0
        libcerror_error_set(
146
0
         error,
147
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
148
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
149
0
         "%s: unable to free location value.",
150
0
         function );
151
152
0
        result = -1;
153
0
      }
154
525
    }
155
667
    if( ( *url_values )->filename != NULL )
156
202
    {
157
202
      if( libfvalue_value_free(
158
202
           &( ( *url_values )->filename ),
159
202
           error ) != 1 )
160
0
      {
161
0
        libcerror_error_set(
162
0
         error,
163
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
164
0
         LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
165
0
         "%s: unable to free filename value.",
166
0
         function );
167
168
0
        result = -1;
169
0
      }
170
202
    }
171
667
    if( ( *url_values )->data != NULL )
172
37
    {
173
37
      memory_free(
174
37
       ( *url_values )->data );
175
37
    }
176
667
    memory_free(
177
667
     *url_values );
178
179
667
    *url_values = NULL;
180
667
  }
181
667
  return( result );
182
667
}
183
184
/* Reads the URL values from an URL record
185
 * Returns 1 if successful or -1 on error
186
 */
187
int libmsiecf_url_values_read_data(
188
     libmsiecf_url_values_t *url_values,
189
     libmsiecf_io_handle_t *io_handle,
190
     const uint8_t *data,
191
     size_t data_size,
192
     uint8_t item_flags,
193
     libcerror_error_t **error )
194
634
{
195
634
  static char *function             = "libmsiecf_url_values_read_data";
196
634
  size_t required_data_size         = 0;
197
634
  ssize_t value_size                = 0;
198
634
  uint32_t cache_entry_flags        = 0;
199
634
  uint32_t filename_offset          = 0;
200
634
  uint32_t location_offset          = 0;
201
634
  uint32_t unknown_offset           = 0;
202
634
  uint32_t url_data_offset          = 0;
203
634
  uint32_t url_data_size            = 0;
204
634
  uint16_t first_year               = 0;
205
634
  uint16_t second_year              = 0;
206
634
  uint8_t first_day_of_month        = 0;
207
634
  uint8_t first_month               = 0;
208
634
  uint8_t number_of_days            = 0;
209
634
  uint8_t second_day_of_month       = 0;
210
634
  uint8_t second_month              = 0;
211
212
#if defined( HAVE_DEBUG_OUTPUT )
213
  const uint8_t *visited_entry_data = NULL;
214
  size_t string_index               = 0;
215
  uint32_t value_32bit              = 0;
216
  uint16_t value_16bit              = 0;
217
  int visited_entry_index           = 0;
218
#endif
219
220
634
  if( url_values == 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 URL values.",
227
0
     function );
228
229
0
    return( -1 );
230
0
  }
231
634
  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
634
  if( ( io_handle->major_version == 4 )
243
3
   && ( io_handle->minor_version == 7 ) )
244
3
  {
245
3
    required_data_size = sizeof( msiecf_url_record_header_v47_t );
246
3
  }
247
631
  else if( ( io_handle->major_version == 5 )
248
631
        && ( io_handle->minor_version == 2 ) )
249
631
  {
250
631
    required_data_size = sizeof( msiecf_url_record_header_v52_t );
251
631
  }
252
0
  else
253
0
  {
254
0
    libcerror_error_set(
255
0
     error,
256
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
257
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
258
0
     "%s: unsupported format version: %d.%d.",
259
0
     function,
260
0
     io_handle->major_version,
261
0
     io_handle->minor_version );
262
263
0
    goto on_error;
264
0
  }
265
634
  if( data == NULL )
266
0
  {
267
0
    libcerror_error_set(
268
0
     error,
269
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
270
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
271
0
     "%s: invalid data.",
272
0
     function );
273
274
0
    return( -1 );
275
0
  }
276
634
  if( data_size < required_data_size )
277
0
  {
278
0
    libcerror_error_set(
279
0
     error,
280
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
281
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
282
0
     "%s: invalid data size value too small.",
283
0
     function );
284
285
0
    return( -1 );
286
0
  }
287
634
  if( data_size > (size_t) SSIZE_MAX )
288
0
  {
289
0
    libcerror_error_set(
290
0
     error,
291
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
292
0
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
293
0
     "%s: invalid data size value exceeds maximum.",
294
0
     function );
295
296
0
    return( -1 );
297
0
  }
298
#if defined( HAVE_DEBUG_OUTPUT )
299
  if( libcnotify_verbose != 0 )
300
  {
301
    libcnotify_printf(
302
     "%s: URL record data:\n",
303
     function );
304
    libcnotify_print_data(
305
     data,
306
     data_size,
307
     0 );
308
  }
309
#endif
310
634
  if( memory_compare(
311
634
       data,
312
634
       "URL ",
313
634
       4 ) != 0 )
314
0
  {
315
0
    libcerror_error_set(
316
0
     error,
317
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
318
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
319
0
     "%s: unsupported signature.",
320
0
     function );
321
322
0
    goto on_error;
323
0
  }
324
634
  if( ( io_handle->major_version == 4 )
325
3
   && ( io_handle->minor_version == 7 ) )
326
3
  {
327
3
    byte_stream_copy_to_uint64_little_endian(
328
3
     ( (msiecf_url_record_header_v47_t *) data )->secondary_filetime,
329
3
     url_values->secondary_time );
330
331
3
    byte_stream_copy_to_uint64_little_endian(
332
3
     ( (msiecf_url_record_header_v47_t *) data )->primary_filetime,
333
3
     url_values->primary_time );
334
335
3
    byte_stream_copy_to_uint64_little_endian(
336
3
     ( (msiecf_url_record_header_v47_t *) data )->expiration_time,
337
3
     url_values->expiration_time );
338
339
3
    byte_stream_copy_to_uint32_little_endian(
340
3
     ( (msiecf_url_record_header_v47_t *) data )->cached_file_size,
341
3
     url_values->cached_file_size );
342
343
3
    byte_stream_copy_to_uint32_little_endian(
344
3
     ( (msiecf_url_record_header_v47_t *) data )->unknown_offset,
345
3
     unknown_offset );
346
347
3
    byte_stream_copy_to_uint32_little_endian(
348
3
     ( (msiecf_url_record_header_v47_t *) data )->location_offset,
349
3
     location_offset );
350
351
3
    url_values->cache_directory_index = ( (msiecf_url_record_header_v47_t *) data )->cache_directory_index;
352
353
3
    byte_stream_copy_to_uint32_little_endian(
354
3
     ( (msiecf_url_record_header_v47_t *) data )->filename_offset,
355
3
     filename_offset );
356
357
3
    byte_stream_copy_to_uint32_little_endian(
358
3
     ( (msiecf_url_record_header_v47_t *) data )->data_offset,
359
3
     url_data_offset );
360
361
3
    byte_stream_copy_to_uint32_little_endian(
362
3
     ( (msiecf_url_record_header_v47_t *) data )->data_size,
363
3
     url_data_size );
364
365
3
    byte_stream_copy_to_uint32_little_endian(
366
3
     ( (msiecf_url_record_header_v47_t *) data )->last_checked_time,
367
3
     url_values->last_checked_time );
368
369
3
    byte_stream_copy_to_uint32_little_endian(
370
3
     ( (msiecf_url_record_header_v47_t *) data )->number_of_hits,
371
3
     url_values->number_of_hits );
372
373
3
    byte_stream_copy_to_uint32_little_endian(
374
3
     ( (msiecf_url_record_header_v47_t *) data )->cache_entry_flags,
375
3
     cache_entry_flags );
376
3
  }
377
631
  else if( ( io_handle->major_version == 5 )
378
631
        && ( io_handle->minor_version == 2 ) )
379
631
  {
380
631
    byte_stream_copy_to_uint64_little_endian(
381
631
     ( (msiecf_url_record_header_v52_t *) data )->secondary_filetime,
382
631
     url_values->secondary_time );
383
384
631
    byte_stream_copy_to_uint64_little_endian(
385
631
     ( (msiecf_url_record_header_v52_t *) data )->primary_filetime,
386
631
     url_values->primary_time );
387
388
631
    byte_stream_copy_to_uint32_little_endian(
389
631
     ( (msiecf_url_record_header_v52_t *) data )->expiration_time,
390
631
     url_values->expiration_time );
391
392
631
    byte_stream_copy_to_uint32_little_endian(
393
631
     ( (msiecf_url_record_header_v52_t *) data )->cached_file_size,
394
631
     url_values->cached_file_size );
395
396
631
    byte_stream_copy_to_uint32_little_endian(
397
631
     ( (msiecf_url_record_header_v52_t *) data )->unknown_offset,
398
631
     unknown_offset );
399
400
631
    byte_stream_copy_to_uint32_little_endian(
401
631
     ( (msiecf_url_record_header_v52_t *) data )->location_offset,
402
631
     location_offset );
403
404
631
    url_values->cache_directory_index = ( (msiecf_url_record_header_v52_t *) data )->cache_directory_index;
405
406
631
    byte_stream_copy_to_uint32_little_endian(
407
631
     ( (msiecf_url_record_header_v52_t *) data )->filename_offset,
408
631
     filename_offset );
409
410
631
    byte_stream_copy_to_uint32_little_endian(
411
631
     ( (msiecf_url_record_header_v52_t *) data )->data_offset,
412
631
     url_data_offset );
413
414
631
    byte_stream_copy_to_uint32_little_endian(
415
631
     ( (msiecf_url_record_header_v52_t *) data )->data_size,
416
631
     url_data_size );
417
418
631
    byte_stream_copy_to_uint32_little_endian(
419
631
     ( (msiecf_url_record_header_v52_t *) data )->last_checked_time,
420
631
     url_values->last_checked_time );
421
422
631
    byte_stream_copy_to_uint32_little_endian(
423
631
     ( (msiecf_url_record_header_v52_t *) data )->number_of_hits,
424
631
     url_values->number_of_hits );
425
426
631
    byte_stream_copy_to_uint32_little_endian(
427
631
     ( (msiecf_url_record_header_v52_t *) data )->cache_entry_flags,
428
631
     cache_entry_flags );
429
631
  }
430
#if defined( HAVE_DEBUG_OUTPUT )
431
  if( libcnotify_verbose != 0 )
432
  {
433
    libcnotify_printf(
434
     "%s: signature\t\t\t\t: %c%c%c%c\n",
435
     function,
436
     data[ 0 ],
437
     data[ 1 ],
438
     data[ 2 ],
439
     data[ 3 ] );
440
441
    byte_stream_copy_to_uint32_little_endian(
442
     ( (msiecf_url_record_header_v47_t *) data )->number_of_blocks,
443
     value_32bit );
444
    libcnotify_printf(
445
     "%s: number of blocks\t\t\t: %" PRIu32 "\n",
446
     function,
447
     value_32bit );
448
449
    if( libmsiecf_debug_print_filetime_value(
450
         function,
451
         "secondary time\t\t\t\t",
452
         ( (msiecf_url_record_header_v47_t *) data )->secondary_filetime,
453
         8,
454
         LIBFDATETIME_ENDIAN_LITTLE,
455
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
456
         error ) != 1 )
457
    {
458
      libcerror_error_set(
459
       error,
460
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
461
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
462
       "%s: unable to print FILETIME value.",
463
       function );
464
465
      goto on_error;
466
    }
467
    if( libmsiecf_debug_print_filetime_value(
468
         function,
469
         "primary time\t\t\t\t",
470
         ( (msiecf_url_record_header_v47_t *) data )->primary_filetime,
471
         8,
472
         LIBFDATETIME_ENDIAN_LITTLE,
473
         LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
474
         error ) != 1 )
475
    {
476
      libcerror_error_set(
477
       error,
478
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
479
       LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
480
       "%s: unable to print FILETIME value.",
481
       function );
482
483
      goto on_error;
484
    }
485
    if( ( io_handle->major_version == 4 )
486
     && ( io_handle->minor_version == 7 ) )
487
    {
488
      if( libmsiecf_debug_print_filetime_value(
489
           function,
490
           "expiration time\t\t\t\t",
491
           ( (msiecf_url_record_header_v47_t *) data )->expiration_time,
492
           8,
493
           LIBFDATETIME_ENDIAN_LITTLE,
494
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
495
           error ) != 1 )
496
      {
497
        libcerror_error_set(
498
         error,
499
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
500
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
501
         "%s: unable to print FILETIME value.",
502
         function );
503
504
        goto on_error;
505
      }
506
    }
507
    else if( ( io_handle->major_version == 5 )
508
          && ( io_handle->minor_version == 2 ) )
509
    {
510
      if( libmsiecf_debug_print_fat_date_time_value(
511
           function,
512
           "expiration time\t\t\t\t",
513
           ( (msiecf_url_record_header_v52_t *) data )->expiration_time,
514
           4,
515
           LIBFDATETIME_ENDIAN_LITTLE,
516
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
517
           error ) != 1 )
518
      {
519
        libcerror_error_set(
520
         error,
521
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
522
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
523
         "%s: unable to print FAT date time value.",
524
         function );
525
526
        goto on_error;
527
      }
528
    }
529
    if( ( io_handle->major_version == 5 )
530
     && ( io_handle->minor_version == 2 ) )
531
    {
532
      byte_stream_copy_to_uint32_little_endian(
533
       ( (msiecf_url_record_header_v52_t *) data )->unknown1,
534
       value_32bit );
535
536
      libcnotify_printf(
537
       "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
538
       function,
539
       value_32bit );
540
    }
541
    libcnotify_printf(
542
     "%s: cached file size\t\t\t: %" PRIu32 " bytes\n",
543
     function,
544
     url_values->cached_file_size );
545
546
    if( ( io_handle->major_version == 4 )
547
     && ( io_handle->minor_version == 7 ) )
548
    {
549
      byte_stream_copy_to_uint32_little_endian(
550
       ( (msiecf_url_record_header_v47_t *) data )->unknown1,
551
       value_32bit );
552
553
      libcnotify_printf(
554
       "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
555
       function,
556
       value_32bit );
557
    }
558
    if( ( io_handle->major_version == 4 )
559
     && ( io_handle->minor_version == 7 ) )
560
    {
561
      byte_stream_copy_to_uint32_little_endian(
562
       ( (msiecf_url_record_header_v47_t *) data )->unknown3,
563
       value_32bit );
564
    }
565
    else if( ( io_handle->major_version == 5 )
566
          && ( io_handle->minor_version == 2 ) )
567
    {
568
      byte_stream_copy_to_uint32_little_endian(
569
       ( (msiecf_url_record_header_v52_t *) data )->unknown3,
570
       value_32bit );
571
    }
572
    libcnotify_printf(
573
     "%s: unknown3\t\t\t\t: 0x%08" PRIx32 "\n",
574
     function,
575
     value_32bit );
576
577
    if( ( io_handle->major_version == 4 )
578
     && ( io_handle->minor_version == 7 ) )
579
    {
580
      byte_stream_copy_to_uint32_little_endian(
581
       ( (msiecf_url_record_header_v47_t *) data )->unknown4,
582
       value_32bit );
583
    }
584
    else if( ( io_handle->major_version == 5 )
585
          && ( io_handle->minor_version == 2 ) )
586
    {
587
      byte_stream_copy_to_uint32_little_endian(
588
       ( (msiecf_url_record_header_v52_t *) data )->unknown4,
589
       value_32bit );
590
    }
591
    libcnotify_printf(
592
     "%s: unknown4\t\t\t\t: 0x%08" PRIx32 "\n",
593
     function,
594
     value_32bit );
595
596
    if( ( io_handle->major_version == 4 )
597
     && ( io_handle->minor_version == 7 ) )
598
    {
599
      byte_stream_copy_to_uint32_little_endian(
600
       ( (msiecf_url_record_header_v47_t *) data )->non_releasable_time_delta,
601
       value_32bit );
602
    }
603
    else if( ( io_handle->major_version == 5 )
604
          && ( io_handle->minor_version == 2 ) )
605
    {
606
      byte_stream_copy_to_uint32_little_endian(
607
       ( (msiecf_url_record_header_v52_t *) data )->non_releasable_time_delta,
608
       value_32bit );
609
    }
610
    libcnotify_printf(
611
     "%s: non-releasable time delta\t\t: %" PRIu32 " seconds\n",
612
     function,
613
     value_32bit );
614
615
    libcnotify_printf(
616
     "%s: unknown offset\t\t\t\t: %" PRIu32 "\n",
617
     function,
618
     unknown_offset );
619
620
    libcnotify_printf(
621
     "%s: location offset\t\t\t\t: %" PRIu32 "\n",
622
     function,
623
     location_offset );
624
625
    libcnotify_printf(
626
     "%s: cache directory index\t\t\t: %" PRIu8 "\n",
627
     function,
628
     url_values->cache_directory_index );
629
630
    if( ( io_handle->major_version == 4 )
631
     && ( io_handle->minor_version == 7 ) )
632
    {
633
      libcnotify_printf(
634
       "%s: unknown6\t\t\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
635
       function,
636
       ( (msiecf_url_record_header_v47_t *) data )->unknown6[ 0 ],
637
       ( (msiecf_url_record_header_v47_t *) data )->unknown6[ 1 ],
638
       ( (msiecf_url_record_header_v47_t *) data )->unknown6[ 2 ] );
639
    }
640
    else if( ( io_handle->major_version == 5 )
641
          && ( io_handle->minor_version == 2 ) )
642
    {
643
      libcnotify_printf(
644
       "%s: unknown6\t\t\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
645
       function,
646
       ( (msiecf_url_record_header_v52_t *) data )->unknown6[ 0 ],
647
       ( (msiecf_url_record_header_v52_t *) data )->unknown6[ 1 ],
648
       ( (msiecf_url_record_header_v52_t *) data )->unknown6[ 2 ] );
649
    }
650
    libcnotify_printf(
651
     "%s: filename offset\t\t\t\t: %" PRIu32 "\n",
652
     function,
653
     filename_offset );
654
655
    libcnotify_printf(
656
     "%s: cache entry flags\t\t\t: 0x%08" PRIx32 "\n",
657
     function,
658
     cache_entry_flags );
659
    libmsiecf_debug_print_cache_entry_flags(
660
     cache_entry_flags );
661
    libcnotify_printf(
662
     "\n" );
663
664
    libcnotify_printf(
665
     "%s: data offset\t\t\t\t: %" PRIu32 "\n",
666
     function,
667
     url_data_offset );
668
    libcnotify_printf(
669
     "%s: data size\t\t\t\t: %" PRIu32 "\n",
670
     function,
671
     url_data_size );
672
673
    if( ( io_handle->major_version == 4 )
674
     && ( io_handle->minor_version == 7 ) )
675
    {
676
      byte_stream_copy_to_uint32_little_endian(
677
       ( (msiecf_url_record_header_v47_t *) data )->unknown8,
678
       value_32bit );
679
    }
680
    else if( ( io_handle->major_version == 5 )
681
          && ( io_handle->minor_version == 2 ) )
682
    {
683
      byte_stream_copy_to_uint32_little_endian(
684
       ( (msiecf_url_record_header_v52_t *) data )->unknown8,
685
       value_32bit );
686
    }
687
    libcnotify_printf(
688
     "%s: unknown8\t\t\t\t: 0x%08" PRIx32 "\n",
689
     function,
690
     value_32bit );
691
692
    if( ( io_handle->major_version == 4 )
693
     && ( io_handle->minor_version == 7 ) )
694
    {
695
      if( libmsiecf_debug_print_fat_date_time_value(
696
           function,
697
           "last checked time\t\t\t",
698
           ( (msiecf_url_record_header_v47_t *) data )->last_checked_time,
699
           4,
700
           LIBFDATETIME_ENDIAN_LITTLE,
701
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
702
           error ) != 1 )
703
      {
704
        libcerror_error_set(
705
         error,
706
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
707
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
708
         "%s: unable to print FAT date time value.",
709
         function );
710
711
        goto on_error;
712
      }
713
    }
714
    else if( ( io_handle->major_version == 5 )
715
          && ( io_handle->minor_version == 2 ) )
716
    {
717
      if( libmsiecf_debug_print_fat_date_time_value(
718
           function,
719
           "last checked time\t\t\t",
720
           ( (msiecf_url_record_header_v52_t *) data )->last_checked_time,
721
           4,
722
           LIBFDATETIME_ENDIAN_LITTLE,
723
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
724
           error ) != 1 )
725
      {
726
        libcerror_error_set(
727
         error,
728
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
729
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
730
         "%s: unable to print FAT date time value.",
731
         function );
732
733
        goto on_error;
734
      }
735
    }
736
    libcnotify_printf(
737
     "%s: number of hits\t\t\t\t: %" PRIu32 "\n",
738
     function,
739
     url_values->number_of_hits );
740
741
    if( ( io_handle->major_version == 4 )
742
     && ( io_handle->minor_version == 7 ) )
743
    {
744
      byte_stream_copy_to_uint32_little_endian(
745
       ( (msiecf_url_record_header_v47_t *) data )->unknown9,
746
       value_32bit );
747
    }
748
    else if( ( io_handle->major_version == 5 )
749
          && ( io_handle->minor_version == 2 ) )
750
    {
751
      byte_stream_copy_to_uint32_little_endian(
752
       ( (msiecf_url_record_header_v52_t *) data )->unknown9,
753
       value_32bit );
754
    }
755
    libcnotify_printf(
756
     "%s: unknown9\t\t\t\t: 0x%08" PRIx32 "\n",
757
     function,
758
     value_32bit );
759
760
    if( ( io_handle->major_version == 4 )
761
     && ( io_handle->minor_version == 7 ) )
762
    {
763
      if( libmsiecf_debug_print_fat_date_time_value(
764
           function,
765
           "unknown time\t\t\t\t",
766
           ( (msiecf_url_record_header_v47_t *) data )->unknown_time,
767
           4,
768
           LIBFDATETIME_ENDIAN_LITTLE,
769
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
770
           error ) != 1 )
771
      {
772
        libcerror_error_set(
773
         error,
774
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
775
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
776
         "%s: unable to print FAT date time value.",
777
         function );
778
779
        goto on_error;
780
      }
781
    }
782
    else if( ( io_handle->major_version == 5 )
783
          && ( io_handle->minor_version == 2 ) )
784
    {
785
      if( libmsiecf_debug_print_fat_date_time_value(
786
           function,
787
           "unknown time\t\t\t\t",
788
           ( (msiecf_url_record_header_v52_t *) data )->unknown_time,
789
           4,
790
           LIBFDATETIME_ENDIAN_LITTLE,
791
           LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
792
           error ) != 1 )
793
      {
794
        libcerror_error_set(
795
         error,
796
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
797
         LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
798
         "%s: unable to print FAT date time value.",
799
         function );
800
801
        goto on_error;
802
      }
803
    }
804
  }
805
#endif /* defined( HAVE_DEBUG_OUTPUT ) */
806
807
634
  if( unknown_offset > 0 )
808
373
  {
809
373
    if( unknown_offset > data_size )
810
52
    {
811
52
      if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
812
52
      {
813
52
        libcerror_error_set(
814
52
         error,
815
52
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
816
52
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
817
52
         "%s: unknown offset exceeds URL record data.",
818
52
         function );
819
820
52
        goto on_error;
821
52
      }
822
0
      else
823
0
      {
824
0
        memory_free(
825
0
         data );
826
827
0
        return( 1 );
828
0
      }
829
52
    }
830
#if defined( HAVE_DEBUG_OUTPUT )
831
    if( libcnotify_verbose != 0 )
832
    {
833
      libcnotify_printf(
834
       "%s: unknown:\n",
835
       function );
836
      libcnotify_print_data(
837
       &( data[ unknown_offset ] ),
838
       8,
839
       0 );
840
    }
841
#endif
842
373
  }
843
582
  if( location_offset > 0 )
844
569
  {
845
569
    if( location_offset > data_size )
846
44
    {
847
44
      if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
848
44
      {
849
44
        libcerror_error_set(
850
44
         error,
851
44
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
852
44
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
853
44
         "%s: location offset exceeds size of URL record data.",
854
44
         function );
855
856
44
        return( -1 );
857
44
      }
858
44
    }
859
525
    else
860
525
    {
861
525
      if( libfvalue_value_type_initialize(
862
525
           &( url_values->location ),
863
525
           LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
864
525
           error ) != 1 )
865
0
      {
866
0
        libcerror_error_set(
867
0
         error,
868
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
869
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
870
0
         "%s: unable to create location value.",
871
0
         function );
872
873
0
        goto on_error;
874
0
      }
875
525
      value_size = libfvalue_value_type_set_data_string(
876
525
                    url_values->location,
877
525
                    &( data[ location_offset ] ),
878
525
                    data_size - location_offset,
879
525
                    io_handle->ascii_codepage,
880
525
                    LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
881
525
                    error );
882
883
525
      if( value_size == -1 )
884
0
      {
885
0
        libcerror_error_set(
886
0
         error,
887
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
888
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
889
0
         "%s: unable to set data of location value.",
890
0
         function );
891
892
0
        goto on_error;
893
0
      }
894
#if defined( HAVE_DEBUG_OUTPUT )
895
      if( libcnotify_verbose != 0 )
896
      {
897
        libcnotify_printf(
898
         "%s: location\t\t\t\t: ",
899
         function );
900
901
        if( libfvalue_value_print(
902
             url_values->location,
903
             0,
904
             0,
905
             error ) != 1 )
906
        {
907
          libcerror_error_set(
908
           error,
909
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
910
           LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
911
           "%s: unable to print location value.",
912
           function );
913
914
          goto on_error;
915
        }
916
        libcnotify_printf(
917
         "\n" );
918
919
        if( libmsiecf_hash_calculate(
920
             &value_32bit,
921
             &( data[ location_offset ] ),
922
             data_size - location_offset,
923
             error ) != 1 )
924
        {
925
          libcerror_error_set(
926
           error,
927
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
928
           LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
929
           "%s: unable to calculate location hash.",
930
           function );
931
932
          goto on_error;
933
        }
934
        libcnotify_printf(
935
         "%s: hash value\t\t\t\t: 0x%08" PRIx32 "\n",
936
         function,
937
         value_32bit );
938
      }
939
#endif
940
525
      if( ( data[ location_offset + value_size - 1 ] != 0 )
941
9
       && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
942
9
      {
943
9
        libcerror_error_set(
944
9
         error,
945
9
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
946
9
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
947
9
         "%s: unsupported unterminated location string.",
948
9
         function );
949
950
9
        goto on_error;
951
9
      }
952
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
953
516
      {
954
516
        if( value_size >= 18 )
955
461
        {
956
461
          if( ( data[ location_offset ] == (uint8_t) ':' )
957
320
           && ( data[ location_offset + 1 ] >= (uint8_t) '0' )
958
313
           && ( data[ location_offset + 1 ] <= (uint8_t) '9' )
959
304
           && ( data[ location_offset + 2 ] >= (uint8_t) '0' )
960
296
           && ( data[ location_offset + 2 ] <= (uint8_t) '9' )
961
289
           && ( data[ location_offset + 3 ] >= (uint8_t) '0' )
962
286
           && ( data[ location_offset + 3 ] <= (uint8_t) '9' )
963
277
           && ( data[ location_offset + 4 ] >= (uint8_t) '0' )
964
269
           && ( data[ location_offset + 4 ] <= (uint8_t) '9' )
965
264
           && ( data[ location_offset + 5 ] >= (uint8_t) '0' )
966
256
           && ( data[ location_offset + 5 ] <= (uint8_t) '9' )
967
249
           && ( data[ location_offset + 6 ] >= (uint8_t) '0' )
968
243
           && ( data[ location_offset + 6 ] <= (uint8_t) '9' )
969
234
           && ( data[ location_offset + 7 ] >= (uint8_t) '0' )
970
227
           && ( data[ location_offset + 7 ] <= (uint8_t) '9' )
971
220
           && ( data[ location_offset + 8 ] >= (uint8_t) '0' )
972
212
           && ( data[ location_offset + 8 ] <= (uint8_t) '9' )
973
207
           && ( data[ location_offset + 9 ] >= (uint8_t) '0' )
974
199
           && ( data[ location_offset + 9 ] <= (uint8_t) '9' )
975
189
           && ( data[ location_offset + 10 ] >= (uint8_t) '0' )
976
181
           && ( data[ location_offset + 10 ] <= (uint8_t) '9' )
977
175
           && ( data[ location_offset + 11 ] >= (uint8_t) '0' )
978
166
           && ( data[ location_offset + 11 ] <= (uint8_t) '9' )
979
162
           && ( data[ location_offset + 12 ] >= (uint8_t) '0' )
980
158
           && ( data[ location_offset + 12 ] <= (uint8_t) '9' )
981
152
           && ( data[ location_offset + 13 ] >= (uint8_t) '0' )
982
142
           && ( data[ location_offset + 13 ] <= (uint8_t) '9' )
983
134
           && ( data[ location_offset + 14 ] >= (uint8_t) '0' )
984
130
           && ( data[ location_offset + 14 ] <= (uint8_t) '9' )
985
125
           && ( data[ location_offset + 15 ] >= (uint8_t) '0' )
986
117
           && ( data[ location_offset + 15 ] <= (uint8_t) '9' )
987
109
           && ( data[ location_offset + 16 ] >= (uint8_t) '0' )
988
102
           && ( data[ location_offset + 16 ] <= (uint8_t) '9' )
989
94
           && ( data[ location_offset + 17 ] == (uint8_t) ':' ) )
990
83
          {
991
83
            first_year  = (uint16_t) data[ location_offset + 1 ] - (uint8_t) '0';
992
83
            first_year *= 10;
993
83
            first_year += (uint16_t) data[ location_offset + 2 ] - (uint8_t) '0';
994
83
            first_year *= 10;
995
83
            first_year += (uint16_t) data[ location_offset + 3 ] - (uint8_t) '0';
996
83
            first_year *= 10;
997
83
            first_year += (uint16_t) data[ location_offset + 4 ] - (uint8_t) '0';
998
999
83
            first_month  = data[ location_offset + 5 ] - (uint8_t) '0';
1000
83
            first_month *= 10;
1001
83
            first_month += data[ location_offset + 6 ] - (uint8_t) '0';
1002
1003
83
            first_day_of_month  = data[ location_offset + 7 ] - (uint8_t) '0';
1004
83
            first_day_of_month *= 10;
1005
83
            first_day_of_month += data[ location_offset + 8 ] - (uint8_t) '0';
1006
1007
83
            second_year  = (uint16_t) data[ location_offset + 9 ] - (uint8_t) '0';
1008
83
            second_year *= 10;
1009
83
            second_year += (uint16_t) data[ location_offset + 10 ] - (uint8_t) '0';
1010
83
            second_year *= 10;
1011
83
            second_year += (uint16_t) data[ location_offset + 11 ] - (uint8_t) '0';
1012
83
            second_year *= 10;
1013
83
            second_year += (uint16_t) data[ location_offset + 12 ] - (uint8_t) '0';
1014
1015
83
            second_month  = data[ location_offset + 13 ] - (uint8_t) '0';
1016
83
            second_month *= 10;
1017
83
            second_month += data[ location_offset + 14 ] - (uint8_t) '0';
1018
1019
83
            second_day_of_month  = data[ location_offset + 15 ] - (uint8_t) '0';
1020
83
            second_day_of_month *= 10;
1021
83
            second_day_of_month += data[ location_offset + 16 ] - (uint8_t) '0';
1022
1023
83
            number_of_days = 0;
1024
1025
83
            if( first_year == second_year )
1026
47
            {
1027
47
              if( first_month == second_month )
1028
11
              {
1029
11
                if( first_day_of_month < second_day_of_month )
1030
3
                {
1031
3
                  number_of_days = second_day_of_month - first_day_of_month;
1032
3
                }
1033
11
              }
1034
36
              else if( ( first_month + 1 ) == second_month )
1035
25
              {
1036
25
                switch( first_month )
1037
25
                {
1038
1
                  case 3:
1039
2
                  case 5:
1040
3
                  case 7:
1041
4
                  case 8:
1042
5
                  case 10:
1043
7
                  case 12:
1044
7
                    number_of_days = ( 31 + second_day_of_month ) - first_day_of_month;
1045
7
                    break;
1046
1047
12
                  case 2:
1048
12
                    if( ( ( ( first_year % 4 ) == 0 )
1049
5
                      &&  ( ( first_year % 100 ) != 0 ) )
1050
8
                     || ( ( first_year % 400 ) == 0 ) )
1051
5
                    {
1052
5
                      number_of_days = ( 29 + second_day_of_month ) - first_day_of_month;
1053
5
                    }
1054
7
                    else
1055
7
                    {
1056
7
                      number_of_days = ( 28 + second_day_of_month ) - first_day_of_month;
1057
7
                    }
1058
12
                    break;
1059
1060
1
                  case 4:
1061
2
                  case 6:
1062
3
                  case 9:
1063
4
                  case 11:
1064
4
                    number_of_days = ( 30 + second_day_of_month ) - first_day_of_month;
1065
4
                    break;
1066
25
                }
1067
25
              }
1068
47
            }
1069
36
            else if( ( first_year + 1 ) == second_year )
1070
12
            {
1071
12
              if( ( first_month == 12 )
1072
9
               && ( second_month == 1 ) )
1073
3
              {
1074
3
                number_of_days = ( 31 + second_day_of_month ) - first_day_of_month;
1075
3
              }
1076
12
            }
1077
83
            if( number_of_days == 1 )
1078
5
            {
1079
5
              url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY_DAILY;
1080
5
            }
1081
78
            else if( number_of_days == 7 )
1082
2
            {
1083
2
              url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY_WEEKLY;
1084
2
            }
1085
83
          }
1086
461
        }
1087
516
      }
1088
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1089
509
      {
1090
509
        if( value_size >= 11 )
1091
473
        {
1092
473
          if( memory_compare(
1093
473
               &( data[ location_offset ] ),
1094
473
               "iedownload:",
1095
473
               11 ) == 0 )
1096
5
          {
1097
5
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_DOWNLOAD;
1098
5
          }
1099
473
        }
1100
509
      }
1101
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1102
504
      {
1103
504
        if( value_size >= 9 )
1104
475
        {
1105
475
          if( memory_compare(
1106
475
               &( data[ location_offset ] ),
1107
475
               "DOMStore:",
1108
475
               9 ) == 0 )
1109
2
          {
1110
2
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_DOM_STORE;
1111
2
          }
1112
473
          else if( memory_compare(
1113
473
                    &( data[ location_offset ] ),
1114
473
                    "feedplat:",
1115
473
                    9 ) == 0 )
1116
3
          {
1117
3
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_RSS_FEED;
1118
3
          }
1119
470
          else if( memory_compare(
1120
470
                    &( data[ location_offset ] ),
1121
470
                    "iecompat:",
1122
470
                    9 ) == 0 )
1123
2
          {
1124
2
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_COMPATIBILITY;
1125
2
          }
1126
468
          else if( memory_compare(
1127
468
                    &( data[ location_offset ] ),
1128
468
                    "PrivacIE:",
1129
468
                    9 ) == 0 )
1130
4
          {
1131
4
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_INPRIVATE_FILTERING;
1132
4
          }
1133
464
          else if( memory_compare(
1134
464
                    &( data[ location_offset ] ),
1135
464
                    "userdata:",
1136
464
                    9 ) == 0 )
1137
1
          {
1138
1
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_USER_DATA;
1139
1
          }
1140
475
        }
1141
504
      }
1142
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1143
492
      {
1144
492
        if( value_size >= 8 )
1145
466
        {
1146
466
          if( memory_compare(
1147
466
               &( data[ location_offset ] ),
1148
466
               "Visited:",
1149
466
               8 ) == 0 )
1150
1
          {
1151
1
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY;
1152
1
          }
1153
466
        }
1154
492
      }
1155
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1156
491
      {
1157
491
        if( value_size >= 7 )
1158
466
        {
1159
466
          if( memory_compare(
1160
466
               &( data[ location_offset ] ),
1161
466
               "Cookie:",
1162
466
               7 ) == 0 )
1163
4
          {
1164
4
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_COOKIE;
1165
4
          }
1166
466
        }
1167
491
      }
1168
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1169
487
      {
1170
487
        if( value_size >= 6 )
1171
468
        {
1172
468
          if( memory_compare(
1173
468
               &( data[ location_offset ] ),
1174
468
               "ietld:",
1175
468
               6 ) == 0 )
1176
2
          {
1177
2
            url_values->type = LIBMSIECF_URL_ITEM_TYPE_TLD;
1178
2
          }
1179
468
        }
1180
487
      }
1181
516
      if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
1182
485
      {
1183
485
        url_values->type = LIBMSIECF_URL_ITEM_TYPE_CACHE;
1184
1185
/* TODO way to determine unknown
1186
        url_values->type = LIBMSIECF_URL_ITEM_TYPE_UNKNOWN;
1187
*/
1188
485
      }
1189
516
    }
1190
569
  }
1191
529
  if( filename_offset > 0 )
1192
431
  {
1193
431
    if( filename_offset > data_size )
1194
229
    {
1195
229
      if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
1196
229
      {
1197
229
        libcerror_error_set(
1198
229
         error,
1199
229
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1200
229
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1201
229
         "%s: filename offset exceeds size of URL record data.",
1202
229
         function );
1203
1204
229
        goto on_error;
1205
229
      }
1206
229
    }
1207
202
    else
1208
202
    {
1209
202
      if( libfvalue_value_type_initialize(
1210
202
           &( url_values->filename ),
1211
202
           LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
1212
202
           error ) != 1 )
1213
0
      {
1214
0
        libcerror_error_set(
1215
0
         error,
1216
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1217
0
         LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
1218
0
         "%s: unable to create filename value.",
1219
0
         function );
1220
1221
0
        goto on_error;
1222
0
      }
1223
202
      value_size = libfvalue_value_type_set_data_string(
1224
202
                    url_values->filename,
1225
202
                    &( data[ filename_offset ] ),
1226
202
                    data_size - filename_offset,
1227
202
                    io_handle->ascii_codepage,
1228
202
                    LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
1229
202
                    error );
1230
1231
202
      if( value_size == -1 )
1232
0
      {
1233
0
        libcerror_error_set(
1234
0
         error,
1235
0
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1236
0
         LIBCERROR_RUNTIME_ERROR_SET_FAILED,
1237
0
         "%s: unable to set data of filename value.",
1238
0
         function );
1239
1240
0
        goto on_error;
1241
0
      }
1242
#if defined( HAVE_DEBUG_OUTPUT )
1243
      if( libcnotify_verbose != 0 )
1244
      {
1245
        libcnotify_printf(
1246
         "%s: filename\t\t\t\t: ",
1247
         function );
1248
1249
        if( libfvalue_value_print(
1250
             url_values->filename,
1251
             0,
1252
             0,
1253
             error ) != 1 )
1254
        {
1255
          libcerror_error_set(
1256
           error,
1257
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1258
           LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
1259
           "%s: unable to print filename value.",
1260
           function );
1261
1262
          goto on_error;
1263
        }
1264
        libcnotify_printf(
1265
         "\n" );
1266
      }
1267
#endif
1268
202
      if( ( data[ filename_offset + value_size - 1 ] != 0 )
1269
24
       && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
1270
24
      {
1271
24
        libcerror_error_set(
1272
24
         error,
1273
24
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1274
24
         LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1275
24
         "%s: unsupported unterminated filename string.",
1276
24
         function );
1277
1278
24
        goto on_error;
1279
24
      }
1280
202
    }
1281
431
  }
1282
276
  if( url_data_offset > 0 )
1283
263
  {
1284
263
    if( url_data_offset > data_size )
1285
155
    {
1286
155
      if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
1287
155
      {
1288
155
        libcerror_error_set(
1289
155
         error,
1290
155
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1291
155
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1292
155
         "%s: data offset exceeds size of URL record data.",
1293
155
         function );
1294
1295
155
        goto on_error;
1296
155
      }
1297
155
    }
1298
108
    else
1299
108
    {
1300
108
      if( ( url_data_offset + url_data_size ) > data_size )
1301
46
      {
1302
46
        if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
1303
46
        {
1304
46
          libcerror_error_set(
1305
46
           error,
1306
46
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
1307
46
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1308
46
           "%s: data size exceeds size of URL record data.",
1309
46
           function );
1310
1311
46
          goto on_error;
1312
46
        }
1313
0
        else
1314
0
        {
1315
0
          url_data_size = data_size - url_data_offset;
1316
0
        }
1317
46
      }
1318
62
      if( ( url_data_size == 0 )
1319
57
       || ( url_data_size > (size_t) MEMORY_MAXIMUM_ALLOCATION_SIZE ) )
1320
25
      {
1321
25
        libcerror_error_set(
1322
25
         error,
1323
25
         LIBCERROR_ERROR_DOMAIN_RUNTIME,
1324
25
         LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
1325
25
         "%s: invalid URL data size value exceeds out of bounds.",
1326
25
         function );
1327
1328
25
        goto on_error;
1329
25
      }
1330
37
      url_values->data = (uint8_t *) memory_allocate(
1331
37
                                      sizeof( uint8_t ) * url_data_size );
1332
1333
37
      if( url_values->data == NULL )
1334
0
      {
1335
0
        libcerror_error_set(
1336
0
         error,
1337
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
1338
0
         LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1339
0
         "%s: unable to create data.",
1340
0
         function );
1341
1342
0
        goto on_error;
1343
0
      }
1344
37
      url_values->data_size = (size_t) url_data_size;
1345
1346
37
      if( memory_copy(
1347
37
           url_values->data,
1348
37
           &( data[ url_data_offset ] ),
1349
37
           url_values->data_size ) == NULL )
1350
0
      {
1351
0
        libcerror_error_set(
1352
0
         error,
1353
0
         LIBCERROR_ERROR_DOMAIN_MEMORY,
1354
0
         LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1355
0
         "%s: unable to copy data.",
1356
0
         function );
1357
1358
0
        goto on_error;
1359
0
      }
1360
#if defined( HAVE_DEBUG_OUTPUT )
1361
      if( libcnotify_verbose != 0 )
1362
      {
1363
        libcnotify_printf(
1364
         "%s: data:\n",
1365
         function );
1366
        libcnotify_print_data(
1367
         &( data[ url_data_offset ] ),
1368
         url_data_size,
1369
         0 );
1370
1371
        if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_CACHE )
1372
        {
1373
          /* The data string in not necessarily terminated by an end-of-string character
1374
           */
1375
          libcnotify_printf(
1376
           "%s: data string\t\t\t\t: ",
1377
           function );
1378
1379
          for( string_index = 0;
1380
               string_index < url_data_size;
1381
               string_index++ )
1382
          {
1383
            libcnotify_printf(
1384
             "%c",
1385
             data[ url_data_offset + string_index ] );
1386
          }
1387
          libcnotify_printf(
1388
           "\n" );
1389
        }
1390
        else if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_HISTORY )
1391
        {
1392
          visited_entry_data = &( data[ url_data_offset ] );
1393
1394
          do
1395
          {
1396
            visited_entry_index++;
1397
1398
            byte_stream_copy_to_uint16_little_endian(
1399
             visited_entry_data,
1400
             value_16bit );
1401
1402
            visited_entry_data += 2;
1403
1404
            libcnotify_printf(
1405
             "%s: data entry: %02d size\t\t\t\t: %" PRIu16 "\n",
1406
             function,
1407
             visited_entry_index,
1408
             value_16bit );
1409
1410
            libcnotify_printf(
1411
             "%s: data entry: %02d type\t\t\t\t: 0x%02" PRIx8 " (%s : %s)\n",
1412
             function,
1413
             visited_entry_index,
1414
             visited_entry_data[ 0 ],
1415
             libmsiecf_property_type_get_identifier(
1416
              NULL,
1417
              (uint32_t) visited_entry_data[ 0 ],
1418
              (uint32_t) visited_entry_data[ 1 ] ),
1419
             libmsiecf_property_type_get_description(
1420
              NULL,
1421
              (uint32_t) visited_entry_data[ 0 ],
1422
              (uint32_t) visited_entry_data[ 1 ] ) );
1423
1424
            libcnotify_printf(
1425
             "%s: data entry: %02d value type\t\t\t: 0x%02" PRIx8 " (%s : %s)\n",
1426
             function,
1427
             visited_entry_index,
1428
             visited_entry_data[ 1 ],
1429
             libfole_value_type_get_identifier(
1430
              (uint32_t) visited_entry_data[ 1 ] ),
1431
             libfole_value_type_get_description(
1432
              (uint32_t) visited_entry_data[ 1 ] ) );
1433
1434
            visited_entry_data += 2;
1435
1436
            if( value_16bit > 4 )
1437
            {
1438
              value_16bit -= 4;
1439
1440
              libcnotify_printf(
1441
               "%s: data entry: %02d value:\n",
1442
               function,
1443
               visited_entry_index );
1444
              libcnotify_print_data(
1445
               visited_entry_data,
1446
               value_16bit,
1447
               0 );
1448
1449
              visited_entry_data += value_16bit;
1450
            }
1451
          }
1452
          while( value_16bit > 0 );
1453
        }
1454
      }
1455
#endif
1456
37
    }
1457
263
  }
1458
#if defined( HAVE_DEBUG_OUTPUT )
1459
  if( libcnotify_verbose != 0 )
1460
  {
1461
    libcnotify_printf(
1462
     "\n" );
1463
  }
1464
#endif
1465
#if defined( HAVE_VERBOSE_OUTPUT )
1466
  switch( url_values->type )
1467
  {
1468
    case LIBMSIECF_URL_ITEM_TYPE_COOKIE:
1469
      if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_COOKIE ) == 0 )
1470
      {
1471
        libcnotify_printf(
1472
         "%s: detected type cookie but corresponding cache entry flag (COOKIE_CACHE_ENTRY) is not set.\n",
1473
         function );
1474
      }
1475
      break;
1476
1477
    case LIBMSIECF_URL_ITEM_TYPE_HISTORY:
1478
      if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_URLHISTORY ) == 0 )
1479
      {
1480
        libcnotify_printf(
1481
         "%s: detected type history but corresponding cache entry flag (URLHISTORY_CACHE_ENTRY) is not set.\n",
1482
         function );
1483
      }
1484
      break;
1485
1486
    case LIBMSIECF_URL_ITEM_TYPE_HISTORY_DAILY:
1487
    case LIBMSIECF_URL_ITEM_TYPE_HISTORY_WEEKLY:
1488
      if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_URLHISTORY ) == 0 )
1489
      {
1490
        libcnotify_printf(
1491
         "%s: detected type history periodic but corresponding cache entry flag (URLHISTORY_CACHE_ENTRY) is not set.\n",
1492
         function );
1493
      }
1494
      break;
1495
  }
1496
#endif /* defined( HAVE_VERBOSE_OUTPUT ) */
1497
1498
50
  return( 1 );
1499
1500
540
on_error:
1501
/* TODO clean up */
1502
540
  return( -1 );
1503
276
}
1504
1505
/* Reads the URL values from an URL record
1506
 * Returns 1 if successful or -1 on error
1507
 */
1508
int libmsiecf_url_values_read_file_io_handle(
1509
     libmsiecf_url_values_t *url_values,
1510
     libmsiecf_io_handle_t *io_handle,
1511
     libbfio_handle_t *file_io_handle,
1512
     off64_t url_record_offset,
1513
     size32_t record_size,
1514
     uint8_t item_flags,
1515
     libcerror_error_t **error )
1516
667
{
1517
667
  uint8_t *record_data  = NULL;
1518
667
  static char *function = "libmsiecf_url_values_read_file_io_handle";
1519
667
  ssize_t read_count    = 0;
1520
1521
667
  if( url_values == NULL )
1522
0
  {
1523
0
    libcerror_error_set(
1524
0
     error,
1525
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
1526
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
1527
0
     "%s: invalid URL values.",
1528
0
     function );
1529
1530
0
    return( -1 );
1531
0
  }
1532
667
  if( record_size > (size32_t) MEMORY_MAXIMUM_ALLOCATION_SIZE )
1533
4
  {
1534
4
    libcerror_error_set(
1535
4
     error,
1536
4
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1537
4
     LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
1538
4
     "%s: invalid record size value exceeds maximum allocation size.",
1539
4
     function );
1540
1541
4
    return( -1 );
1542
4
  }
1543
663
  if( ( record_size == 0 )
1544
663
   || ( ( record_size % 8 ) != 0 ) )
1545
0
  {
1546
0
    libcerror_error_set(
1547
0
     error,
1548
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
1549
0
     LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
1550
0
     "%s: unsupported record size.",
1551
0
     function );
1552
1553
0
    return( -1 );
1554
0
  }
1555
  /* Add one block for tainted records
1556
   */
1557
663
  if( ( item_flags & LIBMSIECF_ITEM_FLAG_TAINTED ) != 0 )
1558
83
  {
1559
83
    record_size += LIBMSIECF_DEFAULT_BLOCK_SIZE;
1560
83
  }
1561
663
  record_data = (uint8_t *) memory_allocate(
1562
663
                             record_size );
1563
1564
663
  if( record_data == NULL )
1565
0
  {
1566
0
    libcerror_error_set(
1567
0
     error,
1568
0
     LIBCERROR_ERROR_DOMAIN_MEMORY,
1569
0
     LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
1570
0
     "%s: unable to create URL record data.",
1571
0
     function );
1572
1573
0
    goto on_error;
1574
0
  }
1575
#if defined( HAVE_DEBUG_OUTPUT )
1576
  if( libcnotify_verbose != 0 )
1577
  {
1578
    libcnotify_printf(
1579
     "%s: reading URL record at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
1580
     function,
1581
     url_record_offset,
1582
     url_record_offset );
1583
  }
1584
#endif
1585
663
  read_count = libbfio_handle_read_buffer_at_offset(
1586
663
                file_io_handle,
1587
663
                record_data,
1588
663
                record_size,
1589
663
                url_record_offset,
1590
663
                error );
1591
1592
663
  if( read_count != (ssize_t) record_size )
1593
29
  {
1594
29
    libcerror_error_set(
1595
29
     error,
1596
29
     LIBCERROR_ERROR_DOMAIN_IO,
1597
29
     LIBCERROR_IO_ERROR_READ_FAILED,
1598
29
     "%s: unable to read URL record data at offset: %" PRIi64 " (0x%08" PRIx64 ").",
1599
29
     function,
1600
29
     url_record_offset,
1601
29
     url_record_offset );
1602
1603
29
    goto on_error;
1604
29
  }
1605
634
  if( libmsiecf_url_values_read_data(
1606
634
       url_values,
1607
634
       io_handle,
1608
634
       record_data,
1609
634
       (size_t) record_size,
1610
634
       item_flags,
1611
634
       error ) != 1 )
1612
584
  {
1613
584
    libcerror_error_set(
1614
584
     error,
1615
584
     LIBCERROR_ERROR_DOMAIN_IO,
1616
584
     LIBCERROR_IO_ERROR_READ_FAILED,
1617
584
     "%s: unable to read URL record.",
1618
584
     function );
1619
1620
584
    goto on_error;
1621
584
  }
1622
50
  memory_free(
1623
50
   record_data );
1624
1625
50
  record_data = NULL;
1626
1627
50
  return( 1 );
1628
1629
613
on_error:
1630
613
  if( record_data != NULL )
1631
613
  {
1632
613
    memory_free(
1633
613
     record_data );
1634
613
  }
1635
613
  return( -1 );
1636
634
}
1637