1191739Sobrien/*-
2191739Sobrien * Copyright (c) 2008 Christos Zoulas
3191739Sobrien * All rights reserved.
4191739Sobrien *
5191739Sobrien * Redistribution and use in source and binary forms, with or without
6191739Sobrien * modification, are permitted provided that the following conditions
7191739Sobrien * are met:
8191739Sobrien * 1. Redistributions of source code must retain the above copyright
9191739Sobrien *    notice, this list of conditions and the following disclaimer.
10191739Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11191739Sobrien *    notice, this list of conditions and the following disclaimer in the
12191739Sobrien *    documentation and/or other materials provided with the distribution.
13191739Sobrien *
14191739Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
15191739Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
16191739Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17191739Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
18191739Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19191739Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20191739Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21191739Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22191739Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23191739Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24191739Sobrien * POSSIBILITY OF SUCH DAMAGE.
25191739Sobrien */
26191739Sobrien/*
27226048Sobrien * Parse Composite Document Files, the format used in Microsoft Office
28226048Sobrien * document files before they switched to zipped XML.
29191739Sobrien * Info from: http://sc.openoffice.org/compdocfileformat.pdf
30226048Sobrien *
31226048Sobrien * N.B. This is the "Composite Document File" format, and not the
32226048Sobrien * "Compound Document Format", nor the "Channel Definition Format".
33191739Sobrien */
34191739Sobrien
35191739Sobrien#include "file.h"
36191739Sobrien
37191739Sobrien#ifndef lint
38354939SdelphijFILE_RCSID("@(#)$File: cdf.c,v 1.116 2019/08/26 14:31:39 christos Exp $")
39191739Sobrien#endif
40191739Sobrien
41191739Sobrien#include <assert.h>
42191739Sobrien#ifdef CDF_DEBUG
43191739Sobrien#include <err.h>
44191739Sobrien#endif
45191739Sobrien#include <stdlib.h>
46191739Sobrien#include <unistd.h>
47191739Sobrien#include <string.h>
48191739Sobrien#include <time.h>
49191739Sobrien#include <ctype.h>
50226048Sobrien#include <limits.h>
51191739Sobrien
52191739Sobrien#ifndef EFTYPE
53191739Sobrien#define EFTYPE EINVAL
54191739Sobrien#endif
55191739Sobrien
56354939Sdelphij#ifndef SIZE_T_MAX
57354939Sdelphij#define SIZE_T_MAX CAST(size_t, ~0ULL)
58354939Sdelphij#endif
59354939Sdelphij
60191739Sobrien#include "cdf.h"
61191739Sobrien
62191739Sobrien#ifdef CDF_DEBUG
63192348Sdelphij#define DPRINTF(a) printf a, fflush(stdout)
64191739Sobrien#else
65191739Sobrien#define DPRINTF(a)
66191739Sobrien#endif
67191739Sobrien
68191739Sobrienstatic union {
69191739Sobrien	char s[4];
70191739Sobrien	uint32_t u;
71191739Sobrien} cdf_bo;
72191739Sobrien
73354939Sdelphij#define NEED_SWAP	(cdf_bo.u == CAST(uint32_t, 0x01020304))
74191739Sobrien
75354939Sdelphij#define CDF_TOLE8(x)	\
76354939Sdelphij    (CAST(uint64_t, NEED_SWAP ? _cdf_tole8(x) : CAST(uint64_t, x)))
77354939Sdelphij#define CDF_TOLE4(x)	\
78354939Sdelphij    (CAST(uint32_t, NEED_SWAP ? _cdf_tole4(x) : CAST(uint32_t, x)))
79354939Sdelphij#define CDF_TOLE2(x)	\
80354939Sdelphij    (CAST(uint16_t, NEED_SWAP ? _cdf_tole2(x) : CAST(uint16_t, x)))
81284237Sdelphij#define CDF_TOLE(x)	(/*CONSTCOND*/sizeof(x) == 2 ? \
82284237Sdelphij			    CDF_TOLE2(CAST(uint16_t, x)) : \
83284237Sdelphij			(/*CONSTCOND*/sizeof(x) == 4 ? \
84284237Sdelphij			    CDF_TOLE4(CAST(uint32_t, x)) : \
85284237Sdelphij			    CDF_TOLE8(CAST(uint64_t, x))))
86226048Sobrien#define CDF_GETUINT32(x, y)	cdf_getuint32(x, y)
87191739Sobrien
88328874Seadler#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n))
89328874Seadler#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n))
90328874Seadler#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u))
91234250Sobrien
92328874Seadler
93337827Seadler/*ARGSUSED*/
94328874Seadlerstatic void *
95328874Seadlercdf_malloc(const char *file __attribute__((__unused__)),
96328874Seadler    size_t line __attribute__((__unused__)), size_t n)
97328874Seadler{
98354939Sdelphij	DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n",
99354939Sdelphij	    file, line, __func__, n));
100328874Seadler	return malloc(n);
101328874Seadler}
102328874Seadler
103337827Seadler/*ARGSUSED*/
104328874Seadlerstatic void *
105328874Seadlercdf_realloc(const char *file __attribute__((__unused__)),
106328874Seadler    size_t line __attribute__((__unused__)), void *p, size_t n)
107328874Seadler{
108354939Sdelphij	DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n",
109354939Sdelphij	    file, line, __func__, n));
110328874Seadler	return realloc(p, n);
111328874Seadler}
112328874Seadler
113337827Seadler/*ARGSUSED*/
114328874Seadlerstatic void *
115328874Seadlercdf_calloc(const char *file __attribute__((__unused__)),
116328874Seadler    size_t line __attribute__((__unused__)), size_t n, size_t u)
117328874Seadler{
118354939Sdelphij	DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %"
119354939Sdelphij	    SIZE_T_FORMAT "u\n", file, line, __func__, n, u));
120328874Seadler	return calloc(n, u);
121328874Seadler}
122328874Seadler
123191739Sobrien/*
124191739Sobrien * swap a short
125191739Sobrien */
126226048Sobrienstatic uint16_t
127226048Sobrien_cdf_tole2(uint16_t sv)
128191739Sobrien{
129191739Sobrien	uint16_t rv;
130354939Sdelphij	uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv));
131354939Sdelphij	uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv));
132191739Sobrien	d[0] = s[1];
133191739Sobrien	d[1] = s[0];
134191739Sobrien	return rv;
135191739Sobrien}
136191739Sobrien
137191739Sobrien/*
138191739Sobrien * swap an int
139191739Sobrien */
140226048Sobrienstatic uint32_t
141226048Sobrien_cdf_tole4(uint32_t sv)
142191739Sobrien{
143191739Sobrien	uint32_t rv;
144354939Sdelphij	uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv));
145354939Sdelphij	uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv));
146191739Sobrien	d[0] = s[3];
147191739Sobrien	d[1] = s[2];
148191739Sobrien	d[2] = s[1];
149191739Sobrien	d[3] = s[0];
150191739Sobrien	return rv;
151191739Sobrien}
152191739Sobrien
153191739Sobrien/*
154191739Sobrien * swap a quad
155191739Sobrien */
156226048Sobrienstatic uint64_t
157226048Sobrien_cdf_tole8(uint64_t sv)
158191739Sobrien{
159191739Sobrien	uint64_t rv;
160354939Sdelphij	uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv));
161354939Sdelphij	uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv));
162191739Sobrien	d[0] = s[7];
163191739Sobrien	d[1] = s[6];
164191739Sobrien	d[2] = s[5];
165191739Sobrien	d[3] = s[4];
166191739Sobrien	d[4] = s[3];
167191739Sobrien	d[5] = s[2];
168191739Sobrien	d[6] = s[1];
169191739Sobrien	d[7] = s[0];
170191739Sobrien	return rv;
171191739Sobrien}
172191739Sobrien
173226048Sobrien/*
174226048Sobrien * grab a uint32_t from a possibly unaligned address, and return it in
175226048Sobrien * the native host order.
176226048Sobrien */
177226048Sobrienstatic uint32_t
178226048Sobriencdf_getuint32(const uint8_t *p, size_t offs)
179226048Sobrien{
180226048Sobrien	uint32_t rv;
181226048Sobrien	(void)memcpy(&rv, p + offs * sizeof(uint32_t), sizeof(rv));
182226048Sobrien	return CDF_TOLE4(rv);
183226048Sobrien}
184226048Sobrien
185191739Sobrien#define CDF_UNPACK(a)	\
186191739Sobrien    (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
187191739Sobrien#define CDF_UNPACKA(a)	\
188191739Sobrien    (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
189191739Sobrien
190226048Sobrienuint16_t
191226048Sobriencdf_tole2(uint16_t sv)
192226048Sobrien{
193226048Sobrien	return CDF_TOLE2(sv);
194226048Sobrien}
195226048Sobrien
196226048Sobrienuint32_t
197226048Sobriencdf_tole4(uint32_t sv)
198226048Sobrien{
199226048Sobrien	return CDF_TOLE4(sv);
200226048Sobrien}
201226048Sobrien
202226048Sobrienuint64_t
203226048Sobriencdf_tole8(uint64_t sv)
204226048Sobrien{
205226048Sobrien	return CDF_TOLE8(sv);
206226048Sobrien}
207226048Sobrien
208191739Sobrienvoid
209191739Sobriencdf_swap_header(cdf_header_t *h)
210191739Sobrien{
211191739Sobrien	size_t i;
212191739Sobrien
213191739Sobrien	h->h_magic = CDF_TOLE8(h->h_magic);
214191739Sobrien	h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]);
215191739Sobrien	h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]);
216191739Sobrien	h->h_revision = CDF_TOLE2(h->h_revision);
217191739Sobrien	h->h_version = CDF_TOLE2(h->h_version);
218191739Sobrien	h->h_byte_order = CDF_TOLE2(h->h_byte_order);
219191739Sobrien	h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2);
220191739Sobrien	h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2);
221191739Sobrien	h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat);
222191739Sobrien	h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory);
223191739Sobrien	h->h_min_size_standard_stream =
224191739Sobrien	    CDF_TOLE4(h->h_min_size_standard_stream);
225191739Sobrien	h->h_secid_first_sector_in_short_sat =
226354939Sdelphij	    CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_short_sat));
227191739Sobrien	h->h_num_sectors_in_short_sat =
228191739Sobrien	    CDF_TOLE4(h->h_num_sectors_in_short_sat);
229191739Sobrien	h->h_secid_first_sector_in_master_sat =
230354939Sdelphij	    CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_master_sat));
231191739Sobrien	h->h_num_sectors_in_master_sat =
232191739Sobrien	    CDF_TOLE4(h->h_num_sectors_in_master_sat);
233354939Sdelphij	for (i = 0; i < __arraycount(h->h_master_sat); i++) {
234354939Sdelphij		h->h_master_sat[i] =
235354939Sdelphij		    CDF_TOLE4(CAST(uint32_t, h->h_master_sat[i]));
236354939Sdelphij	}
237191739Sobrien}
238191739Sobrien
239191739Sobrienvoid
240191739Sobriencdf_unpack_header(cdf_header_t *h, char *buf)
241191739Sobrien{
242191739Sobrien	size_t i;
243191739Sobrien	size_t len = 0;
244191739Sobrien
245191739Sobrien	CDF_UNPACK(h->h_magic);
246191739Sobrien	CDF_UNPACKA(h->h_uuid);
247191739Sobrien	CDF_UNPACK(h->h_revision);
248191739Sobrien	CDF_UNPACK(h->h_version);
249191739Sobrien	CDF_UNPACK(h->h_byte_order);
250191739Sobrien	CDF_UNPACK(h->h_sec_size_p2);
251191739Sobrien	CDF_UNPACK(h->h_short_sec_size_p2);
252191739Sobrien	CDF_UNPACKA(h->h_unused0);
253191739Sobrien	CDF_UNPACK(h->h_num_sectors_in_sat);
254191739Sobrien	CDF_UNPACK(h->h_secid_first_directory);
255191739Sobrien	CDF_UNPACKA(h->h_unused1);
256191739Sobrien	CDF_UNPACK(h->h_min_size_standard_stream);
257191739Sobrien	CDF_UNPACK(h->h_secid_first_sector_in_short_sat);
258191739Sobrien	CDF_UNPACK(h->h_num_sectors_in_short_sat);
259191739Sobrien	CDF_UNPACK(h->h_secid_first_sector_in_master_sat);
260191739Sobrien	CDF_UNPACK(h->h_num_sectors_in_master_sat);
261191739Sobrien	for (i = 0; i < __arraycount(h->h_master_sat); i++)
262191739Sobrien		CDF_UNPACK(h->h_master_sat[i]);
263191739Sobrien}
264191739Sobrien
265191739Sobrienvoid
266191739Sobriencdf_swap_dir(cdf_directory_t *d)
267191739Sobrien{
268191739Sobrien	d->d_namelen = CDF_TOLE2(d->d_namelen);
269354939Sdelphij	d->d_left_child = CDF_TOLE4(CAST(uint32_t, d->d_left_child));
270354939Sdelphij	d->d_right_child = CDF_TOLE4(CAST(uint32_t, d->d_right_child));
271354939Sdelphij	d->d_storage = CDF_TOLE4(CAST(uint32_t, d->d_storage));
272191739Sobrien	d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]);
273191739Sobrien	d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]);
274191739Sobrien	d->d_flags = CDF_TOLE4(d->d_flags);
275354939Sdelphij	d->d_created = CDF_TOLE8(CAST(uint64_t, d->d_created));
276354939Sdelphij	d->d_modified = CDF_TOLE8(CAST(uint64_t, d->d_modified));
277354939Sdelphij	d->d_stream_first_sector = CDF_TOLE4(
278354939Sdelphij	    CAST(uint32_t, d->d_stream_first_sector));
279191739Sobrien	d->d_size = CDF_TOLE4(d->d_size);
280191739Sobrien}
281191739Sobrien
282191739Sobrienvoid
283191739Sobriencdf_swap_class(cdf_classid_t *d)
284191739Sobrien{
285191739Sobrien	d->cl_dword = CDF_TOLE4(d->cl_dword);
286191739Sobrien	d->cl_word[0] = CDF_TOLE2(d->cl_word[0]);
287191739Sobrien	d->cl_word[1] = CDF_TOLE2(d->cl_word[1]);
288191739Sobrien}
289191739Sobrien
290191739Sobrienvoid
291191739Sobriencdf_unpack_dir(cdf_directory_t *d, char *buf)
292191739Sobrien{
293191739Sobrien	size_t len = 0;
294191739Sobrien
295191739Sobrien	CDF_UNPACKA(d->d_name);
296191739Sobrien	CDF_UNPACK(d->d_namelen);
297191739Sobrien	CDF_UNPACK(d->d_type);
298191739Sobrien	CDF_UNPACK(d->d_color);
299191739Sobrien	CDF_UNPACK(d->d_left_child);
300191739Sobrien	CDF_UNPACK(d->d_right_child);
301191739Sobrien	CDF_UNPACK(d->d_storage);
302191739Sobrien	CDF_UNPACKA(d->d_storage_uuid);
303191739Sobrien	CDF_UNPACK(d->d_flags);
304191739Sobrien	CDF_UNPACK(d->d_created);
305191739Sobrien	CDF_UNPACK(d->d_modified);
306191739Sobrien	CDF_UNPACK(d->d_stream_first_sector);
307191739Sobrien	CDF_UNPACK(d->d_size);
308191739Sobrien	CDF_UNPACK(d->d_unused0);
309191739Sobrien}
310191739Sobrien
311309847Sdelphijint
312299736Sdelphijcdf_zero_stream(cdf_stream_t *scn)
313299736Sdelphij{
314299736Sdelphij	scn->sst_len = 0;
315299736Sdelphij	scn->sst_dirlen = 0;
316299736Sdelphij	scn->sst_ss = 0;
317299736Sdelphij	free(scn->sst_tab);
318299736Sdelphij	scn->sst_tab = NULL;
319299736Sdelphij	return -1;
320299736Sdelphij}
321299736Sdelphij
322299736Sdelphijstatic size_t
323299736Sdelphijcdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h)
324299736Sdelphij{
325299736Sdelphij	size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
326299736Sdelphij	    CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
327299736Sdelphij	assert(ss == sst->sst_ss);
328299736Sdelphij	return sst->sst_ss;
329299736Sdelphij}
330299736Sdelphij
331299736Sdelphijstatic int
332226048Sobriencdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h,
333226048Sobrien    const void *p, size_t tail, int line)
334192348Sdelphij{
335354939Sdelphij	const char *b = RCAST(const char *, sst->sst_tab);
336354939Sdelphij	const char *e = RCAST(const char *, p) + tail;
337299736Sdelphij	size_t ss = cdf_check_stream(sst, h);
338284237Sdelphij	/*LINTED*/(void)&line;
339354939Sdelphij	if (e >= b && CAST(size_t, e - b) <= ss * sst->sst_len)
340192348Sdelphij		return 0;
341267843Sdelphij	DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u"
342267843Sdelphij	    " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %"
343226048Sobrien	    SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b),
344267843Sdelphij	    ss * sst->sst_len, ss, sst->sst_len));
345192348Sdelphij	errno = EFTYPE;
346192348Sdelphij	return -1;
347192348Sdelphij}
348192348Sdelphij
349192348Sdelphijstatic ssize_t
350192348Sdelphijcdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
351192348Sdelphij{
352354939Sdelphij	size_t siz = CAST(size_t, off + len);
353192348Sdelphij
354354939Sdelphij	if (CAST(off_t, off + len) != CAST(off_t, siz))
355299736Sdelphij		goto out;
356192348Sdelphij
357192348Sdelphij	if (info->i_buf != NULL && info->i_len >= siz) {
358192348Sdelphij		(void)memcpy(buf, &info->i_buf[off], len);
359354939Sdelphij		return CAST(ssize_t, len);
360192348Sdelphij	}
361192348Sdelphij
362192348Sdelphij	if (info->i_fd == -1)
363299736Sdelphij		goto out;
364192348Sdelphij
365354939Sdelphij	if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len))
366192348Sdelphij		return -1;
367192348Sdelphij
368354939Sdelphij	return CAST(ssize_t, len);
369299736Sdelphijout:
370299736Sdelphij	errno = EINVAL;
371299736Sdelphij	return -1;
372192348Sdelphij}
373192348Sdelphij
374191739Sobrienint
375192348Sdelphijcdf_read_header(const cdf_info_t *info, cdf_header_t *h)
376191739Sobrien{
377192348Sdelphij	char buf[512];
378192348Sdelphij
379191739Sobrien	(void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
380354939Sdelphij	if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1)
381191739Sobrien		return -1;
382191739Sobrien	cdf_unpack_header(h, buf);
383191739Sobrien	cdf_swap_header(h);
384191739Sobrien	if (h->h_magic != CDF_MAGIC) {
385328874Seadler		DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#"
386226048Sobrien		    INT64_T_FORMAT "x\n",
387192348Sdelphij		    (unsigned long long)h->h_magic,
388192348Sdelphij		    (unsigned long long)CDF_MAGIC));
389192348Sdelphij		goto out;
390191739Sobrien	}
391192348Sdelphij	if (h->h_sec_size_p2 > 20) {
392328874Seadler		DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2));
393192348Sdelphij		goto out;
394192348Sdelphij	}
395192348Sdelphij	if (h->h_short_sec_size_p2 > 20) {
396328874Seadler		DPRINTF(("Bad short sector size %hu\n",
397192348Sdelphij		    h->h_short_sec_size_p2));
398192348Sdelphij		goto out;
399192348Sdelphij	}
400191739Sobrien	return 0;
401192348Sdelphijout:
402192348Sdelphij	errno = EFTYPE;
403192348Sdelphij	return -1;
404191739Sobrien}
405191739Sobrien
406191739Sobrien
407191739Sobrienssize_t
408192348Sdelphijcdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
409191739Sobrien    const cdf_header_t *h, cdf_secid_t id)
410191739Sobrien{
411234250Sobrien	size_t ss = CDF_SEC_SIZE(h);
412354939Sdelphij	size_t pos;
413354939Sdelphij
414354939Sdelphij	if (SIZE_T_MAX / ss < CAST(size_t, id))
415354939Sdelphij		return -1;
416354939Sdelphij
417354939Sdelphij	pos = CDF_SEC_POS(h, id);
418234250Sobrien	assert(ss == len);
419354939Sdelphij	return cdf_read(info, CAST(off_t, pos), RCAST(char *, buf) + offs, len);
420191739Sobrien}
421191739Sobrien
422191739Sobrienssize_t
423191739Sobriencdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
424191739Sobrien    size_t len, const cdf_header_t *h, cdf_secid_t id)
425191739Sobrien{
426234250Sobrien	size_t ss = CDF_SHORT_SEC_SIZE(h);
427354939Sdelphij	size_t pos;
428354939Sdelphij
429354939Sdelphij	if (SIZE_T_MAX / ss < CAST(size_t, id))
430354939Sdelphij		return -1;
431354939Sdelphij
432354939Sdelphij	pos = CDF_SHORT_SEC_POS(h, id);
433234250Sobrien	assert(ss == len);
434267843Sdelphij	if (pos + len > CDF_SEC_SIZE(h) * sst->sst_len) {
435234250Sobrien		DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %"
436234250Sobrien		    SIZE_T_FORMAT "u\n",
437267843Sdelphij		    pos + len, CDF_SEC_SIZE(h) * sst->sst_len));
438299736Sdelphij		goto out;
439234250Sobrien	}
440354939Sdelphij	(void)memcpy(RCAST(char *, buf) + offs,
441354939Sdelphij	    RCAST(const char *, sst->sst_tab) + pos, len);
442191739Sobrien	return len;
443299736Sdelphijout:
444299736Sdelphij	errno = EFTYPE;
445299736Sdelphij	return -1;
446191739Sobrien}
447191739Sobrien
448191739Sobrien/*
449191739Sobrien * Read the sector allocation table.
450191739Sobrien */
451191739Sobrienint
452192348Sdelphijcdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
453191739Sobrien{
454191739Sobrien	size_t i, j, k;
455191739Sobrien	size_t ss = CDF_SEC_SIZE(h);
456192348Sdelphij	cdf_secid_t *msa, mid, sec;
457192348Sdelphij	size_t nsatpersec = (ss / sizeof(mid)) - 1;
458191739Sobrien
459191739Sobrien	for (i = 0; i < __arraycount(h->h_master_sat); i++)
460191739Sobrien		if (h->h_master_sat[i] == CDF_SECID_FREE)
461191739Sobrien			break;
462191739Sobrien
463337827Seadler#define CDF_SEC_LIMIT (UINT32_MAX / (64 * ss))
464226048Sobrien	if ((nsatpersec > 0 &&
465226048Sobrien	    h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) ||
466192348Sdelphij	    i > CDF_SEC_LIMIT) {
467226048Sobrien		DPRINTF(("Number of sectors in master SAT too big %u %"
468226048Sobrien		    SIZE_T_FORMAT "u\n", h->h_num_sectors_in_master_sat, i));
469192348Sdelphij		errno = EFTYPE;
470192348Sdelphij		return -1;
471192348Sdelphij	}
472192348Sdelphij
473192348Sdelphij	sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
474226048Sobrien	DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n",
475226048Sobrien	    sat->sat_len, ss));
476328874Seadler	if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss)))
477226048Sobrien	    == NULL)
478191739Sobrien		return -1;
479191739Sobrien
480191739Sobrien	for (i = 0; i < __arraycount(h->h_master_sat); i++) {
481191739Sobrien		if (h->h_master_sat[i] < 0)
482191739Sobrien			break;
483192348Sdelphij		if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
484354939Sdelphij		    h->h_master_sat[i]) != CAST(ssize_t, ss)) {
485191739Sobrien			DPRINTF(("Reading sector %d", h->h_master_sat[i]));
486191739Sobrien			goto out1;
487191739Sobrien		}
488191739Sobrien	}
489191739Sobrien
490328874Seadler	if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL)
491191739Sobrien		goto out1;
492191739Sobrien
493191739Sobrien	mid = h->h_secid_first_sector_in_master_sat;
494191739Sobrien	for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
495192348Sdelphij		if (mid < 0)
496192348Sdelphij			goto out;
497191739Sobrien		if (j >= CDF_LOOP_LIMIT) {
498191739Sobrien			DPRINTF(("Reading master sector loop limit"));
499299736Sdelphij			goto out3;
500191739Sobrien		}
501354939Sdelphij		if (cdf_read_sector(info, msa, 0, ss, h, mid) !=
502354939Sdelphij		    CAST(ssize_t, ss)) {
503191739Sobrien			DPRINTF(("Reading master sector %d", mid));
504191739Sobrien			goto out2;
505191739Sobrien		}
506192348Sdelphij		for (k = 0; k < nsatpersec; k++, i++) {
507354939Sdelphij			sec = CDF_TOLE4(CAST(uint32_t, msa[k]));
508192348Sdelphij			if (sec < 0)
509192348Sdelphij				goto out;
510192348Sdelphij			if (i >= sat->sat_len) {
511354939Sdelphij			    DPRINTF(("Out of bounds reading MSA %"
512354939Sdelphij				SIZE_T_FORMAT "u >= %" SIZE_T_FORMAT "u",
513354939Sdelphij				i, sat->sat_len));
514299736Sdelphij			    goto out3;
515192348Sdelphij			}
516192348Sdelphij			if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
517354939Sdelphij			    sec) != CAST(ssize_t, ss)) {
518191739Sobrien				DPRINTF(("Reading sector %d",
519191739Sobrien				    CDF_TOLE4(msa[k])));
520191739Sobrien				goto out2;
521191739Sobrien			}
522192348Sdelphij		}
523354939Sdelphij		mid = CDF_TOLE4(CAST(uint32_t, msa[nsatpersec]));
524191739Sobrien	}
525192348Sdelphijout:
526192348Sdelphij	sat->sat_len = i;
527191739Sobrien	free(msa);
528191739Sobrien	return 0;
529299736Sdelphijout3:
530299736Sdelphij	errno = EFTYPE;
531191739Sobrienout2:
532191739Sobrien	free(msa);
533191739Sobrienout1:
534191739Sobrien	free(sat->sat_tab);
535191739Sobrien	return -1;
536191739Sobrien}
537191739Sobrien
538191739Sobriensize_t
539192348Sdelphijcdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
540191739Sobrien{
541192348Sdelphij	size_t i, j;
542354939Sdelphij	cdf_secid_t maxsector = CAST(cdf_secid_t, (sat->sat_len * size)
543267843Sdelphij	    / sizeof(maxsector));
544191739Sobrien
545191739Sobrien	DPRINTF(("Chain:"));
546275698Sdelphij	if (sid == CDF_SECID_END_OF_CHAIN) {
547275698Sdelphij		/* 0-length chain. */
548275698Sdelphij		DPRINTF((" empty\n"));
549275698Sdelphij		return 0;
550275698Sdelphij	}
551275698Sdelphij
552191739Sobrien	for (j = i = 0; sid >= 0; i++, j++) {
553191739Sobrien		DPRINTF((" %d", sid));
554191739Sobrien		if (j >= CDF_LOOP_LIMIT) {
555191739Sobrien			DPRINTF(("Counting chain loop limit"));
556299736Sdelphij			goto out;
557191739Sobrien		}
558267843Sdelphij		if (sid >= maxsector) {
559267843Sdelphij			DPRINTF(("Sector %d >= %d\n", sid, maxsector));
560299736Sdelphij			goto out;
561191739Sobrien		}
562354939Sdelphij		sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid]));
563191739Sobrien	}
564267843Sdelphij	if (i == 0) {
565267843Sdelphij		DPRINTF((" none, sid: %d\n", sid));
566299736Sdelphij		goto out;
567267843Sdelphij
568267843Sdelphij	}
569191739Sobrien	DPRINTF(("\n"));
570191739Sobrien	return i;
571299736Sdelphijout:
572299736Sdelphij	errno = EFTYPE;
573354939Sdelphij	return CAST(size_t, -1);
574191739Sobrien}
575191739Sobrien
576191739Sobrienint
577192348Sdelphijcdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
578192348Sdelphij    const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn)
579191739Sobrien{
580191739Sobrien	size_t ss = CDF_SEC_SIZE(h), i, j;
581191739Sobrien	ssize_t nr;
582299736Sdelphij	scn->sst_tab = NULL;
583192348Sdelphij	scn->sst_len = cdf_count_chain(sat, sid, ss);
584328874Seadler	scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len);
585299736Sdelphij	scn->sst_ss = ss;
586191739Sobrien
587328874Seadler	if (sid == CDF_SECID_END_OF_CHAIN || len == 0)
588328874Seadler		return cdf_zero_stream(scn);
589328874Seadler
590354939Sdelphij	if (scn->sst_len == CAST(size_t, -1))
591299736Sdelphij		goto out;
592191739Sobrien
593328874Seadler	scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
594191739Sobrien	if (scn->sst_tab == NULL)
595299736Sdelphij		return cdf_zero_stream(scn);
596191739Sobrien
597191739Sobrien	for (j = i = 0; sid >= 0; i++, j++) {
598192348Sdelphij		if (j >= CDF_LOOP_LIMIT) {
599192348Sdelphij			DPRINTF(("Read long sector chain loop limit"));
600192348Sdelphij			goto out;
601192348Sdelphij		}
602192348Sdelphij		if (i >= scn->sst_len) {
603192348Sdelphij			DPRINTF(("Out of bounds reading long sector chain "
604234250Sobrien			    "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
605234250Sobrien			    scn->sst_len));
606192348Sdelphij			goto out;
607192348Sdelphij		}
608192348Sdelphij		if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
609354939Sdelphij		    sid)) != CAST(ssize_t, ss)) {
610191739Sobrien			if (i == scn->sst_len - 1 && nr > 0) {
611191739Sobrien				/* Last sector might be truncated */
612191739Sobrien				return 0;
613191739Sobrien			}
614191739Sobrien			DPRINTF(("Reading long sector chain %d", sid));
615191739Sobrien			goto out;
616191739Sobrien		}
617354939Sdelphij		sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid]));
618191739Sobrien	}
619191739Sobrien	return 0;
620191739Sobrienout:
621299736Sdelphij	errno = EFTYPE;
622299736Sdelphij	return cdf_zero_stream(scn);
623191739Sobrien}
624191739Sobrien
625191739Sobrienint
626191739Sobriencdf_read_short_sector_chain(const cdf_header_t *h,
627191739Sobrien    const cdf_sat_t *ssat, const cdf_stream_t *sst,
628191739Sobrien    cdf_secid_t sid, size_t len, cdf_stream_t *scn)
629191739Sobrien{
630191739Sobrien	size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
631299736Sdelphij	scn->sst_tab = NULL;
632302221Sdelphij	scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
633191739Sobrien	scn->sst_dirlen = len;
634299736Sdelphij	scn->sst_ss = ss;
635191739Sobrien
636354939Sdelphij	if (scn->sst_len == CAST(size_t, -1))
637299736Sdelphij		goto out;
638191739Sobrien
639328874Seadler	scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
640191739Sobrien	if (scn->sst_tab == NULL)
641299736Sdelphij		return cdf_zero_stream(scn);
642191739Sobrien
643191739Sobrien	for (j = i = 0; sid >= 0; i++, j++) {
644191739Sobrien		if (j >= CDF_LOOP_LIMIT) {
645191739Sobrien			DPRINTF(("Read short sector chain loop limit"));
646191739Sobrien			goto out;
647191739Sobrien		}
648192348Sdelphij		if (i >= scn->sst_len) {
649192348Sdelphij			DPRINTF(("Out of bounds reading short sector chain "
650234250Sobrien			    "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n",
651234250Sobrien			    i, scn->sst_len));
652192348Sdelphij			goto out;
653192348Sdelphij		}
654191739Sobrien		if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
655354939Sdelphij		    sid) != CAST(ssize_t, ss)) {
656191739Sobrien			DPRINTF(("Reading short sector chain %d", sid));
657191739Sobrien			goto out;
658191739Sobrien		}
659354939Sdelphij		sid = CDF_TOLE4(CAST(uint32_t, ssat->sat_tab[sid]));
660191739Sobrien	}
661191739Sobrien	return 0;
662191739Sobrienout:
663299736Sdelphij	errno = EFTYPE;
664299736Sdelphij	return cdf_zero_stream(scn);
665191739Sobrien}
666191739Sobrien
667191739Sobrienint
668192348Sdelphijcdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
669192348Sdelphij    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
670191739Sobrien    cdf_secid_t sid, size_t len, cdf_stream_t *scn)
671191739Sobrien{
672191739Sobrien
673226048Sobrien	if (len < h->h_min_size_standard_stream && sst->sst_tab != NULL)
674191739Sobrien		return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
675191739Sobrien		    scn);
676191739Sobrien	else
677192348Sdelphij		return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
678191739Sobrien}
679191739Sobrien
680191739Sobrienint
681192348Sdelphijcdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
682192348Sdelphij    const cdf_sat_t *sat, cdf_dir_t *dir)
683191739Sobrien{
684191739Sobrien	size_t i, j;
685191739Sobrien	size_t ss = CDF_SEC_SIZE(h), ns, nd;
686191739Sobrien	char *buf;
687191739Sobrien	cdf_secid_t sid = h->h_secid_first_directory;
688191739Sobrien
689192348Sdelphij	ns = cdf_count_chain(sat, sid, ss);
690354939Sdelphij	if (ns == CAST(size_t, -1))
691191739Sobrien		return -1;
692191739Sobrien
693191739Sobrien	nd = ss / CDF_DIRECTORY_SIZE;
694191739Sobrien
695191739Sobrien	dir->dir_len = ns * nd;
696226048Sobrien	dir->dir_tab = CAST(cdf_directory_t *,
697328874Seadler	    CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0])));
698191739Sobrien	if (dir->dir_tab == NULL)
699191739Sobrien		return -1;
700191739Sobrien
701328874Seadler	if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) {
702191739Sobrien		free(dir->dir_tab);
703191739Sobrien		return -1;
704191739Sobrien	}
705191739Sobrien
706191739Sobrien	for (j = i = 0; i < ns; i++, j++) {
707191739Sobrien		if (j >= CDF_LOOP_LIMIT) {
708191739Sobrien			DPRINTF(("Read dir loop limit"));
709191739Sobrien			goto out;
710191739Sobrien		}
711354939Sdelphij		if (cdf_read_sector(info, buf, 0, ss, h, sid) !=
712354939Sdelphij		    CAST(ssize_t, ss)) {
713191739Sobrien			DPRINTF(("Reading directory sector %d", sid));
714191739Sobrien			goto out;
715191739Sobrien		}
716191739Sobrien		for (j = 0; j < nd; j++) {
717191739Sobrien			cdf_unpack_dir(&dir->dir_tab[i * nd + j],
718191739Sobrien			    &buf[j * CDF_DIRECTORY_SIZE]);
719191739Sobrien		}
720354939Sdelphij		sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid]));
721191739Sobrien	}
722191739Sobrien	if (NEED_SWAP)
723191739Sobrien		for (i = 0; i < dir->dir_len; i++)
724191739Sobrien			cdf_swap_dir(&dir->dir_tab[i]);
725191739Sobrien	free(buf);
726191739Sobrien	return 0;
727191739Sobrienout:
728191739Sobrien	free(dir->dir_tab);
729191739Sobrien	free(buf);
730299736Sdelphij	errno = EFTYPE;
731191739Sobrien	return -1;
732191739Sobrien}
733191739Sobrien
734191739Sobrien
735191739Sobrienint
736192348Sdelphijcdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
737192348Sdelphij    const cdf_sat_t *sat, cdf_sat_t *ssat)
738191739Sobrien{
739191739Sobrien	size_t i, j;
740191739Sobrien	size_t ss = CDF_SEC_SIZE(h);
741191739Sobrien	cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
742191739Sobrien
743299736Sdelphij	ssat->sat_tab = NULL;
744302221Sdelphij	ssat->sat_len = cdf_count_chain(sat, sid, ss);
745354939Sdelphij	if (ssat->sat_len == CAST(size_t, -1))
746299736Sdelphij		goto out;
747191739Sobrien
748328874Seadler	ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss));
749191739Sobrien	if (ssat->sat_tab == NULL)
750299736Sdelphij		goto out1;
751191739Sobrien
752191739Sobrien	for (j = i = 0; sid >= 0; i++, j++) {
753191739Sobrien		if (j >= CDF_LOOP_LIMIT) {
754191739Sobrien			DPRINTF(("Read short sat sector loop limit"));
755191739Sobrien			goto out;
756191739Sobrien		}
757192348Sdelphij		if (i >= ssat->sat_len) {
758192348Sdelphij			DPRINTF(("Out of bounds reading short sector chain "
759234250Sobrien			    "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
760234250Sobrien			    ssat->sat_len));
761192348Sdelphij			goto out;
762192348Sdelphij		}
763192348Sdelphij		if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
764354939Sdelphij		    CAST(ssize_t, ss)) {
765191739Sobrien			DPRINTF(("Reading short sat sector %d", sid));
766299736Sdelphij			goto out1;
767191739Sobrien		}
768354939Sdelphij		sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid]));
769191739Sobrien	}
770191739Sobrien	return 0;
771191739Sobrienout:
772299736Sdelphij	errno = EFTYPE;
773299736Sdelphijout1:
774191739Sobrien	free(ssat->sat_tab);
775191739Sobrien	return -1;
776191739Sobrien}
777191739Sobrien
778191739Sobrienint
779192348Sdelphijcdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
780267843Sdelphij    const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn,
781267843Sdelphij    const cdf_directory_t **root)
782191739Sobrien{
783191739Sobrien	size_t i;
784191739Sobrien	const cdf_directory_t *d;
785191739Sobrien
786267843Sdelphij	*root = NULL;
787191739Sobrien	for (i = 0; i < dir->dir_len; i++)
788191739Sobrien		if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
789191739Sobrien			break;
790191739Sobrien
791192348Sdelphij	/* If the it is not there, just fake it; some docs don't have it */
792309847Sdelphij	if (i == dir->dir_len) {
793309847Sdelphij		DPRINTF(("Cannot find root storage dir\n"));
794192348Sdelphij		goto out;
795309847Sdelphij	}
796191739Sobrien	d = &dir->dir_tab[i];
797267843Sdelphij	*root = d;
798191739Sobrien
799191739Sobrien	/* If the it is not there, just fake it; some docs don't have it */
800309847Sdelphij	if (d->d_stream_first_sector < 0) {
801309847Sdelphij		DPRINTF(("No first secror in dir\n"));
802192348Sdelphij		goto out;
803309847Sdelphij	}
804191739Sobrien
805299736Sdelphij	return cdf_read_long_sector_chain(info, h, sat,
806191739Sobrien	    d->d_stream_first_sector, d->d_size, scn);
807192348Sdelphijout:
808192348Sdelphij	scn->sst_tab = NULL;
809299736Sdelphij	(void)cdf_zero_stream(scn);
810309847Sdelphij	return 0;
811191739Sobrien}
812191739Sobrien
813191739Sobrienstatic int
814191739Sobriencdf_namecmp(const char *d, const uint16_t *s, size_t l)
815191739Sobrien{
816191739Sobrien	for (; l--; d++, s++)
817191739Sobrien		if (*d != CDF_TOLE2(*s))
818354939Sdelphij			return CAST(unsigned char, *d) - CDF_TOLE2(*s);
819191739Sobrien	return 0;
820191739Sobrien}
821191739Sobrien
822191739Sobrienint
823309847Sdelphijcdf_read_doc_summary_info(const cdf_info_t *info, const cdf_header_t *h,
824309847Sdelphij    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
825309847Sdelphij    const cdf_dir_t *dir, cdf_stream_t *scn)
826309847Sdelphij{
827309847Sdelphij	return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
828309847Sdelphij	    "\05DocumentSummaryInformation", scn);
829309847Sdelphij}
830309847Sdelphij
831309847Sdelphijint
832192348Sdelphijcdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
833191739Sobrien    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
834191739Sobrien    const cdf_dir_t *dir, cdf_stream_t *scn)
835191739Sobrien{
836267843Sdelphij	return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
837267843Sdelphij	    "\05SummaryInformation", scn);
838267843Sdelphij}
839267843Sdelphij
840267843Sdelphijint
841267843Sdelphijcdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h,
842267843Sdelphij    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
843267843Sdelphij    const cdf_dir_t *dir, const char *name, cdf_stream_t *scn)
844267843Sdelphij{
845191739Sobrien	const cdf_directory_t *d;
846284237Sdelphij	int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM);
847191739Sobrien
848299736Sdelphij	if (i <= 0) {
849299736Sdelphij		memset(scn, 0, sizeof(*scn));
850284237Sdelphij		return -1;
851299736Sdelphij	}
852284237Sdelphij
853284237Sdelphij	d = &dir->dir_tab[i - 1];
854284237Sdelphij	return cdf_read_sector_chain(info, h, sat, ssat, sst,
855284237Sdelphij	    d->d_stream_first_sector, d->d_size, scn);
856284237Sdelphij}
857284237Sdelphij
858284237Sdelphijint
859284237Sdelphijcdf_find_stream(const cdf_dir_t *dir, const char *name, int type)
860284237Sdelphij{
861284237Sdelphij	size_t i, name_len = strlen(name) + 1;
862284237Sdelphij
863226048Sobrien	for (i = dir->dir_len; i > 0; i--)
864284237Sdelphij		if (dir->dir_tab[i - 1].d_type == type &&
865267843Sdelphij		    cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len)
866191739Sobrien		    == 0)
867191739Sobrien			break;
868284237Sdelphij	if (i > 0)
869328874Seadler		return CAST(int, i);
870191739Sobrien
871284237Sdelphij	DPRINTF(("Cannot find type %d `%s'\n", type, name));
872284237Sdelphij	errno = ESRCH;
873284237Sdelphij	return 0;
874191739Sobrien}
875191739Sobrien
876337827Seadler#define CDF_SHLEN_LIMIT (UINT32_MAX / 64)
877337827Seadler#define CDF_PROP_LIMIT (UINT32_MAX / (64 * sizeof(cdf_property_info_t)))
878328874Seadler
879328874Seadlerstatic const void *
880328874Seadlercdf_offset(const void *p, size_t l)
881328874Seadler{
882328874Seadler	return CAST(const void *, CAST(const uint8_t *, p) + l);
883328874Seadler}
884328874Seadler
885328874Seadlerstatic const uint8_t *
886354939Sdelphijcdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h,
887328874Seadler    const uint8_t *p, const uint8_t *e, size_t i)
888328874Seadler{
889328874Seadler	size_t tail = (i << 1) + 1;
890328874Seadler	size_t ofs;
891328874Seadler	const uint8_t *q;
892328874Seadler
893328874Seadler	if (p >= e) {
894328874Seadler		DPRINTF(("Past end %p < %p\n", e, p));
895328874Seadler		return NULL;
896328874Seadler	}
897328874Seadler	if (cdf_check_stream_offset(sst, h, p, (tail + 1) * sizeof(uint32_t),
898328874Seadler	    __LINE__) == -1)
899328874Seadler		return NULL;
900328874Seadler	ofs = CDF_GETUINT32(p, tail);
901354939Sdelphij	q = CAST(const uint8_t *, cdf_offset(CAST(const void *, p),
902328874Seadler	    ofs - 2 * sizeof(uint32_t)));
903328874Seadler
904328874Seadler	if (q < p) {
905328874Seadler		DPRINTF(("Wrapped around %p < %p\n", q, p));
906328874Seadler		return NULL;
907328874Seadler	}
908328874Seadler
909328874Seadler	if (q >= e) {
910328874Seadler		DPRINTF(("Ran off the end %p >= %p\n", q, e));
911328874Seadler		return NULL;
912328874Seadler	}
913328874Seadler	return q;
914328874Seadler}
915328874Seadler
916328874Seadlerstatic cdf_property_info_t *
917328874Seadlercdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr)
918328874Seadler{
919328874Seadler	cdf_property_info_t *inp;
920328874Seadler	size_t newcount = *maxcount + incr;
921328874Seadler
922328874Seadler	if (newcount > CDF_PROP_LIMIT) {
923354939Sdelphij		DPRINTF(("exceeded property limit %" SIZE_T_FORMAT "u > %"
924354939Sdelphij		    SIZE_T_FORMAT "u\n", newcount, CDF_PROP_LIMIT));
925328874Seadler		goto out;
926328874Seadler	}
927328874Seadler	inp = CAST(cdf_property_info_t *,
928328874Seadler	    CDF_REALLOC(*info, newcount * sizeof(*inp)));
929328874Seadler	if (inp == NULL)
930328874Seadler		goto out;
931328874Seadler
932328874Seadler	*info = inp;
933328874Seadler	*maxcount = newcount;
934328874Seadler	return inp;
935328874Seadlerout:
936328874Seadler	free(*info);
937328874Seadler	*maxcount = 0;
938328874Seadler	*info = NULL;
939328874Seadler	return NULL;
940328874Seadler}
941328874Seadler
942328874Seadlerstatic int
943328874Seadlercdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e,
944328874Seadler    size_t len)
945328874Seadler{
946328874Seadler	if (inp->pi_type & CDF_VECTOR)
947328874Seadler		return 0;
948328874Seadler
949354939Sdelphij	if (CAST(size_t, CAST(const char *, e) - CAST(const char *, p)) < len)
950328874Seadler		return 0;
951328874Seadler
952328874Seadler	(void)memcpy(&inp->pi_val, p, len);
953328874Seadler
954328874Seadler	switch (len) {
955328874Seadler	case 2:
956328874Seadler		inp->pi_u16 = CDF_TOLE2(inp->pi_u16);
957328874Seadler		break;
958328874Seadler	case 4:
959328874Seadler		inp->pi_u32 = CDF_TOLE4(inp->pi_u32);
960328874Seadler		break;
961328874Seadler	case 8:
962328874Seadler		inp->pi_u64 = CDF_TOLE8(inp->pi_u64);
963328874Seadler		break;
964328874Seadler	default:
965328874Seadler		abort();
966328874Seadler	}
967328874Seadler	return 1;
968328874Seadler}
969328874Seadler
970191739Sobrienint
971226048Sobriencdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
972226048Sobrien    uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount)
973191739Sobrien{
974191739Sobrien	const cdf_section_header_t *shp;
975191739Sobrien	cdf_section_header_t sh;
976226048Sobrien	const uint8_t *p, *q, *e;
977328874Seadler	size_t i, o4, nelements, j, slen, left;
978191739Sobrien	cdf_property_info_t *inp;
979191739Sobrien
980192348Sdelphij	if (offs > UINT32_MAX / 4) {
981192348Sdelphij		errno = EFTYPE;
982192348Sdelphij		goto out;
983192348Sdelphij	}
984328874Seadler	shp = CAST(const cdf_section_header_t *,
985328874Seadler	    cdf_offset(sst->sst_tab, offs));
986226048Sobrien	if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1)
987192348Sdelphij		goto out;
988191739Sobrien	sh.sh_len = CDF_TOLE4(shp->sh_len);
989192348Sdelphij	if (sh.sh_len > CDF_SHLEN_LIMIT) {
990192348Sdelphij		errno = EFTYPE;
991192348Sdelphij		goto out;
992192348Sdelphij	}
993328874Seadler
994328874Seadler	if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1)
995328874Seadler		goto out;
996328874Seadler
997191739Sobrien	sh.sh_properties = CDF_TOLE4(shp->sh_properties);
998328874Seadler	DPRINTF(("section len: %u properties %u\n", sh.sh_len,
999328874Seadler	    sh.sh_properties));
1000192348Sdelphij	if (sh.sh_properties > CDF_PROP_LIMIT)
1001192348Sdelphij		goto out;
1002328874Seadler	inp = cdf_grow_info(info, maxcount, sh.sh_properties);
1003191739Sobrien	if (inp == NULL)
1004328874Seadler		goto out;
1005191739Sobrien	inp += *count;
1006191739Sobrien	*count += sh.sh_properties;
1007328874Seadler	p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh)));
1008328874Seadler	e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len));
1009328874Seadler	if (p >= e || cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1)
1010192348Sdelphij		goto out;
1011328874Seadler
1012191739Sobrien	for (i = 0; i < sh.sh_properties; i++) {
1013328874Seadler		if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL)
1014267843Sdelphij			goto out;
1015328874Seadler		inp[i].pi_id = CDF_GETUINT32(p, i << 1);
1016328874Seadler		left = CAST(size_t, e - q);
1017328874Seadler		if (left < sizeof(uint32_t)) {
1018328874Seadler			DPRINTF(("short info (no type)_\n"));
1019275698Sdelphij			goto out;
1020275698Sdelphij		}
1021226048Sobrien		inp[i].pi_type = CDF_GETUINT32(q, 0);
1022328874Seadler		DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n",
1023234250Sobrien		    i, inp[i].pi_id, inp[i].pi_type, q - p, offs));
1024191739Sobrien		if (inp[i].pi_type & CDF_VECTOR) {
1025328874Seadler			if (left < sizeof(uint32_t) * 2) {
1026328874Seadler				DPRINTF(("missing CDF_VECTOR length\n"));
1027328874Seadler				goto out;
1028328874Seadler			}
1029226048Sobrien			nelements = CDF_GETUINT32(q, 1);
1030354939Sdelphij			if (nelements > CDF_ELEMENT_LIMIT || nelements == 0) {
1031354939Sdelphij				DPRINTF(("CDF_VECTOR with nelements == %"
1032354939Sdelphij				    SIZE_T_FORMAT "u\n", nelements));
1033267843Sdelphij				goto out;
1034267843Sdelphij			}
1035328874Seadler			slen = 2;
1036191739Sobrien		} else {
1037191739Sobrien			nelements = 1;
1038328874Seadler			slen = 1;
1039191739Sobrien		}
1040328874Seadler		o4 = slen * sizeof(uint32_t);
1041191739Sobrien		if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
1042191739Sobrien			goto unknown;
1043191739Sobrien		switch (inp[i].pi_type & CDF_TYPEMASK) {
1044226048Sobrien		case CDF_NULL:
1045191739Sobrien		case CDF_EMPTY:
1046191739Sobrien			break;
1047191739Sobrien		case CDF_SIGNED16:
1048328874Seadler			if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t)))
1049191739Sobrien				goto unknown;
1050191739Sobrien			break;
1051191739Sobrien		case CDF_SIGNED32:
1052191739Sobrien		case CDF_BOOL:
1053191739Sobrien		case CDF_UNSIGNED32:
1054328874Seadler		case CDF_FLOAT:
1055328874Seadler			if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t)))
1056191739Sobrien				goto unknown;
1057191739Sobrien			break;
1058191739Sobrien		case CDF_SIGNED64:
1059191739Sobrien		case CDF_UNSIGNED64:
1060234250Sobrien		case CDF_DOUBLE:
1061328874Seadler		case CDF_FILETIME:
1062328874Seadler			if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t)))
1063234250Sobrien				goto unknown;
1064234250Sobrien			break;
1065191739Sobrien		case CDF_LENGTH32_STRING:
1066226048Sobrien		case CDF_LENGTH32_WSTRING:
1067191739Sobrien			if (nelements > 1) {
1068191739Sobrien				size_t nelem = inp - *info;
1069328874Seadler				inp = cdf_grow_info(info, maxcount, nelements);
1070328874Seadler				if (inp == NULL)
1071192348Sdelphij					goto out;
1072328874Seadler				inp += nelem;
1073191739Sobrien			}
1074267843Sdelphij			for (j = 0; j < nelements && i < sh.sh_properties;
1075267843Sdelphij			    j++, i++)
1076267843Sdelphij			{
1077328874Seadler				uint32_t l;
1078328874Seadler
1079328874Seadler				if (o4 + sizeof(uint32_t) > left)
1080328874Seadler					goto out;
1081328874Seadler
1082328874Seadler				l = CDF_GETUINT32(q, slen);
1083328874Seadler				o4 += sizeof(uint32_t);
1084328874Seadler				if (o4 + l > left)
1085328874Seadler					goto out;
1086328874Seadler
1087191739Sobrien				inp[i].pi_str.s_len = l;
1088328874Seadler				inp[i].pi_str.s_buf = CAST(const char *,
1089328874Seadler				    CAST(const void *, &q[o4]));
1090328874Seadler
1091354939Sdelphij				DPRINTF(("o=%" SIZE_T_FORMAT "u l=%d(%"
1092354939Sdelphij				    SIZE_T_FORMAT "u), t=%" SIZE_T_FORMAT
1093354939Sdelphij				    "u s=%s\n", o4, l, CDF_ROUND(l, sizeof(l)),
1094354939Sdelphij				    left, inp[i].pi_str.s_buf));
1095328874Seadler
1096234250Sobrien				if (l & 1)
1097234250Sobrien					l++;
1098328874Seadler
1099328874Seadler				slen += l >> 1;
1100328874Seadler				o4 = slen * sizeof(uint32_t);
1101191739Sobrien			}
1102191739Sobrien			i--;
1103191739Sobrien			break;
1104191739Sobrien		case CDF_CLIPBOARD:
1105191739Sobrien			if (inp[i].pi_type & CDF_VECTOR)
1106191739Sobrien				goto unknown;
1107191739Sobrien			break;
1108191739Sobrien		default:
1109191739Sobrien		unknown:
1110328874Seadler			memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val));
1111328874Seadler			DPRINTF(("Don't know how to deal with %#x\n",
1112191739Sobrien			    inp[i].pi_type));
1113234250Sobrien			break;
1114191739Sobrien		}
1115191739Sobrien	}
1116191739Sobrien	return 0;
1117191739Sobrienout:
1118328874Seadler	free(*info);
1119328874Seadler	*info = NULL;
1120328874Seadler	*count = 0;
1121328874Seadler	*maxcount = 0;
1122299736Sdelphij	errno = EFTYPE;
1123191739Sobrien	return -1;
1124191739Sobrien}
1125191739Sobrien
1126191739Sobrienint
1127226048Sobriencdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
1128226048Sobrien    cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count)
1129191739Sobrien{
1130267843Sdelphij	size_t maxcount;
1131226048Sobrien	const cdf_summary_info_header_t *si =
1132226048Sobrien	    CAST(const cdf_summary_info_header_t *, sst->sst_tab);
1133226048Sobrien	const cdf_section_declaration_t *sd =
1134354939Sdelphij	    CAST(const cdf_section_declaration_t *, RCAST(const void *,
1135354939Sdelphij	    RCAST(const char *, sst->sst_tab)
1136354939Sdelphij	    + CDF_SECTION_DECLARATION_OFFSET));
1137191739Sobrien
1138226048Sobrien	if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 ||
1139226048Sobrien	    cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1)
1140192348Sdelphij		return -1;
1141191739Sobrien	ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
1142191739Sobrien	ssi->si_os_version = CDF_TOLE2(si->si_os_version);
1143191739Sobrien	ssi->si_os = CDF_TOLE2(si->si_os);
1144191739Sobrien	ssi->si_class = si->si_class;
1145191739Sobrien	cdf_swap_class(&ssi->si_class);
1146267843Sdelphij	ssi->si_count = CDF_TOLE4(si->si_count);
1147191739Sobrien	*count = 0;
1148191739Sobrien	maxcount = 0;
1149191739Sobrien	*info = NULL;
1150267843Sdelphij	if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info,
1151267843Sdelphij	    count, &maxcount) == -1)
1152267843Sdelphij		return -1;
1153191739Sobrien	return 0;
1154191739Sobrien}
1155191739Sobrien
1156191739Sobrien
1157284237Sdelphij#define extract_catalog_field(t, f, l) \
1158284237Sdelphij    if (b + l + sizeof(cep->f) > eb) { \
1159284237Sdelphij	    cep->ce_namlen = 0; \
1160284237Sdelphij	    break; \
1161284237Sdelphij    } \
1162284237Sdelphij    memcpy(&cep->f, b + (l), sizeof(cep->f)); \
1163284237Sdelphij    ce[i].f = CAST(t, CDF_TOLE(cep->f))
1164191739Sobrien
1165191739Sobrienint
1166275698Sdelphijcdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
1167275698Sdelphij    cdf_catalog_t **cat)
1168275698Sdelphij{
1169299736Sdelphij	size_t ss = cdf_check_stream(sst, h);
1170275698Sdelphij	const char *b = CAST(const char *, sst->sst_tab);
1171328874Seadler	const char *nb, *eb = b + ss * sst->sst_len;
1172284237Sdelphij	size_t nr, i, j, k;
1173275698Sdelphij	cdf_catalog_entry_t *ce;
1174275698Sdelphij	uint16_t reclen;
1175275698Sdelphij	const uint16_t *np;
1176275698Sdelphij
1177284237Sdelphij	for (nr = 0;; nr++) {
1178275698Sdelphij		memcpy(&reclen, b, sizeof(reclen));
1179275698Sdelphij		reclen = CDF_TOLE2(reclen);
1180275698Sdelphij		if (reclen == 0)
1181275698Sdelphij			break;
1182275698Sdelphij		b += reclen;
1183284237Sdelphij		if (b > eb)
1184284237Sdelphij		    break;
1185275698Sdelphij	}
1186302221Sdelphij	if (nr == 0)
1187302221Sdelphij		return -1;
1188284237Sdelphij	nr--;
1189275698Sdelphij	*cat = CAST(cdf_catalog_t *,
1190328874Seadler	    CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
1191299736Sdelphij	if (*cat == NULL)
1192299736Sdelphij		return -1;
1193275698Sdelphij	ce = (*cat)->cat_e;
1194284237Sdelphij	memset(ce, 0, nr * sizeof(*ce));
1195275698Sdelphij	b = CAST(const char *, sst->sst_tab);
1196284237Sdelphij	for (j = i = 0; i < nr; b += reclen) {
1197284237Sdelphij		cdf_catalog_entry_t *cep = &ce[j];
1198284237Sdelphij		uint16_t rlen;
1199284237Sdelphij
1200284237Sdelphij		extract_catalog_field(uint16_t, ce_namlen, 0);
1201284237Sdelphij		extract_catalog_field(uint16_t, ce_num, 4);
1202284237Sdelphij		extract_catalog_field(uint64_t, ce_timestamp, 8);
1203284237Sdelphij		reclen = cep->ce_namlen;
1204284237Sdelphij
1205284237Sdelphij		if (reclen < 14) {
1206284237Sdelphij			cep->ce_namlen = 0;
1207284237Sdelphij			continue;
1208275698Sdelphij		}
1209284237Sdelphij
1210284237Sdelphij		cep->ce_namlen = __arraycount(cep->ce_name) - 1;
1211284237Sdelphij		rlen = reclen - 14;
1212284237Sdelphij		if (cep->ce_namlen > rlen)
1213284237Sdelphij			cep->ce_namlen = rlen;
1214284237Sdelphij
1215284237Sdelphij		np = CAST(const uint16_t *, CAST(const void *, (b + 16)));
1216328874Seadler		nb = CAST(const char *, CAST(const void *,
1217328874Seadler		    (np + cep->ce_namlen)));
1218328874Seadler		if (nb > eb) {
1219284237Sdelphij			cep->ce_namlen = 0;
1220284237Sdelphij			break;
1221284237Sdelphij		}
1222284237Sdelphij
1223284237Sdelphij		for (k = 0; k < cep->ce_namlen; k++)
1224284237Sdelphij			cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */
1225284237Sdelphij		cep->ce_name[cep->ce_namlen] = 0;
1226284237Sdelphij		j = i;
1227284237Sdelphij		i++;
1228275698Sdelphij	}
1229284237Sdelphij	(*cat)->cat_num = j;
1230275698Sdelphij	return 0;
1231275698Sdelphij}
1232275698Sdelphij
1233275698Sdelphijint
1234191739Sobriencdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
1235191739Sobrien{
1236191739Sobrien	return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
1237191739Sobrien	    "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
1238191739Sobrien	    id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
1239191739Sobrien	    id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
1240191739Sobrien	    id->cl_six[5]);
1241191739Sobrien}
1242191739Sobrien
1243191739Sobrienstatic const struct {
1244191739Sobrien	uint32_t v;
1245191739Sobrien	const char *n;
1246191739Sobrien} vn[] = {
1247191739Sobrien	{ CDF_PROPERTY_CODE_PAGE, "Code page" },
1248191739Sobrien	{ CDF_PROPERTY_TITLE, "Title" },
1249191739Sobrien	{ CDF_PROPERTY_SUBJECT, "Subject" },
1250191739Sobrien	{ CDF_PROPERTY_AUTHOR, "Author" },
1251191739Sobrien	{ CDF_PROPERTY_KEYWORDS, "Keywords" },
1252191739Sobrien	{ CDF_PROPERTY_COMMENTS, "Comments" },
1253191739Sobrien	{ CDF_PROPERTY_TEMPLATE, "Template" },
1254191739Sobrien	{ CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
1255191739Sobrien	{ CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
1256191739Sobrien	{ CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
1257191739Sobrien	{ CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
1258191739Sobrien	{ CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
1259191739Sobrien	{ CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
1260191739Sobrien	{ CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
1261191739Sobrien	{ CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
1262191739Sobrien	{ CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
1263191739Sobrien	{ CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
1264191739Sobrien	{ CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
1265191739Sobrien	{ CDF_PROPERTY_SECURITY, "Security" },
1266191739Sobrien	{ CDF_PROPERTY_LOCALE_ID, "Locale ID" },
1267191739Sobrien};
1268191739Sobrien
1269191739Sobrienint
1270191739Sobriencdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
1271191739Sobrien{
1272191739Sobrien	size_t i;
1273191739Sobrien
1274191739Sobrien	for (i = 0; i < __arraycount(vn); i++)
1275191739Sobrien		if (vn[i].v == p)
1276191739Sobrien			return snprintf(buf, bufsiz, "%s", vn[i].n);
1277328874Seadler	return snprintf(buf, bufsiz, "%#x", p);
1278191739Sobrien}
1279191739Sobrien
1280191739Sobrienint
1281191739Sobriencdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
1282191739Sobrien{
1283226048Sobrien	int len = 0;
1284191739Sobrien	int days, hours, mins, secs;
1285191739Sobrien
1286191739Sobrien	ts /= CDF_TIME_PREC;
1287354939Sdelphij	secs = CAST(int, ts % 60);
1288191739Sobrien	ts /= 60;
1289354939Sdelphij	mins = CAST(int, ts % 60);
1290191739Sobrien	ts /= 60;
1291354939Sdelphij	hours = CAST(int, ts % 24);
1292191739Sobrien	ts /= 24;
1293354939Sdelphij	days = CAST(int, ts);
1294191739Sobrien
1295191739Sobrien	if (days) {
1296191739Sobrien		len += snprintf(buf + len, bufsiz - len, "%dd+", days);
1297354939Sdelphij		if (CAST(size_t, len) >= bufsiz)
1298191739Sobrien			return len;
1299191739Sobrien	}
1300191739Sobrien
1301191739Sobrien	if (days || hours) {
1302191739Sobrien		len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
1303354939Sdelphij		if (CAST(size_t, len) >= bufsiz)
1304191739Sobrien			return len;
1305191739Sobrien	}
1306191739Sobrien
1307191739Sobrien	len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
1308354939Sdelphij	if (CAST(size_t, len) >= bufsiz)
1309191739Sobrien		return len;
1310191739Sobrien
1311191739Sobrien	len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
1312191739Sobrien	return len;
1313191739Sobrien}
1314191739Sobrien
1315275698Sdelphijchar *
1316275698Sdelphijcdf_u16tos8(char *buf, size_t len, const uint16_t *p)
1317275698Sdelphij{
1318275698Sdelphij	size_t i;
1319275698Sdelphij	for (i = 0; i < len && p[i]; i++)
1320354939Sdelphij		buf[i] = CAST(char, p[i]);
1321275698Sdelphij	buf[i] = '\0';
1322275698Sdelphij	return buf;
1323275698Sdelphij}
1324191739Sobrien
1325191739Sobrien#ifdef CDF_DEBUG
1326191739Sobrienvoid
1327191739Sobriencdf_dump_header(const cdf_header_t *h)
1328191739Sobrien{
1329191739Sobrien	size_t i;
1330191739Sobrien
1331192348Sdelphij#define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
1332192348Sdelphij#define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
1333192348Sdelphij    h->h_ ## b, 1 << h->h_ ## b)
1334191739Sobrien	DUMP("%d", revision);
1335191739Sobrien	DUMP("%d", version);
1336328874Seadler	DUMP("%#x", byte_order);
1337192348Sdelphij	DUMP2("%d", sec_size_p2);
1338192348Sdelphij	DUMP2("%d", short_sec_size_p2);
1339191739Sobrien	DUMP("%d", num_sectors_in_sat);
1340191739Sobrien	DUMP("%d", secid_first_directory);
1341191739Sobrien	DUMP("%d", min_size_standard_stream);
1342191739Sobrien	DUMP("%d", secid_first_sector_in_short_sat);
1343191739Sobrien	DUMP("%d", num_sectors_in_short_sat);
1344191739Sobrien	DUMP("%d", secid_first_sector_in_master_sat);
1345191739Sobrien	DUMP("%d", num_sectors_in_master_sat);
1346191739Sobrien	for (i = 0; i < __arraycount(h->h_master_sat); i++) {
1347191739Sobrien		if (h->h_master_sat[i] == CDF_SECID_FREE)
1348191739Sobrien			break;
1349275698Sdelphij		(void)fprintf(stderr, "%35.35s[%.3" SIZE_T_FORMAT "u] = %d\n",
1350191739Sobrien		    "master_sat", i, h->h_master_sat[i]);
1351191739Sobrien	}
1352191739Sobrien}
1353191739Sobrien
1354191739Sobrienvoid
1355192348Sdelphijcdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
1356191739Sobrien{
1357192348Sdelphij	size_t i, j, s = size / sizeof(cdf_secid_t);
1358191739Sobrien
1359191739Sobrien	for (i = 0; i < sat->sat_len; i++) {
1360234250Sobrien		(void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6"
1361234250Sobrien		    SIZE_T_FORMAT "u: ", prefix, i, i * s);
1362191739Sobrien		for (j = 0; j < s; j++) {
1363192348Sdelphij			(void)fprintf(stderr, "%5d, ",
1364192348Sdelphij			    CDF_TOLE4(sat->sat_tab[s * i + j]));
1365191739Sobrien			if ((j + 1) % 10 == 0)
1366234250Sobrien				(void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT
1367234250Sobrien				    "u: ", i * s + j + 1);
1368191739Sobrien		}
1369192348Sdelphij		(void)fprintf(stderr, "\n");
1370191739Sobrien	}
1371191739Sobrien}
1372191739Sobrien
1373191739Sobrienvoid
1374284237Sdelphijcdf_dump(const void *v, size_t len)
1375191739Sobrien{
1376191739Sobrien	size_t i, j;
1377284237Sdelphij	const unsigned char *p = v;
1378191739Sobrien	char abuf[16];
1379284237Sdelphij
1380192348Sdelphij	(void)fprintf(stderr, "%.4x: ", 0);
1381191739Sobrien	for (i = 0, j = 0; i < len; i++, p++) {
1382192348Sdelphij		(void)fprintf(stderr, "%.2x ", *p);
1383191739Sobrien		abuf[j++] = isprint(*p) ? *p : '.';
1384191739Sobrien		if (j == 16) {
1385191739Sobrien			j = 0;
1386191739Sobrien			abuf[15] = '\0';
1387234250Sobrien			(void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ",
1388234250Sobrien			    abuf, i + 1);
1389191739Sobrien		}
1390191739Sobrien	}
1391192348Sdelphij	(void)fprintf(stderr, "\n");
1392191739Sobrien}
1393191739Sobrien
1394191739Sobrienvoid
1395309847Sdelphijcdf_dump_stream(const cdf_stream_t *sst)
1396191739Sobrien{
1397299736Sdelphij	size_t ss = sst->sst_ss;
1398191739Sobrien	cdf_dump(sst->sst_tab, ss * sst->sst_len);
1399191739Sobrien}
1400191739Sobrien
1401191739Sobrienvoid
1402192348Sdelphijcdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
1403192348Sdelphij    const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
1404191739Sobrien    const cdf_dir_t *dir)
1405191739Sobrien{
1406191739Sobrien	size_t i, j;
1407191739Sobrien	cdf_directory_t *d;
1408191739Sobrien	char name[__arraycount(d->d_name)];
1409191739Sobrien	cdf_stream_t scn;
1410191739Sobrien	struct timespec ts;
1411191739Sobrien
1412191739Sobrien	static const char *types[] = { "empty", "user storage",
1413191739Sobrien	    "user stream", "lockbytes", "property", "root storage" };
1414191739Sobrien
1415191739Sobrien	for (i = 0; i < dir->dir_len; i++) {
1416267843Sdelphij		char buf[26];
1417191739Sobrien		d = &dir->dir_tab[i];
1418191739Sobrien		for (j = 0; j < sizeof(name); j++)
1419191739Sobrien			name[j] = (char)CDF_TOLE2(d->d_name[j]);
1420226048Sobrien		(void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n",
1421226048Sobrien		    i, name);
1422191739Sobrien		if (d->d_type < __arraycount(types))
1423192348Sdelphij			(void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
1424191739Sobrien		else
1425192348Sdelphij			(void)fprintf(stderr, "Type: %d\n", d->d_type);
1426192348Sdelphij		(void)fprintf(stderr, "Color: %s\n",
1427192348Sdelphij		    d->d_color ? "black" : "red");
1428192348Sdelphij		(void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
1429192348Sdelphij		(void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
1430328874Seadler		(void)fprintf(stderr, "Flags: %#x\n", d->d_flags);
1431191739Sobrien		cdf_timestamp_to_timespec(&ts, d->d_created);
1432267843Sdelphij		(void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf));
1433191739Sobrien		cdf_timestamp_to_timespec(&ts, d->d_modified);
1434267843Sdelphij		(void)fprintf(stderr, "Modified %s",
1435267843Sdelphij		    cdf_ctime(&ts.tv_sec, buf));
1436192348Sdelphij		(void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
1437192348Sdelphij		(void)fprintf(stderr, "Size %d\n", d->d_size);
1438191739Sobrien		switch (d->d_type) {
1439191739Sobrien		case CDF_DIR_TYPE_USER_STORAGE:
1440192348Sdelphij			(void)fprintf(stderr, "Storage: %d\n", d->d_storage);
1441191739Sobrien			break;
1442191739Sobrien		case CDF_DIR_TYPE_USER_STREAM:
1443191739Sobrien			if (sst == NULL)
1444191739Sobrien				break;
1445192348Sdelphij			if (cdf_read_sector_chain(info, h, sat, ssat, sst,
1446191739Sobrien			    d->d_stream_first_sector, d->d_size, &scn) == -1) {
1447191739Sobrien				warn("Can't read stream for %s at %d len %d",
1448191739Sobrien				    name, d->d_stream_first_sector, d->d_size);
1449191739Sobrien				break;
1450191739Sobrien			}
1451309847Sdelphij			cdf_dump_stream(&scn);
1452191739Sobrien			free(scn.sst_tab);
1453191739Sobrien			break;
1454191739Sobrien		default:
1455191739Sobrien			break;
1456191739Sobrien		}
1457226048Sobrien
1458191739Sobrien	}
1459191739Sobrien}
1460191739Sobrien
1461191739Sobrienvoid
1462191739Sobriencdf_dump_property_info(const cdf_property_info_t *info, size_t count)
1463191739Sobrien{
1464191739Sobrien	cdf_timestamp_t tp;
1465191739Sobrien	struct timespec ts;
1466191739Sobrien	char buf[64];
1467226048Sobrien	size_t i, j;
1468191739Sobrien
1469191739Sobrien	for (i = 0; i < count; i++) {
1470191739Sobrien		cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
1471226048Sobrien		(void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf);
1472191739Sobrien		switch (info[i].pi_type) {
1473226048Sobrien		case CDF_NULL:
1474226048Sobrien			break;
1475191739Sobrien		case CDF_SIGNED16:
1476192348Sdelphij			(void)fprintf(stderr, "signed 16 [%hd]\n",
1477192348Sdelphij			    info[i].pi_s16);
1478191739Sobrien			break;
1479191739Sobrien		case CDF_SIGNED32:
1480192348Sdelphij			(void)fprintf(stderr, "signed 32 [%d]\n",
1481192348Sdelphij			    info[i].pi_s32);
1482191739Sobrien			break;
1483191739Sobrien		case CDF_UNSIGNED32:
1484192348Sdelphij			(void)fprintf(stderr, "unsigned 32 [%u]\n",
1485192348Sdelphij			    info[i].pi_u32);
1486191739Sobrien			break;
1487234250Sobrien		case CDF_FLOAT:
1488234250Sobrien			(void)fprintf(stderr, "float [%g]\n",
1489234250Sobrien			    info[i].pi_f);
1490234250Sobrien			break;
1491234250Sobrien		case CDF_DOUBLE:
1492234250Sobrien			(void)fprintf(stderr, "double [%g]\n",
1493234250Sobrien			    info[i].pi_d);
1494234250Sobrien			break;
1495191739Sobrien		case CDF_LENGTH32_STRING:
1496192348Sdelphij			(void)fprintf(stderr, "string %u [%.*s]\n",
1497192348Sdelphij			    info[i].pi_str.s_len,
1498191739Sobrien			    info[i].pi_str.s_len, info[i].pi_str.s_buf);
1499191739Sobrien			break;
1500226048Sobrien		case CDF_LENGTH32_WSTRING:
1501226048Sobrien			(void)fprintf(stderr, "string %u [",
1502226048Sobrien			    info[i].pi_str.s_len);
1503226048Sobrien			for (j = 0; j < info[i].pi_str.s_len - 1; j++)
1504226048Sobrien			    (void)fputc(info[i].pi_str.s_buf[j << 1], stderr);
1505226048Sobrien			(void)fprintf(stderr, "]\n");
1506226048Sobrien			break;
1507191739Sobrien		case CDF_FILETIME:
1508191739Sobrien			tp = info[i].pi_tp;
1509191739Sobrien			if (tp < 1000000000000000LL) {
1510191739Sobrien				cdf_print_elapsed_time(buf, sizeof(buf), tp);
1511192348Sdelphij				(void)fprintf(stderr, "timestamp %s\n", buf);
1512191739Sobrien			} else {
1513284237Sdelphij				char tbuf[26];
1514191739Sobrien				cdf_timestamp_to_timespec(&ts, tp);
1515192348Sdelphij				(void)fprintf(stderr, "timestamp %s",
1516284237Sdelphij				    cdf_ctime(&ts.tv_sec, tbuf));
1517191739Sobrien			}
1518191739Sobrien			break;
1519191739Sobrien		case CDF_CLIPBOARD:
1520192348Sdelphij			(void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
1521191739Sobrien			break;
1522191739Sobrien		default:
1523328874Seadler			DPRINTF(("Don't know how to deal with %#x\n",
1524191739Sobrien			    info[i].pi_type));
1525191739Sobrien			break;
1526191739Sobrien		}
1527191739Sobrien	}
1528191739Sobrien}
1529191739Sobrien
1530191739Sobrien
1531191739Sobrienvoid
1532191739Sobriencdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
1533191739Sobrien{
1534191739Sobrien	char buf[128];
1535191739Sobrien	cdf_summary_info_header_t ssi;
1536191739Sobrien	cdf_property_info_t *info;
1537191739Sobrien	size_t count;
1538191739Sobrien
1539191739Sobrien	(void)&h;
1540226048Sobrien	if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1)
1541191739Sobrien		return;
1542328874Seadler	(void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order);
1543192348Sdelphij	(void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
1544275698Sdelphij	    ssi.si_os_version >> 8);
1545192348Sdelphij	(void)fprintf(stderr, "Os %d\n", ssi.si_os);
1546191739Sobrien	cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
1547192348Sdelphij	(void)fprintf(stderr, "Class %s\n", buf);
1548192348Sdelphij	(void)fprintf(stderr, "Count %d\n", ssi.si_count);
1549191739Sobrien	cdf_dump_property_info(info, count);
1550191739Sobrien	free(info);
1551191739Sobrien}
1552191739Sobrien
1553275698Sdelphij
1554275698Sdelphijvoid
1555275698Sdelphijcdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst)
1556275698Sdelphij{
1557275698Sdelphij	cdf_catalog_t *cat;
1558275698Sdelphij	cdf_unpack_catalog(h, sst, &cat);
1559275698Sdelphij	const cdf_catalog_entry_t *ce = cat->cat_e;
1560275698Sdelphij	struct timespec ts;
1561275698Sdelphij	char tbuf[64], sbuf[256];
1562275698Sdelphij	size_t i;
1563275698Sdelphij
1564275698Sdelphij	printf("Catalog:\n");
1565275698Sdelphij	for (i = 0; i < cat->cat_num; i++) {
1566275698Sdelphij		cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp);
1567275698Sdelphij		printf("\t%d %s %s", ce[i].ce_num,
1568275698Sdelphij		    cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name),
1569275698Sdelphij		    cdf_ctime(&ts.tv_sec, tbuf));
1570275698Sdelphij	}
1571275698Sdelphij	free(cat);
1572275698Sdelphij}
1573275698Sdelphij
1574191739Sobrien#endif
1575191739Sobrien
1576191739Sobrien#ifdef TEST
1577191739Sobrienint
1578191739Sobrienmain(int argc, char *argv[])
1579191739Sobrien{
1580192348Sdelphij	int i;
1581191739Sobrien	cdf_header_t h;
1582191739Sobrien	cdf_sat_t sat, ssat;
1583191739Sobrien	cdf_stream_t sst, scn;
1584191739Sobrien	cdf_dir_t dir;
1585192348Sdelphij	cdf_info_t info;
1586275698Sdelphij	const cdf_directory_t *root;
1587284237Sdelphij#ifdef __linux__
1588284237Sdelphij#define getprogname() __progname
1589284237Sdelphij	extern char *__progname;
1590284237Sdelphij#endif
1591191739Sobrien	if (argc < 2) {
1592191739Sobrien		(void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
1593191739Sobrien		return -1;
1594191739Sobrien	}
1595191739Sobrien
1596192348Sdelphij	info.i_buf = NULL;
1597192348Sdelphij	info.i_len = 0;
1598191739Sobrien	for (i = 1; i < argc; i++) {
1599192348Sdelphij		if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
1600337827Seadler			err(EXIT_FAILURE, "Cannot open `%s'", argv[1]);
1601191739Sobrien
1602192348Sdelphij		if (cdf_read_header(&info, &h) == -1)
1603337827Seadler			err(EXIT_FAILURE, "Cannot read header");
1604191739Sobrien#ifdef CDF_DEBUG
1605191739Sobrien		cdf_dump_header(&h);
1606191739Sobrien#endif
1607191739Sobrien
1608192348Sdelphij		if (cdf_read_sat(&info, &h, &sat) == -1)
1609337827Seadler			err(EXIT_FAILURE, "Cannot read sat");
1610191739Sobrien#ifdef CDF_DEBUG
1611192348Sdelphij		cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
1612191739Sobrien#endif
1613191739Sobrien
1614192348Sdelphij		if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
1615337827Seadler			err(EXIT_FAILURE, "Cannot read ssat");
1616191739Sobrien#ifdef CDF_DEBUG
1617226048Sobrien		cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
1618191739Sobrien#endif
1619191739Sobrien
1620192348Sdelphij		if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
1621337827Seadler			err(EXIT_FAILURE, "Cannot read dir");
1622191739Sobrien
1623275698Sdelphij		if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root)
1624275698Sdelphij		    == -1)
1625337827Seadler			err(EXIT_FAILURE, "Cannot read short stream");
1626191739Sobrien#ifdef CDF_DEBUG
1627309847Sdelphij		cdf_dump_stream(&sst);
1628191739Sobrien#endif
1629191739Sobrien
1630191739Sobrien#ifdef CDF_DEBUG
1631192348Sdelphij		cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
1632191739Sobrien#endif
1633191739Sobrien
1634191739Sobrien
1635192348Sdelphij		if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
1636191739Sobrien		    &scn) == -1)
1637275698Sdelphij			warn("Cannot read summary info");
1638191739Sobrien#ifdef CDF_DEBUG
1639275698Sdelphij		else
1640275698Sdelphij			cdf_dump_summary_info(&h, &scn);
1641191739Sobrien#endif
1642284237Sdelphij		if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst,
1643284237Sdelphij		    &dir, "Catalog", &scn) == -1)
1644275698Sdelphij			warn("Cannot read catalog");
1645275698Sdelphij#ifdef CDF_DEBUG
1646275698Sdelphij		else
1647275698Sdelphij			cdf_dump_catalog(&h, &scn);
1648275698Sdelphij#endif
1649191739Sobrien
1650192348Sdelphij		(void)close(info.i_fd);
1651191739Sobrien	}
1652191739Sobrien
1653191739Sobrien	return 0;
1654191739Sobrien}
1655191739Sobrien#endif
1656