Coverage Report

Created: 2023-09-25 07:18

/src/file/src/readcdf.c
Line
Count
Source (jump to first uncovered line)
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.80 2023/01/24 20:13:40 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.36k
#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
166
{
98
166
  size_t i;
99
331
  for (i = 0; cv[i].mime != NULL; i++) {
100
166
    if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
101
1
      return cv[i].mime;
102
166
  }
103
#ifdef CDF_DEBUG
104
  fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
105
      clsid[1]);
106
#endif
107
165
  return NULL;
108
166
}
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
384
{
151
384
  size_t i;
152
384
  cdf_timestamp_t tp;
153
384
  struct timespec ts;
154
384
  char buf[64];
155
384
  const char *str = NULL;
156
384
  const char *s, *e;
157
384
  int len;
158
159
384
  if (!NOTMIME(ms) && root_storage)
160
0
    str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
161
0
        clsid2mime);
162
163
1.39k
  for (i = 0; i < count; i++) {
164
1.26k
    cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
165
1.26k
    switch (info[i].pi_type) {
166
95
    case CDF_NULL:
167
95
      break;
168
39
    case CDF_SIGNED16:
169
39
      if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
170
39
          info[i].pi_s16) == -1)
171
0
        return -1;
172
39
      break;
173
57
    case CDF_SIGNED32:
174
57
      if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
175
57
          info[i].pi_s32) == -1)
176
0
        return -1;
177
57
      break;
178
57
    case CDF_UNSIGNED32:
179
47
      if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
180
47
          info[i].pi_u32) == -1)
181
0
        return -1;
182
47
      break;
183
84
    case CDF_FLOAT:
184
84
      if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
185
84
          info[i].pi_f) == -1)
186
0
        return -1;
187
84
      break;
188
84
    case CDF_DOUBLE:
189
54
      if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
190
54
          info[i].pi_d) == -1)
191
0
        return -1;
192
54
      break;
193
84
    case CDF_LENGTH32_STRING:
194
186
    case CDF_LENGTH32_WSTRING:
195
186
      len = info[i].pi_str.s_len;
196
186
      if (len > 1) {
197
150
        char vbuf[1024];
198
150
        size_t j, k = 1;
199
200
150
        if (info[i].pi_type == CDF_LENGTH32_WSTRING)
201
79
            k++;
202
150
        s = info[i].pi_str.s_buf;
203
150
        e = info[i].pi_str.s_buf + len;
204
37.6k
        for (j = 0; s < e && j < sizeof(vbuf)
205
37.6k
            && len--; s += k) {
206
37.6k
          if (*s == '\0')
207
105
            break;
208
37.5k
          if (isprint(CAST(unsigned char, *s)))
209
35.6k
            vbuf[j++] = *s;
210
37.5k
        }
211
150
        if (j == sizeof(vbuf))
212
17
          --j;
213
150
        vbuf[j] = '\0';
214
150
        if (NOTMIME(ms)) {
215
150
          if (vbuf[0]) {
216
100
            if (file_printf(ms, ", %s: %s",
217
100
                buf, vbuf) == -1)
218
11
              return -1;
219
100
          }
220
150
        } 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
0
        }
224
150
      }
225
175
      break;
226
424
    case CDF_FILETIME:
227
424
      tp = info[i].pi_tp;
228
424
      if (tp != 0) {
229
383
        char tbuf[64];
230
383
        if (tp < 1000000000000000LL) {
231
226
          cdf_print_elapsed_time(tbuf,
232
226
              sizeof(tbuf), tp);
233
226
          if (NOTMIME(ms) && file_printf(ms,
234
226
              ", %s: %s", buf, tbuf) == -1)
235
0
            return -1;
236
226
        } else {
237
157
          char *c, *ec;
238
157
          cdf_timestamp_to_timespec(&ts, tp);
239
157
          c = cdf_ctime(&ts.tv_sec, tbuf);
240
157
          if (c != NULL &&
241
157
              (ec = strchr(c, '\n')) != NULL)
242
157
            *ec = '\0';
243
244
157
          if (NOTMIME(ms) && file_printf(ms,
245
157
              ", %s: %s", buf, c) == -1)
246
0
            return -1;
247
157
        }
248
383
      }
249
424
      break;
250
424
    case CDF_CLIPBOARD:
251
37
      break;
252
240
    default:
253
240
      return -1;
254
1.26k
    }
255
1.26k
  }
256
133
  if (ms->flags & MAGIC_MIME_TYPE) {
257
0
    if (str == NULL)
258
0
      return 0;
259
0
    if (file_printf(ms, "application/%s", str) == -1)
260
0
      return -1;
261
0
  }
262
133
  return 1;
263
133
}
264
265
file_private int
266
cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
267
    const cdf_stream_t *sst)
268
0
{
269
0
  cdf_catalog_t *cat;
270
0
  size_t i;
271
0
  char buf[256];
272
0
  cdf_catalog_entry_t *ce;
273
274
0
  if (NOTMIME(ms)) {
275
0
    if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
276
0
      return -1;
277
0
    if (cdf_unpack_catalog(h, sst, &cat) == -1)
278
0
      return -1;
279
0
    ce = cat->cat_e;
280
    /* skip first entry since it has a , or paren */
281
0
    for (i = 1; i < cat->cat_num; i++)
282
0
      if (file_printf(ms, "%s%s",
283
0
          cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
284
0
          i == cat->cat_num - 1 ? "]" : ", ") == -1) {
285
0
        free(cat);
286
0
        return -1;
287
0
      }
288
0
    free(cat);
289
0
  } else if (ms->flags & MAGIC_MIME_TYPE) {
290
0
    if (file_printf(ms, "application/CDFV2") == -1)
291
0
      return -1;
292
0
  }
293
0
  return 1;
294
0
}
295
296
file_private int
297
cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
298
    const cdf_stream_t *sst, const cdf_directory_t *root_storage)
299
914
{
300
914
  cdf_summary_info_header_t si;
301
914
  cdf_property_info_t *info;
302
914
  size_t count;
303
914
  int m;
304
305
914
  if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
306
530
    return -1;
307
308
384
  if (NOTMIME(ms)) {
309
384
    const char *str;
310
311
384
    if (file_printf(ms, "Composite Document File V2 Document")
312
384
        == -1)
313
0
      return -1;
314
315
384
    if (file_printf(ms, ", %s Endian",
316
384
        si.si_byte_order == 0xfffe ?  "Little" : "Big") == -1)
317
0
      return -2;
318
384
    switch (si.si_os) {
319
21
    case 2:
320
21
      if (file_printf(ms, ", Os: Windows, Version %d.%d",
321
21
          si.si_os_version & 0xff,
322
21
          CAST(uint32_t, si.si_os_version) >> 8) == -1)
323
0
        return -2;
324
21
      break;
325
21
    case 1:
326
12
      if (file_printf(ms, ", Os: MacOS, Version %d.%d",
327
12
          CAST(uint32_t, si.si_os_version) >> 8,
328
12
          si.si_os_version & 0xff) == -1)
329
0
        return -2;
330
12
      break;
331
351
    default:
332
351
      if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
333
351
          si.si_os_version & 0xff,
334
351
          CAST(uint32_t, si.si_os_version) >> 8) == -1)
335
0
        return -2;
336
351
      break;
337
384
    }
338
384
    if (root_storage) {
339
166
      str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
340
166
          clsid2desc);
341
166
      if (str) {
342
1
        if (file_printf(ms, ", %s", str) == -1)
343
0
          return -2;
344
1
      }
345
166
    }
346
384
  }
347
348
384
  m = cdf_file_property_info(ms, info, count, root_storage);
349
384
  free(info);
350
351
384
  return m == -1 ? -2 : m;
352
384
}
353
354
#ifdef notdef
355
file_private char *
356
format_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
357
  snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
358
      PRIx64 "-%.12" PRIx64,
359
      (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
360
      (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
361
      (uuid[0] >>  0) & (uint64_t)0x0000000000000ffffULL,
362
      (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
363
      (uuid[1] >>  0) & (uint64_t)0x0000fffffffffffffULL);
364
  return buf;
365
}
366
#endif
367
368
file_private int
369
cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
370
    const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
371
    const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
372
0
{
373
0
  int i;
374
375
0
  if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
376
0
      dir, "Catalog", scn)) == -1)
377
0
    return i;
378
#ifdef CDF_DEBUG
379
  cdf_dump_catalog(h, scn);
380
#endif
381
0
  if ((i = cdf_file_catalog(ms, h, scn)) == -1)
382
0
    return -1;
383
0
  return i;
384
0
}
385
386
file_private int
387
cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info,
388
    const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
389
    const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn,
390
    const cdf_directory_t *root_storage, const char **expn)
391
914
{
392
914
  int i;
393
914
  const char *str = NULL;
394
914
  cdf_directory_t *d;
395
914
  char name[__arraycount(d->d_name)];
396
914
  size_t j, k;
397
398
#ifdef CDF_DEBUG
399
  cdf_dump_summary_info(h, scn);
400
#endif
401
914
  if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) {
402
781
      *expn = "Can't expand summary_info";
403
781
      return i;
404
781
  }
405
133
  if (i == 1)
406
133
    return i;
407
0
  for (j = 0; str == NULL && j < dir->dir_len; j++) {
408
0
    d = &dir->dir_tab[j];
409
0
    for (k = 0; k < sizeof(name); k++)
410
0
      name[k] = CAST(char, cdf_tole2(d->d_name[k]));
411
0
    str = cdf_app_to_mime(name,
412
0
              NOTMIME(ms) ? name2desc : name2mime);
413
0
  }
414
0
  if (NOTMIME(ms)) {
415
0
    if (str != NULL) {
416
0
      if (file_printf(ms, "%s", str) == -1)
417
0
        return -1;
418
0
      i = 1;
419
0
    }
420
0
  } else if (ms->flags & MAGIC_MIME_TYPE) {
421
0
    if (str == NULL)
422
0
      str = "vnd.ms-office";
423
0
    if (file_printf(ms, "application/%s", str) == -1)
424
0
      return -1;
425
0
    i = 1;
426
0
  }
427
0
  if (i <= 0) {
428
0
    i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst,
429
0
            dir, scn);
430
0
  }
431
0
  return i;
432
0
}
433
434
file_private struct sinfo {
435
  const char *name;
436
  const char *mime;
437
  const char *sections[5];
438
  const int  types[5];
439
} sectioninfo[] = {
440
  { "Encrypted", "encrypted",
441
    {
442
      "EncryptedPackage", "EncryptedSummary",
443
      NULL, NULL, NULL,
444
    },
445
    {
446
      CDF_DIR_TYPE_USER_STREAM,
447
      CDF_DIR_TYPE_USER_STREAM,
448
      0, 0, 0,
449
450
    },
451
  },
452
  { "QuickBooks", "quickbooks",
453
    {
454
#if 0
455
      "TaxForms", "PDFTaxForms", "modulesInBackup",
456
#endif
457
      "mfbu_header", NULL, NULL, NULL, NULL,
458
    },
459
    {
460
#if 0
461
      CDF_DIR_TYPE_USER_STORAGE,
462
      CDF_DIR_TYPE_USER_STORAGE,
463
      CDF_DIR_TYPE_USER_STREAM,
464
#endif
465
      CDF_DIR_TYPE_USER_STREAM,
466
      0, 0, 0, 0
467
    },
468
  },
469
  { "Microsoft Excel", "vnd.ms-excel",
470
    {
471
      "Book", "Workbook", NULL, NULL, NULL,
472
    },
473
    {
474
      CDF_DIR_TYPE_USER_STREAM,
475
      CDF_DIR_TYPE_USER_STREAM,
476
      0, 0, 0,
477
    },
478
  },
479
  { "Microsoft Word", "msword",
480
    {
481
      "WordDocument", NULL, NULL, NULL, NULL,
482
    },
483
    {
484
      CDF_DIR_TYPE_USER_STREAM,
485
      0, 0, 0, 0,
486
    },
487
  },
488
  { "Microsoft PowerPoint", "vnd.ms-powerpoint",
489
    {
490
      "PowerPoint", NULL, NULL, NULL, NULL,
491
    },
492
    {
493
      CDF_DIR_TYPE_USER_STREAM,
494
      0, 0, 0, 0,
495
    },
496
  },
497
  { "Microsoft Outlook Message", "vnd.ms-outlook",
498
    {
499
      "__properties_version1.0",
500
      "__recip_version1.0_#00000000",
501
      NULL, NULL, NULL,
502
    },
503
    {
504
      CDF_DIR_TYPE_USER_STREAM,
505
      CDF_DIR_TYPE_USER_STORAGE,
506
      0, 0, 0,
507
    },
508
  },
509
};
510
511
file_private int
512
cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
513
1.06k
{
514
1.06k
  size_t sd, j;
515
516
7.45k
  for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
517
6.39k
    const struct sinfo *si = &sectioninfo[sd];
518
15.9k
    for (j = 0; si->sections[j]; j++) {
519
9.58k
      if (cdf_find_stream(dir, si->sections[j], si->types[j])
520
9.58k
          > 0)
521
7
        break;
522
#ifdef CDF_DEBUG
523
      fprintf(stderr, "Can't read %s\n", si->sections[j]);
524
#endif
525
9.58k
    }
526
6.39k
    if (si->sections[j] == NULL)
527
6.38k
      continue;
528
7
    if (NOTMIME(ms)) {
529
7
      if (file_printf(ms, "CDFV2 %s", si->name) == -1)
530
0
        return -1;
531
7
    } else if (ms->flags & MAGIC_MIME_TYPE) {
532
0
      if (file_printf(ms, "application/%s", si->mime) == -1)
533
0
        return -1;
534
0
    }
535
7
    return 1;
536
7
  }
537
1.06k
  return -1;
538
1.06k
}
539
540
file_protected int
541
file_trycdf(struct magic_set *ms, const struct buffer *b)
542
10.2k
{
543
10.2k
  int fd = b->fd;
544
10.2k
  const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
545
10.2k
  size_t nbytes = b->flen;
546
10.2k
  cdf_info_t info;
547
10.2k
  cdf_header_t h;
548
10.2k
  cdf_sat_t sat, ssat;
549
10.2k
  cdf_stream_t sst, scn;
550
10.2k
  cdf_dir_t dir;
551
10.2k
  int i;
552
10.2k
  const char *expn = "";
553
10.2k
  const cdf_directory_t *root_storage;
554
555
10.2k
  scn.sst_tab = NULL;
556
10.2k
  info.i_fd = fd;
557
10.2k
  info.i_buf = buf;
558
10.2k
  info.i_len = nbytes;
559
10.2k
  if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
560
0
    return 0;
561
10.2k
  if (cdf_read_header(&info, &h) == -1)
562
8.39k
    return 0;
563
#ifdef CDF_DEBUG
564
  cdf_dump_header(&h);
565
#endif
566
567
1.86k
  if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
568
170
    expn = "Can't read SAT";
569
170
    goto out0;
570
170
  }
571
#ifdef CDF_DEBUG
572
  cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
573
#endif
574
575
1.69k
  if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
576
249
    expn = "Can't read SSAT";
577
249
    goto out1;
578
249
  }
579
#ifdef CDF_DEBUG
580
  cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
581
#endif
582
583
1.44k
  if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
584
128
    expn = "Can't read directory";
585
128
    goto out2;
586
128
  }
587
588
1.31k
  if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
589
1.31k
      &root_storage)) == -1) {
590
118
    expn = "Cannot read short stream";
591
118
    goto out3;
592
118
  }
593
#ifdef CDF_DEBUG
594
  cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
595
#endif
596
#ifdef notdef
597
  if (root_storage) {
598
    if (NOTMIME(ms)) {
599
      char clsbuf[128];
600
      if (file_printf(ms, "CLSID %s, ",
601
          format_clsid(clsbuf, sizeof(clsbuf),
602
          root_storage->d_storage_uuid)) == -1)
603
        return -1;
604
    }
605
  }
606
#endif
607
608
1.20k
  if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
609
1.20k
      "FileHeader", &scn) != -1) {
610
93
#define HWP5_SIGNATURE "HWP Document File"
611
37
    if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1
612
37
        && memcmp(scn.sst_tab, HWP5_SIGNATURE,
613
28
        sizeof(HWP5_SIGNATURE) - 1) == 0) {
614
1
        if (NOTMIME(ms)) {
615
1
      if (file_printf(ms,
616
1
          "Hancom HWP (Hangul Word Processor) file, version 5.0") == -1)
617
0
          return -1;
618
1
        } else if (ms->flags & MAGIC_MIME_TYPE) {
619
0
      if (file_printf(ms, "application/x-hwp") == -1)
620
0
          return -1;
621
0
        }
622
1
        i = 1;
623
1
        goto out5;
624
36
    } else {
625
36
        cdf_zero_stream(&scn);
626
36
    }
627
37
  }
628
629
1.20k
  if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
630
1.20k
      &scn)) == -1) {
631
427
    if (errno != ESRCH) {
632
77
      expn = "Cannot read summary info";
633
77
    }
634
773
  } else {
635
773
    i = cdf_check_summary_info(ms, &info, &h,
636
773
        &sat, &ssat, &sst, &dir, &scn, root_storage, &expn);
637
773
    cdf_zero_stream(&scn);
638
773
  }
639
1.20k
  if (i <= 0) {
640
1.06k
    if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat,
641
1.06k
        &sst, &dir, &scn)) == -1) {
642
928
      if (errno != ESRCH) {
643
27
        expn = "Cannot read summary info";
644
27
      }
645
928
    } else {
646
141
      i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat,
647
141
          &sst, &dir, &scn, root_storage, &expn);
648
141
    }
649
1.06k
  }
650
1.20k
  if (i <= 0) {
651
1.06k
    i = cdf_file_dir_info(ms, &dir);
652
1.06k
    if (i < 0)
653
1.06k
      expn = "Cannot read section info";
654
1.06k
  }
655
1.20k
out5:
656
1.20k
  cdf_zero_stream(&scn);
657
1.20k
  cdf_zero_stream(&sst);
658
1.31k
out3:
659
1.31k
  free(dir.dir_tab);
660
1.44k
out2:
661
1.44k
  free(ssat.sat_tab);
662
1.69k
out1:
663
1.69k
  free(sat.sat_tab);
664
1.86k
out0:
665
  /* If we handled it already, return */
666
1.86k
  if (i != -1)
667
141
    return i;
668
  /* Provide a default handler */
669
1.72k
  if (NOTMIME(ms)) {
670
1.72k
    if (file_printf(ms,
671
1.72k
        "Composite Document File V2 Document") == -1)
672
0
      return -1;
673
1.72k
    if (*expn)
674
1.72k
      if (file_printf(ms, ", %s", expn) == -1)
675
0
        return -1;
676
1.72k
  } else if (ms->flags & MAGIC_MIME_TYPE) {
677
    /* https://reposcope.com/mimetype/application/x-ole-storage */
678
0
    if (file_printf(ms, "application/x-ole-storage") == -1)
679
0
      return -1;
680
0
  }
681
1.72k
  return 1;
682
1.72k
}