Coverage Report

Created: 2026-04-12 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/file/src/readcdf.c
Line
Count
Source
1
/*-
2
 * Copyright (c) 2008, 2016 Christos Zoulas
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
 * POSSIBILITY OF SUCH DAMAGE.
25
 */
26
#include "file.h"
27
28
#ifndef lint
29
FILE_RCSID("@(#)$File: readcdf.c,v 1.81 2026/02/04 14:56:28 christos Exp $")
30
#endif
31
32
#include <assert.h>
33
#include <stdlib.h>
34
#include <unistd.h>
35
#include <string.h>
36
#include <time.h>
37
#include <ctype.h>
38
39
#include "cdf.h"
40
#include "magic.h"
41
42
4.25k
#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
43
44
static const struct nv {
45
  const char *pattern;
46
  const char *mime;
47
} app2mime[] =  {
48
  { "Word",     "msword",   },
49
  { "Excel",      "vnd.ms-excel",   },
50
  { "Powerpoint",     "vnd.ms-powerpoint",  },
51
  { "Crystal Reports",    "x-rpt",    },
52
  { "Advanced Installer",   "vnd.ms-msi",   },
53
  { "InstallShield",    "vnd.ms-msi",   },
54
  { "Microsoft Patch Compiler", "vnd.ms-msi",   },
55
  { "NAnt",     "vnd.ms-msi",   },
56
  { "Windows Installer",    "vnd.ms-msi",   },
57
  { NULL,       NULL,     },
58
}, name2mime[] = {
59
  { "Book",     "vnd.ms-excel",   },
60
  { "Workbook",     "vnd.ms-excel",   },
61
  { "WordDocument",   "msword",   },
62
  { "PowerPoint",     "vnd.ms-powerpoint",  },
63
  { "DigitalSignature",   "vnd.ms-msi",   },
64
  { NULL,       NULL,     },
65
}, name2desc[] = {
66
  { "Book",     "Microsoft Excel",  },
67
  { "Workbook",     "Microsoft Excel",  },
68
  { "WordDocument",   "Microsoft Word", },
69
  { "PowerPoint",     "Microsoft PowerPoint", },
70
  { "DigitalSignature",   "Microsoft Installer",  },
71
  { NULL,       NULL,     },
72
};
73
74
static const struct cv {
75
  uint64_t clsid[2];
76
  const char *mime;
77
} clsid2mime[] = {
78
  {
79
    { 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
80
    "x-msi",
81
  },
82
  { { 0,       0      },
83
    NULL,
84
  },
85
}, clsid2desc[] = {
86
  {
87
    { 0x00000000000c1084ULL, 0x46000000000000c0ULL  },
88
    "MSI Installer",
89
  },
90
  { { 0,       0      },
91
    NULL,
92
  },
93
};
94
95
file_private const char *
96
cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
97
83
{
98
83
  size_t i;
99
166
  for (i = 0; cv[i].mime != NULL; i++) {
100
83
    if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
101
0
      return cv[i].mime;
102
83
  }
103
#ifdef CDF_DEBUG
104
  fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
105
      clsid[1]);
106
#endif
107
83
  return NULL;
108
83
}
109
110
file_private const char *
111
cdf_app_to_mime(const char *vbuf, const struct nv *nv)
112
0
{
113
0
  size_t i;
114
0
  const char *rv = NULL;
115
0
#ifdef USE_C_LOCALE
116
0
  locale_t old_lc_ctype, c_lc_ctype;
117
118
0
  c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
119
0
  assert(c_lc_ctype != NULL);
120
0
  old_lc_ctype = uselocale(c_lc_ctype);
121
0
  assert(old_lc_ctype != NULL);
122
#else
123
  char *old_lc_ctype = setlocale(LC_CTYPE, NULL);
124
  assert(old_lc_ctype != NULL);
125
  old_lc_ctype = strdup(old_lc_ctype);
126
  assert(old_lc_ctype != NULL);
127
  (void)setlocale(LC_CTYPE, "C");
128
#endif
129
0
  for (i = 0; nv[i].pattern != NULL; i++)
130
0
    if (strcasestr(vbuf, nv[i].pattern) != NULL) {
131
0
      rv = nv[i].mime;
132
0
      break;
133
0
    }
134
#ifdef CDF_DEBUG
135
  fprintf(stderr, "unknown app %s\n", vbuf);
136
#endif
137
0
#ifdef USE_C_LOCALE
138
0
  (void)uselocale(old_lc_ctype);
139
0
  freelocale(c_lc_ctype);
140
#else
141
  (void)setlocale(LC_CTYPE, old_lc_ctype);
142
  free(old_lc_ctype);
143
#endif
144
0
  return rv;
145
0
}
146
147
file_private int
148
cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
149
    size_t count, const cdf_directory_t *root_storage)
150
240
{
151
240
  size_t i;
152
240
  cdf_timestamp_t tp;
153
240
  struct timespec ts;
154
240
  char buf[64];
155
240
  const char *str = NULL;
156
240
  const char *s, *e;
157
240
  int len;
158
159
240
  if (!NOTMIME(ms) && root_storage)
160
0
    str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
161
0
        clsid2mime);
162
163
1.75k
  for (i = 0; i < count; i++) {
164
1.64k
    cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
165
1.64k
    switch (info[i].pi_type) {
166
213
    case CDF_NULL:
167
213
      break;
168
180
    case CDF_SIGNED16:
169
180
      if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
170
180
          info[i].pi_s16) == -1)
171
0
        return -1;
172
180
      break;
173
180
    case CDF_SIGNED32:
174
129
      if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
175
129
          info[i].pi_s32) == -1)
176
0
        return -1;
177
129
      break;
178
163
    case CDF_UNSIGNED32:
179
163
      if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
180
163
          info[i].pi_u32) == -1)
181
0
        return -1;
182
163
      break;
183
163
    case CDF_FLOAT:
184
101
      if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
185
101
          info[i].pi_f) == -1)
186
0
        return -1;
187
101
      break;
188
101
    case CDF_DOUBLE:
189
64
      if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
190
64
          info[i].pi_d) == -1)
191
0
        return -1;
192
64
      break;
193
113
    case CDF_LENGTH32_STRING:
194
236
    case CDF_LENGTH32_WSTRING:
195
236
      len = info[i].pi_str.s_len;
196
236
      if (len > 1) {
197
192
        char vbuf[1024];
198
192
        size_t j, k = 1;
199
200
192
        if (info[i].pi_type == CDF_LENGTH32_WSTRING)
201
93
            k++;
202
192
        s = info[i].pi_str.s_buf;
203
192
        e = info[i].pi_str.s_buf + len;
204
59.1k
        for (j = 0; s < e && j < sizeof(vbuf)
205
59.0k
            && len--; s += k) {
206
59.0k
          if (*s == '\0')
207
148
            break;
208
58.9k
          if (isprint(CAST(unsigned char, *s)))
209
30.3k
            vbuf[j++] = *s;
210
58.9k
        }
211
192
        if (j == sizeof(vbuf))
212
10
          --j;
213
192
        vbuf[j] = '\0';
214
192
        if (NOTMIME(ms)) {
215
192
          if (vbuf[0]) {
216
144
            if (file_printf(ms, ", %s: %s",
217
144
                buf, vbuf) == -1)
218
7
              return -1;
219
144
          }
220
192
        } else if (str == NULL && info[i].pi_id ==
221
0
            CDF_PROPERTY_NAME_OF_APPLICATION) {
222
0
          str = cdf_app_to_mime(vbuf, app2mime);
223
#ifdef CDF_DEBUG
224
          fprintf(stderr, "Found property "
225
              "application name = \"%s\" "
226
              "(mime=%s)\n", vbuf, str);
227
#endif
228
0
        }
229
192
      }
230
229
      break;
231
410
    case CDF_FILETIME:
232
410
      tp = info[i].pi_tp;
233
410
      if (tp != 0) {
234
387
        char tbuf[64];
235
387
        if (tp < 1000000000000000LL) {
236
143
          cdf_print_elapsed_time(tbuf,
237
143
              sizeof(tbuf), tp);
238
143
          if (NOTMIME(ms) && file_printf(ms,
239
143
              ", %s: %s", buf, tbuf) == -1)
240
0
            return -1;
241
244
        } else {
242
244
          char *c, *ec;
243
244
          cdf_timestamp_to_timespec(&ts, tp);
244
244
          c = cdf_ctime(&ts.tv_sec, tbuf);
245
244
          if (c != NULL &&
246
244
              (ec = strchr(c, '\n')) != NULL)
247
244
            *ec = '\0';
248
249
244
          if (NOTMIME(ms) && file_printf(ms,
250
244
              ", %s: %s", buf, c) == -1)
251
0
            return -1;
252
244
        }
253
387
      }
254
410
      break;
255
410
    case CDF_CLIPBOARD:
256
22
      break;
257
127
    default:
258
127
      return -1;
259
1.64k
    }
260
1.64k
  }
261
106
  if (ms->flags & MAGIC_MIME_TYPE) {
262
0
    if (str == NULL)
263
0
      return 0;
264
0
    if (file_printf(ms, "application/%s", str) == -1)
265
0
      return -1;
266
0
  }
267
106
  return 1;
268
106
}
269
270
file_private int
271
cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
272
    const cdf_stream_t *sst)
273
0
{
274
0
  cdf_catalog_t *cat;
275
0
  size_t i;
276
0
  char buf[256];
277
0
  cdf_catalog_entry_t *ce;
278
279
0
  if (NOTMIME(ms)) {
280
0
    if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
281
0
      return -1;
282
0
    if (cdf_unpack_catalog(h, sst, &cat) == -1)
283
0
      return -1;
284
0
    ce = cat->cat_e;
285
    /* skip first entry since it has a , or paren */
286
0
    for (i = 1; i < cat->cat_num; i++)
287
0
      if (file_printf(ms, "%s%s",
288
0
          cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
289
0
          i == cat->cat_num - 1 ? "]" : ", ") == -1) {
290
0
        free(cat);
291
0
        return -1;
292
0
      }
293
0
    free(cat);
294
0
  } else if (ms->flags & MAGIC_MIME_TYPE) {
295
0
    if (file_printf(ms, "application/CDFV2") == -1)
296
0
      return -1;
297
0
  }
298
0
  return 1;
299
0
}
300
301
file_private int
302
cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
303
    const cdf_stream_t *sst, const cdf_directory_t *root_storage)
304
689
{
305
689
  cdf_summary_info_header_t si;
306
689
  cdf_property_info_t *info;
307
689
  size_t count;
308
689
  int m;
309
310
689
  if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
311
449
    return -1;
312
313
240
  if (NOTMIME(ms)) {
314
240
    const char *str;
315
316
240
    if (file_printf(ms, "Composite Document File V2 Document")
317
240
        == -1)
318
0
      return -1;
319
320
240
    if (file_printf(ms, ", %s Endian",
321
240
        si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
322
0
      return -2;
323
240
    switch (si.si_os) {
324
42
    case 2:
325
42
      if (file_printf(ms, ", Os: Windows, Version %d.%d",
326
42
          si.si_os_version & 0xff,
327
42
          CAST(uint32_t, si.si_os_version) >> 8) == -1)
328
0
        return -2;
329
42
      break;
330
42
    case 1:
331
26
      if (file_printf(ms, ", Os: MacOS, Version %d.%d",
332
26
          CAST(uint32_t, si.si_os_version) >> 8,
333
26
          si.si_os_version & 0xff) == -1)
334
0
        return -2;
335
26
      break;
336
172
    default:
337
172
      if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
338
172
          si.si_os_version & 0xff,
339
172
          CAST(uint32_t, si.si_os_version) >> 8) == -1)
340
0
        return -2;
341
172
      break;
342
240
    }
343
240
    if (root_storage) {
344
83
      str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
345
83
          clsid2desc);
346
83
      if (str) {
347
0
        if (file_printf(ms, ", %s", str) == -1)
348
0
          return -2;
349
0
      }
350
83
    }
351
240
  }
352
353
240
  m = cdf_file_property_info(ms, info, count, root_storage);
354
240
  free(info);
355
356
240
  return m == -1 ? -2 : m;
357
240
}
358
359
#ifdef notdef
360
file_private char *
361
format_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
362
  snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
363
      PRIx64 "-%.12" PRIx64,
364
      (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
365
      (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
366
      (uuid[0] >>  0) & (uint64_t)0x0000000000000ffffULL,
367
      (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
368
      (uuid[1] >>  0) & (uint64_t)0x0000fffffffffffffULL);
369
  return buf;
370
}
371
#endif
372
373
file_private int
374
cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
375
    const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
376
    const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
377
0
{
378
0
  int i;
379
380
0
  if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
381
0
      dir, "Catalog", scn)) == -1)
382
0
    return i;
383
#ifdef CDF_DEBUG
384
  cdf_dump_catalog(h, scn);
385
#endif
386
0
  if ((i = cdf_file_catalog(ms, h, scn)) == -1)
387
0
    return -1;
388
0
  return i;
389
0
}
390
391
file_private int
392
cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info,
393
    const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
394
    const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn,
395
    const cdf_directory_t *root_storage, const char **expn)
396
689
{
397
689
  int i;
398
689
  const char *str = NULL;
399
689
  cdf_directory_t *d;
400
689
  char name[__arraycount(d->d_name)];
401
689
  size_t j, k;
402
403
#ifdef CDF_DEBUG
404
  cdf_dump_summary_info(h, scn);
405
#endif
406
689
  if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) {
407
583
      *expn = "Can't expand summary_info";
408
583
      return i;
409
583
  }
410
106
  if (i == 1)
411
106
    return i;
412
0
  for (j = 0; str == NULL && j < dir->dir_len; j++) {
413
0
    d = &dir->dir_tab[j];
414
0
    for (k = 0; k < sizeof(name); k++)
415
0
      name[k] = CAST(char, cdf_tole2(d->d_name[k]));
416
0
    str = cdf_app_to_mime(name,
417
0
              NOTMIME(ms) ? name2desc : name2mime);
418
0
  }
419
0
  if (NOTMIME(ms)) {
420
0
    if (str != NULL) {
421
0
      if (file_printf(ms, "%s", str) == -1)
422
0
        return -1;
423
0
      i = 1;
424
0
    }
425
0
  } else if (ms->flags & MAGIC_MIME_TYPE) {
426
0
    if (str == NULL)
427
0
      str = "vnd.ms-office";
428
0
    if (file_printf(ms, "application/%s", str) == -1)
429
0
      return -1;
430
0
    i = 1;
431
0
  }
432
0
  if (i <= 0) {
433
0
    i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst,
434
0
            dir, scn);
435
0
  }
436
0
  return i;
437
0
}
438
439
file_private struct sinfo {
440
  const char *name;
441
  const char *mime;
442
  const char *sections[5];
443
  const int  types[5];
444
} sectioninfo[] = {
445
  { "Encrypted", "encrypted",
446
    {
447
      "EncryptedPackage", "EncryptedSummary",
448
      NULL, NULL, NULL,
449
    },
450
    {
451
      CDF_DIR_TYPE_USER_STREAM,
452
      CDF_DIR_TYPE_USER_STREAM,
453
      0, 0, 0,
454
455
    },
456
  },
457
  { "QuickBooks", "quickbooks",
458
    {
459
#if 0
460
      "TaxForms", "PDFTaxForms", "modulesInBackup",
461
#endif
462
      "mfbu_header", NULL, NULL, NULL, NULL,
463
    },
464
    {
465
#if 0
466
      CDF_DIR_TYPE_USER_STORAGE,
467
      CDF_DIR_TYPE_USER_STORAGE,
468
      CDF_DIR_TYPE_USER_STREAM,
469
#endif
470
      CDF_DIR_TYPE_USER_STREAM,
471
      0, 0, 0, 0
472
    },
473
  },
474
  { "Microsoft Excel", "vnd.ms-excel",
475
    {
476
      "Book", "Workbook", NULL, NULL, NULL,
477
    },
478
    {
479
      CDF_DIR_TYPE_USER_STREAM,
480
      CDF_DIR_TYPE_USER_STREAM,
481
      0, 0, 0,
482
    },
483
  },
484
  { "Microsoft Word", "msword",
485
    {
486
      "WordDocument", NULL, NULL, NULL, NULL,
487
    },
488
    {
489
      CDF_DIR_TYPE_USER_STREAM,
490
      0, 0, 0, 0,
491
    },
492
  },
493
  { "Microsoft PowerPoint", "vnd.ms-powerpoint",
494
    {
495
      "PowerPoint Document", NULL, NULL, NULL, NULL,
496
    },
497
    {
498
      CDF_DIR_TYPE_USER_STREAM,
499
      0, 0, 0, 0,
500
    },
501
  },
502
  { "Microsoft Outlook Message", "vnd.ms-outlook",
503
    {
504
      "__properties_version1.0",
505
      "__recip_version1.0_#00000000",
506
      NULL, NULL, NULL,
507
    },
508
    {
509
      CDF_DIR_TYPE_USER_STREAM,
510
      CDF_DIR_TYPE_USER_STORAGE,
511
      0, 0, 0,
512
    },
513
  },
514
};
515
516
file_private int
517
cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
518
731
{
519
731
  size_t sd, i, j;
520
731
  uint16_t *dir_name;
521
731
  int dir_type;
522
731
  const char* section_name;
523
524
7.86k
  for (i = 0; i < dir->dir_len; i++) {
525
7.15k
    dir_name = dir->dir_tab[i].d_name;
526
7.15k
    dir_type = dir->dir_tab[i].d_type;
527
528
50.0k
    for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
529
42.8k
      const struct sinfo *si = &sectioninfo[sd];
530
107k
      for (j = 0; si->sections[j]; j++) {
531
64.3k
        if (si->sections[j] == NULL)
532
0
          continue;
533
64.3k
        section_name = si->sections[j];
534
64.3k
        if (si->types[j] != dir_type ||
535
10.3k
            cdf_namecmp(section_name, dir_name,
536
10.3k
          strlen(section_name) + 1) != 0)
537
64.3k
            continue;
538
#ifdef CDF_DEBUG
539
        fprintf(stderr, "Matching directory %"
540
            SIZE_T_FORMAT
541
            "u with expected name \"%s\"\n",
542
            i, section_name);
543
#endif
544
24
        if (NOTMIME(ms)) {
545
24
          if (file_printf(ms, "CDFV2 %s",
546
24
              si->name) == -1)
547
0
            return -1;
548
24
        } else if (ms->flags & MAGIC_MIME_TYPE) {
549
0
          if (file_printf(ms, "application/%s",
550
0
              si->mime) == -1)
551
0
            return -1;
552
0
        }
553
24
        return 1;
554
24
      }
555
42.8k
    }
556
7.15k
  }
557
707
  return -1;
558
731
}
559
560
file_protected int
561
file_trycdf(struct magic_set *ms, const struct buffer *b)
562
12.1k
{
563
12.1k
  int fd = b->fd;
564
12.1k
  const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
565
12.1k
  size_t nbytes = b->flen;
566
12.1k
  cdf_info_t info;
567
12.1k
  cdf_header_t h;
568
12.1k
  cdf_sat_t sat, ssat;
569
12.1k
  cdf_stream_t sst, scn;
570
12.1k
  cdf_dir_t dir;
571
12.1k
  int i;
572
12.1k
  const char *expn = "";
573
12.1k
  const cdf_directory_t *root_storage;
574
575
12.1k
  scn.sst_tab = NULL;
576
12.1k
  info.i_fd = fd;
577
12.1k
  info.i_buf = buf;
578
12.1k
  info.i_len = nbytes;
579
12.1k
  if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
580
0
    return 0;
581
12.1k
  if (cdf_read_header(&info, &h) == -1)
582
10.7k
    return 0;
583
#ifdef CDF_DEBUG
584
  cdf_dump_header(&h);
585
#endif
586
587
1.40k
  if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
588
177
    expn = "Can't read SAT";
589
177
    goto out0;
590
177
  }
591
#ifdef CDF_DEBUG
592
  cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
593
#endif
594
595
1.22k
  if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
596
206
    expn = "Can't read SSAT";
597
206
    goto out1;
598
206
  }
599
#ifdef CDF_DEBUG
600
  cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
601
#endif
602
603
1.02k
  if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
604
92
    expn = "Can't read directory";
605
92
    goto out2;
606
92
  }
607
608
928
  if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
609
928
      &root_storage)) == -1) {
610
90
    expn = "Cannot read short stream";
611
90
    goto out3;
612
90
  }
613
#ifdef CDF_DEBUG
614
  cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
615
#endif
616
#ifdef notdef
617
  if (root_storage) {
618
    if (NOTMIME(ms)) {
619
      char clsbuf[128];
620
      if (file_printf(ms, "CLSID %s, ",
621
          format_clsid(clsbuf, sizeof(clsbuf),
622
          root_storage->d_storage_uuid)) == -1)
623
        return -1;
624
    }
625
  }
626
#endif
627
628
838
  if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
629
838
      "FileHeader", &scn) != -1) {
630
22
#define HWP5_SIGNATURE "HWP Document File"
631
8
    if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1
632
7
        && memcmp(scn.sst_tab, HWP5_SIGNATURE,
633
7
        sizeof(HWP5_SIGNATURE) - 1) == 0) {
634
1
        if (NOTMIME(ms)) {
635
1
      if (file_printf(ms,
636
1
          "Hancom HWP (Hangul Word Processor) file, version 5.0") == -1)
637
0
          return -1;
638
1
        } else if (ms->flags & MAGIC_MIME_TYPE) {
639
0
      if (file_printf(ms, "application/x-hwp") == -1)
640
0
          return -1;
641
0
        }
642
1
        i = 1;
643
1
        goto out5;
644
7
    } else {
645
7
        cdf_zero_stream(&scn);
646
7
    }
647
8
  }
648
649
837
  if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
650
837
      &scn)) == -1) {
651
254
    if (errno != ESRCH) {
652
124
      expn = "Cannot read summary info";
653
124
    }
654
583
  } else {
655
583
    i = cdf_check_summary_info(ms, &info, &h,
656
583
        &sat, &ssat, &sst, &dir, &scn, root_storage, &expn);
657
583
    cdf_zero_stream(&scn);
658
583
  }
659
837
  if (i <= 0) {
660
731
    if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat,
661
731
        &sst, &dir, &scn)) == -1) {
662
625
      if (errno != ESRCH) {
663
37
        expn = "Cannot read summary info";
664
37
      }
665
625
    } else {
666
106
      i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat,
667
106
          &sst, &dir, &scn, root_storage, &expn);
668
106
    }
669
731
  }
670
837
  if (i <= 0) {
671
731
    i = cdf_file_dir_info(ms, &dir);
672
731
    if (i < 0)
673
707
      expn = "Cannot read section info";
674
731
  }
675
838
out5:
676
838
  cdf_zero_stream(&scn);
677
838
  cdf_zero_stream(&sst);
678
928
out3:
679
928
  free(dir.dir_tab);
680
1.02k
out2:
681
1.02k
  free(ssat.sat_tab);
682
1.22k
out1:
683
1.22k
  free(sat.sat_tab);
684
1.40k
out0:
685
  /* If we handled it already, return */
686
1.40k
  if (i != -1)
687
131
    return i;
688
  /* Provide a default handler */
689
1.27k
  if (NOTMIME(ms)) {
690
1.27k
    if (file_printf(ms,
691
1.27k
        "Composite Document File V2 Document") == -1)
692
0
      return -1;
693
1.27k
    if (*expn)
694
1.27k
      if (file_printf(ms, ", %s", expn) == -1)
695
0
        return -1;
696
1.27k
  } else if (ms->flags & MAGIC_MIME_TYPE) {
697
    /* https://reposcope.com/mimetype/application/x-ole-storage */
698
0
    if (file_printf(ms, "application/x-ole-storage") == -1)
699
0
      return -1;
700
0
  }
701
1.27k
  return 1;
702
1.27k
}