2 * Copyright (c) 2008 Christos Zoulas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
29 FILE_RCSID("@(#)$File: readcdf.c,v 1.49 2014/12/04 15:56:46 christos Exp $")
42 #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
44 static const struct nv
{
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", },
59 { "WordDocument", "msword", },
60 { "PowerPoint", "vnd.ms-powerpoint", },
61 { "DigitalSignature", "vnd.ms-msi", },
64 { "WordDocument", "Microsoft Office Word",},
65 { "PowerPoint", "Microsoft PowerPoint", },
66 { "DigitalSignature", "Microsoft Installer", },
70 static const struct cv
{
75 { 0x00000000000c1084ULL
, 0x46000000000000c0ULL
},
83 { 0x00000000000c1084ULL
, 0x46000000000000c0ULL
},
92 cdf_clsid_to_mime(const uint64_t clsid
[2], const struct cv
*cv
)
95 for (i
= 0; cv
[i
].mime
!= NULL
; i
++) {
96 if (clsid
[0] == cv
[i
].clsid
[0] && clsid
[1] == cv
[i
].clsid
[1])
103 cdf_app_to_mime(const char *vbuf
, const struct nv
*nv
)
106 const char *rv
= NULL
;
108 locale_t old_lc_ctype
, c_lc_ctype
;
110 c_lc_ctype
= newlocale(LC_CTYPE_MASK
, "C", 0);
111 assert(c_lc_ctype
!= NULL
);
112 old_lc_ctype
= uselocale(c_lc_ctype
);
113 assert(old_lc_ctype
!= NULL
);
115 for (i
= 0; nv
[i
].pattern
!= NULL
; i
++)
116 if (strcasestr(vbuf
, nv
[i
].pattern
) != NULL
) {
121 (void)uselocale(old_lc_ctype
);
122 freelocale(c_lc_ctype
);
128 cdf_file_property_info(struct magic_set
*ms
, const cdf_property_info_t
*info
,
129 size_t count
, const cdf_directory_t
*root_storage
)
135 const char *str
= NULL
;
139 if (!NOTMIME(ms
) && root_storage
)
140 str
= cdf_clsid_to_mime(root_storage
->d_storage_uuid
,
143 for (i
= 0; i
< count
; i
++) {
144 cdf_print_property_name(buf
, sizeof(buf
), info
[i
].pi_id
);
145 switch (info
[i
].pi_type
) {
149 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %hd", buf
,
150 info
[i
].pi_s16
) == -1)
154 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %d", buf
,
155 info
[i
].pi_s32
) == -1)
159 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %u", buf
,
160 info
[i
].pi_u32
) == -1)
164 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %g", buf
,
169 if (NOTMIME(ms
) && file_printf(ms
, ", %s: %g", buf
,
173 case CDF_LENGTH32_STRING
:
174 case CDF_LENGTH32_WSTRING
:
175 len
= info
[i
].pi_str
.s_len
;
180 if (info
[i
].pi_type
== CDF_LENGTH32_WSTRING
)
182 s
= info
[i
].pi_str
.s_buf
;
183 for (j
= 0; j
< sizeof(vbuf
) && len
--; s
+= k
) {
186 if (isprint((unsigned char)*s
))
189 if (j
== sizeof(vbuf
))
194 if (file_printf(ms
, ", %s: %s",
198 } else if (str
== NULL
&& info
[i
].pi_id
==
199 CDF_PROPERTY_NAME_OF_APPLICATION
) {
200 str
= cdf_app_to_mime(vbuf
, app2mime
);
208 if (tp
< 1000000000000000LL) {
209 cdf_print_elapsed_time(tbuf
,
211 if (NOTMIME(ms
) && file_printf(ms
,
212 ", %s: %s", buf
, tbuf
) == -1)
216 cdf_timestamp_to_timespec(&ts
, tp
);
217 c
= cdf_ctime(&ts
.tv_sec
, tbuf
);
219 (ec
= strchr(c
, '\n')) != NULL
)
222 if (NOTMIME(ms
) && file_printf(ms
,
223 ", %s: %s", buf
, c
) == -1)
237 if (file_printf(ms
, "application/%s", str
) == -1)
244 cdf_file_catalog(struct magic_set
*ms
, const cdf_header_t
*h
,
245 const cdf_stream_t
*sst
)
250 cdf_catalog_entry_t
*ce
;
253 if (file_printf(ms
, "Microsoft Thumbs.db [") == -1)
255 if (cdf_unpack_catalog(h
, sst
, &cat
) == -1)
258 /* skip first entry since it has a , or paren */
259 for (i
= 1; i
< cat
->cat_num
; i
++)
260 if (file_printf(ms
, "%s%s",
261 cdf_u16tos8(buf
, ce
[i
].ce_namlen
, ce
[i
].ce_name
),
262 i
== cat
->cat_num
- 1 ? "]" : ", ") == -1) {
268 if (file_printf(ms
, "application/CDFV2") == -1)
275 cdf_file_summary_info(struct magic_set
*ms
, const cdf_header_t
*h
,
276 const cdf_stream_t
*sst
, const cdf_directory_t
*root_storage
)
278 cdf_summary_info_header_t si
;
279 cdf_property_info_t
*info
;
283 if (cdf_unpack_summary_info(sst
, h
, &si
, &info
, &count
) == -1)
289 if (file_printf(ms
, "Composite Document File V2 Document")
293 if (file_printf(ms
, ", %s Endian",
294 si
.si_byte_order
== 0xfffe ? "Little" : "Big") == -1)
298 if (file_printf(ms
, ", Os: Windows, Version %d.%d",
299 si
.si_os_version
& 0xff,
300 (uint32_t)si
.si_os_version
>> 8) == -1)
304 if (file_printf(ms
, ", Os: MacOS, Version %d.%d",
305 (uint32_t)si
.si_os_version
>> 8,
306 si
.si_os_version
& 0xff) == -1)
310 if (file_printf(ms
, ", Os %d, Version: %d.%d", si
.si_os
,
311 si
.si_os_version
& 0xff,
312 (uint32_t)si
.si_os_version
>> 8) == -1)
317 str
= cdf_clsid_to_mime(root_storage
->d_storage_uuid
,
320 if (file_printf(ms
, ", %s", str
) == -1)
326 m
= cdf_file_property_info(ms
, info
, count
, root_storage
);
329 return m
== -1 ? -2 : m
;
334 format_clsid(char *buf
, size_t len
, const uint64_t uuid
[2]) {
335 snprintf(buf
, len
, "%.8" PRIx64
"-%.4" PRIx64
"-%.4" PRIx64
"-%.4"
336 PRIx64
"-%.12" PRIx64
,
337 (uuid
[0] >> 32) & (uint64_t)0x000000000ffffffffULL
,
338 (uuid
[0] >> 16) & (uint64_t)0x0000000000000ffffULL
,
339 (uuid
[0] >> 0) & (uint64_t)0x0000000000000ffffULL
,
340 (uuid
[1] >> 48) & (uint64_t)0x0000000000000ffffULL
,
341 (uuid
[1] >> 0) & (uint64_t)0x0000fffffffffffffULL
);
347 file_trycdf(struct magic_set
*ms
, int fd
, const unsigned char *buf
,
353 cdf_stream_t sst
, scn
;
356 const char *expn
= "";
357 const char *corrupt
= "corrupt: ";
358 const cdf_directory_t
*root_storage
;
363 if (ms
->flags
& MAGIC_APPLE
)
365 if (cdf_read_header(&info
, &h
) == -1)
371 if ((i
= cdf_read_sat(&info
, &h
, &sat
)) == -1) {
372 expn
= "Can't read SAT";
376 cdf_dump_sat("SAT", &sat
, CDF_SEC_SIZE(&h
));
379 if ((i
= cdf_read_ssat(&info
, &h
, &sat
, &ssat
)) == -1) {
380 expn
= "Can't read SSAT";
384 cdf_dump_sat("SSAT", &ssat
, CDF_SHORT_SEC_SIZE(&h
));
387 if ((i
= cdf_read_dir(&info
, &h
, &sat
, &dir
)) == -1) {
388 expn
= "Can't read directory";
392 if ((i
= cdf_read_short_stream(&info
, &h
, &sat
, &dir
, &sst
,
393 &root_storage
)) == -1) {
394 expn
= "Cannot read short stream";
398 cdf_dump_dir(&info
, &h
, &sat
, &ssat
, &sst
, &dir
);
404 if (file_printf(ms
, "CLSID %s, ",
405 format_clsid(clsbuf
, sizeof(clsbuf
),
406 root_storage
->d_storage_uuid
)) == -1)
412 if ((i
= cdf_read_user_stream(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
413 "FileHeader", &scn
)) != -1) {
414 #define HWP5_SIGNATURE "HWP Document File"
415 if (scn
.sst_dirlen
>= sizeof(HWP5_SIGNATURE
) - 1
416 && memcmp(scn
.sst_tab
, HWP5_SIGNATURE
,
417 sizeof(HWP5_SIGNATURE
) - 1) == 0) {
420 "Hangul (Korean) Word Processor File 5.x") == -1)
423 if (file_printf(ms
, "application/x-hwp") == -1)
436 if ((i
= cdf_read_summary_info(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
438 if (errno
== ESRCH
) {
439 if ((i
= cdf_read_catalog(&info
, &h
, &sat
, &ssat
, &sst
,
440 &dir
, &scn
)) == -1) {
442 if ((i
= cdf_read_encrypted_package(&info
, &h
,
443 &sat
, &ssat
, &sst
, &dir
, &scn
)) == -1)
444 expn
= "No summary info";
452 cdf_dump_catalog(&h
, &scn
);
454 if ((i
= cdf_file_catalog(ms
, &h
, &scn
))
456 expn
= "Can't expand catalog";
458 expn
= "Cannot read summary info";
463 cdf_dump_summary_info(&h
, &scn
);
465 if ((i
= cdf_file_summary_info(ms
, &h
, &scn
, root_storage
)) < 0)
466 expn
= "Can't expand summary_info";
469 const char *str
= NULL
;
471 char name
[__arraycount(d
->d_name
)];
474 for (j
= 0; str
== NULL
&& j
< dir
.dir_len
; j
++) {
476 for (k
= 0; k
< sizeof(name
); k
++)
477 name
[k
] = (char)cdf_tole2(d
->d_name
[k
]);
478 str
= cdf_app_to_mime(name
,
479 NOTMIME(ms
) ? name2desc
: name2mime
);
483 if (file_printf(ms
, "%s", str
) == -1)
489 str
= "vnd.ms-office";
490 if (file_printf(ms
, "application/%s", str
) == -1)
509 "Composite Document File V2 Document") == -1)
512 if (file_printf(ms
, ", %s%s", corrupt
, expn
) == -1)
515 if (file_printf(ms
, "application/CDFV2-%s",
516 *corrupt
? "corrupt" : "encrypted") == -1)