2 * Copyright (c) 2008 Christos Zoulas
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
27 * Parse composite document files, the format used in Microsoft Office
28 * document files before they switched to zipped xml.
29 * Info from: http://sc.openoffice.org/compdocfileformat.pdf
35 FILE_RCSID("@(#)$File: cdf.c,v 1.36 2010/01/22 20:56:26 christos Exp $")
58 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
62 #define DPRINTF(a) printf a, fflush(stdout)
72 #define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304)
74 #define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x)))
75 #define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x)))
76 #define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x)))
82 cdf_tole2(uint16_t sv
)
85 uint8_t *s
= (uint8_t *)(void *)&sv
;
86 uint8_t *d
= (uint8_t *)(void *)&rv
;
96 cdf_tole4(uint32_t sv
)
99 uint8_t *s
= (uint8_t *)(void *)&sv
;
100 uint8_t *d
= (uint8_t *)(void *)&rv
;
112 cdf_tole8(uint64_t sv
)
115 uint8_t *s
= (uint8_t *)(void *)&sv
;
116 uint8_t *d
= (uint8_t *)(void *)&rv
;
128 #define CDF_UNPACK(a) \
129 (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
130 #define CDF_UNPACKA(a) \
131 (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
134 cdf_swap_header(cdf_header_t
*h
)
138 h
->h_magic
= CDF_TOLE8(h
->h_magic
);
139 h
->h_uuid
[0] = CDF_TOLE8(h
->h_uuid
[0]);
140 h
->h_uuid
[1] = CDF_TOLE8(h
->h_uuid
[1]);
141 h
->h_revision
= CDF_TOLE2(h
->h_revision
);
142 h
->h_version
= CDF_TOLE2(h
->h_version
);
143 h
->h_byte_order
= CDF_TOLE2(h
->h_byte_order
);
144 h
->h_sec_size_p2
= CDF_TOLE2(h
->h_sec_size_p2
);
145 h
->h_short_sec_size_p2
= CDF_TOLE2(h
->h_short_sec_size_p2
);
146 h
->h_num_sectors_in_sat
= CDF_TOLE4(h
->h_num_sectors_in_sat
);
147 h
->h_secid_first_directory
= CDF_TOLE4(h
->h_secid_first_directory
);
148 h
->h_min_size_standard_stream
=
149 CDF_TOLE4(h
->h_min_size_standard_stream
);
150 h
->h_secid_first_sector_in_short_sat
=
151 CDF_TOLE4((uint32_t)h
->h_secid_first_sector_in_short_sat
);
152 h
->h_num_sectors_in_short_sat
=
153 CDF_TOLE4(h
->h_num_sectors_in_short_sat
);
154 h
->h_secid_first_sector_in_master_sat
=
155 CDF_TOLE4((uint32_t)h
->h_secid_first_sector_in_master_sat
);
156 h
->h_num_sectors_in_master_sat
=
157 CDF_TOLE4(h
->h_num_sectors_in_master_sat
);
158 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++)
159 h
->h_master_sat
[i
] = CDF_TOLE4((uint32_t)h
->h_master_sat
[i
]);
163 cdf_unpack_header(cdf_header_t
*h
, char *buf
)
168 CDF_UNPACK(h
->h_magic
);
169 CDF_UNPACKA(h
->h_uuid
);
170 CDF_UNPACK(h
->h_revision
);
171 CDF_UNPACK(h
->h_version
);
172 CDF_UNPACK(h
->h_byte_order
);
173 CDF_UNPACK(h
->h_sec_size_p2
);
174 CDF_UNPACK(h
->h_short_sec_size_p2
);
175 CDF_UNPACKA(h
->h_unused0
);
176 CDF_UNPACK(h
->h_num_sectors_in_sat
);
177 CDF_UNPACK(h
->h_secid_first_directory
);
178 CDF_UNPACKA(h
->h_unused1
);
179 CDF_UNPACK(h
->h_min_size_standard_stream
);
180 CDF_UNPACK(h
->h_secid_first_sector_in_short_sat
);
181 CDF_UNPACK(h
->h_num_sectors_in_short_sat
);
182 CDF_UNPACK(h
->h_secid_first_sector_in_master_sat
);
183 CDF_UNPACK(h
->h_num_sectors_in_master_sat
);
184 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++)
185 CDF_UNPACK(h
->h_master_sat
[i
]);
189 cdf_swap_dir(cdf_directory_t
*d
)
191 d
->d_namelen
= CDF_TOLE2(d
->d_namelen
);
192 d
->d_left_child
= CDF_TOLE4((uint32_t)d
->d_left_child
);
193 d
->d_right_child
= CDF_TOLE4((uint32_t)d
->d_right_child
);
194 d
->d_storage
= CDF_TOLE4((uint32_t)d
->d_storage
);
195 d
->d_storage_uuid
[0] = CDF_TOLE8(d
->d_storage_uuid
[0]);
196 d
->d_storage_uuid
[1] = CDF_TOLE8(d
->d_storage_uuid
[1]);
197 d
->d_flags
= CDF_TOLE4(d
->d_flags
);
198 d
->d_created
= CDF_TOLE8((uint64_t)d
->d_created
);
199 d
->d_modified
= CDF_TOLE8((uint64_t)d
->d_modified
);
200 d
->d_stream_first_sector
= CDF_TOLE4((uint32_t)d
->d_stream_first_sector
);
201 d
->d_size
= CDF_TOLE4(d
->d_size
);
205 cdf_swap_class(cdf_classid_t
*d
)
207 d
->cl_dword
= CDF_TOLE4(d
->cl_dword
);
208 d
->cl_word
[0] = CDF_TOLE2(d
->cl_word
[0]);
209 d
->cl_word
[1] = CDF_TOLE2(d
->cl_word
[1]);
213 cdf_unpack_dir(cdf_directory_t
*d
, char *buf
)
217 CDF_UNPACKA(d
->d_name
);
218 CDF_UNPACK(d
->d_namelen
);
219 CDF_UNPACK(d
->d_type
);
220 CDF_UNPACK(d
->d_color
);
221 CDF_UNPACK(d
->d_left_child
);
222 CDF_UNPACK(d
->d_right_child
);
223 CDF_UNPACK(d
->d_storage
);
224 CDF_UNPACKA(d
->d_storage_uuid
);
225 CDF_UNPACK(d
->d_flags
);
226 CDF_UNPACK(d
->d_created
);
227 CDF_UNPACK(d
->d_modified
);
228 CDF_UNPACK(d
->d_stream_first_sector
);
229 CDF_UNPACK(d
->d_size
);
230 CDF_UNPACK(d
->d_unused0
);
234 cdf_check_stream_offset(const cdf_stream_t
*sst
, const void *p
, size_t tail
,
237 const char *b
= (const char *)sst
->sst_tab
;
238 const char *e
= ((const char *)p
) + tail
;
240 if (e
>= b
&& (size_t)(e
- b
) < sst
->sst_dirlen
* sst
->sst_len
)
242 DPRINTF(("%d: offset begin %p end %p %zu >= %zu [%zu %zu]\n",
243 line
, b
, e
, (size_t)(e
- b
), sst
->sst_dirlen
* sst
->sst_len
,
244 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
= CAST(cdf_secid_t
*, calloc(sat
->sat_len
, ss
)))
357 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++) {
358 if (h
->h_master_sat
[i
] < 0)
360 if (cdf_read_sector(info
, sat
->sat_tab
, ss
* i
, ss
, h
,
361 h
->h_master_sat
[i
]) != (ssize_t
)ss
) {
362 DPRINTF(("Reading sector %d", h
->h_master_sat
[i
]));
367 if ((msa
= CAST(cdf_secid_t
*, calloc(1, ss
))) == NULL
)
370 mid
= h
->h_secid_first_sector_in_master_sat
;
371 for (j
= 0; j
< h
->h_num_sectors_in_master_sat
; j
++) {
374 if (j
>= CDF_LOOP_LIMIT
) {
375 DPRINTF(("Reading master sector loop limit"));
379 if (cdf_read_sector(info
, msa
, 0, ss
, h
, mid
) != (ssize_t
)ss
) {
380 DPRINTF(("Reading master sector %d", mid
));
383 for (k
= 0; k
< nsatpersec
; k
++, i
++) {
384 sec
= CDF_TOLE4((uint32_t)msa
[k
]);
387 if (i
>= sat
->sat_len
) {
388 DPRINTF(("Out of bounds reading MSA %u >= %u",
393 if (cdf_read_sector(info
, sat
->sat_tab
, ss
* i
, ss
, h
,
394 sec
) != (ssize_t
)ss
) {
395 DPRINTF(("Reading sector %d",
400 mid
= CDF_TOLE4((uint32_t)msa
[nsatpersec
]);
414 cdf_count_chain(const cdf_sat_t
*sat
, cdf_secid_t sid
, size_t size
)
417 cdf_secid_t maxsector
= (cdf_secid_t
)(sat
->sat_len
* size
);
420 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
421 DPRINTF((" %d", sid
));
422 if (j
>= CDF_LOOP_LIMIT
) {
423 DPRINTF(("Counting chain loop limit"));
427 if (sid
> maxsector
) {
428 DPRINTF(("Sector %d > %d\n", sid
, maxsector
));
432 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
439 cdf_read_long_sector_chain(const cdf_info_t
*info
, const cdf_header_t
*h
,
440 const cdf_sat_t
*sat
, cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
442 size_t ss
= CDF_SEC_SIZE(h
), i
, j
;
444 scn
->sst_len
= cdf_count_chain(sat
, sid
, ss
);
445 scn
->sst_dirlen
= len
;
447 if (scn
->sst_len
== (size_t)-1)
450 scn
->sst_tab
= calloc(scn
->sst_len
, ss
);
451 if (scn
->sst_tab
== NULL
)
454 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
455 if (j
>= CDF_LOOP_LIMIT
) {
456 DPRINTF(("Read long sector chain loop limit"));
460 if (i
>= scn
->sst_len
) {
461 DPRINTF(("Out of bounds reading long sector chain "
462 "%u > %u\n", i
, scn
->sst_len
));
466 if ((nr
= cdf_read_sector(info
, scn
->sst_tab
, i
* ss
, ss
, h
,
467 sid
)) != (ssize_t
)ss
) {
468 if (i
== scn
->sst_len
- 1 && nr
> 0) {
469 /* Last sector might be truncated */
472 DPRINTF(("Reading long sector chain %d", sid
));
475 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
484 cdf_read_short_sector_chain(const cdf_header_t
*h
,
485 const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
486 cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
488 size_t ss
= CDF_SHORT_SEC_SIZE(h
), i
, j
;
489 scn
->sst_len
= cdf_count_chain(ssat
, sid
, CDF_SEC_SIZE(h
));
490 scn
->sst_dirlen
= len
;
492 if (sst
->sst_tab
== NULL
|| scn
->sst_len
== (size_t)-1)
495 scn
->sst_tab
= calloc(scn
->sst_len
, ss
);
496 if (scn
->sst_tab
== NULL
)
499 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
500 if (j
>= CDF_LOOP_LIMIT
) {
501 DPRINTF(("Read short sector chain loop limit"));
505 if (i
>= scn
->sst_len
) {
506 DPRINTF(("Out of bounds reading short sector chain "
507 "%u > %u\n", i
, scn
->sst_len
));
511 if (cdf_read_short_sector(sst
, scn
->sst_tab
, i
* ss
, ss
, h
,
512 sid
) != (ssize_t
)ss
) {
513 DPRINTF(("Reading short sector chain %d", sid
));
516 sid
= CDF_TOLE4((uint32_t)ssat
->sat_tab
[sid
]);
525 cdf_read_sector_chain(const cdf_info_t
*info
, const cdf_header_t
*h
,
526 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
527 cdf_secid_t sid
, size_t len
, cdf_stream_t
*scn
)
530 if (len
< h
->h_min_size_standard_stream
&& sst
->sst_tab
!= NULL
)
531 return cdf_read_short_sector_chain(h
, ssat
, sst
, sid
, len
,
534 return cdf_read_long_sector_chain(info
, h
, sat
, sid
, len
, scn
);
538 cdf_read_dir(const cdf_info_t
*info
, const cdf_header_t
*h
,
539 const cdf_sat_t
*sat
, cdf_dir_t
*dir
)
542 size_t ss
= CDF_SEC_SIZE(h
), ns
, nd
;
544 cdf_secid_t sid
= h
->h_secid_first_directory
;
546 ns
= cdf_count_chain(sat
, sid
, ss
);
547 if (ns
== (size_t)-1)
550 nd
= ss
/ CDF_DIRECTORY_SIZE
;
552 dir
->dir_len
= ns
* nd
;
553 dir
->dir_tab
= CAST(cdf_directory_t
*,
554 calloc(dir
->dir_len
, sizeof(dir
->dir_tab
[0])));
555 if (dir
->dir_tab
== NULL
)
558 if ((buf
= CAST(char *, malloc(ss
))) == NULL
) {
563 for (j
= i
= 0; i
< ns
; i
++, j
++) {
564 if (j
>= CDF_LOOP_LIMIT
) {
565 DPRINTF(("Read dir loop limit"));
569 if (cdf_read_sector(info
, buf
, 0, ss
, h
, sid
) != (ssize_t
)ss
) {
570 DPRINTF(("Reading directory sector %d", sid
));
573 for (j
= 0; j
< nd
; j
++) {
574 cdf_unpack_dir(&dir
->dir_tab
[i
* nd
+ j
],
575 &buf
[j
* CDF_DIRECTORY_SIZE
]);
577 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
580 for (i
= 0; i
< dir
->dir_len
; i
++)
581 cdf_swap_dir(&dir
->dir_tab
[i
]);
592 cdf_read_ssat(const cdf_info_t
*info
, const cdf_header_t
*h
,
593 const cdf_sat_t
*sat
, cdf_sat_t
*ssat
)
596 size_t ss
= CDF_SEC_SIZE(h
);
597 cdf_secid_t sid
= h
->h_secid_first_sector_in_short_sat
;
599 ssat
->sat_len
= cdf_count_chain(sat
, sid
, CDF_SEC_SIZE(h
));
600 if (ssat
->sat_len
== (size_t)-1)
603 ssat
->sat_tab
= CAST(cdf_secid_t
*, calloc(ssat
->sat_len
, ss
));
604 if (ssat
->sat_tab
== NULL
)
607 for (j
= i
= 0; sid
>= 0; i
++, j
++) {
608 if (j
>= CDF_LOOP_LIMIT
) {
609 DPRINTF(("Read short sat sector loop limit"));
613 if (i
>= ssat
->sat_len
) {
614 DPRINTF(("Out of bounds reading short sector chain "
615 "%u > %u\n", i
, ssat
->sat_len
));
619 if (cdf_read_sector(info
, ssat
->sat_tab
, i
* ss
, ss
, h
, sid
) !=
621 DPRINTF(("Reading short sat sector %d", sid
));
624 sid
= CDF_TOLE4((uint32_t)sat
->sat_tab
[sid
]);
633 cdf_read_short_stream(const cdf_info_t
*info
, const cdf_header_t
*h
,
634 const cdf_sat_t
*sat
, const cdf_dir_t
*dir
, cdf_stream_t
*scn
)
637 const cdf_directory_t
*d
;
639 for (i
= 0; i
< dir
->dir_len
; i
++)
640 if (dir
->dir_tab
[i
].d_type
== CDF_DIR_TYPE_ROOT_STORAGE
)
643 /* If the it is not there, just fake it; some docs don't have it */
644 if (i
== dir
->dir_len
)
646 d
= &dir
->dir_tab
[i
];
648 /* If the it is not there, just fake it; some docs don't have it */
649 if (d
->d_stream_first_sector
< 0)
652 return cdf_read_long_sector_chain(info
, h
, sat
,
653 d
->d_stream_first_sector
, d
->d_size
, scn
);
662 cdf_namecmp(const char *d
, const uint16_t *s
, size_t l
)
664 for (; l
--; d
++, s
++)
665 if (*d
!= CDF_TOLE2(*s
))
666 return (unsigned char)*d
- CDF_TOLE2(*s
);
671 cdf_read_summary_info(const cdf_info_t
*info
, const cdf_header_t
*h
,
672 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
673 const cdf_dir_t
*dir
, cdf_stream_t
*scn
)
676 const cdf_directory_t
*d
;
677 static const char name
[] = "\05SummaryInformation";
679 for (i
= dir
->dir_len
; i
> 0; i
--)
680 if (dir
->dir_tab
[i
- 1].d_type
== CDF_DIR_TYPE_USER_STREAM
&&
681 cdf_namecmp(name
, dir
->dir_tab
[i
- 1].d_name
, sizeof(name
))
686 DPRINTF(("Cannot find summary information section\n"));
690 d
= &dir
->dir_tab
[i
- 1];
691 return cdf_read_sector_chain(info
, h
, sat
, ssat
, sst
,
692 d
->d_stream_first_sector
, d
->d_size
, scn
);
696 cdf_read_property_info(const cdf_stream_t
*sst
, uint32_t offs
,
697 cdf_property_info_t
**info
, size_t *count
, size_t *maxcount
)
699 const cdf_section_header_t
*shp
;
700 cdf_section_header_t sh
;
701 const uint32_t *p
, *q
, *e
;
708 size_t i
, o
, nelements
, j
;
709 cdf_property_info_t
*inp
;
711 if (offs
> UINT32_MAX
/ 4) {
715 shp
= CAST(const cdf_section_header_t
*, (const void *)
716 ((const char *)sst
->sst_tab
+ offs
));
717 if (cdf_check_stream_offset(sst
, shp
, sizeof(*shp
), __LINE__
) == -1)
719 sh
.sh_len
= CDF_TOLE4(shp
->sh_len
);
720 #define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
721 if (sh
.sh_len
> CDF_SHLEN_LIMIT
) {
725 sh
.sh_properties
= CDF_TOLE4(shp
->sh_properties
);
726 #define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
727 if (sh
.sh_properties
> CDF_PROP_LIMIT
)
729 DPRINTF(("section len: %u properties %u\n", sh
.sh_len
,
732 if (*maxcount
> CDF_PROP_LIMIT
)
734 *maxcount
+= sh
.sh_properties
;
735 inp
= CAST(cdf_property_info_t
*,
736 realloc(*info
, *maxcount
* sizeof(*inp
)));
738 *maxcount
= sh
.sh_properties
;
739 inp
= CAST(cdf_property_info_t
*,
740 malloc(*maxcount
* sizeof(*inp
)));
746 *count
+= sh
.sh_properties
;
747 p
= CAST(const uint32_t *, (const void *)
748 ((const char *)(const void *)sst
->sst_tab
+
750 e
= CAST(const uint32_t *, (const void *)
751 (((const char *)(const void *)shp
) + sh
.sh_len
));
752 if (cdf_check_stream_offset(sst
, e
, 0, __LINE__
) == -1)
754 for (i
= 0; i
< sh
.sh_properties
; i
++) {
755 q
= (const uint32_t *)(const void *)
756 ((const char *)(const void *)p
+
757 CDF_TOLE4(p
[(i
<< 1) + 1])) - 2;
759 DPRINTF(("Ran of the end %p > %p\n", q
, e
));
762 inp
[i
].pi_id
= CDF_TOLE4(p
[i
<< 1]);
763 inp
[i
].pi_type
= CDF_TOLE4(q
[0]);
764 DPRINTF(("%d) id=%x type=%x offs=%x\n", i
, inp
[i
].pi_id
,
765 inp
[i
].pi_type
, (const char *)q
- (const char *)p
));
766 if (inp
[i
].pi_type
& CDF_VECTOR
) {
767 nelements
= CDF_TOLE4(q
[1]);
773 if (inp
[i
].pi_type
& (CDF_ARRAY
|CDF_BYREF
|CDF_RESERVED
))
775 switch (inp
[i
].pi_type
& CDF_TYPEMASK
) {
780 if (inp
[i
].pi_type
& CDF_VECTOR
)
782 (void)memcpy(&s16
, &q
[o
], sizeof(s16
));
783 inp
[i
].pi_s16
= CDF_TOLE2(s16
);
786 if (inp
[i
].pi_type
& CDF_VECTOR
)
788 (void)memcpy(&s32
, &q
[o
], sizeof(s32
));
789 inp
[i
].pi_s32
= CDF_TOLE4((uint32_t)s32
);
793 if (inp
[i
].pi_type
& CDF_VECTOR
)
795 (void)memcpy(&u32
, &q
[o
], sizeof(u32
));
796 inp
[i
].pi_u32
= CDF_TOLE4(u32
);
799 if (inp
[i
].pi_type
& CDF_VECTOR
)
801 (void)memcpy(&s64
, &q
[o
], sizeof(s64
));
802 inp
[i
].pi_s64
= CDF_TOLE8((uint64_t)s64
);
805 if (inp
[i
].pi_type
& CDF_VECTOR
)
807 (void)memcpy(&u64
, &q
[o
], sizeof(u64
));
808 inp
[i
].pi_u64
= CDF_TOLE8((uint64_t)u64
);
810 case CDF_LENGTH32_STRING
:
811 case CDF_LENGTH32_WSTRING
:
813 size_t nelem
= inp
- *info
;
814 if (*maxcount
> CDF_PROP_LIMIT
815 || nelements
> CDF_PROP_LIMIT
)
817 *maxcount
+= nelements
;
818 inp
= CAST(cdf_property_info_t
*,
819 realloc(*info
, *maxcount
* sizeof(*inp
)));
825 DPRINTF(("nelements = %d\n", nelements
));
826 for (j
= 0; j
< nelements
; j
++, i
++) {
827 uint32_t l
= CDF_TOLE4(q
[o
]);
828 inp
[i
].pi_str
.s_len
= l
;
829 inp
[i
].pi_str
.s_buf
=
830 (const char *)(const void *)(&q
[o
+1]);
831 DPRINTF(("l = %d, r = %d, s = %s\n", l
,
832 CDF_ROUND(l
, sizeof(l
)),
833 inp
[i
].pi_str
.s_buf
));
834 l
= 4 + (uint32_t)CDF_ROUND(l
, sizeof(l
));
840 if (inp
[i
].pi_type
& CDF_VECTOR
)
842 (void)memcpy(&tp
, &q
[o
], sizeof(tp
));
843 inp
[i
].pi_tp
= CDF_TOLE8((uint64_t)tp
);
846 if (inp
[i
].pi_type
& CDF_VECTOR
)
851 DPRINTF(("Don't know how to deal with %x\n",
863 cdf_unpack_summary_info(const cdf_stream_t
*sst
, cdf_summary_info_header_t
*ssi
,
864 cdf_property_info_t
**info
, size_t *count
)
867 const cdf_summary_info_header_t
*si
=
868 CAST(const cdf_summary_info_header_t
*, sst
->sst_tab
);
869 const cdf_section_declaration_t
*sd
=
870 CAST(const cdf_section_declaration_t
*, (const void *)
871 ((const char *)sst
->sst_tab
+ CDF_SECTION_DECLARATION_OFFSET
));
873 if (cdf_check_stream_offset(sst
, si
, sizeof(*si
), __LINE__
) == -1 ||
874 cdf_check_stream_offset(sst
, sd
, sizeof(*sd
), __LINE__
) == -1)
876 ssi
->si_byte_order
= CDF_TOLE2(si
->si_byte_order
);
877 ssi
->si_os_version
= CDF_TOLE2(si
->si_os_version
);
878 ssi
->si_os
= CDF_TOLE2(si
->si_os
);
879 ssi
->si_class
= si
->si_class
;
880 cdf_swap_class(&ssi
->si_class
);
881 ssi
->si_count
= CDF_TOLE2(si
->si_count
);
885 for (i
= 0; i
< CDF_TOLE4(si
->si_count
); i
++) {
886 if (i
>= CDF_LOOP_LIMIT
) {
887 DPRINTF(("Unpack summary info loop limit"));
891 if (cdf_read_property_info(sst
, CDF_TOLE4(sd
->sd_offset
),
892 info
, count
, &maxcount
) == -1)
901 cdf_print_classid(char *buf
, size_t buflen
, const cdf_classid_t
*id
)
903 return snprintf(buf
, buflen
, "%.8x-%.4x-%.4x-%.2x%.2x-"
904 "%.2x%.2x%.2x%.2x%.2x%.2x", id
->cl_dword
, id
->cl_word
[0],
905 id
->cl_word
[1], id
->cl_two
[0], id
->cl_two
[1], id
->cl_six
[0],
906 id
->cl_six
[1], id
->cl_six
[2], id
->cl_six
[3], id
->cl_six
[4],
910 static const struct {
914 { CDF_PROPERTY_CODE_PAGE
, "Code page" },
915 { CDF_PROPERTY_TITLE
, "Title" },
916 { CDF_PROPERTY_SUBJECT
, "Subject" },
917 { CDF_PROPERTY_AUTHOR
, "Author" },
918 { CDF_PROPERTY_KEYWORDS
, "Keywords" },
919 { CDF_PROPERTY_COMMENTS
, "Comments" },
920 { CDF_PROPERTY_TEMPLATE
, "Template" },
921 { CDF_PROPERTY_LAST_SAVED_BY
, "Last Saved By" },
922 { CDF_PROPERTY_REVISION_NUMBER
, "Revision Number" },
923 { CDF_PROPERTY_TOTAL_EDITING_TIME
, "Total Editing Time" },
924 { CDF_PROPERTY_LAST_PRINTED
, "Last Printed" },
925 { CDF_PROPERTY_CREATE_TIME
, "Create Time/Date" },
926 { CDF_PROPERTY_LAST_SAVED_TIME
, "Last Saved Time/Date" },
927 { CDF_PROPERTY_NUMBER_OF_PAGES
, "Number of Pages" },
928 { CDF_PROPERTY_NUMBER_OF_WORDS
, "Number of Words" },
929 { CDF_PROPERTY_NUMBER_OF_CHARACTERS
, "Number of Characters" },
930 { CDF_PROPERTY_THUMBNAIL
, "Thumbnail" },
931 { CDF_PROPERTY_NAME_OF_APPLICATION
, "Name of Creating Application" },
932 { CDF_PROPERTY_SECURITY
, "Security" },
933 { CDF_PROPERTY_LOCALE_ID
, "Locale ID" },
937 cdf_print_property_name(char *buf
, size_t bufsiz
, uint32_t p
)
941 for (i
= 0; i
< __arraycount(vn
); i
++)
943 return snprintf(buf
, bufsiz
, "%s", vn
[i
].n
);
944 return snprintf(buf
, bufsiz
, "0x%x", p
);
948 cdf_print_elapsed_time(char *buf
, size_t bufsiz
, cdf_timestamp_t ts
)
951 int days
, hours
, mins
, secs
;
954 secs
= (int)(ts
% 60);
956 mins
= (int)(ts
% 60);
958 hours
= (int)(ts
% 24);
963 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%dd+", days
);
964 if ((size_t)len
>= bufsiz
)
969 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d:", hours
);
970 if ((size_t)len
>= bufsiz
)
974 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d:", mins
);
975 if ((size_t)len
>= bufsiz
)
978 len
+= snprintf(buf
+ len
, bufsiz
- len
, "%.2d", secs
);
985 cdf_dump_header(const cdf_header_t
*h
)
989 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
990 #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
991 h->h_ ## b, 1 << h->h_ ## b)
992 DUMP("%d", revision
);
994 DUMP("0x%x", byte_order
);
995 DUMP2("%d", sec_size_p2
);
996 DUMP2("%d", short_sec_size_p2
);
997 DUMP("%d", num_sectors_in_sat
);
998 DUMP("%d", secid_first_directory
);
999 DUMP("%d", min_size_standard_stream
);
1000 DUMP("%d", secid_first_sector_in_short_sat
);
1001 DUMP("%d", num_sectors_in_short_sat
);
1002 DUMP("%d", secid_first_sector_in_master_sat
);
1003 DUMP("%d", num_sectors_in_master_sat
);
1004 for (i
= 0; i
< __arraycount(h
->h_master_sat
); i
++) {
1005 if (h
->h_master_sat
[i
] == CDF_SECID_FREE
)
1007 (void)fprintf(stderr
, "%35.35s[%.3zu] = %d\n",
1008 "master_sat", i
, h
->h_master_sat
[i
]);
1013 cdf_dump_sat(const char *prefix
, const cdf_sat_t
*sat
, size_t size
)
1015 size_t i
, j
, s
= size
/ sizeof(cdf_secid_t
);
1017 for (i
= 0; i
< sat
->sat_len
; i
++) {
1018 (void)fprintf(stderr
, "%s[%zu]:\n%.6d: ", prefix
, i
, i
* s
);
1019 for (j
= 0; j
< s
; j
++) {
1020 (void)fprintf(stderr
, "%5d, ",
1021 CDF_TOLE4(sat
->sat_tab
[s
* i
+ j
]));
1022 if ((j
+ 1) % 10 == 0)
1023 (void)fprintf(stderr
, "\n%.6d: ",
1026 (void)fprintf(stderr
, "\n");
1031 cdf_dump(void *v
, size_t len
)
1034 unsigned char *p
= v
;
1036 (void)fprintf(stderr
, "%.4x: ", 0);
1037 for (i
= 0, j
= 0; i
< len
; i
++, p
++) {
1038 (void)fprintf(stderr
, "%.2x ", *p
);
1039 abuf
[j
++] = isprint(*p
) ? *p
: '.';
1043 (void)fprintf(stderr
, "%s\n%.4x: ", abuf
, i
+ 1);
1046 (void)fprintf(stderr
, "\n");
1050 cdf_dump_stream(const cdf_header_t
*h
, const cdf_stream_t
*sst
)
1052 size_t ss
= sst
->sst_dirlen
< h
->h_min_size_standard_stream
?
1053 CDF_SHORT_SEC_SIZE(h
) : CDF_SEC_SIZE(h
);
1054 cdf_dump(sst
->sst_tab
, ss
* sst
->sst_len
);
1058 cdf_dump_dir(const cdf_info_t
*info
, const cdf_header_t
*h
,
1059 const cdf_sat_t
*sat
, const cdf_sat_t
*ssat
, const cdf_stream_t
*sst
,
1060 const cdf_dir_t
*dir
)
1064 char name
[__arraycount(d
->d_name
)];
1068 static const char *types
[] = { "empty", "user storage",
1069 "user stream", "lockbytes", "property", "root storage" };
1071 for (i
= 0; i
< dir
->dir_len
; i
++) {
1072 d
= &dir
->dir_tab
[i
];
1073 for (j
= 0; j
< sizeof(name
); j
++)
1074 name
[j
] = (char)CDF_TOLE2(d
->d_name
[j
]);
1075 (void)fprintf(stderr
, "Directory %zu: %s\n", i
, name
);
1076 if (d
->d_type
< __arraycount(types
))
1077 (void)fprintf(stderr
, "Type: %s\n", types
[d
->d_type
]);
1079 (void)fprintf(stderr
, "Type: %d\n", d
->d_type
);
1080 (void)fprintf(stderr
, "Color: %s\n",
1081 d
->d_color
? "black" : "red");
1082 (void)fprintf(stderr
, "Left child: %d\n", d
->d_left_child
);
1083 (void)fprintf(stderr
, "Right child: %d\n", d
->d_right_child
);
1084 (void)fprintf(stderr
, "Flags: 0x%x\n", d
->d_flags
);
1085 cdf_timestamp_to_timespec(&ts
, d
->d_created
);
1086 (void)fprintf(stderr
, "Created %s", ctime(&ts
.tv_sec
));
1087 cdf_timestamp_to_timespec(&ts
, d
->d_modified
);
1088 (void)fprintf(stderr
, "Modified %s", ctime(&ts
.tv_sec
));
1089 (void)fprintf(stderr
, "Stream %d\n", d
->d_stream_first_sector
);
1090 (void)fprintf(stderr
, "Size %d\n", d
->d_size
);
1091 switch (d
->d_type
) {
1092 case CDF_DIR_TYPE_USER_STORAGE
:
1093 (void)fprintf(stderr
, "Storage: %d\n", d
->d_storage
);
1095 case CDF_DIR_TYPE_USER_STREAM
:
1098 if (cdf_read_sector_chain(info
, h
, sat
, ssat
, sst
,
1099 d
->d_stream_first_sector
, d
->d_size
, &scn
) == -1) {
1100 warn("Can't read stream for %s at %d len %d",
1101 name
, d
->d_stream_first_sector
, d
->d_size
);
1104 cdf_dump_stream(h
, &scn
);
1115 cdf_dump_property_info(const cdf_property_info_t
*info
, size_t count
)
1122 for (i
= 0; i
< count
; i
++) {
1123 cdf_print_property_name(buf
, sizeof(buf
), info
[i
].pi_id
);
1124 (void)fprintf(stderr
, "%zu) %s: ", i
, buf
);
1125 switch (info
[i
].pi_type
) {
1129 (void)fprintf(stderr
, "signed 16 [%hd]\n",
1133 (void)fprintf(stderr
, "signed 32 [%d]\n",
1136 case CDF_UNSIGNED32
:
1137 (void)fprintf(stderr
, "unsigned 32 [%u]\n",
1140 case CDF_LENGTH32_STRING
:
1141 (void)fprintf(stderr
, "string %u [%.*s]\n",
1142 info
[i
].pi_str
.s_len
,
1143 info
[i
].pi_str
.s_len
, info
[i
].pi_str
.s_buf
);
1145 case CDF_LENGTH32_WSTRING
:
1146 (void)fprintf(stderr
, "string %u [",
1147 info
[i
].pi_str
.s_len
);
1148 for (j
= 0; j
< info
[i
].pi_str
.s_len
- 1; j
++)
1149 (void)fputc(info
[i
].pi_str
.s_buf
[j
<< 1], stderr
);
1150 (void)fprintf(stderr
, "]\n");
1154 if (tp
< 1000000000000000LL) {
1155 cdf_print_elapsed_time(buf
, sizeof(buf
), tp
);
1156 (void)fprintf(stderr
, "timestamp %s\n", buf
);
1158 cdf_timestamp_to_timespec(&ts
, tp
);
1159 (void)fprintf(stderr
, "timestamp %s",
1164 (void)fprintf(stderr
, "CLIPBOARD %u\n", info
[i
].pi_u32
);
1167 DPRINTF(("Don't know how to deal with %x\n",
1176 cdf_dump_summary_info(const cdf_header_t
*h
, const cdf_stream_t
*sst
)
1179 cdf_summary_info_header_t ssi
;
1180 cdf_property_info_t
*info
;
1184 if (cdf_unpack_summary_info(sst
, &ssi
, &info
, &count
) == -1)
1186 (void)fprintf(stderr
, "Endian: %x\n", ssi
.si_byte_order
);
1187 (void)fprintf(stderr
, "Os Version %d.%d\n", ssi
.si_os_version
& 0xff,
1188 ssi
.si_os_version
>> 8);
1189 (void)fprintf(stderr
, "Os %d\n", ssi
.si_os
);
1190 cdf_print_classid(buf
, sizeof(buf
), &ssi
.si_class
);
1191 (void)fprintf(stderr
, "Class %s\n", buf
);
1192 (void)fprintf(stderr
, "Count %d\n", ssi
.si_count
);
1193 cdf_dump_property_info(info
, count
);
1201 main(int argc
, char *argv
[])
1205 cdf_sat_t sat
, ssat
;
1206 cdf_stream_t sst
, scn
;
1211 (void)fprintf(stderr
, "Usage: %s <filename>\n", getprogname());
1217 for (i
= 1; i
< argc
; i
++) {
1218 if ((info
.i_fd
= open(argv
[1], O_RDONLY
)) == -1)
1219 err(1, "Cannot open `%s'", argv
[1]);
1221 if (cdf_read_header(&info
, &h
) == -1)
1222 err(1, "Cannot read header");
1224 cdf_dump_header(&h
);
1227 if (cdf_read_sat(&info
, &h
, &sat
) == -1)
1228 err(1, "Cannot read sat");
1230 cdf_dump_sat("SAT", &sat
, CDF_SEC_SIZE(&h
));
1233 if (cdf_read_ssat(&info
, &h
, &sat
, &ssat
) == -1)
1234 err(1, "Cannot read ssat");
1236 cdf_dump_sat("SSAT", &ssat
, CDF_SHORT_SEC_SIZE(&h
));
1239 if (cdf_read_dir(&info
, &h
, &sat
, &dir
) == -1)
1240 err(1, "Cannot read dir");
1242 if (cdf_read_short_stream(&info
, &h
, &sat
, &dir
, &sst
) == -1)
1243 err(1, "Cannot read short stream");
1245 cdf_dump_stream(&h
, &sst
);
1249 cdf_dump_dir(&info
, &h
, &sat
, &ssat
, &sst
, &dir
);
1253 if (cdf_read_summary_info(&info
, &h
, &sat
, &ssat
, &sst
, &dir
,
1255 err(1, "Cannot read summary info");
1257 cdf_dump_summary_info(&h
, &scn
);
1260 (void)close(info
.i_fd
);