1 /* $NetBSD: readcdf.c,v 1.12 2015/01/02 21:15:32 christos Exp $ */
4 * Copyright (c) 2008 Christos Zoulas
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
32 FILE_RCSID("@(#)$File: readcdf.c,v 1.49 2014/12/04 15:56:46 christos Exp $")
34 __RCSID("$NetBSD: readcdf.c,v 1.12 2015/01/02 21:15:32 christos Exp $");
49 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
52 #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
54 static const struct nv
{
58 { "Word", "msword", },
59 { "Excel", "vnd.ms-excel", },
60 { "Powerpoint", "vnd.ms-powerpoint", },
61 { "Crystal Reports", "x-rpt", },
62 { "Advanced Installer", "vnd.ms-msi", },
63 { "InstallShield", "vnd.ms-msi", },
64 { "Microsoft Patch Compiler", "vnd.ms-msi", },
65 { "NAnt", "vnd.ms-msi", },
66 { "Windows Installer", "vnd.ms-msi", },
69 { "WordDocument", "msword", },
70 { "PowerPoint", "vnd.ms-powerpoint", },
71 { "DigitalSignature", "vnd.ms-msi", },
74 { "WordDocument", "Microsoft Office Word",},
75 { "PowerPoint", "Microsoft PowerPoint", },
76 { "DigitalSignature", "Microsoft Installer", },
80 static const struct cv
{
85 { 0x00000000000c1084ULL
, 0x46000000000000c0ULL
},
93 { 0x00000000000c1084ULL
, 0x46000000000000c0ULL
},
102 cdf_clsid_to_mime(const uint64_t clsid
[2], const struct cv
*cv
)
105 for (i
= 0; cv
[i
].mime
!= NULL
; i
++) {
106 if (clsid
[0] == cv
[i
].clsid
[0] && clsid
[1] == cv
[i
].clsid
[1])
113 cdf_app_to_mime(const char *vbuf
, const struct nv
*nv
)
116 const char *rv
= NULL
;
118 locale_t old_lc_ctype
, c_lc_ctype
;
120 c_lc_ctype
= newlocale(LC_CTYPE_MASK
, "C", 0);
121 assert(c_lc_ctype
!= NULL
);
122 old_lc_ctype
= uselocale(c_lc_ctype
);
123 assert(old_lc_ctype
!= NULL
);
125 for (i
= 0; nv
[i
].pattern
!= NULL
; i
++)
126 if (strcasestr(vbuf
, nv
[i
].pattern
) != NULL
) {
131 (void)uselocale(old_lc_ctype
);
132 freelocale(c_lc_ctype
);
138 cdf_file_property_info(struct magic_set
*ms
, const cdf_property_info_t
*info
,
139 size_t count
, const cdf_directory_t
*root_storage
)
145 const char *str
= NULL
;
149 if (!NOTMIME(ms
) && root_storage
)
150 str
= cdf_clsid_to_mime(root_storage
->d_storage_uuid
,
153 for (i
= 0; i
< count
; i
++) {
154 cdf_print_property_name(buf
, sizeof(buf
), info
[i
].pi_id
);
155 switch (info
[i
].pi_type
) {
159 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %hd", buf
,
160 info
[i
].pi_s16
) == -1)
164 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %d", buf
,
165 info
[i
].pi_s32
) == -1)
169 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %u", buf
,
170 info
[i
].pi_u32
) == -1)
174 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %g", buf
,
179 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %g", buf
,
183 case CDF_LENGTH32_STRING
:
184 case CDF_LENGTH32_WSTRING
:
185 len
= info
[i
].pi_str
.s_len
;
190 if (info
[i
].pi_type
== CDF_LENGTH32_WSTRING
)
192 s
= info
[i
].pi_str
.s_buf
;
193 for (j
= 0; j
< sizeof(vbuf
) && len
--; s
+= k
) {
196 if (isprint((unsigned char)*s
))
199 if (j
== sizeof(vbuf
))
204 if (file_printf(ms
, ", %s: %s",
208 } else if (str
== NULL
&& info
[i
].pi_id
==
209 CDF_PROPERTY_NAME_OF_APPLICATION
) {
210 str
= cdf_app_to_mime(vbuf
, app2mime
);
218 if (tp
< 1000000000000000LL) {
219 cdf_print_elapsed_time(tbuf
,
221 if (NOTMIME(ms
) && file_printf(ms
,
222 ", %s: %s", buf
, tbuf
) == -1)
226 cdf_timestamp_to_timespec(&ts
, tp
);
227 c
= cdf_ctime(&ts
.tv_sec
, tbuf
);
229 (ec
= strchr(c
, '\n')) != NULL
)
232 if (NOTMIME(ms
) && file_printf(ms
,
233 ", %s: %s", buf
, c
) == -1)
247 if (file_printf(ms
, "application/%s", str
) == -1)
254 cdf_file_catalog(struct magic_set
*ms
, const cdf_header_t
*h
,
255 const cdf_stream_t
*sst
)
260 cdf_catalog_entry_t
*ce
;
263 if (file_printf(ms
, "Microsoft Thumbs.db [") == -1)
265 if (cdf_unpack_catalog(h
, sst
, &cat
) == -1)
268 /* skip first entry since it has a , or paren */
269 for (i
= 1; i
< cat
->cat_num
; i
++)
270 if (file_printf(ms
, "%s%s",
271 cdf_u16tos8(buf
, ce
[i
].ce_namlen
, ce
[i
].ce_name
),
272 i
== cat
->cat_num
- 1 ? "]" : ", ") == -1) {
278 if (file_printf(ms
, "application/CDFV2") == -1)
285 cdf_file_summary_info(struct magic_set
*ms
, const cdf_header_t
*h
,
286 const cdf_stream_t
*sst
, const cdf_directory_t
*root_storage
)
288 cdf_summary_info_header_t si
;
289 cdf_property_info_t
*info
;
293 if (cdf_unpack_summary_info(sst
, h
, &si
, &info
, &count
) == -1)
299 if (file_printf(ms
, "Composite Document File V2 Document")
303 if (file_printf(ms
, ", %s Endian",
304 si
.si_byte_order
== 0xfffe ? "Little" : "Big") == -1)
308 if (file_printf(ms
, ", Os: Windows, Version %d.%d",
309 si
.si_os_version
& 0xff,
310 (uint32_t)si
.si_os_version
>> 8) == -1)
314 if (file_printf(ms
, ", Os: MacOS, Version %d.%d",
315 (uint32_t)si
.si_os_version
>> 8,
316 si
.si_os_version
& 0xff) == -1)
320 if (file_printf(ms
, ", Os %d, Version: %d.%d", si
.si_os
,
321 si
.si_os_version
& 0xff,
322 (uint32_t)si
.si_os_version
>> 8) == -1)
327 str
= cdf_clsid_to_mime(root_storage
->d_storage_uuid
,
330 if (file_printf(ms
, ", %s", str
) == -1)
336 m
= cdf_file_property_info(ms
, info
, count
, root_storage
);
339 return m
== -1 ? -2 : m
;
344 format_clsid(char *buf
, size_t len
, const uint64_t uuid
[2]) {
345 snprintf(buf
, len
, "%.8" PRIx64
"-%.4" PRIx64
"-%.4" PRIx64
"-%.4"
346 PRIx64
"-%.12" PRIx64
,
347 (uuid
[0] >> 32) & (uint64_t)0x000000000ffffffffULL
,
348 (uuid
[0] >> 16) & (uint64_t)0x0000000000000ffffULL
,
349 (uuid
[0] >> 0) & (uint64_t)0x0000000000000ffffULL
,
350 (uuid
[1] >> 48) & (uint64_t)0x0000000000000ffffULL
,
351 (uuid
[1] >> 0) & (uint64_t)0x0000fffffffffffffULL
);
357 file_trycdf(struct magic_set
*ms
, int fd
, const unsigned char *buf
,
363 cdf_stream_t sst
, scn
;
366 const char *expn
= "";
367 const char *corrupt
= "corrupt: ";
368 const cdf_directory_t
*root_storage
;
373 if (ms
->flags
& MAGIC_APPLE
)
375 if (cdf_read_header(&info
, &h
) == -1)
381 if ((i
= cdf_read_sat(&info
, &h
, &sat
)) == -1) {
382 expn
= "Can't read SAT";
386 cdf_dump_sat("SAT", &sat
, CDF_SEC_SIZE(&h
));
389 if ((i
= cdf_read_ssat(&info
, &h
, &sat
, &ssat
)) == -1) {
390 expn
= "Can't read SSAT";
394 cdf_dump_sat("SSAT", &ssat
, CDF_SHORT_SEC_SIZE(&h
));
397 if ((i
= cdf_read_dir(&info
, &h
, &sat
, &dir
)) == -1) {
398 expn
= "Can't read directory";
402 if ((i
= cdf_read_short_stream(&info
, &h
, &sat
, &dir
, &sst
,
403 &root_storage
)) == -1) {
404 expn
= "Cannot read short stream";
408 cdf_dump_dir(&info
, &h
, &sat
, &ssat
, &sst
, &dir
);
414 if (file_printf(ms
, "CLSID %s, ",
415 format_clsid(clsbuf
, sizeof(clsbuf
),
416 root_storage
->d_storage_uuid
)) == -1)
422 if ((i
= cdf_read_user_stream(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
423 "FileHeader", &scn
)) != -1) {
424 #define HWP5_SIGNATURE "HWP Document File"
425 if (scn
.sst_dirlen
>= sizeof(HWP5_SIGNATURE
) - 1
426 && memcmp(scn
.sst_tab
, HWP5_SIGNATURE
,
427 sizeof(HWP5_SIGNATURE
) - 1) == 0) {
430 "Hangul (Korean) Word Processor File 5.x") == -1)
433 if (file_printf(ms
, "application/x-hwp") == -1)
446 if ((i
= cdf_read_summary_info(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
448 if (errno
== ESRCH
) {
449 if ((i
= cdf_read_catalog(&info
, &h
, &sat
, &ssat
, &sst
,
450 &dir
, &scn
)) == -1) {
452 if ((i
= cdf_read_encrypted_package(&info
, &h
,
453 &sat
, &ssat
, &sst
, &dir
, &scn
)) == -1)
454 expn
= "No summary info";
462 cdf_dump_catalog(&h
, &scn
);
464 if ((i
= cdf_file_catalog(ms
, &h
, &scn
))
466 expn
= "Can't expand catalog";
468 expn
= "Cannot read summary info";
473 cdf_dump_summary_info(&h
, &scn
);
475 if ((i
= cdf_file_summary_info(ms
, &h
, &scn
, root_storage
)) < 0)
476 expn
= "Can't expand summary_info";
479 const char *str
= NULL
;
481 char name
[__arraycount(d
->d_name
)];
484 for (j
= 0; str
== NULL
&& j
< dir
.dir_len
; j
++) {
486 for (k
= 0; k
< sizeof(name
); k
++)
487 name
[k
] = (char)cdf_tole2(d
->d_name
[k
]);
488 str
= cdf_app_to_mime(name
,
489 NOTMIME(ms
) ? name2desc
: name2mime
);
493 if (file_printf(ms
, "%s", str
) == -1)
499 str
= "vnd.ms-office";
500 if (file_printf(ms
, "application/%s", str
) == -1)
519 "Composite Document File V2 Document") == -1)
522 if (file_printf(ms
, ", %s%s", corrupt
, expn
) == -1)
525 if (file_printf(ms
, "application/CDFV2-%s",
526 *corrupt
? "corrupt" : "encrypted") == -1)