1 /* $NetBSD: cdf.c,v 1.2 2009/05/08 17:28:01 christos Exp $ */
4 * Copyright (c) 2008 Christos Zoulas
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 * Parse composite document files, the format used in Microsoft Office
30 * document files before they switched to zipped xml.
31 * Info from: http://sc.openoffice.org/compdocfileformat.pdf
38 FILE_RCSID("@(#)$File: cdf.c,v 1.30 2009/05/06 14:29:47 christos Exp $")
40 __RCSID("$NetBSD: cdf.c,v 1.2 2009/05/08 17:28:01 christos Exp $");
61 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
65 #define DPRINTF(a) printf a, fflush(stdout)
75 #define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304)
77 #define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x)))
78 #define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x)))
79 #define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x)))
85 cdf_tole2(uint16_t sv
)
88 uint8_t *s
= (uint8_t *)(void *)&sv
;
89 uint8_t *d
= (uint8_t *)(void *)&rv
;
99 cdf_tole4(uint32_t sv
)
102 uint8_t *s
= (uint8_t *)(void *)&sv
;
103 uint8_t *d
= (uint8_t *)(void *)&rv
;
115 cdf_tole8(uint64_t sv
)
118 uint8_t *s
= (uint8_t *)(void *)&sv
;
119 uint8_t *d
= (uint8_t *)(void *)&rv
;
131 #define CDF_UNPACK(a) \
132 (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
133 #define CDF_UNPACKA(a) \
134 (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
137 cdf_swap_header(cdf_header_t
*h
)
141 h
->h_magic
= CDF_TOLE8(h
->h_magic
);
142 h
->h_uuid
[0] = CDF_TOLE8(h
->h_uuid
[0]);
143 h
->h_uuid
[1] = CDF_TOLE8(h
->h_uuid
[1]);
144 h
->h_revision
= CDF_TOLE2(h
->h_revision
);
145 h
->h_version
= CDF_TOLE2(h
->h_version
);
146 h
->h_byte_order
= CDF_TOLE2(h
->h_byte_order
);
147 h
->h_sec_size_p2
= CDF_TOLE2(h
->h_sec_size_p2
);
148 h
->h_short_sec_size_p2
= CDF_TOLE2(h
->h_short_sec_size_p2
);
149 h
->h_num_sectors_in_sat
= CDF_TOLE4(h
->h_num_sectors_in_sat
);
150 h
->h_secid_first_directory
= CDF_TOLE4(h
->h_secid_first_directory
);
151 h
->h_min_size_standard_stream
=
152 CDF_TOLE4(h
->h_min_size_standard_stream
);
153 h
->h_secid_first_sector_in_short_sat
=
154 CDF_TOLE4((uint32_t)h
->h_secid_first_sector_in_short_sat
);
155 h
->h_num_sectors_in_short_sat
=
156 CDF_TOLE4(h
->h_num_sectors_in_short_sat
);
157 h
->h_secid_first_sector_in_master_sat
=
158 CDF_TOLE4((uint32_t)h
->h_secid_first_sector_in_master_sat
);
159 h
->h_num_sectors_in_master_sat
=
160 CDF_TOLE4(h
->h_num_sectors_in_master_sat
);
161 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++)
162 h
->h_master_sat
[i
] = CDF_TOLE4((uint32_t)h
->h_master_sat
[i
]);
166 cdf_unpack_header(cdf_header_t
*h
, char *buf
)
171 CDF_UNPACK(h
->h_magic
);
172 CDF_UNPACKA(h
->h_uuid
);
173 CDF_UNPACK(h
->h_revision
);
174 CDF_UNPACK(h
->h_version
);
175 CDF_UNPACK(h
->h_byte_order
);
176 CDF_UNPACK(h
->h_sec_size_p2
);
177 CDF_UNPACK(h
->h_short_sec_size_p2
);
178 CDF_UNPACKA(h
->h_unused0
);
179 CDF_UNPACK(h
->h_num_sectors_in_sat
);
180 CDF_UNPACK(h
->h_secid_first_directory
);
181 CDF_UNPACKA(h
->h_unused1
);
182 CDF_UNPACK(h
->h_min_size_standard_stream
);
183 CDF_UNPACK(h
->h_secid_first_sector_in_short_sat
);
184 CDF_UNPACK(h
->h_num_sectors_in_short_sat
);
185 CDF_UNPACK(h
->h_secid_first_sector_in_master_sat
);
186 CDF_UNPACK(h
->h_num_sectors_in_master_sat
);
187 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++)
188 CDF_UNPACK(h
->h_master_sat
[i
]);
192 cdf_swap_dir(cdf_directory_t
*d
)
194 d
->d_namelen
= CDF_TOLE2(d
->d_namelen
);
195 d
->d_left_child
= CDF_TOLE4((uint32_t)d
->d_left_child
);
196 d
->d_right_child
= CDF_TOLE4((uint32_t)d
->d_right_child
);
197 d
->d_storage
= CDF_TOLE4((uint32_t)d
->d_storage
);
198 d
->d_storage_uuid
[0] = CDF_TOLE8(d
->d_storage_uuid
[0]);
199 d
->d_storage_uuid
[1] = CDF_TOLE8(d
->d_storage_uuid
[1]);
200 d
->d_flags
= CDF_TOLE4(d
->d_flags
);
201 d
->d_created
= CDF_TOLE8((uint64_t)d
->d_created
);
202 d
->d_modified
= CDF_TOLE8((uint64_t)d
->d_modified
);
203 d
->d_stream_first_sector
= CDF_TOLE4((uint32_t)d
->d_stream_first_sector
);
204 d
->d_size
= CDF_TOLE4(d
->d_size
);
208 cdf_swap_class(cdf_classid_t
*d
)
210 d
->cl_dword
= CDF_TOLE4(d
->cl_dword
);
211 d
->cl_word
[0] = CDF_TOLE2(d
->cl_word
[0]);
212 d
->cl_word
[1] = CDF_TOLE2(d
->cl_word
[1]);
216 cdf_unpack_dir(cdf_directory_t
*d
, char *buf
)
220 CDF_UNPACKA(d
->d_name
);
221 CDF_UNPACK(d
->d_namelen
);
222 CDF_UNPACK(d
->d_type
);
223 CDF_UNPACK(d
->d_color
);
224 CDF_UNPACK(d
->d_left_child
);
225 CDF_UNPACK(d
->d_right_child
);
226 CDF_UNPACK(d
->d_storage
);
227 CDF_UNPACKA(d
->d_storage_uuid
);
228 CDF_UNPACK(d
->d_flags
);
229 CDF_UNPACK(d
->d_created
);
230 CDF_UNPACK(d
->d_modified
);
231 CDF_UNPACK(d
->d_stream_first_sector
);
232 CDF_UNPACK(d
->d_size
);
233 CDF_UNPACK(d
->d_unused0
);
237 cdf_check_stream_offset(const cdf_stream_t
*sst
, const void *p
, size_t tail
)
239 const char *b
= (const char *)sst
->sst_tab
;
240 const char *e
= ((const char *)p
) + tail
;
241 if (e
>= b
&& (size_t)(e
- b
) < sst
->sst_dirlen
* sst
->sst_len
)
243 DPRINTF((stderr
, "offset begin %p end %p %zu >= %zu\n", b
, e
,
244 (size_t)(e
- b
), sst
->sst_dirlen
* sst
->sst_len
));
250 cdf_read(const cdf_info_t
*info
, off_t off
, void *buf
, size_t len
)
252 size_t siz
= (size_t)off
+ len
;
254 if ((off_t
)(off
+ len
) != (off_t
)siz
) {
259 if (info
->i_buf
!= NULL
&& info
->i_len
>= siz
) {
260 (void)memcpy(buf
, &info
->i_buf
[off
], len
);
264 if (info
->i_fd
== -1)
267 if (lseek(info
->i_fd
, off
, SEEK_SET
) == (off_t
)-1)
270 if (read(info
->i_fd
, buf
, len
) != (ssize_t
)len
)
277 cdf_read_header(const cdf_info_t
*info
, cdf_header_t
*h
)
281 (void)memcpy(cdf_bo
.s
, "\01\02\03\04", 4);
282 if (cdf_read(info
, (off_t
)0, buf
, sizeof(buf
)) == -1)
284 cdf_unpack_header(h
, buf
);
286 if (h
->h_magic
!= CDF_MAGIC
) {
287 DPRINTF(("Bad magic 0x%llx != 0x%llx\n",
288 (unsigned long long)h
->h_magic
,
289 (unsigned long long)CDF_MAGIC
));
292 if (h
->h_sec_size_p2
> 20) {
293 DPRINTF(("Bad sector size 0x%u\n", h
->h_sec_size_p2
));
296 if (h
->h_short_sec_size_p2
> 20) {
297 DPRINTF(("Bad short sector size 0x%u\n",
298 h
->h_short_sec_size_p2
));
309 cdf_read_sector(const cdf_info_t
*info
, void *buf
, size_t offs
, size_t len
,
310 const cdf_header_t
*h
, cdf_secid_t id
)
312 assert((size_t)CDF_SEC_SIZE(h
) == len
);
313 return cdf_read(info
, (off_t
)CDF_SEC_POS(h
, id
),
314 ((char *)buf
) + offs
, len
);
318 cdf_read_short_sector(const cdf_stream_t
*sst
, void *buf
, size_t offs
,
319 size_t len
, const cdf_header_t
*h
, cdf_secid_t id
)
321 assert((size_t)CDF_SHORT_SEC_SIZE(h
) == len
);
322 (void)memcpy(((char *)buf
) + offs
,
323 ((const char *)sst
->sst_tab
) + CDF_SHORT_SEC_POS(h
, id
), len
);
328 * Read the sector allocation table.
331 cdf_read_sat(const cdf_info_t
*info
, cdf_header_t
*h
, cdf_sat_t
*sat
)
334 size_t ss
= CDF_SEC_SIZE(h
);
335 cdf_secid_t
*msa
, mid
, sec
;
336 size_t nsatpersec
= (ss
/ sizeof(mid
)) - 1;
338 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++)
339 if (h
->h_master_sat
[i
] == CDF_SECID_FREE
)
342 #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
343 if (h
->h_num_sectors_in_master_sat
> CDF_SEC_LIMIT
/ nsatpersec
||
345 DPRINTF(("Number of sectors in master SAT too big %u %zu\n",
346 h
->h_num_sectors_in_master_sat
, i
));
351 sat
->sat_len
= h
->h_num_sectors_in_master_sat
* nsatpersec
+ i
;
352 DPRINTF(("sat_len = %zu ss = %zu\n", sat
->sat_len
, ss
));
353 if ((sat
->sat_tab
= calloc(sat
->sat_len
, ss
)) == NULL
)
356 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++) {
357 if (h
->h_master_sat
[i
] < 0)
359 if (cdf_read_sector(info
, sat
->sat_tab
, ss
* i
, ss
, h
,
360 h
->h_master_sat
[i
]) != (ssize_t
)ss
) {
361 DPRINTF(("Reading sector %d", h
->h_master_sat
[i
]));
366 if ((msa
= calloc(1, ss
)) == NULL
)
369 mid
= h
->h_secid_first_sector_in_master_sat
;
370 for (j
= 0; j
< h
->h_num_sectors_in_master_sat
; j
++) {
373 if (j
>= CDF_LOOP_LIMIT
) {
374 DPRINTF(("Reading master sector loop limit"));
378 if (cdf_read_sector(info
, msa
, 0, ss
, h
, mid
) != (ssize_t
)ss
) {
379 DPRINTF(("Reading master sector %d", mid
));
382 for (k
= 0; k
< nsatpersec
; k
++, i
++) {
383 sec
= CDF_TOLE4((uint32_t)msa
[k
]);
386 if (i
>= sat
->sat_len
) {
387 DPRINTF(("Out of bounds reading MSA %u >= %u",
392 if (cdf_read_sector(info
, sat
->sat_tab
, ss
* i
, ss
, h
,
393 sec
) != (ssize_t
)ss
) {
394 DPRINTF(("Reading sector %d",
399 mid
= CDF_TOLE4((uint32_t)msa
[nsatpersec
]);
413 cdf_count_chain(const cdf_sat_t
*sat
, cdf_secid_t sid
, size_t size
)
416 cdf_secid_t maxsector
= (cdf_secid_t
)(sat
->sat_len
* size
);
419 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
420 DPRINTF((" %d", sid
));
421 if (j
>= CDF_LOOP_LIMIT
) {
422 DPRINTF(("Counting chain loop limit"));
426 if (sid
> maxsector
) {
427 DPRINTF(("Sector %d > %d\n", sid
, maxsector
));
431 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
438 cdf_read_long_sector_chain(const cdf_info_t
*info
, const cdf_header_t
*h
,
439 const cdf_sat_t
*sat
, cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
441 size_t ss
= CDF_SEC_SIZE(h
), i
, j
;
443 scn
->sst_len
= cdf_count_chain(sat
, sid
, ss
);
444 scn
->sst_dirlen
= len
;
446 if (scn
->sst_len
== (size_t)-1)
449 scn
->sst_tab
= calloc(scn
->sst_len
, ss
);
450 if (scn
->sst_tab
== NULL
)
453 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
454 if (j
>= CDF_LOOP_LIMIT
) {
455 DPRINTF(("Read long sector chain loop limit"));
459 if (i
>= scn
->sst_len
) {
460 DPRINTF(("Out of bounds reading long sector chain "
461 "%u > %u\n", i
, scn
->sst_len
));
465 if ((nr
= cdf_read_sector(info
, scn
->sst_tab
, i
* ss
, ss
, h
,
466 sid
)) != (ssize_t
)ss
) {
467 if (i
== scn
->sst_len
- 1 && nr
> 0) {
468 /* Last sector might be truncated */
471 DPRINTF(("Reading long sector chain %d", sid
));
474 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
483 cdf_read_short_sector_chain(const cdf_header_t
*h
,
484 const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
485 cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
487 size_t ss
= CDF_SHORT_SEC_SIZE(h
), i
, j
;
488 scn
->sst_len
= cdf_count_chain(ssat
, sid
, CDF_SEC_SIZE(h
));
489 scn
->sst_dirlen
= len
;
491 if (sst
->sst_tab
== NULL
|| scn
->sst_len
== (size_t)-1)
494 scn
->sst_tab
= calloc(scn
->sst_len
, ss
);
495 if (scn
->sst_tab
== NULL
)
498 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
499 if (j
>= CDF_LOOP_LIMIT
) {
500 DPRINTF(("Read short sector chain loop limit"));
504 if (i
>= scn
->sst_len
) {
505 DPRINTF(("Out of bounds reading short sector chain "
506 "%u > %u\n", i
, scn
->sst_len
));
510 if (cdf_read_short_sector(sst
, scn
->sst_tab
, i
* ss
, ss
, h
,
511 sid
) != (ssize_t
)ss
) {
512 DPRINTF(("Reading short sector chain %d", sid
));
515 sid
= CDF_TOLE4((uint32_t)ssat
->sat_tab
[sid
]);
524 cdf_read_sector_chain(const cdf_info_t
*info
, const cdf_header_t
*h
,
525 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
526 cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
529 if (len
< h
->h_min_size_standard_stream
)
530 return cdf_read_short_sector_chain(h
, ssat
, sst
, sid
, len
,
533 return cdf_read_long_sector_chain(info
, h
, sat
, sid
, len
, scn
);
537 cdf_read_dir(const cdf_info_t
*info
, const cdf_header_t
*h
,
538 const cdf_sat_t
*sat
, cdf_dir_t
*dir
)
541 size_t ss
= CDF_SEC_SIZE(h
), ns
, nd
;
543 cdf_secid_t sid
= h
->h_secid_first_directory
;
545 ns
= cdf_count_chain(sat
, sid
, ss
);
546 if (ns
== (size_t)-1)
549 nd
= ss
/ CDF_DIRECTORY_SIZE
;
551 dir
->dir_len
= ns
* nd
;
552 dir
->dir_tab
= calloc(dir
->dir_len
, sizeof(dir
->dir_tab
[0]));
553 if (dir
->dir_tab
== NULL
)
556 if ((buf
= malloc(ss
)) == NULL
) {
561 for (j
= i
= 0; i
< ns
; i
++, j
++) {
562 if (j
>= CDF_LOOP_LIMIT
) {
563 DPRINTF(("Read dir loop limit"));
567 if (cdf_read_sector(info
, buf
, 0, ss
, h
, sid
) != (ssize_t
)ss
) {
568 DPRINTF(("Reading directory sector %d", sid
));
571 for (j
= 0; j
< nd
; j
++) {
572 cdf_unpack_dir(&dir
->dir_tab
[i
* nd
+ j
],
573 &buf
[j
* CDF_DIRECTORY_SIZE
]);
575 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
578 for (i
= 0; i
< dir
->dir_len
; i
++)
579 cdf_swap_dir(&dir
->dir_tab
[i
]);
590 cdf_read_ssat(const cdf_info_t
*info
, const cdf_header_t
*h
,
591 const cdf_sat_t
*sat
, cdf_sat_t
*ssat
)
594 size_t ss
= CDF_SEC_SIZE(h
);
595 cdf_secid_t sid
= h
->h_secid_first_sector_in_short_sat
;
597 ssat
->sat_len
= cdf_count_chain(sat
, sid
, CDF_SEC_SIZE(h
));
598 if (ssat
->sat_len
== (size_t)-1)
601 ssat
->sat_tab
= calloc(ssat
->sat_len
, ss
);
602 if (ssat
->sat_tab
== NULL
)
605 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
606 if (j
>= CDF_LOOP_LIMIT
) {
607 DPRINTF(("Read short sat sector loop limit"));
611 if (i
>= ssat
->sat_len
) {
612 DPRINTF(("Out of bounds reading short sector chain "
613 "%u > %u\n", i
, ssat
->sat_len
));
617 if (cdf_read_sector(info
, ssat
->sat_tab
, i
* ss
, ss
, h
, sid
) !=
619 DPRINTF(("Reading short sat sector %d", sid
));
622 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
631 cdf_read_short_stream(const cdf_info_t
*info
, const cdf_header_t
*h
,
632 const cdf_sat_t
*sat
, const cdf_dir_t
*dir
, cdf_stream_t
*scn
)
635 const cdf_directory_t
*d
;
637 for (i
= 0; i
< dir
->dir_len
; i
++)
638 if (dir
->dir_tab
[i
].d_type
== CDF_DIR_TYPE_ROOT_STORAGE
)
641 /* If the it is not there, just fake it; some docs don't have it */
642 if (i
== dir
->dir_len
)
644 d
= &dir
->dir_tab
[i
];
646 /* If the it is not there, just fake it; some docs don't have it */
647 if (d
->d_stream_first_sector
< 0)
650 return cdf_read_long_sector_chain(info
, h
, sat
,
651 d
->d_stream_first_sector
, d
->d_size
, scn
);
660 cdf_namecmp(const char *d
, const uint16_t *s
, size_t l
)
662 for (; l
--; d
++, s
++)
663 if (*d
!= CDF_TOLE2(*s
))
664 return (unsigned char)*d
- CDF_TOLE2(*s
);
669 cdf_read_summary_info(const cdf_info_t
*info
, const cdf_header_t
*h
,
670 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
671 const cdf_dir_t
*dir
, cdf_stream_t
*scn
)
674 const cdf_directory_t
*d
;
675 static const char name
[] = "\05SummaryInformation";
677 for (i
= 0; i
< dir
->dir_len
; i
++)
678 if (dir
->dir_tab
[i
].d_type
== CDF_DIR_TYPE_USER_STREAM
&&
679 cdf_namecmp(name
, dir
->dir_tab
[i
].d_name
, sizeof(name
))
683 if (i
== dir
->dir_len
) {
684 DPRINTF(("Cannot find summary information section\n"));
688 d
= &dir
->dir_tab
[i
];
689 return cdf_read_sector_chain(info
, h
, sat
, ssat
, sst
,
690 d
->d_stream_first_sector
, d
->d_size
, scn
);
694 cdf_read_property_info(const cdf_stream_t
*sst
, uint32_t offs
,
695 cdf_property_info_t
**info
, size_t *count
, size_t *maxcount
)
697 const cdf_section_header_t
*shp
;
698 cdf_section_header_t sh
;
699 const uint32_t *p
, *q
, *e
;
706 size_t i
, o
, nelements
, j
;
707 cdf_property_info_t
*inp
;
709 if (offs
> UINT32_MAX
/ 4) {
713 shp
= (const void *)((const char *)sst
->sst_tab
+ offs
);
714 if (cdf_check_stream_offset(sst
, shp
, sizeof(*shp
)) == -1)
716 sh
.sh_len
= CDF_TOLE4(shp
->sh_len
);
717 #define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
718 if (sh
.sh_len
> CDF_SHLEN_LIMIT
) {
722 sh
.sh_properties
= CDF_TOLE4(shp
->sh_properties
);
723 #define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
724 if (sh
.sh_properties
> CDF_PROP_LIMIT
)
726 DPRINTF(("section len: %u properties %u\n", sh
.sh_len
,
729 if (*maxcount
> CDF_PROP_LIMIT
)
731 *maxcount
+= sh
.sh_properties
;
732 inp
= realloc(*info
, *maxcount
* sizeof(*inp
));
734 *maxcount
= sh
.sh_properties
;
735 inp
= malloc(*maxcount
* sizeof(*inp
));
741 *count
+= sh
.sh_properties
;
742 p
= (const void *)((const char *)(const void *)sst
->sst_tab
+
744 e
= (const void *)(((const char *)(const void *)shp
) + sh
.sh_len
);
745 if (cdf_check_stream_offset(sst
, e
, 0) == -1)
747 for (i
= 0; i
< sh
.sh_properties
; i
++) {
748 q
= (const uint32_t *)(const void *)
749 ((const char *)(const void *)p
+
750 CDF_TOLE4(p
[(i
<< 1) + 1])) - 2;
752 DPRINTF(("Ran of the end %p > %p\n", q
, e
));
755 inp
[i
].pi_id
= CDF_TOLE4(p
[i
<< 1]);
756 inp
[i
].pi_type
= CDF_TOLE4(q
[0]);
757 DPRINTF(("%d) id=%x type=%x offs=%x\n", i
, inp
[i
].pi_id
,
758 inp
[i
].pi_type
, (const char *)q
- (const char *)p
));
759 if (inp
[i
].pi_type
& CDF_VECTOR
) {
760 nelements
= CDF_TOLE4(q
[1]);
766 if (inp
[i
].pi_type
& (CDF_ARRAY
|CDF_BYREF
|CDF_RESERVED
))
768 switch (inp
[i
].pi_type
& CDF_TYPEMASK
) {
772 if (inp
[i
].pi_type
& CDF_VECTOR
)
774 (void)memcpy(&s16
, &q
[o
], sizeof(s16
));
775 inp
[i
].pi_s16
= CDF_TOLE2(s16
);
778 if (inp
[i
].pi_type
& CDF_VECTOR
)
780 (void)memcpy(&s32
, &q
[o
], sizeof(s32
));
781 inp
[i
].pi_s32
= CDF_TOLE4((uint32_t)s32
);
785 if (inp
[i
].pi_type
& CDF_VECTOR
)
787 (void)memcpy(&u32
, &q
[o
], sizeof(u32
));
788 inp
[i
].pi_u32
= CDF_TOLE4(u32
);
791 if (inp
[i
].pi_type
& CDF_VECTOR
)
793 (void)memcpy(&s64
, &q
[o
], sizeof(s64
));
794 inp
[i
].pi_s64
= CDF_TOLE8((uint64_t)s64
);
797 if (inp
[i
].pi_type
& CDF_VECTOR
)
799 (void)memcpy(&u64
, &q
[o
], sizeof(u64
));
800 inp
[i
].pi_u64
= CDF_TOLE8((uint64_t)u64
);
802 case CDF_LENGTH32_STRING
:
804 size_t nelem
= inp
- *info
;
805 if (*maxcount
> CDF_PROP_LIMIT
806 || nelements
> CDF_PROP_LIMIT
)
808 *maxcount
+= nelements
;
809 inp
= realloc(*info
, *maxcount
* sizeof(*inp
));
815 DPRINTF(("nelements = %d\n", nelements
));
816 for (j
= 0; j
< nelements
; j
++, i
++) {
817 uint32_t l
= CDF_TOLE4(q
[o
]);
818 inp
[i
].pi_str
.s_len
= l
;
819 inp
[i
].pi_str
.s_buf
=
820 (const char *)(const void *)(&q
[o
+1]);
821 DPRINTF(("l = %d, r = %d, s = %s\n", l
,
822 CDF_ROUND(l
, sizeof(l
)),
823 inp
[i
].pi_str
.s_buf
));
824 l
= 4 + (uint32_t)CDF_ROUND(l
, sizeof(l
));
830 if (inp
[i
].pi_type
& CDF_VECTOR
)
832 (void)memcpy(&tp
, &q
[o
], sizeof(tp
));
833 inp
[i
].pi_tp
= CDF_TOLE8((uint64_t)tp
);
836 if (inp
[i
].pi_type
& CDF_VECTOR
)
841 DPRINTF(("Don't know how to deal with %x\n",
853 cdf_unpack_summary_info(const cdf_stream_t
*sst
, cdf_summary_info_header_t
*ssi
,
854 cdf_property_info_t
**info
, size_t *count
)
857 const cdf_summary_info_header_t
*si
= sst
->sst_tab
;
858 const cdf_section_declaration_t
*sd
= (const void *)
859 ((const char *)sst
->sst_tab
+ CDF_SECTION_DECLARATION_OFFSET
);
861 if (cdf_check_stream_offset(sst
, si
, sizeof(*si
)) == -1 ||
862 cdf_check_stream_offset(sst
, sd
, sizeof(*sd
)) == -1)
864 ssi
->si_byte_order
= CDF_TOLE2(si
->si_byte_order
);
865 ssi
->si_os_version
= CDF_TOLE2(si
->si_os_version
);
866 ssi
->si_os
= CDF_TOLE2(si
->si_os
);
867 ssi
->si_class
= si
->si_class
;
868 cdf_swap_class(&ssi
->si_class
);
869 ssi
->si_count
= CDF_TOLE2(si
->si_count
);
873 for (i
= 0; i
< CDF_TOLE4(si
->si_count
); i
++) {
874 if (i
>= CDF_LOOP_LIMIT
) {
875 DPRINTF(("Unpack summary info loop limit"));
879 if (cdf_read_property_info(sst
, CDF_TOLE4(sd
->sd_offset
),
880 info
, count
, &maxcount
) == -1)
889 cdf_print_classid(char *buf
, size_t buflen
, const cdf_classid_t
*id
)
891 return snprintf(buf
, buflen
, "%.8x-%.4x-%.4x-%.2x%.2x-"
892 "%.2x%.2x%.2x%.2x%.2x%.2x", id
->cl_dword
, id
->cl_word
[0],
893 id
->cl_word
[1], id
->cl_two
[0], id
->cl_two
[1], id
->cl_six
[0],
894 id
->cl_six
[1], id
->cl_six
[2], id
->cl_six
[3], id
->cl_six
[4],
898 static const struct {
902 { CDF_PROPERTY_CODE_PAGE
, "Code page" },
903 { CDF_PROPERTY_TITLE
, "Title" },
904 { CDF_PROPERTY_SUBJECT
, "Subject" },
905 { CDF_PROPERTY_AUTHOR
, "Author" },
906 { CDF_PROPERTY_KEYWORDS
, "Keywords" },
907 { CDF_PROPERTY_COMMENTS
, "Comments" },
908 { CDF_PROPERTY_TEMPLATE
, "Template" },
909 { CDF_PROPERTY_LAST_SAVED_BY
, "Last Saved By" },
910 { CDF_PROPERTY_REVISION_NUMBER
, "Revision Number" },
911 { CDF_PROPERTY_TOTAL_EDITING_TIME
, "Total Editing Time" },
912 { CDF_PROPERTY_LAST_PRINTED
, "Last Printed" },
913 { CDF_PROPERTY_CREATE_TIME
, "Create Time/Date" },
914 { CDF_PROPERTY_LAST_SAVED_TIME
, "Last Saved Time/Date" },
915 { CDF_PROPERTY_NUMBER_OF_PAGES
, "Number of Pages" },
916 { CDF_PROPERTY_NUMBER_OF_WORDS
, "Number of Words" },
917 { CDF_PROPERTY_NUMBER_OF_CHARACTERS
, "Number of Characters" },
918 { CDF_PROPERTY_THUMBNAIL
, "Thumbnail" },
919 { CDF_PROPERTY_NAME_OF_APPLICATION
, "Name of Creating Application" },
920 { CDF_PROPERTY_SECURITY
, "Security" },
921 { CDF_PROPERTY_LOCALE_ID
, "Locale ID" },
925 cdf_print_property_name(char *buf
, size_t bufsiz
, uint32_t p
)
929 for (i
= 0; i
< __arraycount(vn
); i
++)
931 return snprintf(buf
, bufsiz
, "%s", vn
[i
].n
);
932 return snprintf(buf
, bufsiz
, "0x%x", p
);
936 cdf_print_elapsed_time(char *buf
, size_t bufsiz
, cdf_timestamp_t ts
)
939 int days
, hours
, mins
, secs
;
942 secs
= (int)(ts
% 60);
944 mins
= (int)(ts
% 60);
946 hours
= (int)(ts
% 24);
951 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%dd+", days
);
952 if ((size_t)len
>= bufsiz
)
957 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d:", hours
);
958 if ((size_t)len
>= bufsiz
)
962 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d:", mins
);
963 if ((size_t)len
>= bufsiz
)
966 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d", secs
);
973 cdf_dump_header(const cdf_header_t
*h
)
977 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
978 #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
979 h->h_ ## b, 1 << h->h_ ## b)
980 DUMP("%d", revision
);
982 DUMP("0x%x", byte_order
);
983 DUMP2("%d", sec_size_p2
);
984 DUMP2("%d", short_sec_size_p2
);
985 DUMP("%d", num_sectors_in_sat
);
986 DUMP("%d", secid_first_directory
);
987 DUMP("%d", min_size_standard_stream
);
988 DUMP("%d", secid_first_sector_in_short_sat
);
989 DUMP("%d", num_sectors_in_short_sat
);
990 DUMP("%d", secid_first_sector_in_master_sat
);
991 DUMP("%d", num_sectors_in_master_sat
);
992 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++) {
993 if (h
->h_master_sat
[i
] == CDF_SECID_FREE
)
995 (void)fprintf(stderr
, "%35.35s[%.3zu] = %d\n",
996 "master_sat", i
, h
->h_master_sat
[i
]);
1001 cdf_dump_sat(const char *prefix
, const cdf_sat_t
*sat
, size_t size
)
1003 size_t i
, j
, s
= size
/ sizeof(cdf_secid_t
);
1005 for (i
= 0; i
< sat
->sat_len
; i
++) {
1006 (void)fprintf(stderr
, "%s[%zu]:\n%.6d: ", prefix
, i
, i
* s
);
1007 for (j
= 0; j
< s
; j
++) {
1008 (void)fprintf(stderr
, "%5d, ",
1009 CDF_TOLE4(sat
->sat_tab
[s
* i
+ j
]));
1010 if ((j
+ 1) % 10 == 0)
1011 (void)fprintf(stderr
, "\n%.6d: ",
1014 (void)fprintf(stderr
, "\n");
1019 cdf_dump(void *v
, size_t len
)
1022 unsigned char *p
= v
;
1024 (void)fprintf(stderr
, "%.4x: ", 0);
1025 for (i
= 0, j
= 0; i
< len
; i
++, p
++) {
1026 (void)fprintf(stderr
, "%.2x ", *p
);
1027 abuf
[j
++] = isprint(*p
) ? *p
: '.';
1031 (void)fprintf(stderr
, "%s\n%.4x: ", abuf
, i
+ 1);
1034 (void)fprintf(stderr
, "\n");
1038 cdf_dump_stream(const cdf_header_t
*h
, const cdf_stream_t
*sst
)
1040 size_t ss
= sst
->sst_dirlen
< h
->h_min_size_standard_stream
?
1041 CDF_SHORT_SEC_SIZE(h
) : CDF_SEC_SIZE(h
);
1042 cdf_dump(sst
->sst_tab
, ss
* sst
->sst_len
);
1046 cdf_dump_dir(const cdf_info_t
*info
, const cdf_header_t
*h
,
1047 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
1048 const cdf_dir_t
*dir
)
1052 char name
[__arraycount(d
->d_name
)];
1056 static const char *types
[] = { "empty", "user storage",
1057 "user stream", "lockbytes", "property", "root storage" };
1059 for (i
= 0; i
< dir
->dir_len
; i
++) {
1060 d
= &dir
->dir_tab
[i
];
1061 for (j
= 0; j
< sizeof(name
); j
++)
1062 name
[j
] = (char)CDF_TOLE2(d
->d_name
[j
]);
1063 (void)fprintf(stderr
, "Directory %zu: %s\n", i
, name
);
1064 if (d
->d_type
< __arraycount(types
))
1065 (void)fprintf(stderr
, "Type: %s\n", types
[d
->d_type
]);
1067 (void)fprintf(stderr
, "Type: %d\n", d
->d_type
);
1068 (void)fprintf(stderr
, "Color: %s\n",
1069 d
->d_color
? "black" : "red");
1070 (void)fprintf(stderr
, "Left child: %d\n", d
->d_left_child
);
1071 (void)fprintf(stderr
, "Right child: %d\n", d
->d_right_child
);
1072 (void)fprintf(stderr
, "Flags: 0x%x\n", d
->d_flags
);
1073 cdf_timestamp_to_timespec(&ts
, d
->d_created
);
1074 (void)fprintf(stderr
, "Created %s", ctime(&ts
.tv_sec
));
1075 cdf_timestamp_to_timespec(&ts
, d
->d_modified
);
1076 (void)fprintf(stderr
, "Modified %s", ctime(&ts
.tv_sec
));
1077 (void)fprintf(stderr
, "Stream %d\n", d
->d_stream_first_sector
);
1078 (void)fprintf(stderr
, "Size %d\n", d
->d_size
);
1079 switch (d
->d_type
) {
1080 case CDF_DIR_TYPE_USER_STORAGE
:
1081 (void)fprintf(stderr
, "Storage: %d\n", d
->d_storage
);
1083 case CDF_DIR_TYPE_USER_STREAM
:
1086 if (cdf_read_sector_chain(info
, h
, sat
, ssat
, sst
,
1087 d
->d_stream_first_sector
, d
->d_size
, &scn
) == -1) {
1088 warn("Can't read stream for %s at %d len %d",
1089 name
, d
->d_stream_first_sector
, d
->d_size
);
1092 cdf_dump_stream(h
, &scn
);
1103 cdf_dump_property_info(const cdf_property_info_t
*info
, size_t count
)
1110 for (i
= 0; i
< count
; i
++) {
1111 cdf_print_property_name(buf
, sizeof(buf
), info
[i
].pi_id
);
1112 (void)fprintf(stderr
, "%zu) %s: ", i
, buf
);
1113 switch (info
[i
].pi_type
) {
1115 (void)fprintf(stderr
, "signed 16 [%hd]\n",
1119 (void)fprintf(stderr
, "signed 32 [%d]\n",
1122 case CDF_UNSIGNED32
:
1123 (void)fprintf(stderr
, "unsigned 32 [%u]\n",
1126 case CDF_LENGTH32_STRING
:
1127 (void)fprintf(stderr
, "string %u [%.*s]\n",
1128 info
[i
].pi_str
.s_len
,
1129 info
[i
].pi_str
.s_len
, info
[i
].pi_str
.s_buf
);
1133 if (tp
< 1000000000000000LL) {
1134 cdf_print_elapsed_time(buf
, sizeof(buf
), tp
);
1135 (void)fprintf(stderr
, "timestamp %s\n", buf
);
1137 cdf_timestamp_to_timespec(&ts
, tp
);
1138 (void)fprintf(stderr
, "timestamp %s",
1143 (void)fprintf(stderr
, "CLIPBOARD %u\n", info
[i
].pi_u32
);
1146 DPRINTF(("Don't know how to deal with %x\n",
1155 cdf_dump_summary_info(const cdf_header_t
*h
, const cdf_stream_t
*sst
)
1158 cdf_summary_info_header_t ssi
;
1159 cdf_property_info_t
*info
;
1163 if (cdf_unpack_summary_info(sst
, &ssi
, &info
, &count
) == -1)
1165 (void)fprintf(stderr
, "Endian: %x\n", ssi
.si_byte_order
);
1166 (void)fprintf(stderr
, "Os Version %d.%d\n", ssi
.si_os_version
& 0xff,
1167 ssi
.si_os_version
>> 8);
1168 (void)fprintf(stderr
, "Os %d\n", ssi
.si_os
);
1169 cdf_print_classid(buf
, sizeof(buf
), &ssi
.si_class
);
1170 (void)fprintf(stderr
, "Class %s\n", buf
);
1171 (void)fprintf(stderr
, "Count %d\n", ssi
.si_count
);
1172 cdf_dump_property_info(info
, count
);
1180 main(int argc
, char *argv
[])
1184 cdf_sat_t sat
, ssat
;
1185 cdf_stream_t sst
, scn
;
1190 (void)fprintf(stderr
, "Usage: %s <filename>\n", getprogname());
1196 for (i
= 1; i
< argc
; i
++) {
1197 if ((info
.i_fd
= open(argv
[1], O_RDONLY
)) == -1)
1198 err(1, "Cannot open `%s'", argv
[1]);
1200 if (cdf_read_header(&info
, &h
) == -1)
1201 err(1, "Cannot read header");
1203 cdf_dump_header(&h
);
1206 if (cdf_read_sat(&info
, &h
, &sat
) == -1)
1207 err(1, "Cannot read sat");
1209 cdf_dump_sat("SAT", &sat
, CDF_SEC_SIZE(&h
));
1212 if (cdf_read_ssat(&info
, &h
, &sat
, &ssat
) == -1)
1213 err(1, "Cannot read ssat");
1215 cdf_dump_sat("SSAT", &h
, &ssat
, CDF_SHORT_SEC_SIZE(&h
));
1218 if (cdf_read_dir(&info
, &h
, &sat
, &dir
) == -1)
1219 err(1, "Cannot read dir");
1221 if (cdf_read_short_stream(&info
, &h
, &sat
, &dir
, &sst
) == -1)
1222 err(1, "Cannot read short stream");
1224 cdf_dump_stream(&h
, &sst
);
1228 cdf_dump_dir(&info
, &h
, &sat
, &ssat
, &sst
, &dir
);
1232 if (cdf_read_summary_info(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
1234 err(1, "Cannot read summary info");
1236 cdf_dump_summary_info(&h
, &scn
);
1239 (void)close(info
.i_fd
);