Annotation of embedaddon/php/ext/fileinfo/libmagic/cdf.c, revision 1.1.1.4
1.1 misho 1: /*-
2: * Copyright (c) 2008 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: /*
1.1.1.2 misho 27: * Parse Composite Document Files, the format used in Microsoft Office
28: * document files before they switched to zipped XML.
1.1 misho 29: * Info from: http://sc.openoffice.org/compdocfileformat.pdf
1.1.1.2 misho 30: *
31: * N.B. This is the "Composite Document File" format, and not the
32: * "Compound Document Format", nor the "Channel Definition Format".
1.1 misho 33: */
34:
35: #include "file.h"
36:
37: #ifndef lint
1.1.1.3 misho 38: FILE_RCSID("@(#)$File: cdf.c,v 1.53 2013/02/26 16:20:42 christos Exp $")
1.1 misho 39: #endif
40:
41: #include <assert.h>
42: #ifdef CDF_DEBUG
43: #include <err.h>
44: #endif
45: #include <stdlib.h>
46:
47: #ifdef PHP_WIN32
48: #include "win32/unistd.h"
49: #else
50: #include <unistd.h>
51: #endif
52:
53: #ifndef UINT32_MAX
54: # define UINT32_MAX (0xffffffff)
55: #endif
56:
57: #include <string.h>
58: #include <time.h>
59: #include <ctype.h>
1.1.1.2 misho 60: #ifdef HAVE_LIMITS_H
61: #include <limits.h>
62: #endif
1.1 misho 63:
64: #ifndef EFTYPE
65: #define EFTYPE EINVAL
66: #endif
67:
68: #include "cdf.h"
69:
70: #ifdef CDF_DEBUG
71: #define DPRINTF(a) printf a, fflush(stdout)
72: #else
73: #define DPRINTF(a)
74: #endif
75:
76: static union {
77: char s[4];
78: uint32_t u;
79: } cdf_bo;
80:
81: #define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304)
82:
1.1.1.2 misho 83: #define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x)))
84: #define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x)))
85: #define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x)))
86: #define CDF_GETUINT32(x, y) cdf_getuint32(x, y)
87:
1.1 misho 88:
89: /*
90: * swap a short
91: */
1.1.1.2 misho 92: static uint16_t
93: _cdf_tole2(uint16_t sv)
1.1 misho 94: {
95: uint16_t rv;
1.1.1.2 misho 96: uint8_t *s = (uint8_t *)(void *)&sv;
97: uint8_t *d = (uint8_t *)(void *)&rv;
1.1 misho 98: d[0] = s[1];
99: d[1] = s[0];
100: return rv;
101: }
102:
103: /*
104: * swap an int
105: */
1.1.1.2 misho 106: static uint32_t
107: _cdf_tole4(uint32_t sv)
1.1 misho 108: {
109: uint32_t rv;
1.1.1.2 misho 110: uint8_t *s = (uint8_t *)(void *)&sv;
111: uint8_t *d = (uint8_t *)(void *)&rv;
1.1 misho 112: d[0] = s[3];
113: d[1] = s[2];
114: d[2] = s[1];
115: d[3] = s[0];
116: return rv;
117: }
118:
119: /*
120: * swap a quad
121: */
1.1.1.2 misho 122: static uint64_t
123: _cdf_tole8(uint64_t sv)
1.1 misho 124: {
125: uint64_t rv;
1.1.1.2 misho 126: uint8_t *s = (uint8_t *)(void *)&sv;
127: uint8_t *d = (uint8_t *)(void *)&rv;
1.1 misho 128: d[0] = s[7];
129: d[1] = s[6];
130: d[2] = s[5];
131: d[3] = s[4];
132: d[4] = s[3];
133: d[5] = s[2];
134: d[6] = s[1];
135: d[7] = s[0];
136: return rv;
137: }
138:
1.1.1.2 misho 139: /*
140: * grab a uint32_t from a possibly unaligned address, and return it in
141: * the native host order.
142: */
143: static uint32_t
144: cdf_getuint32(const uint8_t *p, size_t offs)
145: {
146: uint32_t rv;
147: (void)memcpy(&rv, p + offs * sizeof(uint32_t), sizeof(rv));
148: return CDF_TOLE4(rv);
149: }
150:
1.1 misho 151: #define CDF_UNPACK(a) \
152: (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
153: #define CDF_UNPACKA(a) \
154: (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
155:
1.1.1.2 misho 156: uint16_t
157: cdf_tole2(uint16_t sv)
158: {
159: return CDF_TOLE2(sv);
160: }
161:
162: uint32_t
163: cdf_tole4(uint32_t sv)
164: {
165: return CDF_TOLE4(sv);
166: }
167:
168: uint64_t
169: cdf_tole8(uint64_t sv)
170: {
171: return CDF_TOLE8(sv);
172: }
173:
1.1 misho 174: void
175: cdf_swap_header(cdf_header_t *h)
176: {
177: size_t i;
178:
179: h->h_magic = CDF_TOLE8(h->h_magic);
180: h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]);
181: h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]);
182: h->h_revision = CDF_TOLE2(h->h_revision);
183: h->h_version = CDF_TOLE2(h->h_version);
184: h->h_byte_order = CDF_TOLE2(h->h_byte_order);
185: h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2);
186: h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2);
187: h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat);
188: h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory);
189: h->h_min_size_standard_stream =
190: CDF_TOLE4(h->h_min_size_standard_stream);
191: h->h_secid_first_sector_in_short_sat =
1.1.1.2 misho 192: CDF_TOLE4((uint32_t)h->h_secid_first_sector_in_short_sat);
1.1 misho 193: h->h_num_sectors_in_short_sat =
194: CDF_TOLE4(h->h_num_sectors_in_short_sat);
195: h->h_secid_first_sector_in_master_sat =
1.1.1.2 misho 196: CDF_TOLE4((uint32_t)h->h_secid_first_sector_in_master_sat);
1.1 misho 197: h->h_num_sectors_in_master_sat =
198: CDF_TOLE4(h->h_num_sectors_in_master_sat);
199: for (i = 0; i < __arraycount(h->h_master_sat); i++)
1.1.1.2 misho 200: h->h_master_sat[i] = CDF_TOLE4((uint32_t)h->h_master_sat[i]);
1.1 misho 201: }
202:
203: void
204: cdf_unpack_header(cdf_header_t *h, char *buf)
205: {
206: size_t i;
207: size_t len = 0;
208:
209: CDF_UNPACK(h->h_magic);
210: CDF_UNPACKA(h->h_uuid);
211: CDF_UNPACK(h->h_revision);
212: CDF_UNPACK(h->h_version);
213: CDF_UNPACK(h->h_byte_order);
214: CDF_UNPACK(h->h_sec_size_p2);
215: CDF_UNPACK(h->h_short_sec_size_p2);
216: CDF_UNPACKA(h->h_unused0);
217: CDF_UNPACK(h->h_num_sectors_in_sat);
218: CDF_UNPACK(h->h_secid_first_directory);
219: CDF_UNPACKA(h->h_unused1);
220: CDF_UNPACK(h->h_min_size_standard_stream);
221: CDF_UNPACK(h->h_secid_first_sector_in_short_sat);
222: CDF_UNPACK(h->h_num_sectors_in_short_sat);
223: CDF_UNPACK(h->h_secid_first_sector_in_master_sat);
224: CDF_UNPACK(h->h_num_sectors_in_master_sat);
225: for (i = 0; i < __arraycount(h->h_master_sat); i++)
226: CDF_UNPACK(h->h_master_sat[i]);
227: }
228:
229: void
230: cdf_swap_dir(cdf_directory_t *d)
231: {
232: d->d_namelen = CDF_TOLE2(d->d_namelen);
1.1.1.2 misho 233: d->d_left_child = CDF_TOLE4((uint32_t)d->d_left_child);
234: d->d_right_child = CDF_TOLE4((uint32_t)d->d_right_child);
235: d->d_storage = CDF_TOLE4((uint32_t)d->d_storage);
1.1 misho 236: d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]);
237: d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]);
238: d->d_flags = CDF_TOLE4(d->d_flags);
1.1.1.2 misho 239: d->d_created = CDF_TOLE8((uint64_t)d->d_created);
240: d->d_modified = CDF_TOLE8((uint64_t)d->d_modified);
241: d->d_stream_first_sector = CDF_TOLE4((uint32_t)d->d_stream_first_sector);
1.1 misho 242: d->d_size = CDF_TOLE4(d->d_size);
243: }
244:
245: void
246: cdf_swap_class(cdf_classid_t *d)
247: {
248: d->cl_dword = CDF_TOLE4(d->cl_dword);
249: d->cl_word[0] = CDF_TOLE2(d->cl_word[0]);
250: d->cl_word[1] = CDF_TOLE2(d->cl_word[1]);
251: }
252:
253: void
254: cdf_unpack_dir(cdf_directory_t *d, char *buf)
255: {
256: size_t len = 0;
257:
258: CDF_UNPACKA(d->d_name);
259: CDF_UNPACK(d->d_namelen);
260: CDF_UNPACK(d->d_type);
261: CDF_UNPACK(d->d_color);
262: CDF_UNPACK(d->d_left_child);
263: CDF_UNPACK(d->d_right_child);
264: CDF_UNPACK(d->d_storage);
265: CDF_UNPACKA(d->d_storage_uuid);
266: CDF_UNPACK(d->d_flags);
267: CDF_UNPACK(d->d_created);
268: CDF_UNPACK(d->d_modified);
269: CDF_UNPACK(d->d_stream_first_sector);
270: CDF_UNPACK(d->d_size);
271: CDF_UNPACK(d->d_unused0);
272: }
273:
274: static int
1.1.1.2 misho 275: cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h,
276: const void *p, size_t tail, int line)
1.1 misho 277: {
278: const char *b = (const char *)sst->sst_tab;
279: const char *e = ((const char *)p) + tail;
1.1.1.2 misho 280: (void)&line;
1.1.1.3 misho 281: if (e >= b && (size_t)(e - b) <= CDF_SEC_SIZE(h) * sst->sst_len)
1.1 misho 282: return 0;
1.1.1.3 misho 283: DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u"
284: " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %"
1.1.1.2 misho 285: SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b),
286: CDF_SEC_SIZE(h) * sst->sst_len, CDF_SEC_SIZE(h), sst->sst_len));
1.1 misho 287: errno = EFTYPE;
288: return -1;
289: }
290:
291: static ssize_t
292: cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
293: {
294: size_t siz = (size_t)off + len;
295:
296: if ((off_t)(off + len) != (off_t)siz) {
297: errno = EINVAL;
298: return -1;
299: }
300:
301: if (info->i_buf != NULL && info->i_len >= siz) {
302: (void)memcpy(buf, &info->i_buf[off], len);
303: return (ssize_t)len;
304: }
305:
306: if (info->i_fd == -1)
307: return -1;
308:
1.1.1.2 misho 309: if (FINFO_LSEEK_FUNC(info->i_fd, off, SEEK_SET) == (off_t)-1)
1.1 misho 310: return -1;
311:
1.1.1.2 misho 312: if (FINFO_READ_FUNC(info->i_fd, buf, len) != (ssize_t)len)
1.1 misho 313: return -1;
314:
315: return (ssize_t)len;
316: }
317:
318: int
319: cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
320: {
321: char buf[512];
322:
323: (void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
324: if (cdf_read(info, (off_t)0, buf, sizeof(buf)) == -1)
325: return -1;
326: cdf_unpack_header(h, buf);
327: cdf_swap_header(h);
328: if (h->h_magic != CDF_MAGIC) {
1.1.1.2 misho 329: DPRINTF(("Bad magic 0x%" INT64_T_FORMAT "x != 0x%"
330: INT64_T_FORMAT "x\n",
1.1 misho 331: (unsigned long long)h->h_magic,
332: (unsigned long long)CDF_MAGIC));
333: goto out;
334: }
335: if (h->h_sec_size_p2 > 20) {
336: DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
337: goto out;
338: }
339: if (h->h_short_sec_size_p2 > 20) {
340: DPRINTF(("Bad short sector size 0x%u\n",
341: h->h_short_sec_size_p2));
342: goto out;
343: }
344: return 0;
345: out:
346: errno = EFTYPE;
347: return -1;
348: }
349:
350:
351: ssize_t
352: cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
353: const cdf_header_t *h, cdf_secid_t id)
354: {
1.1.1.2 misho 355: size_t ss = CDF_SEC_SIZE(h);
356: size_t pos = CDF_SEC_POS(h, id);
357: assert(ss == len);
358: return cdf_read(info, (off_t)pos, ((char *)buf) + offs, len);
1.1 misho 359: }
360:
361: ssize_t
362: cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
363: size_t len, const cdf_header_t *h, cdf_secid_t id)
364: {
1.1.1.2 misho 365: size_t ss = CDF_SHORT_SEC_SIZE(h);
366: size_t pos = CDF_SHORT_SEC_POS(h, id);
367: assert(ss == len);
368: if (pos > CDF_SEC_SIZE(h) * sst->sst_len) {
369: DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %"
370: SIZE_T_FORMAT "u\n",
371: pos, CDF_SEC_SIZE(h) * sst->sst_len));
372: return -1;
373: }
1.1 misho 374: (void)memcpy(((char *)buf) + offs,
1.1.1.2 misho 375: ((const char *)sst->sst_tab) + pos, len);
1.1 misho 376: return len;
377: }
378:
379: /*
380: * Read the sector allocation table.
381: */
382: int
383: cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
384: {
385: size_t i, j, k;
386: size_t ss = CDF_SEC_SIZE(h);
387: cdf_secid_t *msa, mid, sec;
388: size_t nsatpersec = (ss / sizeof(mid)) - 1;
389:
390: for (i = 0; i < __arraycount(h->h_master_sat); i++)
391: if (h->h_master_sat[i] == CDF_SECID_FREE)
392: break;
393:
394: #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
1.1.1.2 misho 395: if ((nsatpersec > 0 &&
396: h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) ||
1.1 misho 397: i > CDF_SEC_LIMIT) {
1.1.1.2 misho 398: DPRINTF(("Number of sectors in master SAT too big %u %"
399: SIZE_T_FORMAT "u\n", h->h_num_sectors_in_master_sat, i));
1.1 misho 400: errno = EFTYPE;
401: return -1;
402: }
403:
404: sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
1.1.1.2 misho 405: DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n",
406: sat->sat_len, ss));
407: if ((sat->sat_tab = CAST(cdf_secid_t *, calloc(sat->sat_len, ss)))
408: == NULL)
1.1 misho 409: return -1;
410:
411: for (i = 0; i < __arraycount(h->h_master_sat); i++) {
412: if (h->h_master_sat[i] < 0)
413: break;
414: if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
415: h->h_master_sat[i]) != (ssize_t)ss) {
416: DPRINTF(("Reading sector %d", h->h_master_sat[i]));
417: goto out1;
418: }
419: }
420:
1.1.1.2 misho 421: if ((msa = CAST(cdf_secid_t *, calloc(1, ss))) == NULL)
1.1 misho 422: goto out1;
423:
424: mid = h->h_secid_first_sector_in_master_sat;
425: for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
426: if (mid < 0)
427: goto out;
428: if (j >= CDF_LOOP_LIMIT) {
429: DPRINTF(("Reading master sector loop limit"));
430: errno = EFTYPE;
431: goto out2;
432: }
433: if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
434: DPRINTF(("Reading master sector %d", mid));
435: goto out2;
436: }
437: for (k = 0; k < nsatpersec; k++, i++) {
1.1.1.2 misho 438: sec = CDF_TOLE4((uint32_t)msa[k]);
1.1 misho 439: if (sec < 0)
440: goto out;
441: if (i >= sat->sat_len) {
1.1.1.2 misho 442: DPRINTF(("Out of bounds reading MSA %" SIZE_T_FORMAT
443: "u >= %" SIZE_T_FORMAT "u", i, sat->sat_len));
1.1 misho 444: errno = EFTYPE;
445: goto out2;
446: }
447: if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
448: sec) != (ssize_t)ss) {
449: DPRINTF(("Reading sector %d",
450: CDF_TOLE4(msa[k])));
451: goto out2;
452: }
453: }
1.1.1.2 misho 454: mid = CDF_TOLE4((uint32_t)msa[nsatpersec]);
1.1 misho 455: }
456: out:
457: sat->sat_len = i;
458: free(msa);
459: return 0;
460: out2:
461: free(msa);
462: out1:
463: free(sat->sat_tab);
464: return -1;
465: }
466:
467: size_t
468: cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
469: {
470: size_t i, j;
471: cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * size);
472:
473: DPRINTF(("Chain:"));
474: for (j = i = 0; sid >= 0; i++, j++) {
475: DPRINTF((" %d", sid));
476: if (j >= CDF_LOOP_LIMIT) {
477: DPRINTF(("Counting chain loop limit"));
478: errno = EFTYPE;
479: return (size_t)-1;
480: }
481: if (sid > maxsector) {
482: DPRINTF(("Sector %d > %d\n", sid, maxsector));
483: errno = EFTYPE;
484: return (size_t)-1;
485: }
1.1.1.2 misho 486: sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
1.1 misho 487: }
488: DPRINTF(("\n"));
489: return i;
490: }
491:
492: int
493: cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
494: const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn)
495: {
496: size_t ss = CDF_SEC_SIZE(h), i, j;
497: ssize_t nr;
498: scn->sst_len = cdf_count_chain(sat, sid, ss);
499: scn->sst_dirlen = len;
500:
501: if (scn->sst_len == (size_t)-1)
502: return -1;
503:
504: scn->sst_tab = calloc(scn->sst_len, ss);
505: if (scn->sst_tab == NULL)
506: return -1;
507:
508: for (j = i = 0; sid >= 0; i++, j++) {
509: if (j >= CDF_LOOP_LIMIT) {
510: DPRINTF(("Read long sector chain loop limit"));
511: errno = EFTYPE;
512: goto out;
513: }
514: if (i >= scn->sst_len) {
515: DPRINTF(("Out of bounds reading long sector chain "
1.1.1.2 misho 516: "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
517: scn->sst_len));
1.1 misho 518: errno = EFTYPE;
519: goto out;
520: }
521: if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
522: sid)) != (ssize_t)ss) {
523: if (i == scn->sst_len - 1 && nr > 0) {
524: /* Last sector might be truncated */
525: return 0;
526: }
527: DPRINTF(("Reading long sector chain %d", sid));
528: goto out;
529: }
1.1.1.2 misho 530: sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
1.1 misho 531: }
532: return 0;
533: out:
534: free(scn->sst_tab);
535: return -1;
536: }
537:
538: int
539: cdf_read_short_sector_chain(const cdf_header_t *h,
540: const cdf_sat_t *ssat, const cdf_stream_t *sst,
541: cdf_secid_t sid, size_t len, cdf_stream_t *scn)
542: {
543: size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
544: scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
545: scn->sst_dirlen = len;
546:
547: if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
548: return -1;
549:
550: scn->sst_tab = calloc(scn->sst_len, ss);
551: if (scn->sst_tab == NULL)
552: return -1;
553:
554: for (j = i = 0; sid >= 0; i++, j++) {
555: if (j >= CDF_LOOP_LIMIT) {
556: DPRINTF(("Read short sector chain loop limit"));
557: errno = EFTYPE;
558: goto out;
559: }
560: if (i >= scn->sst_len) {
561: DPRINTF(("Out of bounds reading short sector chain "
1.1.1.2 misho 562: "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n",
563: i, scn->sst_len));
1.1 misho 564: errno = EFTYPE;
565: goto out;
566: }
567: if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
568: sid) != (ssize_t)ss) {
569: DPRINTF(("Reading short sector chain %d", sid));
570: goto out;
571: }
1.1.1.2 misho 572: sid = CDF_TOLE4((uint32_t)ssat->sat_tab[sid]);
1.1 misho 573: }
574: return 0;
575: out:
576: free(scn->sst_tab);
577: return -1;
578: }
579:
580: int
581: cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
582: const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
583: cdf_secid_t sid, size_t len, cdf_stream_t *scn)
584: {
585:
1.1.1.2 misho 586: if (len < h->h_min_size_standard_stream && sst->sst_tab != NULL)
1.1 misho 587: return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
588: scn);
589: else
590: return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
591: }
592:
593: int
594: cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
595: const cdf_sat_t *sat, cdf_dir_t *dir)
596: {
597: size_t i, j;
598: size_t ss = CDF_SEC_SIZE(h), ns, nd;
599: char *buf;
600: cdf_secid_t sid = h->h_secid_first_directory;
601:
602: ns = cdf_count_chain(sat, sid, ss);
603: if (ns == (size_t)-1)
604: return -1;
605:
606: nd = ss / CDF_DIRECTORY_SIZE;
607:
608: dir->dir_len = ns * nd;
1.1.1.2 misho 609: dir->dir_tab = CAST(cdf_directory_t *,
610: calloc(dir->dir_len, sizeof(dir->dir_tab[0])));
1.1 misho 611: if (dir->dir_tab == NULL)
612: return -1;
613:
1.1.1.2 misho 614: if ((buf = CAST(char *, malloc(ss))) == NULL) {
1.1 misho 615: free(dir->dir_tab);
616: return -1;
617: }
618:
619: for (j = i = 0; i < ns; i++, j++) {
620: if (j >= CDF_LOOP_LIMIT) {
621: DPRINTF(("Read dir loop limit"));
622: errno = EFTYPE;
623: goto out;
624: }
625: if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
626: DPRINTF(("Reading directory sector %d", sid));
627: goto out;
628: }
629: for (j = 0; j < nd; j++) {
630: cdf_unpack_dir(&dir->dir_tab[i * nd + j],
631: &buf[j * CDF_DIRECTORY_SIZE]);
632: }
1.1.1.2 misho 633: sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
1.1 misho 634: }
635: if (NEED_SWAP)
636: for (i = 0; i < dir->dir_len; i++)
637: cdf_swap_dir(&dir->dir_tab[i]);
638: free(buf);
639: return 0;
640: out:
641: free(dir->dir_tab);
642: free(buf);
643: return -1;
644: }
645:
646:
647: int
648: cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
649: const cdf_sat_t *sat, cdf_sat_t *ssat)
650: {
651: size_t i, j;
652: size_t ss = CDF_SEC_SIZE(h);
653: cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
654:
655: ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h));
656: if (ssat->sat_len == (size_t)-1)
657: return -1;
658:
1.1.1.2 misho 659: ssat->sat_tab = CAST(cdf_secid_t *, calloc(ssat->sat_len, ss));
1.1 misho 660: if (ssat->sat_tab == NULL)
661: return -1;
662:
663: for (j = i = 0; sid >= 0; i++, j++) {
664: if (j >= CDF_LOOP_LIMIT) {
665: DPRINTF(("Read short sat sector loop limit"));
666: errno = EFTYPE;
667: goto out;
668: }
669: if (i >= ssat->sat_len) {
670: DPRINTF(("Out of bounds reading short sector chain "
1.1.1.2 misho 671: "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
672: ssat->sat_len));
1.1 misho 673: errno = EFTYPE;
674: goto out;
675: }
676: if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
677: (ssize_t)ss) {
678: DPRINTF(("Reading short sat sector %d", sid));
679: goto out;
680: }
1.1.1.2 misho 681: sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
1.1 misho 682: }
683: return 0;
684: out:
685: free(ssat->sat_tab);
686: return -1;
687: }
688:
689: int
690: cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
691: const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn)
692: {
693: size_t i;
694: const cdf_directory_t *d;
695:
696: for (i = 0; i < dir->dir_len; i++)
697: if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
698: break;
699:
700: /* If the it is not there, just fake it; some docs don't have it */
701: if (i == dir->dir_len)
702: goto out;
703: d = &dir->dir_tab[i];
704:
705: /* If the it is not there, just fake it; some docs don't have it */
706: if (d->d_stream_first_sector < 0)
707: goto out;
708:
1.1.1.2 misho 709: return cdf_read_long_sector_chain(info, h, sat,
1.1 misho 710: d->d_stream_first_sector, d->d_size, scn);
711: out:
712: scn->sst_tab = NULL;
713: scn->sst_len = 0;
714: scn->sst_dirlen = 0;
715: return 0;
716: }
717:
718: static int
719: cdf_namecmp(const char *d, const uint16_t *s, size_t l)
720: {
721: for (; l--; d++, s++)
722: if (*d != CDF_TOLE2(*s))
723: return (unsigned char)*d - CDF_TOLE2(*s);
724: return 0;
725: }
726:
727: int
728: cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
729: const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
730: const cdf_dir_t *dir, cdf_stream_t *scn)
731: {
732: size_t i;
733: const cdf_directory_t *d;
734: static const char name[] = "\05SummaryInformation";
735:
1.1.1.2 misho 736: for (i = dir->dir_len; i > 0; i--)
737: if (dir->dir_tab[i - 1].d_type == CDF_DIR_TYPE_USER_STREAM &&
738: cdf_namecmp(name, dir->dir_tab[i - 1].d_name, sizeof(name))
1.1 misho 739: == 0)
740: break;
741:
1.1.1.2 misho 742: if (i == 0) {
1.1 misho 743: DPRINTF(("Cannot find summary information section\n"));
1.1.1.2 misho 744: errno = ESRCH;
1.1 misho 745: return -1;
746: }
1.1.1.2 misho 747: d = &dir->dir_tab[i - 1];
1.1 misho 748: return cdf_read_sector_chain(info, h, sat, ssat, sst,
749: d->d_stream_first_sector, d->d_size, scn);
750: }
751:
752: int
1.1.1.2 misho 753: cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
754: uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount)
1.1 misho 755: {
756: const cdf_section_header_t *shp;
757: cdf_section_header_t sh;
1.1.1.2 misho 758: const uint8_t *p, *q, *e;
1.1 misho 759: int16_t s16;
760: int32_t s32;
761: uint32_t u32;
762: int64_t s64;
763: uint64_t u64;
764: cdf_timestamp_t tp;
1.1.1.2 misho 765: size_t i, o, o4, nelements, j;
1.1 misho 766: cdf_property_info_t *inp;
767:
768: if (offs > UINT32_MAX / 4) {
769: errno = EFTYPE;
770: goto out;
771: }
1.1.1.2 misho 772: shp = CAST(const cdf_section_header_t *, (const void *)
773: ((const char *)sst->sst_tab + offs));
774: if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1)
1.1 misho 775: goto out;
776: sh.sh_len = CDF_TOLE4(shp->sh_len);
777: #define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
778: if (sh.sh_len > CDF_SHLEN_LIMIT) {
779: errno = EFTYPE;
780: goto out;
781: }
782: sh.sh_properties = CDF_TOLE4(shp->sh_properties);
783: #define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
784: if (sh.sh_properties > CDF_PROP_LIMIT)
785: goto out;
786: DPRINTF(("section len: %u properties %u\n", sh.sh_len,
787: sh.sh_properties));
788: if (*maxcount) {
789: if (*maxcount > CDF_PROP_LIMIT)
790: goto out;
791: *maxcount += sh.sh_properties;
1.1.1.2 misho 792: inp = CAST(cdf_property_info_t *,
793: realloc(*info, *maxcount * sizeof(*inp)));
1.1 misho 794: } else {
795: *maxcount = sh.sh_properties;
1.1.1.2 misho 796: inp = CAST(cdf_property_info_t *,
797: malloc(*maxcount * sizeof(*inp)));
1.1 misho 798: }
799: if (inp == NULL)
800: goto out;
801: *info = inp;
802: inp += *count;
803: *count += sh.sh_properties;
1.1.1.2 misho 804: p = CAST(const uint8_t *, (const void *)
805: ((const char *)(const void *)sst->sst_tab +
806: offs + sizeof(sh)));
807: e = CAST(const uint8_t *, (const void *)
808: (((const char *)(const void *)shp) + sh.sh_len));
809: if (cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1)
1.1 misho 810: goto out;
811: for (i = 0; i < sh.sh_properties; i++) {
1.1.1.2 misho 812: size_t ofs = CDF_GETUINT32(p, (i << 1) + 1);
813: q = (const uint8_t *)(const void *)
814: ((const char *)(const void *)p + ofs
815: - 2 * sizeof(uint32_t));
1.1 misho 816: if (q > e) {
817: DPRINTF(("Ran of the end %p > %p\n", q, e));
818: goto out;
819: }
1.1.1.2 misho 820: inp[i].pi_id = CDF_GETUINT32(p, i << 1);
821: inp[i].pi_type = CDF_GETUINT32(q, 0);
822: DPRINTF(("%" SIZE_T_FORMAT "u) id=%x type=%x offs=0x%tx,0x%x\n",
823: i, inp[i].pi_id, inp[i].pi_type, q - p, offs));
1.1 misho 824: if (inp[i].pi_type & CDF_VECTOR) {
1.1.1.2 misho 825: nelements = CDF_GETUINT32(q, 1);
1.1.1.4 ! misho 826: if (nelements == 0) {
! 827: DPRINTF(("CDF_VECTOR with nelements == 0\n"));
! 828: goto out;
! 829: }
1.1 misho 830: o = 2;
831: } else {
832: nelements = 1;
833: o = 1;
834: }
1.1.1.2 misho 835: o4 = o * sizeof(uint32_t);
1.1 misho 836: if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
837: goto unknown;
838: switch (inp[i].pi_type & CDF_TYPEMASK) {
1.1.1.2 misho 839: case CDF_NULL:
1.1 misho 840: case CDF_EMPTY:
841: break;
842: case CDF_SIGNED16:
843: if (inp[i].pi_type & CDF_VECTOR)
844: goto unknown;
1.1.1.2 misho 845: (void)memcpy(&s16, &q[o4], sizeof(s16));
1.1 misho 846: inp[i].pi_s16 = CDF_TOLE2(s16);
847: break;
848: case CDF_SIGNED32:
849: if (inp[i].pi_type & CDF_VECTOR)
850: goto unknown;
1.1.1.2 misho 851: (void)memcpy(&s32, &q[o4], sizeof(s32));
852: inp[i].pi_s32 = CDF_TOLE4((uint32_t)s32);
1.1 misho 853: break;
854: case CDF_BOOL:
855: case CDF_UNSIGNED32:
856: if (inp[i].pi_type & CDF_VECTOR)
857: goto unknown;
1.1.1.2 misho 858: (void)memcpy(&u32, &q[o4], sizeof(u32));
1.1 misho 859: inp[i].pi_u32 = CDF_TOLE4(u32);
860: break;
861: case CDF_SIGNED64:
862: if (inp[i].pi_type & CDF_VECTOR)
863: goto unknown;
1.1.1.2 misho 864: (void)memcpy(&s64, &q[o4], sizeof(s64));
865: inp[i].pi_s64 = CDF_TOLE8((uint64_t)s64);
1.1 misho 866: break;
867: case CDF_UNSIGNED64:
868: if (inp[i].pi_type & CDF_VECTOR)
869: goto unknown;
1.1.1.2 misho 870: (void)memcpy(&u64, &q[o4], sizeof(u64));
871: inp[i].pi_u64 = CDF_TOLE8((uint64_t)u64);
872: break;
873: case CDF_FLOAT:
874: if (inp[i].pi_type & CDF_VECTOR)
875: goto unknown;
876: (void)memcpy(&u32, &q[o4], sizeof(u32));
877: u32 = CDF_TOLE4(u32);
878: memcpy(&inp[i].pi_f, &u32, sizeof(inp[i].pi_f));
879: break;
880: case CDF_DOUBLE:
881: if (inp[i].pi_type & CDF_VECTOR)
882: goto unknown;
883: (void)memcpy(&u64, &q[o4], sizeof(u64));
884: u64 = CDF_TOLE8((uint64_t)u64);
885: memcpy(&inp[i].pi_d, &u64, sizeof(inp[i].pi_d));
1.1 misho 886: break;
887: case CDF_LENGTH32_STRING:
1.1.1.2 misho 888: case CDF_LENGTH32_WSTRING:
1.1 misho 889: if (nelements > 1) {
890: size_t nelem = inp - *info;
891: if (*maxcount > CDF_PROP_LIMIT
892: || nelements > CDF_PROP_LIMIT)
893: goto out;
894: *maxcount += nelements;
1.1.1.2 misho 895: inp = CAST(cdf_property_info_t *,
896: realloc(*info, *maxcount * sizeof(*inp)));
1.1 misho 897: if (inp == NULL)
898: goto out;
899: *info = inp;
900: inp = *info + nelem;
901: }
1.1.1.2 misho 902: DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n",
903: nelements));
1.1.1.4 ! misho 904: for (j = 0; j < nelements && i < sh.sh_properties;
! 905: j++, i++)
! 906: {
1.1.1.2 misho 907: uint32_t l = CDF_GETUINT32(q, o);
1.1 misho 908: inp[i].pi_str.s_len = l;
1.1.1.2 misho 909: inp[i].pi_str.s_buf = (const char *)
910: (const void *)(&q[o4 + sizeof(l)]);
911: DPRINTF(("l = %d, r = %" SIZE_T_FORMAT
912: "u, s = %s\n", l,
1.1 misho 913: CDF_ROUND(l, sizeof(l)),
914: inp[i].pi_str.s_buf));
1.1.1.2 misho 915: if (l & 1)
916: l++;
917: o += l >> 1;
918: if (q + o >= e)
919: goto out;
920: o4 = o * sizeof(uint32_t);
1.1 misho 921: }
922: i--;
923: break;
924: case CDF_FILETIME:
925: if (inp[i].pi_type & CDF_VECTOR)
926: goto unknown;
1.1.1.2 misho 927: (void)memcpy(&tp, &q[o4], sizeof(tp));
928: inp[i].pi_tp = CDF_TOLE8((uint64_t)tp);
1.1 misho 929: break;
930: case CDF_CLIPBOARD:
931: if (inp[i].pi_type & CDF_VECTOR)
932: goto unknown;
933: break;
934: default:
935: unknown:
936: DPRINTF(("Don't know how to deal with %x\n",
937: inp[i].pi_type));
1.1.1.2 misho 938: break;
1.1 misho 939: }
940: }
941: return 0;
942: out:
943: free(*info);
944: return -1;
945: }
946:
947: int
1.1.1.2 misho 948: cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
949: cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count)
1.1 misho 950: {
1.1.1.4 ! misho 951: size_t maxcount;
1.1.1.2 misho 952: const cdf_summary_info_header_t *si =
953: CAST(const cdf_summary_info_header_t *, sst->sst_tab);
954: const cdf_section_declaration_t *sd =
955: CAST(const cdf_section_declaration_t *, (const void *)
956: ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET));
1.1 misho 957:
1.1.1.2 misho 958: if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 ||
959: cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1)
1.1 misho 960: return -1;
961: ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
962: ssi->si_os_version = CDF_TOLE2(si->si_os_version);
963: ssi->si_os = CDF_TOLE2(si->si_os);
964: ssi->si_class = si->si_class;
965: cdf_swap_class(&ssi->si_class);
1.1.1.4 ! misho 966: ssi->si_count = CDF_TOLE4(si->si_count);
1.1 misho 967: *count = 0;
968: maxcount = 0;
969: *info = NULL;
1.1.1.4 ! misho 970: if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info,
! 971: count, &maxcount) == -1)
1.1 misho 972: return -1;
973: return 0;
974: }
975:
976:
977:
978: int
979: cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
980: {
981: return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
982: "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
983: id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
984: id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
985: id->cl_six[5]);
986: }
987:
988: static const struct {
989: uint32_t v;
990: const char *n;
991: } vn[] = {
992: { CDF_PROPERTY_CODE_PAGE, "Code page" },
993: { CDF_PROPERTY_TITLE, "Title" },
994: { CDF_PROPERTY_SUBJECT, "Subject" },
995: { CDF_PROPERTY_AUTHOR, "Author" },
996: { CDF_PROPERTY_KEYWORDS, "Keywords" },
997: { CDF_PROPERTY_COMMENTS, "Comments" },
998: { CDF_PROPERTY_TEMPLATE, "Template" },
999: { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
1000: { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
1001: { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
1002: { CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
1003: { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
1004: { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
1005: { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
1006: { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
1007: { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
1008: { CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
1009: { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
1010: { CDF_PROPERTY_SECURITY, "Security" },
1011: { CDF_PROPERTY_LOCALE_ID, "Locale ID" },
1012: };
1013:
1014: int
1015: cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
1016: {
1017: size_t i;
1018:
1019: for (i = 0; i < __arraycount(vn); i++)
1020: if (vn[i].v == p)
1021: return snprintf(buf, bufsiz, "%s", vn[i].n);
1022: return snprintf(buf, bufsiz, "0x%x", p);
1023: }
1024:
1025: int
1026: cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
1027: {
1.1.1.2 misho 1028: int len = 0;
1.1 misho 1029: int days, hours, mins, secs;
1030:
1031: ts /= CDF_TIME_PREC;
1.1.1.2 misho 1032: secs = (int)(ts % 60);
1.1 misho 1033: ts /= 60;
1.1.1.2 misho 1034: mins = (int)(ts % 60);
1.1 misho 1035: ts /= 60;
1.1.1.2 misho 1036: hours = (int)(ts % 24);
1.1 misho 1037: ts /= 24;
1.1.1.2 misho 1038: days = (int)ts;
1.1 misho 1039:
1040: if (days) {
1041: len += snprintf(buf + len, bufsiz - len, "%dd+", days);
1.1.1.2 misho 1042: if ((size_t)len >= bufsiz)
1.1 misho 1043: return len;
1044: }
1045:
1046: if (days || hours) {
1047: len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
1.1.1.2 misho 1048: if ((size_t)len >= bufsiz)
1.1 misho 1049: return len;
1050: }
1051:
1052: len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
1.1.1.2 misho 1053: if ((size_t)len >= bufsiz)
1.1 misho 1054: return len;
1055:
1056: len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
1057: return len;
1058: }
1059:
1060:
1061: #ifdef CDF_DEBUG
1062: void
1063: cdf_dump_header(const cdf_header_t *h)
1064: {
1065: size_t i;
1066:
1067: #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
1068: #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
1069: h->h_ ## b, 1 << h->h_ ## b)
1070: DUMP("%d", revision);
1071: DUMP("%d", version);
1072: DUMP("0x%x", byte_order);
1073: DUMP2("%d", sec_size_p2);
1074: DUMP2("%d", short_sec_size_p2);
1075: DUMP("%d", num_sectors_in_sat);
1076: DUMP("%d", secid_first_directory);
1077: DUMP("%d", min_size_standard_stream);
1078: DUMP("%d", secid_first_sector_in_short_sat);
1079: DUMP("%d", num_sectors_in_short_sat);
1080: DUMP("%d", secid_first_sector_in_master_sat);
1081: DUMP("%d", num_sectors_in_master_sat);
1082: for (i = 0; i < __arraycount(h->h_master_sat); i++) {
1083: if (h->h_master_sat[i] == CDF_SECID_FREE)
1084: break;
1085: (void)fprintf(stderr, "%35.35s[%.3zu] = %d\n",
1086: "master_sat", i, h->h_master_sat[i]);
1087: }
1088: }
1089:
1090: void
1091: cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
1092: {
1093: size_t i, j, s = size / sizeof(cdf_secid_t);
1094:
1095: for (i = 0; i < sat->sat_len; i++) {
1.1.1.2 misho 1096: (void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6"
1097: SIZE_T_FORMAT "u: ", prefix, i, i * s);
1.1 misho 1098: for (j = 0; j < s; j++) {
1099: (void)fprintf(stderr, "%5d, ",
1100: CDF_TOLE4(sat->sat_tab[s * i + j]));
1101: if ((j + 1) % 10 == 0)
1.1.1.2 misho 1102: (void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT
1103: "u: ", i * s + j + 1);
1.1 misho 1104: }
1105: (void)fprintf(stderr, "\n");
1106: }
1107: }
1108:
1109: void
1110: cdf_dump(void *v, size_t len)
1111: {
1112: size_t i, j;
1113: unsigned char *p = v;
1114: char abuf[16];
1115: (void)fprintf(stderr, "%.4x: ", 0);
1116: for (i = 0, j = 0; i < len; i++, p++) {
1117: (void)fprintf(stderr, "%.2x ", *p);
1118: abuf[j++] = isprint(*p) ? *p : '.';
1119: if (j == 16) {
1120: j = 0;
1121: abuf[15] = '\0';
1.1.1.2 misho 1122: (void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ",
1123: abuf, i + 1);
1.1 misho 1124: }
1125: }
1126: (void)fprintf(stderr, "\n");
1127: }
1128:
1129: void
1130: cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
1131: {
1132: size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
1133: CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
1134: cdf_dump(sst->sst_tab, ss * sst->sst_len);
1135: }
1136:
1137: void
1138: cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
1139: const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
1140: const cdf_dir_t *dir)
1141: {
1142: size_t i, j;
1143: cdf_directory_t *d;
1144: char name[__arraycount(d->d_name)];
1145: cdf_stream_t scn;
1146: struct timeval ts;
1147:
1148: static const char *types[] = { "empty", "user storage",
1149: "user stream", "lockbytes", "property", "root storage" };
1150:
1151: for (i = 0; i < dir->dir_len; i++) {
1152: d = &dir->dir_tab[i];
1153: for (j = 0; j < sizeof(name); j++)
1154: name[j] = (char)CDF_TOLE2(d->d_name[j]);
1.1.1.2 misho 1155: (void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n",
1156: i, name);
1.1 misho 1157: if (d->d_type < __arraycount(types))
1158: (void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
1159: else
1160: (void)fprintf(stderr, "Type: %d\n", d->d_type);
1161: (void)fprintf(stderr, "Color: %s\n",
1162: d->d_color ? "black" : "red");
1163: (void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
1164: (void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
1165: (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags);
1166: cdf_timestamp_to_timespec(&ts, d->d_created);
1.1.1.2 misho 1167: (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec));
1.1 misho 1168: cdf_timestamp_to_timespec(&ts, d->d_modified);
1.1.1.2 misho 1169: (void)fprintf(stderr, "Modified %s", cdf_ctime(&ts.tv_sec));
1.1 misho 1170: (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
1171: (void)fprintf(stderr, "Size %d\n", d->d_size);
1172: switch (d->d_type) {
1173: case CDF_DIR_TYPE_USER_STORAGE:
1174: (void)fprintf(stderr, "Storage: %d\n", d->d_storage);
1175: break;
1176: case CDF_DIR_TYPE_USER_STREAM:
1177: if (sst == NULL)
1178: break;
1179: if (cdf_read_sector_chain(info, h, sat, ssat, sst,
1180: d->d_stream_first_sector, d->d_size, &scn) == -1) {
1181: warn("Can't read stream for %s at %d len %d",
1182: name, d->d_stream_first_sector, d->d_size);
1183: break;
1184: }
1185: cdf_dump_stream(h, &scn);
1186: free(scn.sst_tab);
1187: break;
1188: default:
1189: break;
1190: }
1.1.1.2 misho 1191:
1.1 misho 1192: }
1193: }
1194:
1195: void
1196: cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
1197: {
1198: cdf_timestamp_t tp;
1199: struct timeval ts;
1200: char buf[64];
1.1.1.2 misho 1201: size_t i, j;
1.1 misho 1202:
1203: for (i = 0; i < count; i++) {
1204: cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
1.1.1.2 misho 1205: (void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf);
1.1 misho 1206: switch (info[i].pi_type) {
1.1.1.2 misho 1207: case CDF_NULL:
1208: break;
1.1 misho 1209: case CDF_SIGNED16:
1210: (void)fprintf(stderr, "signed 16 [%hd]\n",
1211: info[i].pi_s16);
1212: break;
1213: case CDF_SIGNED32:
1214: (void)fprintf(stderr, "signed 32 [%d]\n",
1215: info[i].pi_s32);
1216: break;
1217: case CDF_UNSIGNED32:
1218: (void)fprintf(stderr, "unsigned 32 [%u]\n",
1219: info[i].pi_u32);
1220: break;
1.1.1.2 misho 1221: case CDF_FLOAT:
1222: (void)fprintf(stderr, "float [%g]\n",
1223: info[i].pi_f);
1224: break;
1225: case CDF_DOUBLE:
1226: (void)fprintf(stderr, "double [%g]\n",
1227: info[i].pi_d);
1228: break;
1.1 misho 1229: case CDF_LENGTH32_STRING:
1230: (void)fprintf(stderr, "string %u [%.*s]\n",
1231: info[i].pi_str.s_len,
1232: info[i].pi_str.s_len, info[i].pi_str.s_buf);
1233: break;
1.1.1.2 misho 1234: case CDF_LENGTH32_WSTRING:
1235: (void)fprintf(stderr, "string %u [",
1236: info[i].pi_str.s_len);
1237: for (j = 0; j < info[i].pi_str.s_len - 1; j++)
1238: (void)fputc(info[i].pi_str.s_buf[j << 1], stderr);
1239: (void)fprintf(stderr, "]\n");
1240: break;
1.1 misho 1241: case CDF_FILETIME:
1242: tp = info[i].pi_tp;
1243: #if defined(PHP_WIN32) && _MSC_VER <= 1500
1244: if (tp < 1000000000000000i64) {
1245: #else
1246: if (tp < 1000000000000000LL) {
1247: #endif
1248: cdf_print_elapsed_time(buf, sizeof(buf), tp);
1249: (void)fprintf(stderr, "timestamp %s\n", buf);
1250: } else {
1251: cdf_timestamp_to_timespec(&ts, tp);
1252: (void)fprintf(stderr, "timestamp %s",
1.1.1.2 misho 1253: cdf_ctime(&ts.tv_sec));
1.1 misho 1254: }
1255: break;
1256: case CDF_CLIPBOARD:
1257: (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
1258: break;
1259: default:
1260: DPRINTF(("Don't know how to deal with %x\n",
1261: info[i].pi_type));
1262: break;
1263: }
1264: }
1265: }
1266:
1267:
1268: void
1269: cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
1270: {
1271: char buf[128];
1272: cdf_summary_info_header_t ssi;
1273: cdf_property_info_t *info;
1274: size_t count;
1275:
1276: (void)&h;
1.1.1.2 misho 1277: if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1)
1.1 misho 1278: return;
1279: (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
1280: (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
1281: ssi.si_os_version >> 8);
1282: (void)fprintf(stderr, "Os %d\n", ssi.si_os);
1283: cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
1284: (void)fprintf(stderr, "Class %s\n", buf);
1285: (void)fprintf(stderr, "Count %d\n", ssi.si_count);
1286: cdf_dump_property_info(info, count);
1287: free(info);
1288: }
1289:
1290: #endif
1291:
1292: #ifdef TEST
1293: int
1294: main(int argc, char *argv[])
1295: {
1296: int i;
1297: cdf_header_t h;
1298: cdf_sat_t sat, ssat;
1299: cdf_stream_t sst, scn;
1300: cdf_dir_t dir;
1301: cdf_info_t info;
1302:
1303: if (argc < 2) {
1304: (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
1305: return -1;
1306: }
1307:
1308: info.i_buf = NULL;
1309: info.i_len = 0;
1310: for (i = 1; i < argc; i++) {
1311: if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
1312: err(1, "Cannot open `%s'", argv[1]);
1313:
1314: if (cdf_read_header(&info, &h) == -1)
1315: err(1, "Cannot read header");
1316: #ifdef CDF_DEBUG
1317: cdf_dump_header(&h);
1318: #endif
1319:
1320: if (cdf_read_sat(&info, &h, &sat) == -1)
1321: err(1, "Cannot read sat");
1322: #ifdef CDF_DEBUG
1323: cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
1324: #endif
1325:
1326: if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
1327: err(1, "Cannot read ssat");
1328: #ifdef CDF_DEBUG
1.1.1.2 misho 1329: cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
1.1 misho 1330: #endif
1331:
1332: if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
1333: err(1, "Cannot read dir");
1334:
1335: if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
1336: err(1, "Cannot read short stream");
1337: #ifdef CDF_DEBUG
1338: cdf_dump_stream(&h, &sst);
1339: #endif
1340:
1341: #ifdef CDF_DEBUG
1342: cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
1343: #endif
1344:
1345:
1346: if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
1347: &scn) == -1)
1348: err(1, "Cannot read summary info");
1349: #ifdef CDF_DEBUG
1350: cdf_dump_summary_info(&h, &scn);
1351: #endif
1352:
1353: (void)close(info.i_fd);
1354: }
1355:
1356: return 0;
1357: }
1358: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>