Line | Count | Source (jump to first uncovered line) |
1 | | /*- |
2 | | * Copyright (c) 2008 Christos Zoulas |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
15 | | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
16 | | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
18 | | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
24 | | * POSSIBILITY OF SUCH DAMAGE. |
25 | | */ |
26 | | /* |
27 | | * Parse Composite Document Files, the format used in Microsoft Office |
28 | | * document files before they switched to zipped XML. |
29 | | * Info from: http://sc.openoffice.org/compdocfileformat.pdf |
30 | | * |
31 | | * N.B. This is the "Composite Document File" format, and not the |
32 | | * "Compound Document Format", nor the "Channel Definition Format". |
33 | | */ |
34 | | |
35 | | #include "file.h" |
36 | | |
37 | | #ifndef lint |
38 | | FILE_RCSID("@(#)$File: cdf.c,v 1.121 2021/10/20 13:56:15 christos Exp $") |
39 | | #endif |
40 | | |
41 | | #include <assert.h> |
42 | | #ifdef CDF_DEBUG |
43 | | #include <err.h> |
44 | | #endif |
45 | | #include <stdlib.h> |
46 | | #include <unistd.h> |
47 | | #include <string.h> |
48 | | #include <time.h> |
49 | | #include <ctype.h> |
50 | | #include <limits.h> |
51 | | #ifdef HAVE_BYTESWAP_H |
52 | | #include <byteswap.h> |
53 | | #endif |
54 | | #ifdef HAVE_SYS_BSWAP_H |
55 | | #include <sys/bswap.h> |
56 | | #endif |
57 | | |
58 | | #ifndef EFTYPE |
59 | 2.83k | #define EFTYPE EINVAL |
60 | | #endif |
61 | | |
62 | | #ifndef SIZE_T_MAX |
63 | 7.09M | #define SIZE_T_MAX CAST(size_t, ~0ULL) |
64 | | #endif |
65 | | |
66 | | #include "cdf.h" |
67 | | |
68 | | #ifdef CDF_DEBUG |
69 | | #define DPRINTF(a) printf a, fflush(stdout) |
70 | | #else |
71 | | #define DPRINTF(a) |
72 | | #endif |
73 | | |
74 | | static union { |
75 | | char s[4]; |
76 | | uint32_t u; |
77 | | } cdf_bo; |
78 | | |
79 | 1.51k | #define NEED_SWAP (cdf_bo.u == CAST(uint32_t, 0x01020304)) |
80 | | |
81 | | #define CDF_TOLE8(x) \ |
82 | 9.67k | (CAST(uint64_t, NEED_SWAP ? _cdf_tole8(x) : CAST(uint64_t, x))) |
83 | | #define CDF_TOLE4(x) \ |
84 | 9.56M | (CAST(uint32_t, NEED_SWAP ? _cdf_tole4(x) : CAST(uint32_t, x))) |
85 | | #define CDF_TOLE2(x) \ |
86 | 95.5k | (CAST(uint16_t, NEED_SWAP ? _cdf_tole2(x) : CAST(uint16_t, x))) |
87 | | #define CDF_TOLE(x) (/*CONSTCOND*/sizeof(x) == 2 ? \ |
88 | | CDF_TOLE2(CAST(uint16_t, x)) : \ |
89 | | (/*CONSTCOND*/sizeof(x) == 4 ? \ |
90 | | CDF_TOLE4(CAST(uint32_t, x)) : \ |
91 | | CDF_TOLE8(CAST(uint64_t, x)))) |
92 | 1.89M | #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) |
93 | | |
94 | | #define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) |
95 | | #define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) |
96 | 1.54k | #define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) |
97 | | |
98 | | |
99 | | /*ARGSUSED*/ |
100 | | static void * |
101 | | cdf_malloc(const char *file __attribute__((__unused__)), |
102 | | size_t line __attribute__((__unused__)), size_t n) |
103 | 1.54k | { |
104 | 1.54k | DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", |
105 | 1.54k | file, line, __func__, n)); |
106 | 1.54k | if (n == 0) |
107 | 0 | n++; |
108 | 1.54k | return malloc(n); |
109 | 1.54k | } |
110 | | |
111 | | /*ARGSUSED*/ |
112 | | static void * |
113 | | cdf_realloc(const char *file __attribute__((__unused__)), |
114 | | size_t line __attribute__((__unused__)), void *p, size_t n) |
115 | 1.08k | { |
116 | 1.08k | DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", |
117 | 1.08k | file, line, __func__, n)); |
118 | 1.08k | return realloc(p, n); |
119 | 1.08k | } |
120 | | |
121 | | /*ARGSUSED*/ |
122 | | static void * |
123 | | cdf_calloc(const char *file __attribute__((__unused__)), |
124 | | size_t line __attribute__((__unused__)), size_t n, size_t u) |
125 | 8.72k | { |
126 | 8.72k | DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %" |
127 | 8.72k | SIZE_T_FORMAT "u\n", file, line, __func__, n, u)); |
128 | 8.72k | if (n == 0) |
129 | 146 | n++; |
130 | 8.72k | return calloc(n, u); |
131 | 8.72k | } |
132 | | |
133 | | #if defined(HAVE_BYTESWAP_H) |
134 | | # define _cdf_tole2(x) bswap_16(x) |
135 | | # define _cdf_tole4(x) bswap_32(x) |
136 | | # define _cdf_tole8(x) bswap_64(x) |
137 | | #elif defined(HAVE_SYS_BSWAP_H) |
138 | | # define _cdf_tole2(x) bswap16(x) |
139 | | # define _cdf_tole4(x) bswap32(x) |
140 | | # define _cdf_tole8(x) bswap64(x) |
141 | | #else |
142 | | /* |
143 | | * swap a short |
144 | | */ |
145 | | static uint16_t |
146 | | _cdf_tole2(uint16_t sv) |
147 | | { |
148 | | uint16_t rv; |
149 | | uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); |
150 | | uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); |
151 | | d[0] = s[1]; |
152 | | d[1] = s[0]; |
153 | | return rv; |
154 | | } |
155 | | |
156 | | /* |
157 | | * swap an int |
158 | | */ |
159 | | static uint32_t |
160 | | _cdf_tole4(uint32_t sv) |
161 | | { |
162 | | uint32_t rv; |
163 | | uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); |
164 | | uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); |
165 | | d[0] = s[3]; |
166 | | d[1] = s[2]; |
167 | | d[2] = s[1]; |
168 | | d[3] = s[0]; |
169 | | return rv; |
170 | | } |
171 | | |
172 | | /* |
173 | | * swap a quad |
174 | | */ |
175 | | static uint64_t |
176 | | _cdf_tole8(uint64_t sv) |
177 | | { |
178 | | uint64_t rv; |
179 | | uint8_t *s = RCAST(uint8_t *, RCAST(void *, &sv)); |
180 | | uint8_t *d = RCAST(uint8_t *, RCAST(void *, &rv)); |
181 | | d[0] = s[7]; |
182 | | d[1] = s[6]; |
183 | | d[2] = s[5]; |
184 | | d[3] = s[4]; |
185 | | d[4] = s[3]; |
186 | | d[5] = s[2]; |
187 | | d[6] = s[1]; |
188 | | d[7] = s[0]; |
189 | | return rv; |
190 | | } |
191 | | #endif |
192 | | |
193 | | /* |
194 | | * grab a uint32_t from a possibly unaligned address, and return it in |
195 | | * the native host order. |
196 | | */ |
197 | | static uint32_t |
198 | | cdf_getuint32(const uint8_t *p, size_t offs) |
199 | 1.89M | { |
200 | 1.89M | uint32_t rv; |
201 | 1.89M | (void)memcpy(&rv, p + offs * sizeof(uint32_t), sizeof(rv)); |
202 | 1.89M | return CDF_TOLE4(rv); |
203 | 1.89M | } |
204 | | |
205 | | #define CDF_UNPACK(a) \ |
206 | 1.01M | (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a) |
207 | | #define CDF_UNPACKA(a) \ |
208 | 119k | (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a) |
209 | | |
210 | | uint16_t |
211 | | cdf_tole2(uint16_t sv) |
212 | 0 | { |
213 | 0 | return CDF_TOLE2(sv); |
214 | 0 | } |
215 | | |
216 | | uint32_t |
217 | | cdf_tole4(uint32_t sv) |
218 | 0 | { |
219 | 0 | return CDF_TOLE4(sv); |
220 | 0 | } |
221 | | |
222 | | uint64_t |
223 | | cdf_tole8(uint64_t sv) |
224 | 0 | { |
225 | 0 | return CDF_TOLE8(sv); |
226 | 0 | } |
227 | | |
228 | | void |
229 | | cdf_swap_header(cdf_header_t *h) |
230 | 2.89k | { |
231 | 2.89k | size_t i; |
232 | | |
233 | 2.89k | h->h_magic = CDF_TOLE8(h->h_magic); |
234 | 2.89k | h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]); |
235 | 2.89k | h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]); |
236 | 2.89k | h->h_revision = CDF_TOLE2(h->h_revision); |
237 | 2.89k | h->h_version = CDF_TOLE2(h->h_version); |
238 | 2.89k | h->h_byte_order = CDF_TOLE2(h->h_byte_order); |
239 | 2.89k | h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2); |
240 | 2.89k | h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2); |
241 | 2.89k | h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat); |
242 | 2.89k | h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory); |
243 | 2.89k | h->h_min_size_standard_stream = |
244 | 2.89k | CDF_TOLE4(h->h_min_size_standard_stream); |
245 | 2.89k | h->h_secid_first_sector_in_short_sat = |
246 | 2.89k | CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_short_sat)); |
247 | 2.89k | h->h_num_sectors_in_short_sat = |
248 | 2.89k | CDF_TOLE4(h->h_num_sectors_in_short_sat); |
249 | 2.89k | h->h_secid_first_sector_in_master_sat = |
250 | 2.89k | CDF_TOLE4(CAST(uint32_t, h->h_secid_first_sector_in_master_sat)); |
251 | 2.89k | h->h_num_sectors_in_master_sat = |
252 | 2.89k | CDF_TOLE4(h->h_num_sectors_in_master_sat); |
253 | 318k | for (i = 0; i < __arraycount(h->h_master_sat); i++) { |
254 | 315k | h->h_master_sat[i] = |
255 | 315k | CDF_TOLE4(CAST(uint32_t, h->h_master_sat[i])); |
256 | 315k | } |
257 | 2.89k | } |
258 | | |
259 | | void |
260 | | cdf_unpack_header(cdf_header_t *h, char *buf) |
261 | 2.89k | { |
262 | 2.89k | size_t i; |
263 | 2.89k | size_t len = 0; |
264 | | |
265 | 2.89k | CDF_UNPACK(h->h_magic); |
266 | 2.89k | CDF_UNPACKA(h->h_uuid); |
267 | 2.89k | CDF_UNPACK(h->h_revision); |
268 | 2.89k | CDF_UNPACK(h->h_version); |
269 | 2.89k | CDF_UNPACK(h->h_byte_order); |
270 | 2.89k | CDF_UNPACK(h->h_sec_size_p2); |
271 | 2.89k | CDF_UNPACK(h->h_short_sec_size_p2); |
272 | 2.89k | CDF_UNPACKA(h->h_unused0); |
273 | 2.89k | CDF_UNPACK(h->h_num_sectors_in_sat); |
274 | 2.89k | CDF_UNPACK(h->h_secid_first_directory); |
275 | 2.89k | CDF_UNPACKA(h->h_unused1); |
276 | 2.89k | CDF_UNPACK(h->h_min_size_standard_stream); |
277 | 2.89k | CDF_UNPACK(h->h_secid_first_sector_in_short_sat); |
278 | 2.89k | CDF_UNPACK(h->h_num_sectors_in_short_sat); |
279 | 2.89k | CDF_UNPACK(h->h_secid_first_sector_in_master_sat); |
280 | 2.89k | CDF_UNPACK(h->h_num_sectors_in_master_sat); |
281 | 318k | for (i = 0; i < __arraycount(h->h_master_sat); i++) |
282 | 315k | CDF_UNPACK(h->h_master_sat[i]); |
283 | 2.89k | } |
284 | | |
285 | | void |
286 | | cdf_swap_dir(cdf_directory_t *d) |
287 | 0 | { |
288 | 0 | d->d_namelen = CDF_TOLE2(d->d_namelen); |
289 | 0 | d->d_left_child = CDF_TOLE4(CAST(uint32_t, d->d_left_child)); |
290 | 0 | d->d_right_child = CDF_TOLE4(CAST(uint32_t, d->d_right_child)); |
291 | 0 | d->d_storage = CDF_TOLE4(CAST(uint32_t, d->d_storage)); |
292 | 0 | d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]); |
293 | 0 | d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]); |
294 | 0 | d->d_flags = CDF_TOLE4(d->d_flags); |
295 | 0 | d->d_created = CDF_TOLE8(CAST(uint64_t, d->d_created)); |
296 | 0 | d->d_modified = CDF_TOLE8(CAST(uint64_t, d->d_modified)); |
297 | 0 | d->d_stream_first_sector = CDF_TOLE4( |
298 | 0 | CAST(uint32_t, d->d_stream_first_sector)); |
299 | 0 | d->d_size = CDF_TOLE4(d->d_size); |
300 | 0 | } |
301 | | |
302 | | void |
303 | | cdf_swap_class(cdf_classid_t *d) |
304 | 1.14k | { |
305 | 1.14k | d->cl_dword = CDF_TOLE4(d->cl_dword); |
306 | 1.14k | d->cl_word[0] = CDF_TOLE2(d->cl_word[0]); |
307 | 1.14k | d->cl_word[1] = CDF_TOLE2(d->cl_word[1]); |
308 | 1.14k | } |
309 | | |
310 | | void |
311 | | cdf_unpack_dir(cdf_directory_t *d, char *buf) |
312 | 55.1k | { |
313 | 55.1k | size_t len = 0; |
314 | | |
315 | 55.1k | CDF_UNPACKA(d->d_name); |
316 | 55.1k | CDF_UNPACK(d->d_namelen); |
317 | 55.1k | CDF_UNPACK(d->d_type); |
318 | 55.1k | CDF_UNPACK(d->d_color); |
319 | 55.1k | CDF_UNPACK(d->d_left_child); |
320 | 55.1k | CDF_UNPACK(d->d_right_child); |
321 | 55.1k | CDF_UNPACK(d->d_storage); |
322 | 55.1k | CDF_UNPACKA(d->d_storage_uuid); |
323 | 55.1k | CDF_UNPACK(d->d_flags); |
324 | 55.1k | CDF_UNPACK(d->d_created); |
325 | 55.1k | CDF_UNPACK(d->d_modified); |
326 | 55.1k | CDF_UNPACK(d->d_stream_first_sector); |
327 | 55.1k | CDF_UNPACK(d->d_size); |
328 | 55.1k | CDF_UNPACK(d->d_unused0); |
329 | 55.1k | } |
330 | | |
331 | | int |
332 | | cdf_zero_stream(cdf_stream_t *scn) |
333 | 5.49k | { |
334 | 5.49k | scn->sst_len = 0; |
335 | 5.49k | scn->sst_dirlen = 0; |
336 | 5.49k | scn->sst_ss = 0; |
337 | 5.49k | free(scn->sst_tab); |
338 | 5.49k | scn->sst_tab = NULL; |
339 | 5.49k | return -1; |
340 | 5.49k | } |
341 | | |
342 | | static size_t |
343 | | cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) |
344 | 10.3k | { |
345 | 10.3k | size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? |
346 | 10.3k | CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); |
347 | 10.3k | assert(ss == sst->sst_ss); |
348 | 10.3k | return sst->sst_ss; |
349 | 10.3k | } |
350 | | |
351 | | static int |
352 | | cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h, |
353 | | const void *p, size_t tail, int line) |
354 | 10.3k | { |
355 | 10.3k | const char *b = RCAST(const char *, sst->sst_tab); |
356 | 10.3k | const char *e = RCAST(const char *, p) + tail; |
357 | 10.3k | size_t ss = cdf_check_stream(sst, h); |
358 | 10.3k | /*LINTED*/(void)&line; |
359 | 10.3k | if (e >= b && CAST(size_t, e - b) <= ss * sst->sst_len) |
360 | 10.1k | return 0; |
361 | 186 | DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u" |
362 | 186 | " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %" |
363 | 186 | SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b), |
364 | 186 | ss * sst->sst_len, ss, sst->sst_len)); |
365 | 186 | errno = EFTYPE; |
366 | 186 | return -1; |
367 | 10.3k | } |
368 | | |
369 | | static ssize_t |
370 | | cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) |
371 | 7.09M | { |
372 | 7.09M | size_t siz = CAST(size_t, off + len); |
373 | | |
374 | 7.09M | if (CAST(off_t, off + len) != CAST(off_t, siz)) |
375 | 0 | goto out; |
376 | | |
377 | 7.09M | if (info->i_buf != NULL && info->i_len >= siz) { |
378 | 7.09M | (void)memcpy(buf, &info->i_buf[off], len); |
379 | 7.09M | return CAST(ssize_t, len); |
380 | 7.09M | } |
381 | | |
382 | 5.50k | if (info->i_fd == -1) |
383 | 5.50k | goto out; |
384 | | |
385 | 0 | if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len)) |
386 | 0 | return -1; |
387 | | |
388 | 0 | return CAST(ssize_t, len); |
389 | 5.50k | out: |
390 | 5.50k | errno = EINVAL; |
391 | 5.50k | return -1; |
392 | 0 | } |
393 | | |
394 | | int |
395 | | cdf_read_header(const cdf_info_t *info, cdf_header_t *h) |
396 | 8.09k | { |
397 | 8.09k | char buf[512]; |
398 | | |
399 | 8.09k | (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); |
400 | 8.09k | if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1) |
401 | 5.20k | return -1; |
402 | 2.89k | cdf_unpack_header(h, buf); |
403 | 2.89k | cdf_swap_header(h); |
404 | 2.89k | if (h->h_magic != CDF_MAGIC) { |
405 | 853 | DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#" |
406 | 853 | INT64_T_FORMAT "x\n", |
407 | 853 | (unsigned long long)h->h_magic, |
408 | 853 | (unsigned long long)CDF_MAGIC)); |
409 | 853 | goto out; |
410 | 853 | } |
411 | 2.04k | if (h->h_sec_size_p2 > 20) { |
412 | 11 | DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2)); |
413 | 11 | goto out; |
414 | 11 | } |
415 | 2.03k | if (h->h_short_sec_size_p2 > 20) { |
416 | 7 | DPRINTF(("Bad short sector size %hu\n", |
417 | 7 | h->h_short_sec_size_p2)); |
418 | 7 | goto out; |
419 | 7 | } |
420 | 2.02k | return 0; |
421 | 871 | out: |
422 | 871 | errno = EFTYPE; |
423 | 871 | return -1; |
424 | 2.03k | } |
425 | | |
426 | | |
427 | | ssize_t |
428 | | cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len, |
429 | | const cdf_header_t *h, cdf_secid_t id) |
430 | 7.09M | { |
431 | 7.09M | size_t ss = CDF_SEC_SIZE(h); |
432 | 7.09M | size_t pos; |
433 | | |
434 | 7.09M | if (SIZE_T_MAX / ss < CAST(size_t, id)) |
435 | 0 | return -1; |
436 | | |
437 | 7.09M | pos = CDF_SEC_POS(h, id); |
438 | 7.09M | assert(ss == len); |
439 | 7.09M | return cdf_read(info, CAST(off_t, pos), RCAST(char *, buf) + offs, len); |
440 | 7.09M | } |
441 | | |
442 | | ssize_t |
443 | | cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, |
444 | | size_t len, const cdf_header_t *h, cdf_secid_t id) |
445 | 734 | { |
446 | 734 | size_t ss = CDF_SHORT_SEC_SIZE(h); |
447 | 734 | size_t pos; |
448 | | |
449 | 734 | if (SIZE_T_MAX / ss < CAST(size_t, id)) |
450 | 0 | return -1; |
451 | | |
452 | 734 | pos = CDF_SHORT_SEC_POS(h, id); |
453 | 734 | assert(ss == len); |
454 | 734 | if (pos + len > CDF_SEC_SIZE(h) * sst->sst_len) { |
455 | 39 | DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %" |
456 | 39 | SIZE_T_FORMAT "u\n", |
457 | 39 | pos + len, CDF_SEC_SIZE(h) * sst->sst_len)); |
458 | 39 | goto out; |
459 | 39 | } |
460 | 695 | (void)memcpy(RCAST(char *, buf) + offs, |
461 | 695 | RCAST(const char *, sst->sst_tab) + pos, len); |
462 | 695 | return len; |
463 | 39 | out: |
464 | 39 | errno = EFTYPE; |
465 | 39 | return -1; |
466 | 734 | } |
467 | | |
468 | | /* |
469 | | * Read the sector allocation table. |
470 | | */ |
471 | | int |
472 | | cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) |
473 | 2.02k | { |
474 | 2.02k | size_t i, j, k; |
475 | 2.02k | size_t ss = CDF_SEC_SIZE(h); |
476 | 2.02k | cdf_secid_t *msa, mid, sec; |
477 | 2.02k | size_t nsatpersec = (ss / sizeof(mid)) - 1; |
478 | | |
479 | 104k | for (i = 0; i < __arraycount(h->h_master_sat); i++) |
480 | 103k | if (h->h_master_sat[i] == CDF_SECID_FREE) |
481 | 1.47k | break; |
482 | | |
483 | 3.93k | #define CDF_SEC_LIMIT (UINT32_MAX / (64 * ss)) |
484 | 2.02k | if ((nsatpersec > 0 && |
485 | 2.02k | h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) || |
486 | 2.02k | i > CDF_SEC_LIMIT) { |
487 | 19 | DPRINTF(("Number of sectors in master SAT too big %u %" |
488 | 19 | SIZE_T_FORMAT "u\n", h->h_num_sectors_in_master_sat, i)); |
489 | 19 | errno = EFTYPE; |
490 | 19 | return -1; |
491 | 19 | } |
492 | | |
493 | 2.00k | sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i; |
494 | 2.00k | DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n", |
495 | 2.00k | sat->sat_len, ss)); |
496 | 2.00k | if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss))) |
497 | 2.00k | == NULL) |
498 | 0 | return -1; |
499 | | |
500 | 8.98k | for (i = 0; i < __arraycount(h->h_master_sat); i++) { |
501 | 8.98k | if (h->h_master_sat[i] < 0) |
502 | 1.94k | break; |
503 | 7.03k | if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h, |
504 | 7.03k | h->h_master_sat[i]) != CAST(ssize_t, ss)) { |
505 | 58 | DPRINTF(("Reading sector %d", h->h_master_sat[i])); |
506 | 58 | goto out1; |
507 | 58 | } |
508 | 7.03k | } |
509 | | |
510 | 1.94k | if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL) |
511 | 0 | goto out1; |
512 | | |
513 | 1.94k | mid = h->h_secid_first_sector_in_master_sat; |
514 | 246k | for (j = 0; j < h->h_num_sectors_in_master_sat; j++) { |
515 | 245k | if (mid < 0) |
516 | 743 | goto out; |
517 | 244k | if (j >= CDF_LOOP_LIMIT) { |
518 | 2 | DPRINTF(("Reading master sector loop limit")); |
519 | 2 | goto out3; |
520 | 2 | } |
521 | 244k | if (cdf_read_sector(info, msa, 0, ss, h, mid) != |
522 | 244k | CAST(ssize_t, ss)) { |
523 | 65 | DPRINTF(("Reading master sector %d", mid)); |
524 | 65 | goto out2; |
525 | 65 | } |
526 | 7.06M | for (k = 0; k < nsatpersec; k++, i++) { |
527 | 6.82M | sec = CDF_TOLE4(CAST(uint32_t, msa[k])); |
528 | 6.82M | if (sec < 0) |
529 | 152 | goto out; |
530 | 6.82M | if (i >= sat->sat_len) { |
531 | 0 | DPRINTF(("Out of bounds reading MSA %" |
532 | 0 | SIZE_T_FORMAT "u >= %" SIZE_T_FORMAT "u", |
533 | 0 | i, sat->sat_len)); |
534 | 0 | goto out3; |
535 | 0 | } |
536 | 6.82M | if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h, |
537 | 6.82M | sec) != CAST(ssize_t, ss)) { |
538 | 56 | DPRINTF(("Reading sector %d", |
539 | 56 | CDF_TOLE4(msa[k]))); |
540 | 56 | goto out2; |
541 | 56 | } |
542 | 6.82M | } |
543 | 244k | mid = CDF_TOLE4(CAST(uint32_t, msa[nsatpersec])); |
544 | 244k | } |
545 | 1.82k | out: |
546 | 1.82k | sat->sat_len = i; |
547 | 1.82k | free(msa); |
548 | 1.82k | return 0; |
549 | 2 | out3: |
550 | 2 | errno = EFTYPE; |
551 | 123 | out2: |
552 | 123 | free(msa); |
553 | 181 | out1: |
554 | 181 | free(sat->sat_tab); |
555 | 181 | return -1; |
556 | 123 | } |
557 | | |
558 | | size_t |
559 | | cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size) |
560 | 5.30k | { |
561 | 5.30k | size_t i, j; |
562 | 5.30k | cdf_secid_t maxsector = CAST(cdf_secid_t, (sat->sat_len * size) |
563 | 5.30k | / sizeof(maxsector)); |
564 | | |
565 | 5.30k | DPRINTF(("Chain:")); |
566 | 5.30k | if (sid == CDF_SECID_END_OF_CHAIN) { |
567 | | /* 0-length chain. */ |
568 | 113 | DPRINTF((" empty\n")); |
569 | 113 | return 0; |
570 | 113 | } |
571 | | |
572 | 250k | for (j = i = 0; sid >= 0; i++, j++) { |
573 | 245k | DPRINTF((" %d", sid)); |
574 | 245k | if (j >= CDF_LOOP_LIMIT) { |
575 | 23 | DPRINTF(("Counting chain loop limit")); |
576 | 23 | goto out; |
577 | 23 | } |
578 | 245k | if (sid >= maxsector) { |
579 | 309 | DPRINTF(("Sector %d >= %d\n", sid, maxsector)); |
580 | 309 | goto out; |
581 | 309 | } |
582 | 245k | sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); |
583 | 245k | } |
584 | 4.85k | if (i == 0) { |
585 | 182 | DPRINTF((" none, sid: %d\n", sid)); |
586 | 182 | goto out; |
587 | | |
588 | 182 | } |
589 | 4.67k | DPRINTF(("\n")); |
590 | 4.67k | return i; |
591 | 514 | out: |
592 | 514 | errno = EFTYPE; |
593 | 514 | return CAST(size_t, -1); |
594 | 4.85k | } |
595 | | |
596 | | int |
597 | | cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h, |
598 | | const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn) |
599 | 1.59k | { |
600 | 1.59k | size_t ss = CDF_SEC_SIZE(h), i, j; |
601 | 1.59k | ssize_t nr; |
602 | 1.59k | scn->sst_tab = NULL; |
603 | 1.59k | scn->sst_len = cdf_count_chain(sat, sid, ss); |
604 | 1.59k | scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len); |
605 | 1.59k | scn->sst_ss = ss; |
606 | | |
607 | 1.59k | if (sid == CDF_SECID_END_OF_CHAIN || len == 0) |
608 | 30 | return cdf_zero_stream(scn); |
609 | | |
610 | 1.56k | if (scn->sst_len == CAST(size_t, -1)) |
611 | 141 | goto out; |
612 | | |
613 | 1.42k | scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); |
614 | 1.42k | if (scn->sst_tab == NULL) |
615 | 0 | return cdf_zero_stream(scn); |
616 | | |
617 | 6.03k | for (j = i = 0; sid >= 0; i++, j++) { |
618 | 4.67k | if (j >= CDF_LOOP_LIMIT) { |
619 | 0 | DPRINTF(("Read long sector chain loop limit")); |
620 | 0 | goto out; |
621 | 0 | } |
622 | 4.67k | if (i >= scn->sst_len) { |
623 | 0 | DPRINTF(("Out of bounds reading long sector chain " |
624 | 0 | "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, |
625 | 0 | scn->sst_len)); |
626 | 0 | goto out; |
627 | 0 | } |
628 | 4.67k | if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h, |
629 | 4.67k | sid)) != CAST(ssize_t, ss)) { |
630 | 64 | if (i == scn->sst_len - 1 && nr > 0) { |
631 | | /* Last sector might be truncated */ |
632 | 0 | return 0; |
633 | 0 | } |
634 | 64 | DPRINTF(("Reading long sector chain %d", sid)); |
635 | 64 | goto out; |
636 | 64 | } |
637 | 4.60k | sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); |
638 | 4.60k | } |
639 | 1.35k | return 0; |
640 | 205 | out: |
641 | 205 | errno = EFTYPE; |
642 | 205 | return cdf_zero_stream(scn); |
643 | 1.42k | } |
644 | | |
645 | | int |
646 | | cdf_read_short_sector_chain(const cdf_header_t *h, |
647 | | const cdf_sat_t *ssat, const cdf_stream_t *sst, |
648 | | cdf_secid_t sid, size_t len, cdf_stream_t *scn) |
649 | 234 | { |
650 | 234 | size_t ss = CDF_SHORT_SEC_SIZE(h), i, j; |
651 | 234 | scn->sst_tab = NULL; |
652 | 234 | scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h)); |
653 | 234 | scn->sst_dirlen = len; |
654 | 234 | scn->sst_ss = ss; |
655 | | |
656 | 234 | if (scn->sst_len == CAST(size_t, -1)) |
657 | 112 | goto out; |
658 | | |
659 | 122 | scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); |
660 | 122 | if (scn->sst_tab == NULL) |
661 | 0 | return cdf_zero_stream(scn); |
662 | | |
663 | 817 | for (j = i = 0; sid >= 0; i++, j++) { |
664 | 734 | if (j >= CDF_LOOP_LIMIT) { |
665 | 0 | DPRINTF(("Read short sector chain loop limit")); |
666 | 0 | goto out; |
667 | 0 | } |
668 | 734 | if (i >= scn->sst_len) { |
669 | 0 | DPRINTF(("Out of bounds reading short sector chain " |
670 | 0 | "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", |
671 | 0 | i, scn->sst_len)); |
672 | 0 | goto out; |
673 | 0 | } |
674 | 734 | if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h, |
675 | 734 | sid) != CAST(ssize_t, ss)) { |
676 | 39 | DPRINTF(("Reading short sector chain %d", sid)); |
677 | 39 | goto out; |
678 | 39 | } |
679 | 695 | sid = CDF_TOLE4(CAST(uint32_t, ssat->sat_tab[sid])); |
680 | 695 | } |
681 | 83 | return 0; |
682 | 151 | out: |
683 | 151 | errno = EFTYPE; |
684 | 151 | return cdf_zero_stream(scn); |
685 | 122 | } |
686 | | |
687 | | int |
688 | | cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h, |
689 | | const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, |
690 | | cdf_secid_t sid, size_t len, cdf_stream_t *scn) |
691 | 1.50k | { |
692 | | |
693 | 1.50k | if (len < h->h_min_size_standard_stream && sst->sst_tab != NULL) |
694 | 234 | return cdf_read_short_sector_chain(h, ssat, sst, sid, len, |
695 | 234 | scn); |
696 | 1.27k | else |
697 | 1.27k | return cdf_read_long_sector_chain(info, h, sat, sid, len, scn); |
698 | 1.50k | } |
699 | | |
700 | | int |
701 | | cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h, |
702 | | const cdf_sat_t *sat, cdf_dir_t *dir) |
703 | 1.64k | { |
704 | 1.64k | size_t i, j; |
705 | 1.64k | size_t ss = CDF_SEC_SIZE(h), ns, nd; |
706 | 1.64k | char *buf; |
707 | 1.64k | cdf_secid_t sid = h->h_secid_first_directory; |
708 | | |
709 | 1.64k | ns = cdf_count_chain(sat, sid, ss); |
710 | 1.64k | if (ns == CAST(size_t, -1)) |
711 | 98 | return -1; |
712 | | |
713 | 1.54k | nd = ss / CDF_DIRECTORY_SIZE; |
714 | | |
715 | 1.54k | dir->dir_len = ns * nd; |
716 | 1.54k | dir->dir_tab = CAST(cdf_directory_t *, |
717 | 1.54k | CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0]))); |
718 | 1.54k | if (dir->dir_tab == NULL) |
719 | 0 | return -1; |
720 | | |
721 | 1.54k | if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { |
722 | 0 | free(dir->dir_tab); |
723 | 0 | return -1; |
724 | 0 | } |
725 | | |
726 | 6.90k | for (j = i = 0; i < ns; i++, j++) { |
727 | 5.38k | if (j >= CDF_LOOP_LIMIT) { |
728 | 0 | DPRINTF(("Read dir loop limit")); |
729 | 0 | goto out; |
730 | 0 | } |
731 | 5.38k | if (cdf_read_sector(info, buf, 0, ss, h, sid) != |
732 | 5.38k | CAST(ssize_t, ss)) { |
733 | 34 | DPRINTF(("Reading directory sector %d", sid)); |
734 | 34 | goto out; |
735 | 34 | } |
736 | 60.5k | for (j = 0; j < nd; j++) { |
737 | 55.1k | cdf_unpack_dir(&dir->dir_tab[i * nd + j], |
738 | 55.1k | &buf[j * CDF_DIRECTORY_SIZE]); |
739 | 55.1k | } |
740 | 5.35k | sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); |
741 | 5.35k | } |
742 | 1.51k | if (NEED_SWAP) |
743 | 0 | for (i = 0; i < dir->dir_len; i++) |
744 | 0 | cdf_swap_dir(&dir->dir_tab[i]); |
745 | 1.51k | free(buf); |
746 | 1.51k | return 0; |
747 | 34 | out: |
748 | 34 | free(dir->dir_tab); |
749 | 34 | free(buf); |
750 | 34 | errno = EFTYPE; |
751 | 34 | return -1; |
752 | 1.54k | } |
753 | | |
754 | | |
755 | | int |
756 | | cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h, |
757 | | const cdf_sat_t *sat, cdf_sat_t *ssat) |
758 | 1.82k | { |
759 | 1.82k | size_t i, j; |
760 | 1.82k | size_t ss = CDF_SEC_SIZE(h); |
761 | 1.82k | cdf_secid_t sid = h->h_secid_first_sector_in_short_sat; |
762 | | |
763 | 1.82k | ssat->sat_tab = NULL; |
764 | 1.82k | ssat->sat_len = cdf_count_chain(sat, sid, ss); |
765 | 1.82k | if (ssat->sat_len == CAST(size_t, -1)) |
766 | 149 | goto out; |
767 | | |
768 | 1.67k | ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss)); |
769 | 1.67k | if (ssat->sat_tab == NULL) |
770 | 0 | goto out1; |
771 | | |
772 | 5.11k | for (j = i = 0; sid >= 0; i++, j++) { |
773 | 3.46k | if (j >= CDF_LOOP_LIMIT) { |
774 | 0 | DPRINTF(("Read short sat sector loop limit")); |
775 | 0 | goto out; |
776 | 0 | } |
777 | 3.46k | if (i >= ssat->sat_len) { |
778 | 0 | DPRINTF(("Out of bounds reading short sector chain " |
779 | 0 | "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, |
780 | 0 | ssat->sat_len)); |
781 | 0 | goto out; |
782 | 0 | } |
783 | 3.46k | if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) != |
784 | 3.46k | CAST(ssize_t, ss)) { |
785 | 29 | DPRINTF(("Reading short sat sector %d", sid)); |
786 | 29 | goto out1; |
787 | 29 | } |
788 | 3.44k | sid = CDF_TOLE4(CAST(uint32_t, sat->sat_tab[sid])); |
789 | 3.44k | } |
790 | 1.64k | return 0; |
791 | 149 | out: |
792 | 149 | errno = EFTYPE; |
793 | 178 | out1: |
794 | 178 | free(ssat->sat_tab); |
795 | 178 | return -1; |
796 | 149 | } |
797 | | |
798 | | int |
799 | | cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h, |
800 | | const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn, |
801 | | const cdf_directory_t **root) |
802 | 1.51k | { |
803 | 1.51k | size_t i; |
804 | 1.51k | const cdf_directory_t *d; |
805 | | |
806 | 1.51k | *root = NULL; |
807 | 25.3k | for (i = 0; i < dir->dir_len; i++) |
808 | 24.5k | if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE) |
809 | 752 | break; |
810 | | |
811 | | /* If the it is not there, just fake it; some docs don't have it */ |
812 | 1.51k | if (i == dir->dir_len) { |
813 | 763 | DPRINTF(("Cannot find root storage dir\n")); |
814 | 763 | goto out; |
815 | 763 | } |
816 | 752 | d = &dir->dir_tab[i]; |
817 | 752 | *root = d; |
818 | | |
819 | | /* If the it is not there, just fake it; some docs don't have it */ |
820 | 752 | if (d->d_stream_first_sector < 0) { |
821 | 433 | DPRINTF(("No first secror in dir\n")); |
822 | 433 | goto out; |
823 | 433 | } |
824 | | |
825 | 319 | return cdf_read_long_sector_chain(info, h, sat, |
826 | 319 | d->d_stream_first_sector, d->d_size, scn); |
827 | 1.19k | out: |
828 | 1.19k | scn->sst_tab = NULL; |
829 | 1.19k | (void)cdf_zero_stream(scn); |
830 | 1.19k | return 0; |
831 | 752 | } |
832 | | |
833 | | static int |
834 | | cdf_namecmp(const char *d, const uint16_t *s, size_t l) |
835 | 22.1k | { |
836 | 55.9k | for (; l--; d++, s++) |
837 | 54.4k | if (*d != CDF_TOLE2(*s)) |
838 | 20.6k | return CAST(unsigned char, *d) - CDF_TOLE2(*s); |
839 | 1.51k | return 0; |
840 | 22.1k | } |
841 | | |
842 | | int |
843 | | cdf_read_doc_summary_info(const cdf_info_t *info, const cdf_header_t *h, |
844 | | const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, |
845 | | const cdf_dir_t *dir, cdf_stream_t *scn) |
846 | 1.33k | { |
847 | 1.33k | return cdf_read_user_stream(info, h, sat, ssat, sst, dir, |
848 | 1.33k | "\05DocumentSummaryInformation", scn); |
849 | 1.33k | } |
850 | | |
851 | | int |
852 | | cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h, |
853 | | const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, |
854 | | const cdf_dir_t *dir, cdf_stream_t *scn) |
855 | 1.43k | { |
856 | 1.43k | return cdf_read_user_stream(info, h, sat, ssat, sst, dir, |
857 | 1.43k | "\05SummaryInformation", scn); |
858 | 1.43k | } |
859 | | |
860 | | int |
861 | | cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h, |
862 | | const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, |
863 | | const cdf_dir_t *dir, const char *name, cdf_stream_t *scn) |
864 | 4.19k | { |
865 | 4.19k | const cdf_directory_t *d; |
866 | 4.19k | int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM); |
867 | | |
868 | 4.19k | if (i <= 0) { |
869 | 2.68k | memset(scn, 0, sizeof(*scn)); |
870 | 2.68k | return -1; |
871 | 2.68k | } |
872 | | |
873 | 1.50k | d = &dir->dir_tab[i - 1]; |
874 | 1.50k | return cdf_read_sector_chain(info, h, sat, ssat, sst, |
875 | 1.50k | d->d_stream_first_sector, d->d_size, scn); |
876 | 4.19k | } |
877 | | |
878 | | int |
879 | | cdf_find_stream(const cdf_dir_t *dir, const char *name, int type) |
880 | 16.1k | { |
881 | 16.1k | size_t i, name_len = strlen(name) + 1; |
882 | | |
883 | 496k | for (i = dir->dir_len; i > 0; i--) |
884 | 481k | if (dir->dir_tab[i - 1].d_type == type && |
885 | 481k | cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len) |
886 | 22.1k | == 0) |
887 | 1.51k | break; |
888 | 16.1k | if (i > 0) |
889 | 1.51k | return CAST(int, i); |
890 | | |
891 | 14.6k | DPRINTF(("Cannot find type %d `%s'\n", type, name)); |
892 | 14.6k | errno = ESRCH; |
893 | 14.6k | return 0; |
894 | 16.1k | } |
895 | | |
896 | 1.03k | #define CDF_SHLEN_LIMIT (UINT32_MAX / 64) |
897 | 2.05k | #define CDF_PROP_LIMIT (UINT32_MAX / (64 * sizeof(cdf_property_info_t))) |
898 | | |
899 | | static const void * |
900 | | cdf_offset(const void *p, size_t l) |
901 | 7.72k | { |
902 | 7.72k | return CAST(const void *, CAST(const uint8_t *, p) + l); |
903 | 7.72k | } |
904 | | |
905 | | static const uint8_t * |
906 | | cdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h, |
907 | | const uint8_t *p, const uint8_t *e, size_t i) |
908 | 4.98k | { |
909 | 4.98k | size_t tail = (i << 1) + 1; |
910 | 4.98k | size_t ofs; |
911 | | |
912 | 4.98k | if (p >= e) { |
913 | 0 | DPRINTF(("Past end %p < %p\n", e, p)); |
914 | 0 | return NULL; |
915 | 0 | } |
916 | | |
917 | 4.98k | if (cdf_check_stream_offset(sst, h, p, (tail + 1) * sizeof(uint32_t), |
918 | 4.98k | __LINE__) == -1) |
919 | 32 | return NULL; |
920 | | |
921 | 4.95k | ofs = CDF_GETUINT32(p, tail); |
922 | 4.95k | if (ofs < 2 * sizeof(uint32_t)) { |
923 | 26 | DPRINTF(("Offset too small %zu\n", ofs)); |
924 | 26 | return NULL; |
925 | 26 | } |
926 | | |
927 | 4.93k | ofs -= 2 * sizeof(uint32_t); |
928 | 4.93k | if (ofs > CAST(size_t, e - p)) { |
929 | 204 | DPRINTF(("Offset too big %zu %td\n", ofs, e - p)); |
930 | 204 | return NULL; |
931 | 204 | } |
932 | | |
933 | 4.72k | return CAST(const uint8_t *, cdf_offset(CAST(const void *, p), ofs)); |
934 | 4.93k | } |
935 | | |
936 | | static cdf_property_info_t * |
937 | | cdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr) |
938 | 1.09k | { |
939 | 1.09k | cdf_property_info_t *inp; |
940 | 1.09k | size_t newcount = *maxcount + incr; |
941 | | |
942 | 1.09k | if (newcount > CDF_PROP_LIMIT) { |
943 | 6 | DPRINTF(("exceeded property limit %" SIZE_T_FORMAT "u > %" |
944 | 6 | SIZE_T_FORMAT "u\n", newcount, CDF_PROP_LIMIT)); |
945 | 6 | goto out; |
946 | 6 | } |
947 | 1.08k | inp = CAST(cdf_property_info_t *, |
948 | 1.08k | CDF_REALLOC(*info, newcount * sizeof(*inp))); |
949 | 1.08k | if (inp == NULL) |
950 | 0 | goto out; |
951 | | |
952 | 1.08k | *info = inp; |
953 | 1.08k | *maxcount = newcount; |
954 | 1.08k | return inp; |
955 | 6 | out: |
956 | 6 | free(*info); |
957 | 6 | *maxcount = 0; |
958 | 6 | *info = NULL; |
959 | 6 | return NULL; |
960 | 1.08k | } |
961 | | |
962 | | static int |
963 | | cdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e, |
964 | | size_t len) |
965 | 2.16k | { |
966 | 2.16k | if (inp->pi_type & CDF_VECTOR) |
967 | 229 | return 0; |
968 | | |
969 | 1.93k | if (CAST(size_t, CAST(const char *, e) - CAST(const char *, p)) < len) |
970 | 231 | return 0; |
971 | | |
972 | 1.70k | (void)memcpy(&inp->pi_val, p, len); |
973 | | |
974 | 1.70k | switch (len) { |
975 | 174 | case 2: |
976 | 174 | inp->pi_u16 = CDF_TOLE2(inp->pi_u16); |
977 | 174 | break; |
978 | 545 | case 4: |
979 | 545 | inp->pi_u32 = CDF_TOLE4(inp->pi_u32); |
980 | 545 | break; |
981 | 989 | case 8: |
982 | 989 | inp->pi_u64 = CDF_TOLE8(inp->pi_u64); |
983 | 989 | break; |
984 | 0 | default: |
985 | 0 | abort(); |
986 | 1.70k | } |
987 | 1.70k | return 1; |
988 | 1.70k | } |
989 | | |
990 | | int |
991 | | cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, |
992 | | uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount) |
993 | 1.14k | { |
994 | 1.14k | const cdf_section_header_t *shp; |
995 | 1.14k | cdf_section_header_t sh; |
996 | 1.14k | const uint8_t *p, *q, *e; |
997 | 1.14k | size_t i, o4, nelements, j, slen, left; |
998 | 1.14k | cdf_property_info_t *inp; |
999 | | |
1000 | 1.14k | if (offs > UINT32_MAX / 4) { |
1001 | 21 | errno = EFTYPE; |
1002 | 21 | goto out; |
1003 | 21 | } |
1004 | 1.12k | shp = CAST(const cdf_section_header_t *, |
1005 | 1.12k | cdf_offset(sst->sst_tab, offs)); |
1006 | 1.12k | if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1) |
1007 | 88 | goto out; |
1008 | 1.03k | sh.sh_len = CDF_TOLE4(shp->sh_len); |
1009 | 1.03k | if (sh.sh_len > CDF_SHLEN_LIMIT) { |
1010 | 25 | errno = EFTYPE; |
1011 | 25 | goto out; |
1012 | 25 | } |
1013 | | |
1014 | 1.00k | if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1) |
1015 | 44 | goto out; |
1016 | | |
1017 | 964 | sh.sh_properties = CDF_TOLE4(shp->sh_properties); |
1018 | 964 | DPRINTF(("section len: %u properties %u\n", sh.sh_len, |
1019 | 964 | sh.sh_properties)); |
1020 | 964 | if (sh.sh_properties > CDF_PROP_LIMIT) |
1021 | 26 | goto out; |
1022 | 938 | inp = cdf_grow_info(info, maxcount, sh.sh_properties); |
1023 | 938 | if (inp == NULL) |
1024 | 0 | goto out; |
1025 | 938 | inp += *count; |
1026 | 938 | *count += sh.sh_properties; |
1027 | 938 | p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh))); |
1028 | 938 | e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len)); |
1029 | 938 | if (p >= e || cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1) |
1030 | 10 | goto out; |
1031 | | |
1032 | 5.50k | for (i = 0; i < sh.sh_properties; i++) { |
1033 | 4.98k | if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL) |
1034 | 262 | goto out; |
1035 | 4.72k | inp[i].pi_id = CDF_GETUINT32(p, i << 1); |
1036 | 4.72k | left = CAST(size_t, e - q); |
1037 | 4.72k | if (left < sizeof(uint32_t)) { |
1038 | 4 | DPRINTF(("short info (no type)_\n")); |
1039 | 4 | goto out; |
1040 | 4 | } |
1041 | 4.72k | inp[i].pi_type = CDF_GETUINT32(q, 0); |
1042 | 4.72k | DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n", |
1043 | 4.72k | i, inp[i].pi_id, inp[i].pi_type, q - p, offs)); |
1044 | 4.72k | if (inp[i].pi_type & CDF_VECTOR) { |
1045 | 898 | if (left < sizeof(uint32_t) * 2) { |
1046 | 4 | DPRINTF(("missing CDF_VECTOR length\n")); |
1047 | 4 | goto out; |
1048 | 4 | } |
1049 | 894 | nelements = CDF_GETUINT32(q, 1); |
1050 | 894 | if (nelements > CDF_ELEMENT_LIMIT || nelements == 0) { |
1051 | 55 | DPRINTF(("CDF_VECTOR with nelements == %" |
1052 | 55 | SIZE_T_FORMAT "u\n", nelements)); |
1053 | 55 | goto out; |
1054 | 55 | } |
1055 | 839 | slen = 2; |
1056 | 3.82k | } else { |
1057 | 3.82k | nelements = 1; |
1058 | 3.82k | slen = 1; |
1059 | 3.82k | } |
1060 | 4.66k | o4 = slen * sizeof(uint32_t); |
1061 | 4.66k | if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED)) |
1062 | 659 | goto unknown; |
1063 | 4.00k | switch (inp[i].pi_type & CDF_TYPEMASK) { |
1064 | 168 | case CDF_NULL: |
1065 | 577 | case CDF_EMPTY: |
1066 | 577 | break; |
1067 | 280 | case CDF_SIGNED16: |
1068 | 280 | if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t))) |
1069 | 106 | goto unknown; |
1070 | 174 | break; |
1071 | 291 | case CDF_SIGNED32: |
1072 | 400 | case CDF_BOOL: |
1073 | 555 | case CDF_UNSIGNED32: |
1074 | 737 | case CDF_FLOAT: |
1075 | 737 | if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t))) |
1076 | 192 | goto unknown; |
1077 | 545 | break; |
1078 | 545 | case CDF_SIGNED64: |
1079 | 186 | case CDF_UNSIGNED64: |
1080 | 390 | case CDF_DOUBLE: |
1081 | 1.15k | case CDF_FILETIME: |
1082 | 1.15k | if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t))) |
1083 | 162 | goto unknown; |
1084 | 989 | break; |
1085 | 989 | case CDF_LENGTH32_STRING: |
1086 | 548 | case CDF_LENGTH32_WSTRING: |
1087 | 548 | if (nelements > 1) { |
1088 | 154 | size_t nelem = inp - *info; |
1089 | 154 | inp = cdf_grow_info(info, maxcount, nelements); |
1090 | 154 | if (inp == NULL) |
1091 | 6 | goto out; |
1092 | 148 | inp += nelem; |
1093 | 148 | } |
1094 | 1.87M | for (j = 0; j < nelements && i < sh.sh_properties; |
1095 | 1.87M | j++, i++) |
1096 | 1.87M | { |
1097 | 1.87M | uint32_t l; |
1098 | | |
1099 | 1.87M | if (o4 + sizeof(uint32_t) > left) |
1100 | 10 | goto out; |
1101 | | |
1102 | 1.87M | l = CDF_GETUINT32(q, slen); |
1103 | 1.87M | o4 += sizeof(uint32_t); |
1104 | 1.87M | if (o4 + l > left) |
1105 | 68 | goto out; |
1106 | | |
1107 | 1.87M | inp[i].pi_str.s_len = l; |
1108 | 1.87M | inp[i].pi_str.s_buf = CAST(const char *, |
1109 | 1.87M | CAST(const void *, &q[o4])); |
1110 | | |
1111 | 1.87M | DPRINTF(("o=%" SIZE_T_FORMAT "u l=%d(%" |
1112 | 1.87M | SIZE_T_FORMAT "u), t=%" SIZE_T_FORMAT |
1113 | 1.87M | "u s=%.*s\n", o4, l, |
1114 | 1.87M | CDF_ROUND(l, sizeof(l)), |
1115 | 1.87M | left, (int)l, inp[i].pi_str.s_buf)); |
1116 | | |
1117 | 1.87M | if (l & 1) |
1118 | 187 | l++; |
1119 | | |
1120 | 1.87M | slen += l >> 1; |
1121 | 1.87M | o4 = slen * sizeof(uint32_t); |
1122 | 1.87M | } |
1123 | 464 | i--; |
1124 | 464 | break; |
1125 | 215 | case CDF_CLIPBOARD: |
1126 | 215 | if (inp[i].pi_type & CDF_VECTOR) |
1127 | 74 | goto unknown; |
1128 | 141 | break; |
1129 | 496 | default: |
1130 | 1.68k | unknown: |
1131 | 1.68k | memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val)); |
1132 | 1.68k | DPRINTF(("Don't know how to deal with %#x\n", |
1133 | 1.68k | inp[i].pi_type)); |
1134 | 1.68k | break; |
1135 | 4.00k | } |
1136 | 4.00k | } |
1137 | 519 | return 0; |
1138 | 623 | out: |
1139 | 623 | free(*info); |
1140 | 623 | *info = NULL; |
1141 | 623 | *count = 0; |
1142 | 623 | *maxcount = 0; |
1143 | 623 | errno = EFTYPE; |
1144 | 623 | return -1; |
1145 | 928 | } |
1146 | | |
1147 | | int |
1148 | | cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h, |
1149 | | cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count) |
1150 | 1.16k | { |
1151 | 1.16k | size_t maxcount; |
1152 | 1.16k | const cdf_summary_info_header_t *si = |
1153 | 1.16k | CAST(const cdf_summary_info_header_t *, sst->sst_tab); |
1154 | 1.16k | const cdf_section_declaration_t *sd = |
1155 | 1.16k | CAST(const cdf_section_declaration_t *, RCAST(const void *, |
1156 | 1.16k | RCAST(const char *, sst->sst_tab) |
1157 | 1.16k | + CDF_SECTION_DECLARATION_OFFSET)); |
1158 | | |
1159 | 1.16k | if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 || |
1160 | 1.16k | cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1) |
1161 | 22 | return -1; |
1162 | 1.14k | ssi->si_byte_order = CDF_TOLE2(si->si_byte_order); |
1163 | 1.14k | ssi->si_os_version = CDF_TOLE2(si->si_os_version); |
1164 | 1.14k | ssi->si_os = CDF_TOLE2(si->si_os); |
1165 | 1.14k | ssi->si_class = si->si_class; |
1166 | 1.14k | cdf_swap_class(&ssi->si_class); |
1167 | 1.14k | ssi->si_count = CDF_TOLE4(si->si_count); |
1168 | 1.14k | *count = 0; |
1169 | 1.14k | maxcount = 0; |
1170 | 1.14k | *info = NULL; |
1171 | 1.14k | if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info, |
1172 | 1.14k | count, &maxcount) == -1) |
1173 | 623 | return -1; |
1174 | 519 | return 0; |
1175 | 1.14k | } |
1176 | | |
1177 | | |
1178 | | #define extract_catalog_field(t, f, l) \ |
1179 | 0 | if (b + l + sizeof(cep->f) > eb) { \ |
1180 | 0 | cep->ce_namlen = 0; \ |
1181 | 0 | break; \ |
1182 | 0 | } \ |
1183 | 0 | memcpy(&cep->f, b + (l), sizeof(cep->f)); \ |
1184 | 0 | ce[i].f = CAST(t, CDF_TOLE(cep->f)) |
1185 | | |
1186 | | int |
1187 | | cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst, |
1188 | | cdf_catalog_t **cat) |
1189 | 0 | { |
1190 | 0 | size_t ss = cdf_check_stream(sst, h); |
1191 | 0 | const char *b = CAST(const char *, sst->sst_tab); |
1192 | 0 | const char *nb, *eb = b + ss * sst->sst_len; |
1193 | 0 | size_t nr, i, j, k; |
1194 | 0 | cdf_catalog_entry_t *ce; |
1195 | 0 | uint16_t reclen; |
1196 | 0 | const uint16_t *np; |
1197 | |
|
1198 | 0 | for (nr = 0;; nr++) { |
1199 | 0 | memcpy(&reclen, b, sizeof(reclen)); |
1200 | 0 | reclen = CDF_TOLE2(reclen); |
1201 | 0 | if (reclen == 0) |
1202 | 0 | break; |
1203 | 0 | b += reclen; |
1204 | 0 | if (b > eb) |
1205 | 0 | break; |
1206 | 0 | } |
1207 | 0 | if (nr == 0) |
1208 | 0 | return -1; |
1209 | 0 | nr--; |
1210 | 0 | *cat = CAST(cdf_catalog_t *, |
1211 | 0 | CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce))); |
1212 | 0 | if (*cat == NULL) |
1213 | 0 | return -1; |
1214 | 0 | ce = (*cat)->cat_e; |
1215 | 0 | memset(ce, 0, nr * sizeof(*ce)); |
1216 | 0 | b = CAST(const char *, sst->sst_tab); |
1217 | 0 | for (j = i = 0; i < nr; b += reclen) { |
1218 | 0 | cdf_catalog_entry_t *cep = &ce[j]; |
1219 | 0 | uint16_t rlen; |
1220 | |
|
1221 | 0 | extract_catalog_field(uint16_t, ce_namlen, 0); |
1222 | 0 | extract_catalog_field(uint16_t, ce_num, 4); |
1223 | 0 | extract_catalog_field(uint64_t, ce_timestamp, 8); |
1224 | 0 | reclen = cep->ce_namlen; |
1225 | |
|
1226 | 0 | if (reclen < 14) { |
1227 | 0 | cep->ce_namlen = 0; |
1228 | 0 | continue; |
1229 | 0 | } |
1230 | | |
1231 | 0 | cep->ce_namlen = __arraycount(cep->ce_name) - 1; |
1232 | 0 | rlen = reclen - 14; |
1233 | 0 | if (cep->ce_namlen > rlen) |
1234 | 0 | cep->ce_namlen = rlen; |
1235 | |
|
1236 | 0 | np = CAST(const uint16_t *, CAST(const void *, (b + 16))); |
1237 | 0 | nb = CAST(const char *, CAST(const void *, |
1238 | 0 | (np + cep->ce_namlen))); |
1239 | 0 | if (nb > eb) { |
1240 | 0 | cep->ce_namlen = 0; |
1241 | 0 | break; |
1242 | 0 | } |
1243 | | |
1244 | 0 | for (k = 0; k < cep->ce_namlen; k++) |
1245 | 0 | cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */ |
1246 | 0 | cep->ce_name[cep->ce_namlen] = 0; |
1247 | 0 | j = i; |
1248 | 0 | i++; |
1249 | 0 | } |
1250 | 0 | (*cat)->cat_num = j; |
1251 | 0 | return 0; |
1252 | 0 | } |
1253 | | |
1254 | | int |
1255 | | cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id) |
1256 | 0 | { |
1257 | 0 | return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-" |
1258 | 0 | "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0], |
1259 | 0 | id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0], |
1260 | 0 | id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4], |
1261 | 0 | id->cl_six[5]); |
1262 | 0 | } |
1263 | | |
1264 | | static const struct { |
1265 | | uint32_t v; |
1266 | | const char *n; |
1267 | | } vn[] = { |
1268 | | { CDF_PROPERTY_CODE_PAGE, "Code page" }, |
1269 | | { CDF_PROPERTY_TITLE, "Title" }, |
1270 | | { CDF_PROPERTY_SUBJECT, "Subject" }, |
1271 | | { CDF_PROPERTY_AUTHOR, "Author" }, |
1272 | | { CDF_PROPERTY_KEYWORDS, "Keywords" }, |
1273 | | { CDF_PROPERTY_COMMENTS, "Comments" }, |
1274 | | { CDF_PROPERTY_TEMPLATE, "Template" }, |
1275 | | { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" }, |
1276 | | { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" }, |
1277 | | { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" }, |
1278 | | { CDF_PROPERTY_LAST_PRINTED, "Last Printed" }, |
1279 | | { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" }, |
1280 | | { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" }, |
1281 | | { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" }, |
1282 | | { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" }, |
1283 | | { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" }, |
1284 | | { CDF_PROPERTY_THUMBNAIL, "Thumbnail" }, |
1285 | | { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" }, |
1286 | | { CDF_PROPERTY_SECURITY, "Security" }, |
1287 | | { CDF_PROPERTY_LOCALE_ID, "Locale ID" }, |
1288 | | }; |
1289 | | |
1290 | | int |
1291 | | cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p) |
1292 | 1.88k | { |
1293 | 1.88k | size_t i; |
1294 | | |
1295 | 35.9k | for (i = 0; i < __arraycount(vn); i++) |
1296 | 34.4k | if (vn[i].v == p) |
1297 | 362 | return snprintf(buf, bufsiz, "%s", vn[i].n); |
1298 | 1.51k | return snprintf(buf, bufsiz, "%#x", p); |
1299 | 1.88k | } |
1300 | | |
1301 | | int |
1302 | | cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts) |
1303 | 338 | { |
1304 | 338 | int len = 0; |
1305 | 338 | int days, hours, mins, secs; |
1306 | | |
1307 | 338 | ts /= CDF_TIME_PREC; |
1308 | 338 | secs = CAST(int, ts % 60); |
1309 | 338 | ts /= 60; |
1310 | 338 | mins = CAST(int, ts % 60); |
1311 | 338 | ts /= 60; |
1312 | 338 | hours = CAST(int, ts % 24); |
1313 | 338 | ts /= 24; |
1314 | 338 | days = CAST(int, ts); |
1315 | | |
1316 | 338 | if (days) { |
1317 | 187 | len += snprintf(buf + len, bufsiz - len, "%dd+", days); |
1318 | 187 | if (CAST(size_t, len) >= bufsiz) |
1319 | 0 | return len; |
1320 | 187 | } |
1321 | | |
1322 | 338 | if (days || hours) { |
1323 | 237 | len += snprintf(buf + len, bufsiz - len, "%.2d:", hours); |
1324 | 237 | if (CAST(size_t, len) >= bufsiz) |
1325 | 0 | return len; |
1326 | 237 | } |
1327 | | |
1328 | 338 | len += snprintf(buf + len, bufsiz - len, "%.2d:", mins); |
1329 | 338 | if (CAST(size_t, len) >= bufsiz) |
1330 | 0 | return len; |
1331 | | |
1332 | 338 | len += snprintf(buf + len, bufsiz - len, "%.2d", secs); |
1333 | 338 | return len; |
1334 | 338 | } |
1335 | | |
1336 | | char * |
1337 | | cdf_u16tos8(char *buf, size_t len, const uint16_t *p) |
1338 | 0 | { |
1339 | 0 | size_t i; |
1340 | 0 | for (i = 0; i < len && p[i]; i++) |
1341 | 0 | buf[i] = CAST(char, p[i]); |
1342 | 0 | buf[i] = '\0'; |
1343 | 0 | return buf; |
1344 | 0 | } |
1345 | | |
1346 | | #ifdef CDF_DEBUG |
1347 | | void |
1348 | | cdf_dump_header(const cdf_header_t *h) |
1349 | | { |
1350 | | size_t i; |
1351 | | |
1352 | | #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b) |
1353 | | #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \ |
1354 | | h->h_ ## b, 1 << h->h_ ## b) |
1355 | | DUMP("%d", revision); |
1356 | | DUMP("%d", version); |
1357 | | DUMP("%#x", byte_order); |
1358 | | DUMP2("%d", sec_size_p2); |
1359 | | DUMP2("%d", short_sec_size_p2); |
1360 | | DUMP("%d", num_sectors_in_sat); |
1361 | | DUMP("%d", secid_first_directory); |
1362 | | DUMP("%d", min_size_standard_stream); |
1363 | | DUMP("%d", secid_first_sector_in_short_sat); |
1364 | | DUMP("%d", num_sectors_in_short_sat); |
1365 | | DUMP("%d", secid_first_sector_in_master_sat); |
1366 | | DUMP("%d", num_sectors_in_master_sat); |
1367 | | for (i = 0; i < __arraycount(h->h_master_sat); i++) { |
1368 | | if (h->h_master_sat[i] == CDF_SECID_FREE) |
1369 | | break; |
1370 | | (void)fprintf(stderr, "%35.35s[%.3" SIZE_T_FORMAT "u] = %d\n", |
1371 | | "master_sat", i, h->h_master_sat[i]); |
1372 | | } |
1373 | | } |
1374 | | |
1375 | | void |
1376 | | cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size) |
1377 | | { |
1378 | | size_t i, j, s = size / sizeof(cdf_secid_t); |
1379 | | |
1380 | | for (i = 0; i < sat->sat_len; i++) { |
1381 | | (void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6" |
1382 | | SIZE_T_FORMAT "u: ", prefix, i, i * s); |
1383 | | for (j = 0; j < s; j++) { |
1384 | | (void)fprintf(stderr, "%5d, ", |
1385 | | CDF_TOLE4(sat->sat_tab[s * i + j])); |
1386 | | if ((j + 1) % 10 == 0) |
1387 | | (void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT |
1388 | | "u: ", i * s + j + 1); |
1389 | | } |
1390 | | (void)fprintf(stderr, "\n"); |
1391 | | } |
1392 | | } |
1393 | | |
1394 | | void |
1395 | | cdf_dump(const void *v, size_t len) |
1396 | | { |
1397 | | size_t i, j; |
1398 | | const unsigned char *p = v; |
1399 | | char abuf[16]; |
1400 | | |
1401 | | (void)fprintf(stderr, "%.4x: ", 0); |
1402 | | for (i = 0, j = 0; i < len; i++, p++) { |
1403 | | (void)fprintf(stderr, "%.2x ", *p); |
1404 | | abuf[j++] = isprint(*p) ? *p : '.'; |
1405 | | if (j == 16) { |
1406 | | j = 0; |
1407 | | abuf[15] = '\0'; |
1408 | | (void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ", |
1409 | | abuf, i + 1); |
1410 | | } |
1411 | | } |
1412 | | (void)fprintf(stderr, "\n"); |
1413 | | } |
1414 | | |
1415 | | void |
1416 | | cdf_dump_stream(const cdf_stream_t *sst) |
1417 | | { |
1418 | | size_t ss = sst->sst_ss; |
1419 | | cdf_dump(sst->sst_tab, ss * sst->sst_len); |
1420 | | } |
1421 | | |
1422 | | void |
1423 | | cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, |
1424 | | const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, |
1425 | | const cdf_dir_t *dir) |
1426 | | { |
1427 | | size_t i, j; |
1428 | | cdf_directory_t *d; |
1429 | | char name[__arraycount(d->d_name)]; |
1430 | | cdf_stream_t scn; |
1431 | | struct timespec ts; |
1432 | | |
1433 | | static const char *types[] = { "empty", "user storage", |
1434 | | "user stream", "lockbytes", "property", "root storage" }; |
1435 | | |
1436 | | for (i = 0; i < dir->dir_len; i++) { |
1437 | | char buf[26]; |
1438 | | d = &dir->dir_tab[i]; |
1439 | | for (j = 0; j < sizeof(name); j++) |
1440 | | name[j] = (char)CDF_TOLE2(d->d_name[j]); |
1441 | | (void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n", |
1442 | | i, name); |
1443 | | if (d->d_type < __arraycount(types)) |
1444 | | (void)fprintf(stderr, "Type: %s\n", types[d->d_type]); |
1445 | | else |
1446 | | (void)fprintf(stderr, "Type: %d\n", d->d_type); |
1447 | | (void)fprintf(stderr, "Color: %s\n", |
1448 | | d->d_color ? "black" : "red"); |
1449 | | (void)fprintf(stderr, "Left child: %d\n", d->d_left_child); |
1450 | | (void)fprintf(stderr, "Right child: %d\n", d->d_right_child); |
1451 | | (void)fprintf(stderr, "Flags: %#x\n", d->d_flags); |
1452 | | cdf_timestamp_to_timespec(&ts, d->d_created); |
1453 | | (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf)); |
1454 | | cdf_timestamp_to_timespec(&ts, d->d_modified); |
1455 | | (void)fprintf(stderr, "Modified %s", |
1456 | | cdf_ctime(&ts.tv_sec, buf)); |
1457 | | (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector); |
1458 | | (void)fprintf(stderr, "Size %d\n", d->d_size); |
1459 | | switch (d->d_type) { |
1460 | | case CDF_DIR_TYPE_USER_STORAGE: |
1461 | | (void)fprintf(stderr, "Storage: %d\n", d->d_storage); |
1462 | | break; |
1463 | | case CDF_DIR_TYPE_USER_STREAM: |
1464 | | if (sst == NULL) |
1465 | | break; |
1466 | | if (cdf_read_sector_chain(info, h, sat, ssat, sst, |
1467 | | d->d_stream_first_sector, d->d_size, &scn) == -1) { |
1468 | | warn("Can't read stream for %s at %d len %d", |
1469 | | name, d->d_stream_first_sector, d->d_size); |
1470 | | break; |
1471 | | } |
1472 | | cdf_dump_stream(&scn); |
1473 | | free(scn.sst_tab); |
1474 | | break; |
1475 | | default: |
1476 | | break; |
1477 | | } |
1478 | | |
1479 | | } |
1480 | | } |
1481 | | |
1482 | | void |
1483 | | cdf_dump_property_info(const cdf_property_info_t *info, size_t count) |
1484 | | { |
1485 | | cdf_timestamp_t tp; |
1486 | | struct timespec ts; |
1487 | | char buf[64]; |
1488 | | size_t i, j; |
1489 | | |
1490 | | for (i = 0; i < count; i++) { |
1491 | | cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); |
1492 | | (void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf); |
1493 | | switch (info[i].pi_type) { |
1494 | | case CDF_NULL: |
1495 | | break; |
1496 | | case CDF_SIGNED16: |
1497 | | (void)fprintf(stderr, "signed 16 [%hd]\n", |
1498 | | info[i].pi_s16); |
1499 | | break; |
1500 | | case CDF_SIGNED32: |
1501 | | (void)fprintf(stderr, "signed 32 [%d]\n", |
1502 | | info[i].pi_s32); |
1503 | | break; |
1504 | | case CDF_UNSIGNED32: |
1505 | | (void)fprintf(stderr, "unsigned 32 [%u]\n", |
1506 | | info[i].pi_u32); |
1507 | | break; |
1508 | | case CDF_FLOAT: |
1509 | | (void)fprintf(stderr, "float [%g]\n", |
1510 | | info[i].pi_f); |
1511 | | break; |
1512 | | case CDF_DOUBLE: |
1513 | | (void)fprintf(stderr, "double [%g]\n", |
1514 | | info[i].pi_d); |
1515 | | break; |
1516 | | case CDF_LENGTH32_STRING: |
1517 | | (void)fprintf(stderr, "string %u [%.*s]\n", |
1518 | | info[i].pi_str.s_len, |
1519 | | info[i].pi_str.s_len, info[i].pi_str.s_buf); |
1520 | | break; |
1521 | | case CDF_LENGTH32_WSTRING: |
1522 | | (void)fprintf(stderr, "string %u [", |
1523 | | info[i].pi_str.s_len); |
1524 | | for (j = 0; j < info[i].pi_str.s_len - 1; j++) |
1525 | | (void)fputc(info[i].pi_str.s_buf[j << 1], stderr); |
1526 | | (void)fprintf(stderr, "]\n"); |
1527 | | break; |
1528 | | case CDF_FILETIME: |
1529 | | tp = info[i].pi_tp; |
1530 | | if (tp < 1000000000000000LL) { |
1531 | | cdf_print_elapsed_time(buf, sizeof(buf), tp); |
1532 | | (void)fprintf(stderr, "timestamp %s\n", buf); |
1533 | | } else { |
1534 | | char tbuf[26]; |
1535 | | cdf_timestamp_to_timespec(&ts, tp); |
1536 | | (void)fprintf(stderr, "timestamp %s", |
1537 | | cdf_ctime(&ts.tv_sec, tbuf)); |
1538 | | } |
1539 | | break; |
1540 | | case CDF_CLIPBOARD: |
1541 | | (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32); |
1542 | | break; |
1543 | | default: |
1544 | | DPRINTF(("Don't know how to deal with %#x\n", |
1545 | | info[i].pi_type)); |
1546 | | break; |
1547 | | } |
1548 | | } |
1549 | | } |
1550 | | |
1551 | | |
1552 | | void |
1553 | | cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) |
1554 | | { |
1555 | | char buf[128]; |
1556 | | cdf_summary_info_header_t ssi; |
1557 | | cdf_property_info_t *info; |
1558 | | size_t count; |
1559 | | |
1560 | | (void)&h; |
1561 | | if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1) |
1562 | | return; |
1563 | | (void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order); |
1564 | | (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff, |
1565 | | ssi.si_os_version >> 8); |
1566 | | (void)fprintf(stderr, "Os %d\n", ssi.si_os); |
1567 | | cdf_print_classid(buf, sizeof(buf), &ssi.si_class); |
1568 | | (void)fprintf(stderr, "Class %s\n", buf); |
1569 | | (void)fprintf(stderr, "Count %d\n", ssi.si_count); |
1570 | | cdf_dump_property_info(info, count); |
1571 | | free(info); |
1572 | | } |
1573 | | |
1574 | | |
1575 | | void |
1576 | | cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst) |
1577 | | { |
1578 | | cdf_catalog_t *cat; |
1579 | | cdf_unpack_catalog(h, sst, &cat); |
1580 | | const cdf_catalog_entry_t *ce = cat->cat_e; |
1581 | | struct timespec ts; |
1582 | | char tbuf[64], sbuf[256]; |
1583 | | size_t i; |
1584 | | |
1585 | | printf("Catalog:\n"); |
1586 | | for (i = 0; i < cat->cat_num; i++) { |
1587 | | cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp); |
1588 | | printf("\t%d %s %s", ce[i].ce_num, |
1589 | | cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), |
1590 | | cdf_ctime(&ts.tv_sec, tbuf)); |
1591 | | } |
1592 | | free(cat); |
1593 | | } |
1594 | | |
1595 | | #endif |
1596 | | |
1597 | | #ifdef TEST |
1598 | | int |
1599 | | main(int argc, char *argv[]) |
1600 | | { |
1601 | | int i; |
1602 | | cdf_header_t h; |
1603 | | cdf_sat_t sat, ssat; |
1604 | | cdf_stream_t sst, scn; |
1605 | | cdf_dir_t dir; |
1606 | | cdf_info_t info; |
1607 | | const cdf_directory_t *root; |
1608 | | #ifdef __linux__ |
1609 | | #define getprogname() __progname |
1610 | | extern char *__progname; |
1611 | | #endif |
1612 | | if (argc < 2) { |
1613 | | (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname()); |
1614 | | return -1; |
1615 | | } |
1616 | | |
1617 | | info.i_buf = NULL; |
1618 | | info.i_len = 0; |
1619 | | for (i = 1; i < argc; i++) { |
1620 | | if ((info.i_fd = open(argv[1], O_RDONLY)) == -1) |
1621 | | err(EXIT_FAILURE, "Cannot open `%s'", argv[1]); |
1622 | | |
1623 | | if (cdf_read_header(&info, &h) == -1) |
1624 | | err(EXIT_FAILURE, "Cannot read header"); |
1625 | | #ifdef CDF_DEBUG |
1626 | | cdf_dump_header(&h); |
1627 | | #endif |
1628 | | |
1629 | | if (cdf_read_sat(&info, &h, &sat) == -1) |
1630 | | err(EXIT_FAILURE, "Cannot read sat"); |
1631 | | #ifdef CDF_DEBUG |
1632 | | cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); |
1633 | | #endif |
1634 | | |
1635 | | if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1) |
1636 | | err(EXIT_FAILURE, "Cannot read ssat"); |
1637 | | #ifdef CDF_DEBUG |
1638 | | cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); |
1639 | | #endif |
1640 | | |
1641 | | if (cdf_read_dir(&info, &h, &sat, &dir) == -1) |
1642 | | err(EXIT_FAILURE, "Cannot read dir"); |
1643 | | |
1644 | | if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root) |
1645 | | == -1) |
1646 | | err(EXIT_FAILURE, "Cannot read short stream"); |
1647 | | #ifdef CDF_DEBUG |
1648 | | cdf_dump_stream(&sst); |
1649 | | #endif |
1650 | | |
1651 | | #ifdef CDF_DEBUG |
1652 | | cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); |
1653 | | #endif |
1654 | | |
1655 | | |
1656 | | if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, |
1657 | | &scn) == -1) |
1658 | | warn("Cannot read summary info"); |
1659 | | #ifdef CDF_DEBUG |
1660 | | else |
1661 | | cdf_dump_summary_info(&h, &scn); |
1662 | | #endif |
1663 | | if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, |
1664 | | &dir, "Catalog", &scn) == -1) |
1665 | | warn("Cannot read catalog"); |
1666 | | #ifdef CDF_DEBUG |
1667 | | else |
1668 | | cdf_dump_catalog(&h, &scn); |
1669 | | #endif |
1670 | | |
1671 | | (void)close(info.i_fd); |
1672 | | } |
1673 | | |
1674 | | return 0; |
1675 | | } |
1676 | | #endif |