Coverage Report

Created: 2023-06-07 06:53

/src/libpff/libpff/libpff_mapi_value.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * MAPI value functions
3
 *
4
 * Copyright (C) 2008-2023, 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
#include "libpff_libcerror.h"
26
#include "libpff_libuna.h"
27
#include "libpff_mapi.h"
28
#include "libpff_mapi_value.h"
29
30
/* Determines if there are zero bytes in a string, trailing zero bytes not included
31
 * Returns 1 if the data contains zero bytes, 0 if not or -1 on error
32
 */
33
int libpff_mapi_value_data_contains_zero_bytes(
34
     const uint8_t *data,
35
     size_t data_size,
36
     libcerror_error_t **error )
37
0
{
38
0
  static char *function   = "libpff_mapi_value_data_contains_zero_bytes";
39
0
  size_t data_offset      = 0;
40
0
  uint8_t zero_byte_found = 0;
41
42
0
  if( data == NULL )
43
0
  {
44
0
    libcerror_error_set(
45
0
     error,
46
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
47
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
48
0
     "%s: invalid data.",
49
0
     function );
50
51
0
    return( -1 );
52
0
  }
53
0
  if( data_size > (size_t) SSIZE_MAX )
54
0
  {
55
0
    libcerror_error_set(
56
0
     error,
57
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
58
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
59
0
     "%s: invalid data size value exceeds maximum.",
60
0
     function );
61
62
0
    return( -1 );
63
0
  }
64
0
  for( data_offset = 0;
65
0
       data_offset < data_size;
66
0
       data_offset++ )
67
0
  {
68
0
    if( zero_byte_found == 0 )
69
0
    {
70
0
      if( data[ data_offset ] == 0 )
71
0
      {
72
0
        zero_byte_found = 1;
73
0
      }
74
0
    }
75
0
    else
76
0
    {
77
0
      if( data[ data_offset ] != 0 )
78
0
      {
79
0
        return( 1 );
80
0
      }
81
0
    }
82
0
  }
83
0
  return( 0 );
84
0
}
85
86
/* Retrieves the size of the MAPI value formatted as an UTF-8 string
87
 * The returned size includes the end of string character
88
 * Returns 1 if successful or -1 on error
89
 */
90
int libpff_mapi_value_get_data_as_utf8_string_size(
91
     uint32_t value_type,
92
     const uint8_t *value_data,
93
     size_t value_data_size,
94
     int ascii_codepage,
95
     size_t *utf8_string_size,
96
     libcerror_error_t **error )
97
0
{
98
0
  static char *function   = "libpff_mapi_value_get_data_as_utf8_string_size";
99
0
  uint8_t is_ascii_string = 0;
100
0
  int result              = 0;
101
102
0
  if( utf8_string_size == NULL )
103
0
  {
104
0
    libcerror_error_set(
105
0
     error,
106
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
107
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
108
0
     "%s: invalid UTF-8 string size.",
109
0
     function );
110
111
0
    return( -1 );
112
0
  }
113
0
  if( ( value_data == NULL )
114
0
   || ( value_data_size == 0 ) )
115
0
  {
116
0
    *utf8_string_size = 0;
117
118
0
    return( 1 );
119
0
  }
120
0
  if( value_type == LIBPFF_VALUE_TYPE_STRING_ASCII )
121
0
  {
122
0
    is_ascii_string = 1;
123
0
  }
124
  /* Codepage 1200 represents Unicode
125
   * If the codepage is 1200 find out if the string is encoded in UTF-8 or UTF-16 little-endian
126
   */
127
0
  if( ( is_ascii_string != 0 )
128
0
   && ( ascii_codepage == 1200 ) )
129
0
  {
130
0
    result = libpff_mapi_value_data_contains_zero_bytes(
131
0
        value_data,
132
0
        value_data_size,
133
0
        error );
134
135
0
    if( result == -1 )
136
0
    {
137
0
      libcerror_error_set(
138
0
       error,
139
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
140
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
141
0
       "%s: unable to determine if value data contains zero bytes.",
142
0
       function );
143
144
0
      return( -1 );
145
0
    }
146
0
    else if( result != 0 )
147
0
    {
148
0
      is_ascii_string = 0;
149
0
    }
150
0
  }
151
  /* String is in UTF-16 little-endian
152
   */
153
0
  if( is_ascii_string == 0 )
154
0
  {
155
0
    result = libuna_utf8_string_size_from_utf16_stream(
156
0
              value_data,
157
0
              value_data_size,
158
0
              LIBUNA_ENDIAN_LITTLE,
159
0
              utf8_string_size,
160
0
              error );
161
0
  }
162
  /* Codepage 65000 represents UTF-7
163
   */
164
0
  else if( ascii_codepage == 65000 )
165
0
  {
166
0
    result = libuna_utf8_string_size_from_utf7_stream(
167
0
        value_data,
168
0
        value_data_size,
169
0
        utf8_string_size,
170
0
        error );
171
0
  }
172
  /* Codepage 1200 or 65001 represents UTF-8
173
   */
174
0
  else if( ( ascii_codepage == 1200 )
175
0
        || ( ascii_codepage == 65001 ) )
176
0
  {
177
0
    result = libuna_utf8_string_size_from_utf8_stream(
178
0
        value_data,
179
0
        value_data_size,
180
0
        utf8_string_size,
181
0
        error );
182
0
  }
183
0
  else
184
0
  {
185
    /* TODO currently libuna uses the same numeric values for the codepages as PFF
186
     * add a mapping function if this implementation changes
187
     */
188
0
    result = libuna_utf8_string_size_from_byte_stream(
189
0
        value_data,
190
0
        value_data_size,
191
0
        ascii_codepage,
192
0
        utf8_string_size,
193
0
        error );
194
0
  }
195
0
  if( result != 1 )
196
0
  {
197
0
    libcerror_error_set(
198
0
     error,
199
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
200
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
201
0
     "%s: unable to determine size of value data as UTF-8 string.",
202
0
     function );
203
204
0
    return( -1 );
205
0
  }
206
0
  return( 1 );
207
0
}
208
209
/* Retrieves the MAPI value formatted as an UTF-8 string value
210
 * The size should include the end of string character
211
 * Returns 1 if successful or -1 on error
212
 */
213
int libpff_mapi_value_get_data_as_utf8_string(
214
     uint32_t value_type,
215
     const uint8_t *value_data,
216
     size_t value_data_size,
217
     int ascii_codepage,
218
     uint8_t *utf8_string,
219
     size_t utf8_string_size,
220
     libcerror_error_t **error )
221
0
{
222
0
  static char *function   = "libpff_mapi_value_get_data_as_utf8_string";
223
0
  uint8_t is_ascii_string = 0;
224
0
  int result              = 0;
225
226
0
  if( utf8_string == NULL )
227
0
  {
228
0
    libcerror_error_set(
229
0
     error,
230
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
231
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
232
0
     "%s: invalid UTF-8 string.",
233
0
     function );
234
235
0
    return( -1 );
236
0
  }
237
0
  if( utf8_string_size == 0 )
238
0
  {
239
0
    libcerror_error_set(
240
0
     error,
241
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
242
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
243
0
     "%s: invalid UTF-8 string size value zero or less.",
244
0
     function );
245
246
0
    return( -1 );
247
0
  }
248
0
  if( utf8_string_size > (size_t) SSIZE_MAX )
249
0
  {
250
0
    libcerror_error_set(
251
0
     error,
252
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
253
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
254
0
     "%s: invalid UTF-8 string size value exceeds maximum.",
255
0
     function );
256
257
0
    return( -1 );
258
0
  }
259
0
  if( ( value_data == NULL )
260
0
   || ( value_data_size == 0 ) )
261
0
  {
262
0
    utf8_string[ 0 ] = 0;
263
264
0
    return( 1 );
265
0
  }
266
0
  if( value_type == LIBPFF_VALUE_TYPE_STRING_ASCII )
267
0
  {
268
0
    is_ascii_string = 1;
269
0
  }
270
  /* Codepage 1200 represents Unicode
271
   * If the codepage is 1200 find out if the string is encoded in UTF-8 or UTF-16 little-endian
272
   */
273
0
  if( ( is_ascii_string != 0 )
274
0
   && ( ascii_codepage == 1200 ) )
275
0
  {
276
0
    result = libpff_mapi_value_data_contains_zero_bytes(
277
0
        value_data,
278
0
        value_data_size,
279
0
        error );
280
281
0
    if( result == -1 )
282
0
    {
283
0
      libcerror_error_set(
284
0
       error,
285
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
286
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
287
0
       "%s: unable to determine if value data contains zero bytes.",
288
0
       function );
289
290
0
      return( -1 );
291
0
    }
292
0
    else if( result != 0 )
293
0
    {
294
0
      is_ascii_string = 0;
295
0
    }
296
0
  }
297
  /* String is in UTF-16 little-endian
298
   */
299
0
  if( is_ascii_string == 0 )
300
0
  {
301
0
    result = libuna_utf8_string_copy_from_utf16_stream(
302
0
              utf8_string,
303
0
              utf8_string_size,
304
0
              value_data,
305
0
              value_data_size,
306
0
              LIBUNA_ENDIAN_LITTLE,
307
0
              error );
308
0
  }
309
  /* Codepage 65000 represents UTF-7
310
   */
311
0
  else if( ascii_codepage == 65000 )
312
0
  {
313
0
    result = libuna_utf8_string_copy_from_utf7_stream(
314
0
              utf8_string,
315
0
              utf8_string_size,
316
0
              value_data,
317
0
              value_data_size,
318
0
              error );
319
0
  }
320
  /* Codepage 1200 or 65001 represents UTF-8
321
   */
322
0
  else if( ( ascii_codepage == 1200 )
323
0
        || ( ascii_codepage == 65001 ) )
324
0
  {
325
0
    result = libuna_utf8_string_copy_from_utf8_stream(
326
0
              utf8_string,
327
0
              utf8_string_size,
328
0
              value_data,
329
0
              value_data_size,
330
0
              error );
331
0
  }
332
0
  else
333
0
  {
334
    /* TODO currently libuna uses the same numeric values for the codepages as PFF
335
     * add a mapping function if this implementation changes
336
     */
337
0
    result = libuna_utf8_string_copy_from_byte_stream(
338
0
              utf8_string,
339
0
              utf8_string_size,
340
0
              value_data,
341
0
              value_data_size,
342
0
              ascii_codepage,
343
0
              error );
344
0
  }
345
0
  if( result != 1 )
346
0
  {
347
0
    libcerror_error_set(
348
0
     error,
349
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
350
0
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
351
0
     "%s: unable to copy value data to UTF-8 string.",
352
0
     function );
353
354
0
    return( -1 );
355
0
  }
356
0
  return( 1 );
357
0
}
358
359
/* Retrieves the size of the MAPI value formatted as an UTF-16 string
360
 * The returned size includes the end of string character
361
 * Returns 1 if successful or -1 on error
362
 */
363
int libpff_mapi_value_get_data_as_utf16_string_size(
364
     uint32_t value_type,
365
     const uint8_t *value_data,
366
     size_t value_data_size,
367
     int ascii_codepage,
368
     size_t *utf16_string_size,
369
     libcerror_error_t **error )
370
0
{
371
0
  static char *function   = "libpff_mapi_value_get_data_as_utf16_string_size";
372
0
  uint8_t is_ascii_string = 0;
373
0
  int result              = 0;
374
375
0
  if( utf16_string_size == NULL )
376
0
  {
377
0
    libcerror_error_set(
378
0
     error,
379
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
380
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
381
0
     "%s: invalid UTF-16 string size.",
382
0
     function );
383
384
0
    return( -1 );
385
0
  }
386
0
  if( ( value_data == NULL )
387
0
   || ( value_data_size == 0 ) )
388
0
  {
389
0
    *utf16_string_size = 0;
390
391
0
    return( 1 );
392
0
  }
393
0
  if( value_type == LIBPFF_VALUE_TYPE_STRING_ASCII )
394
0
  {
395
0
    is_ascii_string = 1;
396
0
  }
397
  /* Codepage 1200 represents Unicode
398
   * If the codepage is 1200 find out if the string is encoded in UTF-8 or UTF-16 little-endian
399
   */
400
0
  if( ( is_ascii_string != 0 )
401
0
   && ( ascii_codepage == 1200 ) )
402
0
  {
403
0
    result = libpff_mapi_value_data_contains_zero_bytes(
404
0
        value_data,
405
0
        value_data_size,
406
0
        error );
407
408
0
    if( result == -1 )
409
0
    {
410
0
      libcerror_error_set(
411
0
       error,
412
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
413
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
414
0
       "%s: unable to determine if value data contains zero bytes.",
415
0
       function );
416
417
0
      return( -1 );
418
0
    }
419
0
    else if( result != 0 )
420
0
    {
421
0
      is_ascii_string = 0;
422
0
    }
423
0
  }
424
  /* String is in UTF-16 little-endian
425
   */
426
0
  if( is_ascii_string == 0 )
427
0
  {
428
0
    result = libuna_utf16_string_size_from_utf16_stream(
429
0
              value_data,
430
0
              value_data_size,
431
0
              LIBUNA_ENDIAN_LITTLE,
432
0
              utf16_string_size,
433
0
              error );
434
0
  }
435
  /* Codepage 65000 represents UTF-7
436
   */
437
0
  else if( ascii_codepage == 65000 )
438
0
  {
439
0
    result = libuna_utf16_string_size_from_utf7_stream(
440
0
        value_data,
441
0
        value_data_size,
442
0
        utf16_string_size,
443
0
        error );
444
0
  }
445
  /* Codepage 1200 or 65001 represents UTF-8
446
   */
447
0
  else if( ( ascii_codepage == 1200 )
448
0
        || ( ascii_codepage == 65001 ) )
449
0
  {
450
0
    result = libuna_utf16_string_size_from_utf8_stream(
451
0
        value_data,
452
0
        value_data_size,
453
0
        utf16_string_size,
454
0
        error );
455
0
  }
456
0
  else
457
0
  {
458
    /* TODO currently libuna uses the same numeric values for the codepages as PFF
459
     * add a mapping function if this implementation changes
460
     */
461
0
    result = libuna_utf16_string_size_from_byte_stream(
462
0
        value_data,
463
0
        value_data_size,
464
0
        ascii_codepage,
465
0
        utf16_string_size,
466
0
        error );
467
0
  }
468
0
  if( result != 1 )
469
0
  {
470
0
    libcerror_error_set(
471
0
     error,
472
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
473
0
     LIBCERROR_RUNTIME_ERROR_GET_FAILED,
474
0
     "%s: unable to determine size of value data as UTF-16 string.",
475
0
     function );
476
477
0
    return( -1 );
478
0
  }
479
0
  return( 1 );
480
0
}
481
482
/* Retrieves the MAPI value formatted as an UTF-16 string value
483
 * The size should include the end of string character
484
 * Returns 1 if successful or -1 on error
485
 */
486
int libpff_mapi_value_get_data_as_utf16_string(
487
     uint32_t value_type,
488
     const uint8_t *value_data,
489
     size_t value_data_size,
490
     int ascii_codepage,
491
     uint16_t *utf16_string,
492
     size_t utf16_string_size,
493
     libcerror_error_t **error )
494
0
{
495
0
  static char *function   = "libpff_mapi_value_get_data_as_utf16_string";
496
0
  uint8_t is_ascii_string = 0;
497
0
  int result              = 0;
498
499
0
  if( utf16_string == NULL )
500
0
  {
501
0
    libcerror_error_set(
502
0
     error,
503
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
504
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
505
0
     "%s: invalid UTF-16 string.",
506
0
     function );
507
508
0
    return( -1 );
509
0
  }
510
0
  if( utf16_string_size == 0 )
511
0
  {
512
0
    libcerror_error_set(
513
0
     error,
514
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
515
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
516
0
     "%s: invalid UTF-16 string size value zero or less.",
517
0
     function );
518
519
0
    return( -1 );
520
0
  }
521
0
  if( utf16_string_size > (size_t) SSIZE_MAX )
522
0
  {
523
0
    libcerror_error_set(
524
0
     error,
525
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
526
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
527
0
     "%s: invalid UTF-16 string size value exceeds maximum.",
528
0
     function );
529
530
0
    return( -1 );
531
0
  }
532
0
  if( ( value_data == NULL )
533
0
   || ( value_data_size == 0 ) )
534
0
  {
535
0
    utf16_string[ 0 ] = 0;
536
537
0
    return( 1 );
538
0
  }
539
0
  if( value_type == LIBPFF_VALUE_TYPE_STRING_ASCII )
540
0
  {
541
0
    is_ascii_string = 1;
542
0
  }
543
  /* Codepage 1200 represents Unicode
544
   * If the codepage is 1200 find out if the string is encoded in UTF-8 or UTF-16 little-endian
545
   */
546
0
  if( ( is_ascii_string != 0 )
547
0
   && ( ascii_codepage == 1200 ) )
548
0
  {
549
0
    result = libpff_mapi_value_data_contains_zero_bytes(
550
0
        value_data,
551
0
        value_data_size,
552
0
        error );
553
554
0
    if( result == -1 )
555
0
    {
556
0
      libcerror_error_set(
557
0
       error,
558
0
       LIBCERROR_ERROR_DOMAIN_RUNTIME,
559
0
       LIBCERROR_RUNTIME_ERROR_GET_FAILED,
560
0
       "%s: unable to determine if value data contains zero bytes.",
561
0
       function );
562
563
0
      return( -1 );
564
0
    }
565
0
    else if( result != 0 )
566
0
    {
567
0
      is_ascii_string = 0;
568
0
    }
569
0
  }
570
  /* String is in UTF-16 little-endian
571
   */
572
0
  if( is_ascii_string == 0 )
573
0
  {
574
0
    result = libuna_utf16_string_copy_from_utf16_stream(
575
0
              utf16_string,
576
0
              utf16_string_size,
577
0
              value_data,
578
0
              value_data_size,
579
0
              LIBUNA_ENDIAN_LITTLE,
580
0
              error );
581
0
  }
582
  /* Codepage 65000 represents UTF-7
583
   */
584
0
  else if( ascii_codepage == 65000 )
585
0
  {
586
0
    result = libuna_utf16_string_copy_from_utf7_stream(
587
0
              utf16_string,
588
0
              utf16_string_size,
589
0
              value_data,
590
0
              value_data_size,
591
0
              error );
592
0
  }
593
  /* Codepage 1200 or 65001 represents UTF-8
594
   */
595
0
  else if( ( ascii_codepage == 1200 )
596
0
        || ( ascii_codepage == 65001 ) )
597
0
  {
598
0
    result = libuna_utf16_string_copy_from_utf8_stream(
599
0
              utf16_string,
600
0
              utf16_string_size,
601
0
              value_data,
602
0
              value_data_size,
603
0
              error );
604
0
  }
605
0
  else
606
0
  {
607
    /* TODO currently libuna uses the same numeric values for the codepages as PFF
608
     * add a mapping function if this implementation changes
609
     */
610
0
    result = libuna_utf16_string_copy_from_byte_stream(
611
0
              utf16_string,
612
0
              utf16_string_size,
613
0
              value_data,
614
0
              value_data_size,
615
0
              ascii_codepage,
616
0
              error );
617
0
  }
618
0
  if( result != 1 )
619
0
  {
620
0
    libcerror_error_set(
621
0
     error,
622
0
     LIBCERROR_ERROR_DOMAIN_RUNTIME,
623
0
     LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
624
0
     "%s: unable to copy value data to UTF-16 string.",
625
0
     function );
626
627
0
    return( -1 );
628
0
  }
629
0
  return( 1 );
630
0
}
631