xref: /netbsd-src/external/bsd/file/dist/src/cdf.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: cdf.c,v 1.3 2009/05/08 17:43:54 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 Christos Zoulas
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
27  */
28 /*
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
32  */
33 
34 #include "file.h"
35 
36 #ifndef lint
37 #if 0
38 FILE_RCSID("@(#)$File: cdf.c,v 1.30 2009/05/06 14:29:47 christos Exp $")
39 #else
40 __RCSID("$NetBSD: cdf.c,v 1.3 2009/05/08 17:43:54 christos Exp $");
41 #endif
42 #endif
43 
44 #include <assert.h>
45 #ifdef CDF_DEBUG
46 #include <err.h>
47 #endif
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <time.h>
52 #include <ctype.h>
53 
54 #ifndef EFTYPE
55 #define EFTYPE EINVAL
56 #endif
57 
58 #include "cdf.h"
59 
60 #ifndef __arraycount
61 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
62 #endif
63 
64 #ifdef CDF_DEBUG
65 #define DPRINTF(a) printf a, fflush(stdout)
66 #else
67 #define DPRINTF(a)
68 #endif
69 
70 static union {
71 	char s[4];
72 	uint32_t u;
73 } cdf_bo;
74 
75 #define NEED_SWAP	(cdf_bo.u == (uint32_t)0x01020304)
76 
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)))
80 
81 /*
82  * swap a short
83  */
84 uint16_t
85 cdf_tole2(uint16_t sv)
86 {
87 	uint16_t rv;
88 	uint8_t *s = (uint8_t *)(void *)&sv;
89 	uint8_t *d = (uint8_t *)(void *)&rv;
90 	d[0] = s[1];
91 	d[1] = s[0];
92 	return rv;
93 }
94 
95 /*
96  * swap an int
97  */
98 uint32_t
99 cdf_tole4(uint32_t sv)
100 {
101 	uint32_t rv;
102 	uint8_t *s = (uint8_t *)(void *)&sv;
103 	uint8_t *d = (uint8_t *)(void *)&rv;
104 	d[0] = s[3];
105 	d[1] = s[2];
106 	d[2] = s[1];
107 	d[3] = s[0];
108 	return rv;
109 }
110 
111 /*
112  * swap a quad
113  */
114 uint64_t
115 cdf_tole8(uint64_t sv)
116 {
117 	uint64_t rv;
118 	uint8_t *s = (uint8_t *)(void *)&sv;
119 	uint8_t *d = (uint8_t *)(void *)&rv;
120 	d[0] = s[7];
121 	d[1] = s[6];
122 	d[2] = s[5];
123 	d[3] = s[4];
124 	d[4] = s[3];
125 	d[5] = s[2];
126 	d[6] = s[1];
127 	d[7] = s[0];
128 	return rv;
129 }
130 
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)
135 
136 void
137 cdf_swap_header(cdf_header_t *h)
138 {
139 	size_t i;
140 
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]);
163 }
164 
165 void
166 cdf_unpack_header(cdf_header_t *h, char *buf)
167 {
168 	size_t i;
169 	size_t len = 0;
170 
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]);
189 }
190 
191 void
192 cdf_swap_dir(cdf_directory_t *d)
193 {
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);
205 }
206 
207 void
208 cdf_swap_class(cdf_classid_t *d)
209 {
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]);
213 }
214 
215 void
216 cdf_unpack_dir(cdf_directory_t *d, char *buf)
217 {
218 	size_t len = 0;
219 
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);
234 }
235 
236 static int
237 cdf_check_stream_offset(const cdf_stream_t *sst, const void *p, size_t tail)
238 {
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)
242 		return 0;
243 	DPRINTF((stderr, "offset begin %p end %p %zu >= %zu\n", b, e,
244 	    (size_t)(e - b), sst->sst_dirlen * sst->sst_len));
245 	errno = EFTYPE;
246 	return -1;
247 }
248 
249 static ssize_t
250 cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
251 {
252 	size_t siz = (size_t)off + len;
253 
254 	if ((off_t)(off + len) != (off_t)siz) {
255 		errno = EINVAL;
256 		return -1;
257 	}
258 
259 	if (info->i_buf != NULL && info->i_len >= siz) {
260 		(void)memcpy(buf, &info->i_buf[off], len);
261 		return (ssize_t)len;
262 	}
263 
264 	if (info->i_fd == -1)
265 		return -1;
266 
267 	if (lseek(info->i_fd, off, SEEK_SET) == (off_t)-1)
268 		return -1;
269 
270 	if (read(info->i_fd, buf, len) != (ssize_t)len)
271 		return -1;
272 
273 	return (ssize_t)len;
274 }
275 
276 int
277 cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
278 {
279 	char buf[512];
280 
281 	(void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
282 	if (cdf_read(info, (off_t)0, buf, sizeof(buf)) == -1)
283 		return -1;
284 	cdf_unpack_header(h, buf);
285 	cdf_swap_header(h);
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));
290 		goto out;
291 	}
292 	if (h->h_sec_size_p2 > 20) {
293 		DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
294 		goto out;
295 	}
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));
299 		goto out;
300 	}
301 	return 0;
302 out:
303 	errno = EFTYPE;
304 	return -1;
305 }
306 
307 
308 ssize_t
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)
311 {
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);
315 }
316 
317 ssize_t
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)
320 {
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);
324 	return len;
325 }
326 
327 /*
328  * Read the sector allocation table.
329  */
330 int
331 cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
332 {
333 	size_t i, j, k;
334 	size_t ss = CDF_SEC_SIZE(h);
335 	cdf_secid_t *msa, mid, sec;
336 	size_t nsatpersec = (ss / sizeof(mid)) - 1;
337 
338 	for (i = 0; i < __arraycount(h->h_master_sat); i++)
339 		if (h->h_master_sat[i] == CDF_SECID_FREE)
340 			break;
341 
342 #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
343 	if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec ||
344 	    i > CDF_SEC_LIMIT) {
345 		DPRINTF(("Number of sectors in master SAT too big %u %zu\n",
346 		    h->h_num_sectors_in_master_sat, i));
347 		errno = EFTYPE;
348 		return -1;
349 	}
350 
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)
354 		return -1;
355 
356 	for (i = 0; i < __arraycount(h->h_master_sat); i++) {
357 		if (h->h_master_sat[i] < 0)
358 			break;
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]));
362 			goto out1;
363 		}
364 	}
365 
366 	if ((msa = calloc(1, ss)) == NULL)
367 		goto out1;
368 
369 	mid = h->h_secid_first_sector_in_master_sat;
370 	for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
371 		if (mid < 0)
372 			goto out;
373 		if (j >= CDF_LOOP_LIMIT) {
374 			DPRINTF(("Reading master sector loop limit"));
375 			errno = EFTYPE;
376 			goto out2;
377 		}
378 		if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
379 			DPRINTF(("Reading master sector %d", mid));
380 			goto out2;
381 		}
382 		for (k = 0; k < nsatpersec; k++, i++) {
383 			sec = CDF_TOLE4((uint32_t)msa[k]);
384 			if (sec < 0)
385 				goto out;
386 			if (i >= sat->sat_len) {
387 			    DPRINTF(("Out of bounds reading MSA %u >= %u",
388 				i, sat->sat_len));
389 			    errno = EFTYPE;
390 			    goto out2;
391 			}
392 			if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
393 			    sec) != (ssize_t)ss) {
394 				DPRINTF(("Reading sector %d",
395 				    CDF_TOLE4(msa[k])));
396 				goto out2;
397 			}
398 		}
399 		mid = CDF_TOLE4((uint32_t)msa[nsatpersec]);
400 	}
401 out:
402 	sat->sat_len = i;
403 	free(msa);
404 	return 0;
405 out2:
406 	free(msa);
407 out1:
408 	free(sat->sat_tab);
409 	return -1;
410 }
411 
412 size_t
413 cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
414 {
415 	size_t i, j;
416 	cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * size);
417 
418 	DPRINTF(("Chain:"));
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"));
423 			errno = EFTYPE;
424 			return (size_t)-1;
425 		}
426 		if (sid > maxsector) {
427 			DPRINTF(("Sector %d > %d\n", sid, maxsector));
428 			errno = EFTYPE;
429 			return (size_t)-1;
430 		}
431 		sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
432 	}
433 	DPRINTF(("\n"));
434 	return i;
435 }
436 
437 int
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)
440 {
441 	size_t ss = CDF_SEC_SIZE(h), i, j;
442 	ssize_t nr;
443 	scn->sst_len = cdf_count_chain(sat, sid, ss);
444 	scn->sst_dirlen = len;
445 
446 	if (scn->sst_len == (size_t)-1)
447 		return -1;
448 
449 	scn->sst_tab = calloc(scn->sst_len, ss);
450 	if (scn->sst_tab == NULL)
451 		return -1;
452 
453 	for (j = i = 0; sid >= 0; i++, j++) {
454 		if (j >= CDF_LOOP_LIMIT) {
455 			DPRINTF(("Read long sector chain loop limit"));
456 			errno = EFTYPE;
457 			goto out;
458 		}
459 		if (i >= scn->sst_len) {
460 			DPRINTF(("Out of bounds reading long sector chain "
461 			    "%u > %u\n", i, scn->sst_len));
462 			errno = EFTYPE;
463 			goto out;
464 		}
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 */
469 				return 0;
470 			}
471 			DPRINTF(("Reading long sector chain %d", sid));
472 			goto out;
473 		}
474 		sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
475 	}
476 	return 0;
477 out:
478 	free(scn->sst_tab);
479 	return -1;
480 }
481 
482 int
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)
486 {
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;
490 
491 	if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
492 		return -1;
493 
494 	scn->sst_tab = calloc(scn->sst_len, ss);
495 	if (scn->sst_tab == NULL)
496 		return -1;
497 
498 	for (j = i = 0; sid >= 0; i++, j++) {
499 		if (j >= CDF_LOOP_LIMIT) {
500 			DPRINTF(("Read short sector chain loop limit"));
501 			errno = EFTYPE;
502 			goto out;
503 		}
504 		if (i >= scn->sst_len) {
505 			DPRINTF(("Out of bounds reading short sector chain "
506 			    "%u > %u\n", i, scn->sst_len));
507 			errno = EFTYPE;
508 			goto out;
509 		}
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));
513 			goto out;
514 		}
515 		sid = CDF_TOLE4((uint32_t)ssat->sat_tab[sid]);
516 	}
517 	return 0;
518 out:
519 	free(scn->sst_tab);
520 	return -1;
521 }
522 
523 int
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)
527 {
528 
529 	if (len < h->h_min_size_standard_stream)
530 		return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
531 		    scn);
532 	else
533 		return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
534 }
535 
536 int
537 cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
538     const cdf_sat_t *sat, cdf_dir_t *dir)
539 {
540 	size_t i, j;
541 	size_t ss = CDF_SEC_SIZE(h), ns, nd;
542 	char *buf;
543 	cdf_secid_t sid = h->h_secid_first_directory;
544 
545 	ns = cdf_count_chain(sat, sid, ss);
546 	if (ns == (size_t)-1)
547 		return -1;
548 
549 	nd = ss / CDF_DIRECTORY_SIZE;
550 
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)
554 		return -1;
555 
556 	if ((buf = malloc(ss)) == NULL) {
557 		free(dir->dir_tab);
558 		return -1;
559 	}
560 
561 	for (j = i = 0; i < ns; i++, j++) {
562 		if (j >= CDF_LOOP_LIMIT) {
563 			DPRINTF(("Read dir loop limit"));
564 			errno = EFTYPE;
565 			goto out;
566 		}
567 		if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
568 			DPRINTF(("Reading directory sector %d", sid));
569 			goto out;
570 		}
571 		for (j = 0; j < nd; j++) {
572 			cdf_unpack_dir(&dir->dir_tab[i * nd + j],
573 			    &buf[j * CDF_DIRECTORY_SIZE]);
574 		}
575 		sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
576 	}
577 	if (NEED_SWAP)
578 		for (i = 0; i < dir->dir_len; i++)
579 			cdf_swap_dir(&dir->dir_tab[i]);
580 	free(buf);
581 	return 0;
582 out:
583 	free(dir->dir_tab);
584 	free(buf);
585 	return -1;
586 }
587 
588 
589 int
590 cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
591     const cdf_sat_t *sat, cdf_sat_t *ssat)
592 {
593 	size_t i, j;
594 	size_t ss = CDF_SEC_SIZE(h);
595 	cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
596 
597 	ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h));
598 	if (ssat->sat_len == (size_t)-1)
599 		return -1;
600 
601 	ssat->sat_tab = calloc(ssat->sat_len, ss);
602 	if (ssat->sat_tab == NULL)
603 		return -1;
604 
605 	for (j = i = 0; sid >= 0; i++, j++) {
606 		if (j >= CDF_LOOP_LIMIT) {
607 			DPRINTF(("Read short sat sector loop limit"));
608 			errno = EFTYPE;
609 			goto out;
610 		}
611 		if (i >= ssat->sat_len) {
612 			DPRINTF(("Out of bounds reading short sector chain "
613 			    "%u > %u\n", i, ssat->sat_len));
614 			errno = EFTYPE;
615 			goto out;
616 		}
617 		if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
618 		    (ssize_t)ss) {
619 			DPRINTF(("Reading short sat sector %d", sid));
620 			goto out;
621 		}
622 		sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
623 	}
624 	return 0;
625 out:
626 	free(ssat->sat_tab);
627 	return -1;
628 }
629 
630 int
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)
633 {
634 	size_t i;
635 	const cdf_directory_t *d;
636 
637 	for (i = 0; i < dir->dir_len; i++)
638 		if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
639 			break;
640 
641 	/* If the it is not there, just fake it; some docs don't have it */
642 	if (i == dir->dir_len)
643 		goto out;
644 	d = &dir->dir_tab[i];
645 
646 	/* If the it is not there, just fake it; some docs don't have it */
647 	if (d->d_stream_first_sector < 0)
648 		goto out;
649 
650 	return  cdf_read_long_sector_chain(info, h, sat,
651 	    d->d_stream_first_sector, d->d_size, scn);
652 out:
653 	scn->sst_tab = NULL;
654 	scn->sst_len = 0;
655 	scn->sst_dirlen = 0;
656 	return 0;
657 }
658 
659 static int
660 cdf_namecmp(const char *d, const uint16_t *s, size_t l)
661 {
662 	for (; l--; d++, s++)
663 		if (*d != CDF_TOLE2(*s))
664 			return (unsigned char)*d - CDF_TOLE2(*s);
665 	return 0;
666 }
667 
668 int
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)
672 {
673 	size_t i;
674 	const cdf_directory_t *d;
675 	static const char name[] = "\05SummaryInformation";
676 
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))
680 		    == 0)
681 			break;
682 
683 	if (i == dir->dir_len) {
684 		DPRINTF(("Cannot find summary information section\n"));
685 		errno = EFTYPE;
686 		return -1;
687 	}
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);
691 }
692 
693 int
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)
696 {
697 	const cdf_section_header_t *shp;
698 	cdf_section_header_t sh;
699 	const uint32_t *p, *q, *e;
700 	int16_t s16;
701 	int32_t s32;
702 	uint32_t u32;
703 	int64_t s64;
704 	uint64_t u64;
705 	cdf_timestamp_t tp;
706 	size_t i, o, nelements, j;
707 	cdf_property_info_t *inp;
708 
709 	if (offs > UINT32_MAX / 4) {
710 		errno = EFTYPE;
711 		goto out;
712 	}
713 	shp = (const void *)((const char *)sst->sst_tab + offs);
714 	if (cdf_check_stream_offset(sst, shp, sizeof(*shp)) == -1)
715 		goto out;
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) {
719 		errno = EFTYPE;
720 		goto out;
721 	}
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)
725 		goto out;
726 	DPRINTF(("section len: %u properties %u\n", sh.sh_len,
727 	    sh.sh_properties));
728 	if (*maxcount) {
729 		if (*maxcount > CDF_PROP_LIMIT)
730 			goto out;
731 		*maxcount += sh.sh_properties;
732 		inp = realloc(*info, *maxcount * sizeof(*inp));
733 	} else {
734 		*maxcount = sh.sh_properties;
735 		inp = malloc(*maxcount * sizeof(*inp));
736 	}
737 	if (inp == NULL)
738 		goto out;
739 	*info = inp;
740 	inp += *count;
741 	*count += sh.sh_properties;
742 	p = (const void *)((const char *)(const void *)sst->sst_tab +
743 	    offs + sizeof(sh));
744 	e = (const void *)(((const char *)(const void *)shp) + sh.sh_len);
745 	if (cdf_check_stream_offset(sst, e, 0) == -1)
746 		goto out;
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;
751 		if (q > e) {
752 			DPRINTF(("Ran of the end %p > %p\n", q, e));
753 			goto out;
754 		}
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]);
761 			o = 2;
762 		} else {
763 			nelements = 1;
764 			o = 1;
765 		}
766 		if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
767 			goto unknown;
768 		switch (inp[i].pi_type & CDF_TYPEMASK) {
769 		case CDF_EMPTY:
770 			break;
771 		case CDF_SIGNED16:
772 			if (inp[i].pi_type & CDF_VECTOR)
773 				goto unknown;
774 			(void)memcpy(&s16, &q[o], sizeof(s16));
775 			inp[i].pi_s16 = CDF_TOLE2(s16);
776 			break;
777 		case CDF_SIGNED32:
778 			if (inp[i].pi_type & CDF_VECTOR)
779 				goto unknown;
780 			(void)memcpy(&s32, &q[o], sizeof(s32));
781 			inp[i].pi_s32 = CDF_TOLE4((uint32_t)s32);
782 			break;
783 		case CDF_BOOL:
784 		case CDF_UNSIGNED32:
785 			if (inp[i].pi_type & CDF_VECTOR)
786 				goto unknown;
787 			(void)memcpy(&u32, &q[o], sizeof(u32));
788 			inp[i].pi_u32 = CDF_TOLE4(u32);
789 			break;
790 		case CDF_SIGNED64:
791 			if (inp[i].pi_type & CDF_VECTOR)
792 				goto unknown;
793 			(void)memcpy(&s64, &q[o], sizeof(s64));
794 			inp[i].pi_s64 = CDF_TOLE8((uint64_t)s64);
795 			break;
796 		case CDF_UNSIGNED64:
797 			if (inp[i].pi_type & CDF_VECTOR)
798 				goto unknown;
799 			(void)memcpy(&u64, &q[o], sizeof(u64));
800 			inp[i].pi_u64 = CDF_TOLE8((uint64_t)u64);
801 			break;
802 		case CDF_LENGTH32_STRING:
803 			if (nelements > 1) {
804 				size_t nelem = inp - *info;
805 				if (*maxcount > CDF_PROP_LIMIT
806 				    || nelements > CDF_PROP_LIMIT)
807 					goto out;
808 				*maxcount += nelements;
809 				inp = realloc(*info, *maxcount * sizeof(*inp));
810 				if (inp == NULL)
811 					goto out;
812 				*info = inp;
813 				inp = *info + nelem;
814 			}
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));
825 				o += l >> 2;
826 			}
827 			i--;
828 			break;
829 		case CDF_FILETIME:
830 			if (inp[i].pi_type & CDF_VECTOR)
831 				goto unknown;
832 			(void)memcpy(&tp, &q[o], sizeof(tp));
833 			inp[i].pi_tp = CDF_TOLE8((uint64_t)tp);
834 			break;
835 		case CDF_CLIPBOARD:
836 			if (inp[i].pi_type & CDF_VECTOR)
837 				goto unknown;
838 			break;
839 		default:
840 		unknown:
841 			DPRINTF(("Don't know how to deal with %x\n",
842 			    inp[i].pi_type));
843 			goto out;
844 		}
845 	}
846 	return 0;
847 out:
848 	free(*info);
849 	return -1;
850 }
851 
852 int
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)
855 {
856 	size_t i, maxcount;
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);
860 
861 	if (cdf_check_stream_offset(sst, si, sizeof(*si)) == -1 ||
862 	    cdf_check_stream_offset(sst, sd, sizeof(*sd)) == -1)
863 		return -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);
870 	*count = 0;
871 	maxcount = 0;
872 	*info = NULL;
873 	for (i = 0; i < CDF_TOLE4(si->si_count); i++) {
874 		if (i >= CDF_LOOP_LIMIT) {
875 			DPRINTF(("Unpack summary info loop limit"));
876 			errno = EFTYPE;
877 			return -1;
878 		}
879 		if (cdf_read_property_info(sst, CDF_TOLE4(sd->sd_offset),
880 		    info, count, &maxcount) == -1)
881 			return -1;
882 	}
883 	return 0;
884 }
885 
886 
887 
888 int
889 cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
890 {
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],
895 	    id->cl_six[5]);
896 }
897 
898 static const struct {
899 	uint32_t v;
900 	const char *n;
901 } vn[] = {
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" },
922 };
923 
924 int
925 cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
926 {
927 	size_t i;
928 
929 	for (i = 0; i < __arraycount(vn); i++)
930 		if (vn[i].v == p)
931 			return snprintf(buf, bufsiz, "%s", vn[i].n);
932 	return snprintf(buf, bufsiz, "0x%x", p);
933 }
934 
935 int
936 cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
937 {
938 	int len = 0;
939 	int days, hours, mins, secs;
940 
941 	ts /= CDF_TIME_PREC;
942 	secs = (int)(ts % 60);
943 	ts /= 60;
944 	mins = (int)(ts % 60);
945 	ts /= 60;
946 	hours = (int)(ts % 24);
947 	ts /= 24;
948 	days = (int)ts;
949 
950 	if (days) {
951 		len += snprintf(buf + len, bufsiz - len, "%dd+", days);
952 		if ((size_t)len >= bufsiz)
953 			return len;
954 	}
955 
956 	if (days || hours) {
957 		len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
958 		if ((size_t)len >= bufsiz)
959 			return len;
960 	}
961 
962 	len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
963 	if ((size_t)len >= bufsiz)
964 		return len;
965 
966 	len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
967 	return len;
968 }
969 
970 
971 #ifdef CDF_DEBUG
972 void
973 cdf_dump_header(const cdf_header_t *h)
974 {
975 	size_t i;
976 
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);
981 	DUMP("%d", version);
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)
994 			break;
995 		(void)fprintf(stderr, "%35.35s[%.3zu] = %d\n",
996 		    "master_sat", i, h->h_master_sat[i]);
997 	}
998 }
999 
1000 void
1001 cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
1002 {
1003 	size_t i, j, s = size / sizeof(cdf_secid_t);
1004 
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: ",
1012 				    i * s + j + 1);
1013 		}
1014 		(void)fprintf(stderr, "\n");
1015 	}
1016 }
1017 
1018 void
1019 cdf_dump(void *v, size_t len)
1020 {
1021 	size_t i, j;
1022 	unsigned char *p = v;
1023 	char abuf[16];
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 : '.';
1028 		if (j == 16) {
1029 			j = 0;
1030 			abuf[15] = '\0';
1031 			(void)fprintf(stderr, "%s\n%.4x: ", abuf, i + 1);
1032 		}
1033 	}
1034 	(void)fprintf(stderr, "\n");
1035 }
1036 
1037 void
1038 cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
1039 {
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);
1043 }
1044 
1045 void
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)
1049 {
1050 	size_t i, j;
1051 	cdf_directory_t *d;
1052 	char name[__arraycount(d->d_name)];
1053 	cdf_stream_t scn;
1054 	struct timespec ts;
1055 
1056 	static const char *types[] = { "empty", "user storage",
1057 	    "user stream", "lockbytes", "property", "root storage" };
1058 
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]);
1066 		else
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);
1082 			break;
1083 		case CDF_DIR_TYPE_USER_STREAM:
1084 			if (sst == NULL)
1085 				break;
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);
1090 				break;
1091 			}
1092 			cdf_dump_stream(h, &scn);
1093 			free(scn.sst_tab);
1094 			break;
1095 		default:
1096 			break;
1097 		}
1098 
1099 	}
1100 }
1101 
1102 void
1103 cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
1104 {
1105 	cdf_timestamp_t tp;
1106 	struct timespec ts;
1107 	char buf[64];
1108 	size_t i;
1109 
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) {
1114 		case CDF_SIGNED16:
1115 			(void)fprintf(stderr, "signed 16 [%hd]\n",
1116 			    info[i].pi_s16);
1117 			break;
1118 		case CDF_SIGNED32:
1119 			(void)fprintf(stderr, "signed 32 [%d]\n",
1120 			    info[i].pi_s32);
1121 			break;
1122 		case CDF_UNSIGNED32:
1123 			(void)fprintf(stderr, "unsigned 32 [%u]\n",
1124 			    info[i].pi_u32);
1125 			break;
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);
1130 			break;
1131 		case CDF_FILETIME:
1132 			tp = info[i].pi_tp;
1133 			if (tp < 1000000000000000LL) {
1134 				cdf_print_elapsed_time(buf, sizeof(buf), tp);
1135 				(void)fprintf(stderr, "timestamp %s\n", buf);
1136 			} else {
1137 				cdf_timestamp_to_timespec(&ts, tp);
1138 				(void)fprintf(stderr, "timestamp %s",
1139 				    ctime(&ts.tv_sec));
1140 			}
1141 			break;
1142 		case CDF_CLIPBOARD:
1143 			(void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
1144 			break;
1145 		default:
1146 			DPRINTF(("Don't know how to deal with %x\n",
1147 			    info[i].pi_type));
1148 			break;
1149 		}
1150 	}
1151 }
1152 
1153 
1154 void
1155 cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
1156 {
1157 	char buf[128];
1158 	cdf_summary_info_header_t ssi;
1159 	cdf_property_info_t *info;
1160 	size_t count;
1161 
1162 	(void)&h;
1163 	if (cdf_unpack_summary_info(sst, &ssi, &info, &count) == -1)
1164 		return;
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);
1173 	free(info);
1174 }
1175 
1176 #endif
1177 
1178 #ifdef TEST
1179 int
1180 main(int argc, char *argv[])
1181 {
1182 	int i;
1183 	cdf_header_t h;
1184 	cdf_sat_t sat, ssat;
1185 	cdf_stream_t sst, scn;
1186 	cdf_dir_t dir;
1187 	cdf_info_t info;
1188 
1189 	if (argc < 2) {
1190 		(void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
1191 		return -1;
1192 	}
1193 
1194 	info.i_buf = NULL;
1195 	info.i_len = 0;
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]);
1199 
1200 		if (cdf_read_header(&info, &h) == -1)
1201 			err(1, "Cannot read header");
1202 #ifdef CDF_DEBUG
1203 		cdf_dump_header(&h);
1204 #endif
1205 
1206 		if (cdf_read_sat(&info, &h, &sat) == -1)
1207 			err(1, "Cannot read sat");
1208 #ifdef CDF_DEBUG
1209 		cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
1210 #endif
1211 
1212 		if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
1213 			err(1, "Cannot read ssat");
1214 #ifdef CDF_DEBUG
1215 		cdf_dump_sat("SSAT", &h, &ssat, CDF_SHORT_SEC_SIZE(&h));
1216 #endif
1217 
1218 		if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
1219 			err(1, "Cannot read dir");
1220 
1221 		if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
1222 			err(1, "Cannot read short stream");
1223 #ifdef CDF_DEBUG
1224 		cdf_dump_stream(&h, &sst);
1225 #endif
1226 
1227 #ifdef CDF_DEBUG
1228 		cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
1229 #endif
1230 
1231 
1232 		if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
1233 		    &scn) == -1)
1234 			err(1, "Cannot read summary info");
1235 #ifdef CDF_DEBUG
1236 		cdf_dump_summary_info(&h, &scn);
1237 #endif
1238 
1239 		(void)close(info.i_fd);
1240 	}
1241 
1242 	return 0;
1243 }
1244 #endif
1245