Annotation of embedaddon/php/ext/fileinfo/libmagic/cdf.c, revision 1.1.1.2
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.2 ! misho 38: FILE_RCSID("@(#)$File: cdf.c,v 1.50 2012/02/20 22:35:29 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;
! 281: if (e >= b && (size_t)(e - b) < CDF_SEC_SIZE(h) * sst->sst_len)
1.1 misho 282: return 0;
1.1.1.2 ! misho 283: DPRINTF(("%d: offset begin %p end %p %" SIZE_T_FORMAT "u"
! 284: " >= %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %"
! 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 misho 826: o = 2;
827: } else {
828: nelements = 1;
829: o = 1;
830: }
1.1.1.2 ! misho 831: o4 = o * sizeof(uint32_t);
1.1 misho 832: if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
833: goto unknown;
834: switch (inp[i].pi_type & CDF_TYPEMASK) {
1.1.1.2 ! misho 835: case CDF_NULL:
1.1 misho 836: case CDF_EMPTY:
837: break;
838: case CDF_SIGNED16:
839: if (inp[i].pi_type & CDF_VECTOR)
840: goto unknown;
1.1.1.2 ! misho 841: (void)memcpy(&s16, &q[o4], sizeof(s16));
1.1 misho 842: inp[i].pi_s16 = CDF_TOLE2(s16);
843: break;
844: case CDF_SIGNED32:
845: if (inp[i].pi_type & CDF_VECTOR)
846: goto unknown;
1.1.1.2 ! misho 847: (void)memcpy(&s32, &q[o4], sizeof(s32));
! 848: inp[i].pi_s32 = CDF_TOLE4((uint32_t)s32);
1.1 misho 849: break;
850: case CDF_BOOL:
851: case CDF_UNSIGNED32:
852: if (inp[i].pi_type & CDF_VECTOR)
853: goto unknown;
1.1.1.2 ! misho 854: (void)memcpy(&u32, &q[o4], sizeof(u32));
1.1 misho 855: inp[i].pi_u32 = CDF_TOLE4(u32);
856: break;
857: case CDF_SIGNED64:
858: if (inp[i].pi_type & CDF_VECTOR)
859: goto unknown;
1.1.1.2 ! misho 860: (void)memcpy(&s64, &q[o4], sizeof(s64));
! 861: inp[i].pi_s64 = CDF_TOLE8((uint64_t)s64);
1.1 misho 862: break;
863: case CDF_UNSIGNED64:
864: if (inp[i].pi_type & CDF_VECTOR)
865: goto unknown;
1.1.1.2 ! misho 866: (void)memcpy(&u64, &q[o4], sizeof(u64));
! 867: inp[i].pi_u64 = CDF_TOLE8((uint64_t)u64);
! 868: break;
! 869: case CDF_FLOAT:
! 870: if (inp[i].pi_type & CDF_VECTOR)
! 871: goto unknown;
! 872: (void)memcpy(&u32, &q[o4], sizeof(u32));
! 873: u32 = CDF_TOLE4(u32);
! 874: memcpy(&inp[i].pi_f, &u32, sizeof(inp[i].pi_f));
! 875: break;
! 876: case CDF_DOUBLE:
! 877: if (inp[i].pi_type & CDF_VECTOR)
! 878: goto unknown;
! 879: (void)memcpy(&u64, &q[o4], sizeof(u64));
! 880: u64 = CDF_TOLE8((uint64_t)u64);
! 881: memcpy(&inp[i].pi_d, &u64, sizeof(inp[i].pi_d));
1.1 misho 882: break;
883: case CDF_LENGTH32_STRING:
1.1.1.2 ! misho 884: case CDF_LENGTH32_WSTRING:
1.1 misho 885: if (nelements > 1) {
886: size_t nelem = inp - *info;
887: if (*maxcount > CDF_PROP_LIMIT
888: || nelements > CDF_PROP_LIMIT)
889: goto out;
890: *maxcount += nelements;
1.1.1.2 ! misho 891: inp = CAST(cdf_property_info_t *,
! 892: realloc(*info, *maxcount * sizeof(*inp)));
1.1 misho 893: if (inp == NULL)
894: goto out;
895: *info = inp;
896: inp = *info + nelem;
897: }
1.1.1.2 ! misho 898: DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n",
! 899: nelements));
1.1 misho 900: for (j = 0; j < nelements; j++, i++) {
1.1.1.2 ! misho 901: uint32_t l = CDF_GETUINT32(q, o);
1.1 misho 902: inp[i].pi_str.s_len = l;
1.1.1.2 ! misho 903: inp[i].pi_str.s_buf = (const char *)
! 904: (const void *)(&q[o4 + sizeof(l)]);
! 905: DPRINTF(("l = %d, r = %" SIZE_T_FORMAT
! 906: "u, s = %s\n", l,
1.1 misho 907: CDF_ROUND(l, sizeof(l)),
908: inp[i].pi_str.s_buf));
1.1.1.2 ! misho 909: if (l & 1)
! 910: l++;
! 911: o += l >> 1;
! 912: if (q + o >= e)
! 913: goto out;
! 914: o4 = o * sizeof(uint32_t);
1.1 misho 915: }
916: i--;
917: break;
918: case CDF_FILETIME:
919: if (inp[i].pi_type & CDF_VECTOR)
920: goto unknown;
1.1.1.2 ! misho 921: (void)memcpy(&tp, &q[o4], sizeof(tp));
! 922: inp[i].pi_tp = CDF_TOLE8((uint64_t)tp);
1.1 misho 923: break;
924: case CDF_CLIPBOARD:
925: if (inp[i].pi_type & CDF_VECTOR)
926: goto unknown;
927: break;
928: default:
929: unknown:
930: DPRINTF(("Don't know how to deal with %x\n",
931: inp[i].pi_type));
1.1.1.2 ! misho 932: break;
1.1 misho 933: }
934: }
935: return 0;
936: out:
937: free(*info);
938: return -1;
939: }
940:
941: int
1.1.1.2 ! misho 942: cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
! 943: cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count)
1.1 misho 944: {
945: size_t i, maxcount;
1.1.1.2 ! misho 946: const cdf_summary_info_header_t *si =
! 947: CAST(const cdf_summary_info_header_t *, sst->sst_tab);
! 948: const cdf_section_declaration_t *sd =
! 949: CAST(const cdf_section_declaration_t *, (const void *)
! 950: ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET));
1.1 misho 951:
1.1.1.2 ! misho 952: if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 ||
! 953: cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1)
1.1 misho 954: return -1;
955: ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
956: ssi->si_os_version = CDF_TOLE2(si->si_os_version);
957: ssi->si_os = CDF_TOLE2(si->si_os);
958: ssi->si_class = si->si_class;
959: cdf_swap_class(&ssi->si_class);
960: ssi->si_count = CDF_TOLE2(si->si_count);
961: *count = 0;
962: maxcount = 0;
963: *info = NULL;
964: for (i = 0; i < CDF_TOLE4(si->si_count); i++) {
965: if (i >= CDF_LOOP_LIMIT) {
966: DPRINTF(("Unpack summary info loop limit"));
967: errno = EFTYPE;
968: return -1;
969: }
1.1.1.2 ! misho 970: if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset),
! 971: info, count, &maxcount) == -1) {
1.1 misho 972: return -1;
1.1.1.2 ! misho 973: }
1.1 misho 974: }
975: return 0;
976: }
977:
978:
979:
980: int
981: cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
982: {
983: return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
984: "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
985: id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
986: id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
987: id->cl_six[5]);
988: }
989:
990: static const struct {
991: uint32_t v;
992: const char *n;
993: } vn[] = {
994: { CDF_PROPERTY_CODE_PAGE, "Code page" },
995: { CDF_PROPERTY_TITLE, "Title" },
996: { CDF_PROPERTY_SUBJECT, "Subject" },
997: { CDF_PROPERTY_AUTHOR, "Author" },
998: { CDF_PROPERTY_KEYWORDS, "Keywords" },
999: { CDF_PROPERTY_COMMENTS, "Comments" },
1000: { CDF_PROPERTY_TEMPLATE, "Template" },
1001: { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
1002: { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
1003: { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
1004: { CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
1005: { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
1006: { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
1007: { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
1008: { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
1009: { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
1010: { CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
1011: { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
1012: { CDF_PROPERTY_SECURITY, "Security" },
1013: { CDF_PROPERTY_LOCALE_ID, "Locale ID" },
1014: };
1015:
1016: int
1017: cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
1018: {
1019: size_t i;
1020:
1021: for (i = 0; i < __arraycount(vn); i++)
1022: if (vn[i].v == p)
1023: return snprintf(buf, bufsiz, "%s", vn[i].n);
1024: return snprintf(buf, bufsiz, "0x%x", p);
1025: }
1026:
1027: int
1028: cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
1029: {
1.1.1.2 ! misho 1030: int len = 0;
1.1 misho 1031: int days, hours, mins, secs;
1032:
1033: ts /= CDF_TIME_PREC;
1.1.1.2 ! misho 1034: secs = (int)(ts % 60);
1.1 misho 1035: ts /= 60;
1.1.1.2 ! misho 1036: mins = (int)(ts % 60);
1.1 misho 1037: ts /= 60;
1.1.1.2 ! misho 1038: hours = (int)(ts % 24);
1.1 misho 1039: ts /= 24;
1.1.1.2 ! misho 1040: days = (int)ts;
1.1 misho 1041:
1042: if (days) {
1043: len += snprintf(buf + len, bufsiz - len, "%dd+", days);
1.1.1.2 ! misho 1044: if ((size_t)len >= bufsiz)
1.1 misho 1045: return len;
1046: }
1047:
1048: if (days || hours) {
1049: len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
1.1.1.2 ! misho 1050: if ((size_t)len >= bufsiz)
1.1 misho 1051: return len;
1052: }
1053:
1054: len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
1.1.1.2 ! misho 1055: if ((size_t)len >= bufsiz)
1.1 misho 1056: return len;
1057:
1058: len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
1059: return len;
1060: }
1061:
1062:
1063: #ifdef CDF_DEBUG
1064: void
1065: cdf_dump_header(const cdf_header_t *h)
1066: {
1067: size_t i;
1068:
1069: #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
1070: #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
1071: h->h_ ## b, 1 << h->h_ ## b)
1072: DUMP("%d", revision);
1073: DUMP("%d", version);
1074: DUMP("0x%x", byte_order);
1075: DUMP2("%d", sec_size_p2);
1076: DUMP2("%d", short_sec_size_p2);
1077: DUMP("%d", num_sectors_in_sat);
1078: DUMP("%d", secid_first_directory);
1079: DUMP("%d", min_size_standard_stream);
1080: DUMP("%d", secid_first_sector_in_short_sat);
1081: DUMP("%d", num_sectors_in_short_sat);
1082: DUMP("%d", secid_first_sector_in_master_sat);
1083: DUMP("%d", num_sectors_in_master_sat);
1084: for (i = 0; i < __arraycount(h->h_master_sat); i++) {
1085: if (h->h_master_sat[i] == CDF_SECID_FREE)
1086: break;
1087: (void)fprintf(stderr, "%35.35s[%.3zu] = %d\n",
1088: "master_sat", i, h->h_master_sat[i]);
1089: }
1090: }
1091:
1092: void
1093: cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
1094: {
1095: size_t i, j, s = size / sizeof(cdf_secid_t);
1096:
1097: for (i = 0; i < sat->sat_len; i++) {
1.1.1.2 ! misho 1098: (void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6"
! 1099: SIZE_T_FORMAT "u: ", prefix, i, i * s);
1.1 misho 1100: for (j = 0; j < s; j++) {
1101: (void)fprintf(stderr, "%5d, ",
1102: CDF_TOLE4(sat->sat_tab[s * i + j]));
1103: if ((j + 1) % 10 == 0)
1.1.1.2 ! misho 1104: (void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT
! 1105: "u: ", i * s + j + 1);
1.1 misho 1106: }
1107: (void)fprintf(stderr, "\n");
1108: }
1109: }
1110:
1111: void
1112: cdf_dump(void *v, size_t len)
1113: {
1114: size_t i, j;
1115: unsigned char *p = v;
1116: char abuf[16];
1117: (void)fprintf(stderr, "%.4x: ", 0);
1118: for (i = 0, j = 0; i < len; i++, p++) {
1119: (void)fprintf(stderr, "%.2x ", *p);
1120: abuf[j++] = isprint(*p) ? *p : '.';
1121: if (j == 16) {
1122: j = 0;
1123: abuf[15] = '\0';
1.1.1.2 ! misho 1124: (void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ",
! 1125: abuf, i + 1);
1.1 misho 1126: }
1127: }
1128: (void)fprintf(stderr, "\n");
1129: }
1130:
1131: void
1132: cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
1133: {
1134: size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
1135: CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
1136: cdf_dump(sst->sst_tab, ss * sst->sst_len);
1137: }
1138:
1139: void
1140: cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
1141: const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
1142: const cdf_dir_t *dir)
1143: {
1144: size_t i, j;
1145: cdf_directory_t *d;
1146: char name[__arraycount(d->d_name)];
1147: cdf_stream_t scn;
1148: struct timeval ts;
1149:
1150: static const char *types[] = { "empty", "user storage",
1151: "user stream", "lockbytes", "property", "root storage" };
1152:
1153: for (i = 0; i < dir->dir_len; i++) {
1154: d = &dir->dir_tab[i];
1155: for (j = 0; j < sizeof(name); j++)
1156: name[j] = (char)CDF_TOLE2(d->d_name[j]);
1.1.1.2 ! misho 1157: (void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n",
! 1158: i, name);
1.1 misho 1159: if (d->d_type < __arraycount(types))
1160: (void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
1161: else
1162: (void)fprintf(stderr, "Type: %d\n", d->d_type);
1163: (void)fprintf(stderr, "Color: %s\n",
1164: d->d_color ? "black" : "red");
1165: (void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
1166: (void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
1167: (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags);
1168: cdf_timestamp_to_timespec(&ts, d->d_created);
1.1.1.2 ! misho 1169: (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec));
1.1 misho 1170: cdf_timestamp_to_timespec(&ts, d->d_modified);
1.1.1.2 ! misho 1171: (void)fprintf(stderr, "Modified %s", cdf_ctime(&ts.tv_sec));
1.1 misho 1172: (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
1173: (void)fprintf(stderr, "Size %d\n", d->d_size);
1174: switch (d->d_type) {
1175: case CDF_DIR_TYPE_USER_STORAGE:
1176: (void)fprintf(stderr, "Storage: %d\n", d->d_storage);
1177: break;
1178: case CDF_DIR_TYPE_USER_STREAM:
1179: if (sst == NULL)
1180: break;
1181: if (cdf_read_sector_chain(info, h, sat, ssat, sst,
1182: d->d_stream_first_sector, d->d_size, &scn) == -1) {
1183: warn("Can't read stream for %s at %d len %d",
1184: name, d->d_stream_first_sector, d->d_size);
1185: break;
1186: }
1187: cdf_dump_stream(h, &scn);
1188: free(scn.sst_tab);
1189: break;
1190: default:
1191: break;
1192: }
1.1.1.2 ! misho 1193:
1.1 misho 1194: }
1195: }
1196:
1197: void
1198: cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
1199: {
1200: cdf_timestamp_t tp;
1201: struct timeval ts;
1202: char buf[64];
1.1.1.2 ! misho 1203: size_t i, j;
1.1 misho 1204:
1205: for (i = 0; i < count; i++) {
1206: cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
1.1.1.2 ! misho 1207: (void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf);
1.1 misho 1208: switch (info[i].pi_type) {
1.1.1.2 ! misho 1209: case CDF_NULL:
! 1210: break;
1.1 misho 1211: case CDF_SIGNED16:
1212: (void)fprintf(stderr, "signed 16 [%hd]\n",
1213: info[i].pi_s16);
1214: break;
1215: case CDF_SIGNED32:
1216: (void)fprintf(stderr, "signed 32 [%d]\n",
1217: info[i].pi_s32);
1218: break;
1219: case CDF_UNSIGNED32:
1220: (void)fprintf(stderr, "unsigned 32 [%u]\n",
1221: info[i].pi_u32);
1222: break;
1.1.1.2 ! misho 1223: case CDF_FLOAT:
! 1224: (void)fprintf(stderr, "float [%g]\n",
! 1225: info[i].pi_f);
! 1226: break;
! 1227: case CDF_DOUBLE:
! 1228: (void)fprintf(stderr, "double [%g]\n",
! 1229: info[i].pi_d);
! 1230: break;
1.1 misho 1231: case CDF_LENGTH32_STRING:
1232: (void)fprintf(stderr, "string %u [%.*s]\n",
1233: info[i].pi_str.s_len,
1234: info[i].pi_str.s_len, info[i].pi_str.s_buf);
1235: break;
1.1.1.2 ! misho 1236: case CDF_LENGTH32_WSTRING:
! 1237: (void)fprintf(stderr, "string %u [",
! 1238: info[i].pi_str.s_len);
! 1239: for (j = 0; j < info[i].pi_str.s_len - 1; j++)
! 1240: (void)fputc(info[i].pi_str.s_buf[j << 1], stderr);
! 1241: (void)fprintf(stderr, "]\n");
! 1242: break;
1.1 misho 1243: case CDF_FILETIME:
1244: tp = info[i].pi_tp;
1245: #if defined(PHP_WIN32) && _MSC_VER <= 1500
1246: if (tp < 1000000000000000i64) {
1247: #else
1248: if (tp < 1000000000000000LL) {
1249: #endif
1250: cdf_print_elapsed_time(buf, sizeof(buf), tp);
1251: (void)fprintf(stderr, "timestamp %s\n", buf);
1252: } else {
1253: cdf_timestamp_to_timespec(&ts, tp);
1254: (void)fprintf(stderr, "timestamp %s",
1.1.1.2 ! misho 1255: cdf_ctime(&ts.tv_sec));
1.1 misho 1256: }
1257: break;
1258: case CDF_CLIPBOARD:
1259: (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
1260: break;
1261: default:
1262: DPRINTF(("Don't know how to deal with %x\n",
1263: info[i].pi_type));
1264: break;
1265: }
1266: }
1267: }
1268:
1269:
1270: void
1271: cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
1272: {
1273: char buf[128];
1274: cdf_summary_info_header_t ssi;
1275: cdf_property_info_t *info;
1276: size_t count;
1277:
1278: (void)&h;
1.1.1.2 ! misho 1279: if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1)
1.1 misho 1280: return;
1281: (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
1282: (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
1283: ssi.si_os_version >> 8);
1284: (void)fprintf(stderr, "Os %d\n", ssi.si_os);
1285: cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
1286: (void)fprintf(stderr, "Class %s\n", buf);
1287: (void)fprintf(stderr, "Count %d\n", ssi.si_count);
1288: cdf_dump_property_info(info, count);
1289: free(info);
1290: }
1291:
1292: #endif
1293:
1294: #ifdef TEST
1295: int
1296: main(int argc, char *argv[])
1297: {
1298: int i;
1299: cdf_header_t h;
1300: cdf_sat_t sat, ssat;
1301: cdf_stream_t sst, scn;
1302: cdf_dir_t dir;
1303: cdf_info_t info;
1304:
1305: if (argc < 2) {
1306: (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
1307: return -1;
1308: }
1309:
1310: info.i_buf = NULL;
1311: info.i_len = 0;
1312: for (i = 1; i < argc; i++) {
1313: if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
1314: err(1, "Cannot open `%s'", argv[1]);
1315:
1316: if (cdf_read_header(&info, &h) == -1)
1317: err(1, "Cannot read header");
1318: #ifdef CDF_DEBUG
1319: cdf_dump_header(&h);
1320: #endif
1321:
1322: if (cdf_read_sat(&info, &h, &sat) == -1)
1323: err(1, "Cannot read sat");
1324: #ifdef CDF_DEBUG
1325: cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
1326: #endif
1327:
1328: if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
1329: err(1, "Cannot read ssat");
1330: #ifdef CDF_DEBUG
1.1.1.2 ! misho 1331: cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
1.1 misho 1332: #endif
1333:
1334: if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
1335: err(1, "Cannot read dir");
1336:
1337: if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
1338: err(1, "Cannot read short stream");
1339: #ifdef CDF_DEBUG
1340: cdf_dump_stream(&h, &sst);
1341: #endif
1342:
1343: #ifdef CDF_DEBUG
1344: cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
1345: #endif
1346:
1347:
1348: if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
1349: &scn) == -1)
1350: err(1, "Cannot read summary info");
1351: #ifdef CDF_DEBUG
1352: cdf_dump_summary_info(&h, &scn);
1353: #endif
1354:
1355: (void)close(info.i_fd);
1356: }
1357:
1358: return 0;
1359: }
1360: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>