Merge branch 'vendor/SENDMAIL'
[dragonfly.git] / contrib / file / src / cdf.c
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
32 #include "file.h"
33
34 #ifndef lint
35 FILE_RCSID("@(#)$File: cdf.c,v 1.30 2009/05/06 14:29:47 christos Exp $")
36 #endif
37
38 #include <assert.h>
39 #ifdef CDF_DEBUG
40 #include <err.h>
41 #endif
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <time.h>
46 #include <ctype.h>
47
48 #ifndef EFTYPE
49 #define EFTYPE EINVAL
50 #endif
51
52 #include "cdf.h"
53
54 #ifndef __arraycount
55 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
56 #endif
57
58 #ifdef CDF_DEBUG
59 #define DPRINTF(a) printf a, fflush(stdout)
60 #else
61 #define DPRINTF(a)
62 #endif
63
64 static union {
65         char s[4];
66         uint32_t u;
67 } cdf_bo;
68
69 #define NEED_SWAP       (cdf_bo.u == (uint32_t)0x01020304)
70
71 #define CDF_TOLE8(x)    (NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x))
72 #define CDF_TOLE4(x)    (NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x))
73 #define CDF_TOLE2(x)    (NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x))
74
75 /*
76  * swap a short
77  */
78 uint16_t
79 cdf_tole2(uint16_t sv)
80 {
81         uint16_t rv;
82         uint8_t *s = (uint8_t *)(void *)&sv; 
83         uint8_t *d = (uint8_t *)(void *)&rv; 
84         d[0] = s[1];
85         d[1] = s[0];
86         return rv;
87 }
88
89 /*
90  * swap an int
91  */
92 uint32_t
93 cdf_tole4(uint32_t sv)
94 {
95         uint32_t rv;
96         uint8_t *s = (uint8_t *)(void *)&sv; 
97         uint8_t *d = (uint8_t *)(void *)&rv; 
98         d[0] = s[3];
99         d[1] = s[2];
100         d[2] = s[1];
101         d[3] = s[0];
102         return rv;
103 }
104
105 /*
106  * swap a quad
107  */
108 uint64_t
109 cdf_tole8(uint64_t sv)
110 {
111         uint64_t rv;
112         uint8_t *s = (uint8_t *)(void *)&sv; 
113         uint8_t *d = (uint8_t *)(void *)&rv; 
114         d[0] = s[7];
115         d[1] = s[6];
116         d[2] = s[5];
117         d[3] = s[4];
118         d[4] = s[3];
119         d[5] = s[2];
120         d[6] = s[1];
121         d[7] = s[0];
122         return rv;
123 }
124
125 #define CDF_UNPACK(a)   \
126     (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
127 #define CDF_UNPACKA(a)  \
128     (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
129
130 void
131 cdf_swap_header(cdf_header_t *h)
132 {
133         size_t i;
134
135         h->h_magic = CDF_TOLE8(h->h_magic);
136         h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]);
137         h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]);
138         h->h_revision = CDF_TOLE2(h->h_revision);
139         h->h_version = CDF_TOLE2(h->h_version);
140         h->h_byte_order = CDF_TOLE2(h->h_byte_order);
141         h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2);
142         h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2);
143         h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat);
144         h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory);
145         h->h_min_size_standard_stream =
146             CDF_TOLE4(h->h_min_size_standard_stream);
147         h->h_secid_first_sector_in_short_sat =
148             CDF_TOLE4(h->h_secid_first_sector_in_short_sat);
149         h->h_num_sectors_in_short_sat =
150             CDF_TOLE4(h->h_num_sectors_in_short_sat);
151         h->h_secid_first_sector_in_master_sat =
152             CDF_TOLE4(h->h_secid_first_sector_in_master_sat);
153         h->h_num_sectors_in_master_sat =
154             CDF_TOLE4(h->h_num_sectors_in_master_sat);
155         for (i = 0; i < __arraycount(h->h_master_sat); i++)
156                 h->h_master_sat[i] = CDF_TOLE4(h->h_master_sat[i]);
157 }
158
159 void
160 cdf_unpack_header(cdf_header_t *h, char *buf)
161 {
162         size_t i;
163         size_t len = 0;
164
165         CDF_UNPACK(h->h_magic);
166         CDF_UNPACKA(h->h_uuid);
167         CDF_UNPACK(h->h_revision);
168         CDF_UNPACK(h->h_version);
169         CDF_UNPACK(h->h_byte_order);
170         CDF_UNPACK(h->h_sec_size_p2);
171         CDF_UNPACK(h->h_short_sec_size_p2);
172         CDF_UNPACKA(h->h_unused0);
173         CDF_UNPACK(h->h_num_sectors_in_sat);
174         CDF_UNPACK(h->h_secid_first_directory);
175         CDF_UNPACKA(h->h_unused1);
176         CDF_UNPACK(h->h_min_size_standard_stream);
177         CDF_UNPACK(h->h_secid_first_sector_in_short_sat);
178         CDF_UNPACK(h->h_num_sectors_in_short_sat);
179         CDF_UNPACK(h->h_secid_first_sector_in_master_sat);
180         CDF_UNPACK(h->h_num_sectors_in_master_sat);
181         for (i = 0; i < __arraycount(h->h_master_sat); i++)
182                 CDF_UNPACK(h->h_master_sat[i]);
183 }
184
185 void
186 cdf_swap_dir(cdf_directory_t *d)
187 {
188         d->d_namelen = CDF_TOLE2(d->d_namelen);
189         d->d_left_child = CDF_TOLE4(d->d_left_child);
190         d->d_right_child = CDF_TOLE4(d->d_right_child);
191         d->d_storage = CDF_TOLE4(d->d_storage);
192         d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]);
193         d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]);
194         d->d_flags = CDF_TOLE4(d->d_flags);
195         d->d_created = CDF_TOLE8(d->d_created);
196         d->d_modified = CDF_TOLE8(d->d_modified);
197         d->d_stream_first_sector = CDF_TOLE4(d->d_stream_first_sector);
198         d->d_size = CDF_TOLE4(d->d_size);
199 }
200
201 void
202 cdf_swap_class(cdf_classid_t *d)
203 {
204         d->cl_dword = CDF_TOLE4(d->cl_dword);
205         d->cl_word[0] = CDF_TOLE2(d->cl_word[0]);
206         d->cl_word[1] = CDF_TOLE2(d->cl_word[1]);
207 }
208
209 void
210 cdf_unpack_dir(cdf_directory_t *d, char *buf)
211 {
212         size_t len = 0;
213
214         CDF_UNPACKA(d->d_name);
215         CDF_UNPACK(d->d_namelen);
216         CDF_UNPACK(d->d_type);
217         CDF_UNPACK(d->d_color);
218         CDF_UNPACK(d->d_left_child);
219         CDF_UNPACK(d->d_right_child);
220         CDF_UNPACK(d->d_storage);
221         CDF_UNPACKA(d->d_storage_uuid);
222         CDF_UNPACK(d->d_flags);
223         CDF_UNPACK(d->d_created);
224         CDF_UNPACK(d->d_modified);
225         CDF_UNPACK(d->d_stream_first_sector);
226         CDF_UNPACK(d->d_size);
227         CDF_UNPACK(d->d_unused0);
228 }
229
230 static int
231 cdf_check_stream_offset(const cdf_stream_t *sst, const void *p, size_t tail)
232 {
233         const char *b = (const char *)sst->sst_tab;
234         const char *e = ((const char *)p) + tail;
235         if (e >= b && (size_t)(e - b) < sst->sst_dirlen * sst->sst_len)
236                 return 0;
237         DPRINTF((stderr, "offset begin %p end %p %zu >= %zu\n", b, e,
238             (size_t)(e - b), sst->sst_dirlen * sst->sst_len));
239         errno = EFTYPE;
240         return -1;
241 }
242
243 static ssize_t
244 cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
245 {
246         size_t siz = (size_t)off + len;
247
248         if ((off_t)(off + len) != (off_t)siz) {
249                 errno = EINVAL;
250                 return -1;
251         }
252
253         if (info->i_buf != NULL && info->i_len >= siz) {
254                 (void)memcpy(buf, &info->i_buf[off], len);
255                 return (ssize_t)len;
256         }
257
258         if (info->i_fd == -1)
259                 return -1;
260
261         if (lseek(info->i_fd, off, SEEK_SET) == (off_t)-1)
262                 return -1;
263
264         if (read(info->i_fd, buf, len) != (ssize_t)len)
265                 return -1;
266
267         return (ssize_t)len;
268 }
269
270 int
271 cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
272 {
273         char buf[512];
274
275         (void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
276         if (cdf_read(info, (off_t)0, buf, sizeof(buf)) == -1)
277                 return -1;
278         cdf_unpack_header(h, buf);
279         cdf_swap_header(h);
280         if (h->h_magic != CDF_MAGIC) {
281                 DPRINTF(("Bad magic 0x%llx != 0x%llx\n",
282                     (unsigned long long)h->h_magic,
283                     (unsigned long long)CDF_MAGIC));
284                 goto out;
285         }
286         if (h->h_sec_size_p2 > 20) {
287                 DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
288                 goto out;
289         }
290         if (h->h_short_sec_size_p2 > 20) {
291                 DPRINTF(("Bad short sector size 0x%u\n",
292                     h->h_short_sec_size_p2));
293                 goto out;
294         }
295         return 0;
296 out:
297         errno = EFTYPE;
298         return -1;
299 }
300
301
302 ssize_t
303 cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
304     const cdf_header_t *h, cdf_secid_t id)
305 {
306         assert((size_t)CDF_SEC_SIZE(h) == len);
307         return cdf_read(info, (off_t)CDF_SEC_POS(h, id),
308             ((char *)buf) + offs, len);
309 }
310
311 ssize_t
312 cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
313     size_t len, const cdf_header_t *h, cdf_secid_t id)
314 {
315         assert((size_t)CDF_SHORT_SEC_SIZE(h) == len);
316         (void)memcpy(((char *)buf) + offs,
317             ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len);
318         return len;
319 }
320
321 /*
322  * Read the sector allocation table.
323  */
324 int
325 cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
326 {
327         size_t i, j, k;
328         size_t ss = CDF_SEC_SIZE(h);
329         cdf_secid_t *msa, mid, sec;
330         size_t nsatpersec = (ss / sizeof(mid)) - 1;
331
332         for (i = 0; i < __arraycount(h->h_master_sat); i++)
333                 if (h->h_master_sat[i] == CDF_SECID_FREE)
334                         break;
335
336 #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
337         if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec ||
338             i > CDF_SEC_LIMIT) {
339                 DPRINTF(("Number of sectors in master SAT too big %u %zu\n",
340                     h->h_num_sectors_in_master_sat, i));
341                 errno = EFTYPE;
342                 return -1;
343         }
344
345         sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
346         DPRINTF(("sat_len = %zu ss = %zu\n", sat->sat_len, ss));
347         if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL)
348                 return -1;
349
350         for (i = 0; i < __arraycount(h->h_master_sat); i++) {
351                 if (h->h_master_sat[i] < 0)
352                         break;
353                 if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
354                     h->h_master_sat[i]) != (ssize_t)ss) {
355                         DPRINTF(("Reading sector %d", h->h_master_sat[i]));
356                         goto out1;
357                 }
358         }
359
360         if ((msa = calloc(1, ss)) == NULL)
361                 goto out1;
362
363         mid = h->h_secid_first_sector_in_master_sat;
364         for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
365                 if (mid < 0)
366                         goto out;
367                 if (j >= CDF_LOOP_LIMIT) {
368                         DPRINTF(("Reading master sector loop limit"));
369                         errno = EFTYPE;
370                         goto out2;
371                 }
372                 if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
373                         DPRINTF(("Reading master sector %d", mid));
374                         goto out2;
375                 }
376                 for (k = 0; k < nsatpersec; k++, i++) {
377                         sec = CDF_TOLE4(msa[k]);
378                         if (sec < 0)
379                                 goto out;
380                         if (i >= sat->sat_len) {
381                             DPRINTF(("Out of bounds reading MSA %u >= %u",
382                                 i, sat->sat_len));
383                             errno = EFTYPE;
384                             goto out2;
385                         }
386                         if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
387                             sec) != (ssize_t)ss) {
388                                 DPRINTF(("Reading sector %d",
389                                     CDF_TOLE4(msa[k])));
390                                 goto out2;
391                         }
392                 }
393                 mid = CDF_TOLE4(msa[nsatpersec]);
394         }
395 out:
396         sat->sat_len = i;
397         free(msa);
398         return 0;
399 out2:
400         free(msa);
401 out1:
402         free(sat->sat_tab);
403         return -1;
404 }
405
406 size_t
407 cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
408 {
409         size_t i, j;
410         cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * size);
411
412         DPRINTF(("Chain:"));
413         for (j = i = 0; sid >= 0; i++, j++) {
414                 DPRINTF((" %d", sid));
415                 if (j >= CDF_LOOP_LIMIT) {
416                         DPRINTF(("Counting chain loop limit"));
417                         errno = EFTYPE;
418                         return (size_t)-1;
419                 }
420                 if (sid > maxsector) {
421                         DPRINTF(("Sector %d > %d\n", sid, maxsector));
422                         errno = EFTYPE;
423                         return (size_t)-1;
424                 }
425                 sid = CDF_TOLE4(sat->sat_tab[sid]);
426         }
427         DPRINTF(("\n"));
428         return i;
429 }
430
431 int
432 cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
433     const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn)
434 {
435         size_t ss = CDF_SEC_SIZE(h), i, j;
436         ssize_t nr;
437         scn->sst_len = cdf_count_chain(sat, sid, ss);
438         scn->sst_dirlen = len;
439
440         if (scn->sst_len == (size_t)-1)
441                 return -1;
442
443         scn->sst_tab = calloc(scn->sst_len, ss);
444         if (scn->sst_tab == NULL)
445                 return -1;
446
447         for (j = i = 0; sid >= 0; i++, j++) {
448                 if (j >= CDF_LOOP_LIMIT) {
449                         DPRINTF(("Read long sector chain loop limit"));
450                         errno = EFTYPE;
451                         goto out;
452                 }
453                 if (i >= scn->sst_len) {
454                         DPRINTF(("Out of bounds reading long sector chain "
455                             "%u > %u\n", i, scn->sst_len));
456                         errno = EFTYPE;
457                         goto out;
458                 }
459                 if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
460                     sid)) != (ssize_t)ss) {
461                         if (i == scn->sst_len - 1 && nr > 0) {
462                                 /* Last sector might be truncated */
463                                 return 0;
464                         }
465                         DPRINTF(("Reading long sector chain %d", sid));
466                         goto out;
467                 }
468                 sid = CDF_TOLE4(sat->sat_tab[sid]);
469         }
470         return 0;
471 out:
472         free(scn->sst_tab);
473         return -1;
474 }
475
476 int
477 cdf_read_short_sector_chain(const cdf_header_t *h,
478     const cdf_sat_t *ssat, const cdf_stream_t *sst,
479     cdf_secid_t sid, size_t len, cdf_stream_t *scn)
480 {
481         size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
482         scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
483         scn->sst_dirlen = len;
484
485         if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
486                 return -1;
487
488         scn->sst_tab = calloc(scn->sst_len, ss);
489         if (scn->sst_tab == NULL)
490                 return -1;
491
492         for (j = i = 0; sid >= 0; i++, j++) {
493                 if (j >= CDF_LOOP_LIMIT) {
494                         DPRINTF(("Read short sector chain loop limit"));
495                         errno = EFTYPE;
496                         goto out;
497                 }
498                 if (i >= scn->sst_len) {
499                         DPRINTF(("Out of bounds reading short sector chain "
500                             "%u > %u\n", i, scn->sst_len));
501                         errno = EFTYPE;
502                         goto out;
503                 }
504                 if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
505                     sid) != (ssize_t)ss) {
506                         DPRINTF(("Reading short sector chain %d", sid));
507                         goto out;
508                 }
509                 sid = CDF_TOLE4(ssat->sat_tab[sid]);
510         }
511         return 0;
512 out:
513         free(scn->sst_tab);
514         return -1;
515 }
516
517 int
518 cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
519     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
520     cdf_secid_t sid, size_t len, cdf_stream_t *scn)
521 {
522
523         if (len < h->h_min_size_standard_stream)
524                 return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
525                     scn);
526         else
527                 return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
528 }
529
530 int
531 cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
532     const cdf_sat_t *sat, cdf_dir_t *dir)
533 {
534         size_t i, j;
535         size_t ss = CDF_SEC_SIZE(h), ns, nd;
536         char *buf;
537         cdf_secid_t sid = h->h_secid_first_directory;
538
539         ns = cdf_count_chain(sat, sid, ss);
540         if (ns == (size_t)-1)
541                 return -1;
542
543         nd = ss / CDF_DIRECTORY_SIZE;
544
545         dir->dir_len = ns * nd;
546         dir->dir_tab = calloc(dir->dir_len, sizeof(dir->dir_tab[0]));
547         if (dir->dir_tab == NULL)
548                 return -1;
549
550         if ((buf = malloc(ss)) == NULL) {
551                 free(dir->dir_tab);
552                 return -1;
553         }
554
555         for (j = i = 0; i < ns; i++, j++) {
556                 if (j >= CDF_LOOP_LIMIT) {
557                         DPRINTF(("Read dir loop limit"));
558                         errno = EFTYPE;
559                         goto out;
560                 }
561                 if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
562                         DPRINTF(("Reading directory sector %d", sid));
563                         goto out;
564                 }
565                 for (j = 0; j < nd; j++) {
566                         cdf_unpack_dir(&dir->dir_tab[i * nd + j],
567                             &buf[j * CDF_DIRECTORY_SIZE]);
568                 }
569                 sid = CDF_TOLE4(sat->sat_tab[sid]);
570         }
571         if (NEED_SWAP)
572                 for (i = 0; i < dir->dir_len; i++)
573                         cdf_swap_dir(&dir->dir_tab[i]);
574         free(buf);
575         return 0;
576 out:
577         free(dir->dir_tab);
578         free(buf);
579         return -1;
580 }
581
582
583 int
584 cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
585     const cdf_sat_t *sat, cdf_sat_t *ssat)
586 {
587         size_t i, j;
588         size_t ss = CDF_SEC_SIZE(h);
589         cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
590
591         ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h));
592         if (ssat->sat_len == (size_t)-1)
593                 return -1;
594
595         ssat->sat_tab = calloc(ssat->sat_len, ss);
596         if (ssat->sat_tab == NULL)
597                 return -1;
598
599         for (j = i = 0; sid >= 0; i++, j++) {
600                 if (j >= CDF_LOOP_LIMIT) {
601                         DPRINTF(("Read short sat sector loop limit"));
602                         errno = EFTYPE;
603                         goto out;
604                 }
605                 if (i >= ssat->sat_len) {
606                         DPRINTF(("Out of bounds reading short sector chain "
607                             "%u > %u\n", i, ssat->sat_len));
608                         errno = EFTYPE;
609                         goto out;
610                 }
611                 if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
612                     (ssize_t)ss) {
613                         DPRINTF(("Reading short sat sector %d", sid));
614                         goto out;
615                 }
616                 sid = CDF_TOLE4(sat->sat_tab[sid]);
617         }
618         return 0;
619 out:
620         free(ssat->sat_tab);
621         return -1;
622 }
623
624 int
625 cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
626     const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn)
627 {
628         size_t i;
629         const cdf_directory_t *d;
630
631         for (i = 0; i < dir->dir_len; i++)
632                 if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
633                         break;
634
635         /* If the it is not there, just fake it; some docs don't have it */
636         if (i == dir->dir_len)
637                 goto out;
638         d = &dir->dir_tab[i];
639
640         /* If the it is not there, just fake it; some docs don't have it */
641         if (d->d_stream_first_sector < 0)
642                 goto out;
643
644         return  cdf_read_long_sector_chain(info, h, sat,
645             d->d_stream_first_sector, d->d_size, scn);
646 out:
647         scn->sst_tab = NULL;
648         scn->sst_len = 0;
649         scn->sst_dirlen = 0;
650         return 0;
651 }
652
653 static int
654 cdf_namecmp(const char *d, const uint16_t *s, size_t l)
655 {
656         for (; l--; d++, s++)
657                 if (*d != CDF_TOLE2(*s))
658                         return (unsigned char)*d - CDF_TOLE2(*s);
659         return 0;
660 }
661
662 int
663 cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
664     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
665     const cdf_dir_t *dir, cdf_stream_t *scn)
666 {
667         size_t i;
668         const cdf_directory_t *d;
669         static const char name[] = "\05SummaryInformation";
670
671         for (i = 0; i < dir->dir_len; i++)
672                 if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_USER_STREAM &&
673                     cdf_namecmp(name, dir->dir_tab[i].d_name, sizeof(name))
674                     == 0)
675                         break;
676
677         if (i == dir->dir_len) {
678                 DPRINTF(("Cannot find summary information section\n"));
679                 errno = EFTYPE;
680                 return -1;
681         }
682         d = &dir->dir_tab[i];
683         return cdf_read_sector_chain(info, h, sat, ssat, sst,
684             d->d_stream_first_sector, d->d_size, scn);
685 }
686
687 int
688 cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
689     cdf_property_info_t **info, size_t *count, size_t *maxcount)
690 {
691         const cdf_section_header_t *shp;
692         cdf_section_header_t sh;
693         const uint32_t *p, *q, *e;
694         int16_t s16;
695         int32_t s32;
696         uint32_t u32;
697         int64_t s64;
698         uint64_t u64;
699         cdf_timestamp_t tp;
700         size_t i, o, nelements, j;
701         cdf_property_info_t *inp;
702
703         if (offs > UINT32_MAX / 4) {
704                 errno = EFTYPE;
705                 goto out;
706         }
707         shp = (const void *)((const char *)sst->sst_tab + offs);
708         if (cdf_check_stream_offset(sst, shp, sizeof(*shp)) == -1)
709                 goto out;
710         sh.sh_len = CDF_TOLE4(shp->sh_len);
711 #define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
712         if (sh.sh_len > CDF_SHLEN_LIMIT) {
713                 errno = EFTYPE;
714                 goto out;
715         }
716         sh.sh_properties = CDF_TOLE4(shp->sh_properties);
717 #define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
718         if (sh.sh_properties > CDF_PROP_LIMIT)
719                 goto out;
720         DPRINTF(("section len: %u properties %u\n", sh.sh_len,
721             sh.sh_properties));
722         if (*maxcount) {
723                 if (*maxcount > CDF_PROP_LIMIT)
724                         goto out;
725                 *maxcount += sh.sh_properties;
726                 inp = realloc(*info, *maxcount * sizeof(*inp));
727         } else {
728                 *maxcount = sh.sh_properties;
729                 inp = malloc(*maxcount * sizeof(*inp));
730         }
731         if (inp == NULL)
732                 goto out;
733         *info = inp;
734         inp += *count;
735         *count += sh.sh_properties;
736         p = (const void *)((const char *)sst->sst_tab + offs + sizeof(sh));
737         e = (const void *)(((const char *)shp) + sh.sh_len);
738         if (cdf_check_stream_offset(sst, e, 0) == -1)
739                 goto out;
740         for (i = 0; i < sh.sh_properties; i++) {
741                 q = (const uint32_t *)((const char *)p +
742                     CDF_TOLE4(p[(i << 1) + 1])) - 2;
743                 if (q > e) {
744                         DPRINTF(("Ran of the end %p > %p\n", q, e));
745                         goto out;
746                 }
747                 inp[i].pi_id = CDF_TOLE4(p[i << 1]);
748                 inp[i].pi_type = CDF_TOLE4(q[0]);
749                 DPRINTF(("%d) id=%x type=%x offs=%x\n", i, inp[i].pi_id,
750                     inp[i].pi_type, (const char *)q - (const char *)p));
751                 if (inp[i].pi_type & CDF_VECTOR) {
752                         nelements = CDF_TOLE4(q[1]);
753                         o = 2;
754                 } else {
755                         nelements = 1;
756                         o = 1;
757                 }
758                 if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
759                         goto unknown;
760                 switch (inp[i].pi_type & CDF_TYPEMASK) {
761                 case CDF_EMPTY:
762                         break;
763                 case CDF_SIGNED16:
764                         if (inp[i].pi_type & CDF_VECTOR)
765                                 goto unknown;
766                         (void)memcpy(&s16, &q[o], sizeof(s16));
767                         inp[i].pi_s16 = CDF_TOLE2(s16);
768                         break;
769                 case CDF_SIGNED32:
770                         if (inp[i].pi_type & CDF_VECTOR)
771                                 goto unknown;
772                         (void)memcpy(&s32, &q[o], sizeof(s32));
773                         inp[i].pi_s32 = CDF_TOLE4(s32);
774                         break;
775                 case CDF_BOOL:
776                 case CDF_UNSIGNED32:
777                         if (inp[i].pi_type & CDF_VECTOR)
778                                 goto unknown;
779                         (void)memcpy(&u32, &q[o], sizeof(u32));
780                         inp[i].pi_u32 = CDF_TOLE4(u32);
781                         break;
782                 case CDF_SIGNED64:
783                         if (inp[i].pi_type & CDF_VECTOR)
784                                 goto unknown;
785                         (void)memcpy(&s64, &q[o], sizeof(s64));
786                         inp[i].pi_s64 = CDF_TOLE4(s64);
787                         break;
788                 case CDF_UNSIGNED64:
789                         if (inp[i].pi_type & CDF_VECTOR)
790                                 goto unknown;
791                         (void)memcpy(&u64, &q[o], sizeof(u64));
792                         inp[i].pi_u64 = CDF_TOLE4(u64);
793                         break;
794                 case CDF_LENGTH32_STRING:
795                         if (nelements > 1) {
796                                 size_t nelem = inp - *info;
797                                 if (*maxcount > CDF_PROP_LIMIT
798                                     || nelements > CDF_PROP_LIMIT)
799                                         goto out;
800                                 *maxcount += nelements;
801                                 inp = realloc(*info, *maxcount * sizeof(*inp));
802                                 if (inp == NULL)
803                                         goto out;
804                                 *info = inp;
805                                 inp = *info + nelem;
806                         }
807                         DPRINTF(("nelements = %d\n", nelements));
808                         for (j = 0; j < nelements; j++, i++) {
809                                 uint32_t l = CDF_TOLE4(q[o]);
810                                 inp[i].pi_str.s_len = l;
811                                 inp[i].pi_str.s_buf = (const char *)(&q[o+1]);
812                                 DPRINTF(("l = %d, r = %d, s = %s\n", l,
813                                     CDF_ROUND(l, sizeof(l)),
814                                     inp[i].pi_str.s_buf));
815                                 l = 4 + CDF_ROUND(l, sizeof(l));
816                                 o += l >> 2;
817                         }
818                         i--;
819                         break;
820                 case CDF_FILETIME:
821                         if (inp[i].pi_type & CDF_VECTOR)
822                                 goto unknown;
823                         (void)memcpy(&tp, &q[o], sizeof(tp));
824                         inp[i].pi_tp = CDF_TOLE8(tp);
825                         break;
826                 case CDF_CLIPBOARD:
827                         if (inp[i].pi_type & CDF_VECTOR)
828                                 goto unknown;
829                         break;
830                 default:
831                 unknown:
832                         DPRINTF(("Don't know how to deal with %x\n",
833                             inp[i].pi_type));
834                         goto out;
835                 }
836         }
837         return 0;
838 out:
839         free(*info);
840         return -1;
841 }
842
843 int
844 cdf_unpack_summary_info(const cdf_stream_t *sst, cdf_summary_info_header_t *ssi,
845     cdf_property_info_t **info, size_t *count)
846 {
847         size_t i, maxcount;
848         const cdf_summary_info_header_t *si = sst->sst_tab;
849         const cdf_section_declaration_t *sd = (const void *)
850             ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET);
851
852         if (cdf_check_stream_offset(sst, si, sizeof(*si)) == -1 ||
853             cdf_check_stream_offset(sst, sd, sizeof(*sd)) == -1)
854                 return -1;
855         ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
856         ssi->si_os_version = CDF_TOLE2(si->si_os_version);
857         ssi->si_os = CDF_TOLE2(si->si_os);
858         ssi->si_class = si->si_class;
859         cdf_swap_class(&ssi->si_class);
860         ssi->si_count = CDF_TOLE2(si->si_count);
861         *count = 0;
862         maxcount = 0;
863         *info = NULL;
864         for (i = 0; i < CDF_TOLE4(si->si_count); i++) {
865                 if (i >= CDF_LOOP_LIMIT) {
866                         DPRINTF(("Unpack summary info loop limit"));
867                         errno = EFTYPE;
868                         return -1;
869                 }
870                 if (cdf_read_property_info(sst, CDF_TOLE4(sd->sd_offset),
871                     info, count, &maxcount) == -1)
872                         return -1;
873         }
874         return 0;
875 }
876
877
878
879 int
880 cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
881 {
882         return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
883             "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
884             id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
885             id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
886             id->cl_six[5]);
887 }
888
889 static const struct {
890         uint32_t v;
891         const char *n;
892 } vn[] = {
893         { CDF_PROPERTY_CODE_PAGE, "Code page" },
894         { CDF_PROPERTY_TITLE, "Title" },
895         { CDF_PROPERTY_SUBJECT, "Subject" },
896         { CDF_PROPERTY_AUTHOR, "Author" },
897         { CDF_PROPERTY_KEYWORDS, "Keywords" },
898         { CDF_PROPERTY_COMMENTS, "Comments" },
899         { CDF_PROPERTY_TEMPLATE, "Template" },
900         { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
901         { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
902         { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
903         { CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
904         { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
905         { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
906         { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
907         { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
908         { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
909         { CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
910         { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
911         { CDF_PROPERTY_SECURITY, "Security" },
912         { CDF_PROPERTY_LOCALE_ID, "Locale ID" },
913 };
914
915 int
916 cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
917 {
918         size_t i;
919
920         for (i = 0; i < __arraycount(vn); i++)
921                 if (vn[i].v == p)
922                         return snprintf(buf, bufsiz, "%s", vn[i].n);
923         return snprintf(buf, bufsiz, "0x%x", p);
924 }
925
926 int
927 cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
928 {
929         size_t len = 0;
930         int days, hours, mins, secs;
931
932         ts /= CDF_TIME_PREC;
933         secs = ts % 60;
934         ts /= 60;
935         mins = ts % 60;
936         ts /= 60;
937         hours = ts % 24;
938         ts /= 24;
939         days = ts;
940
941         if (days) {
942                 len += snprintf(buf + len, bufsiz - len, "%dd+", days);
943                 if (len >= bufsiz)
944                         return len;
945         }
946
947         if (days || hours) {
948                 len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
949                 if (len >= bufsiz)
950                         return len;
951         }
952
953         len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
954         if (len >= bufsiz)
955                 return len;
956
957         len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
958         return len;
959 }
960
961
962 #ifdef CDF_DEBUG
963 void
964 cdf_dump_header(const cdf_header_t *h)
965 {
966         size_t i;
967
968 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
969 #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
970     h->h_ ## b, 1 << h->h_ ## b)
971         DUMP("%d", revision);
972         DUMP("%d", version);
973         DUMP("0x%x", byte_order);
974         DUMP2("%d", sec_size_p2);
975         DUMP2("%d", short_sec_size_p2);
976         DUMP("%d", num_sectors_in_sat);
977         DUMP("%d", secid_first_directory);
978         DUMP("%d", min_size_standard_stream);
979         DUMP("%d", secid_first_sector_in_short_sat);
980         DUMP("%d", num_sectors_in_short_sat);
981         DUMP("%d", secid_first_sector_in_master_sat);
982         DUMP("%d", num_sectors_in_master_sat);
983         for (i = 0; i < __arraycount(h->h_master_sat); i++) {
984                 if (h->h_master_sat[i] == CDF_SECID_FREE)
985                         break;
986                 (void)fprintf(stderr, "%35.35s[%.3zu] = %d\n",
987                     "master_sat", i, h->h_master_sat[i]);
988         }
989 }
990
991 void
992 cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
993 {
994         size_t i, j, s = size / sizeof(cdf_secid_t);
995
996         for (i = 0; i < sat->sat_len; i++) {
997                 (void)fprintf(stderr, "%s[%zu]:\n%.6d: ", prefix, i, i * s);
998                 for (j = 0; j < s; j++) {
999                         (void)fprintf(stderr, "%5d, ",
1000                             CDF_TOLE4(sat->sat_tab[s * i + j]));
1001                         if ((j + 1) % 10 == 0)
1002                                 (void)fprintf(stderr, "\n%.6d: ",
1003                                     i * s + j + 1);
1004                 }
1005                 (void)fprintf(stderr, "\n");
1006         }
1007 }
1008
1009 void
1010 cdf_dump(void *v, size_t len)
1011 {
1012         size_t i, j;
1013         unsigned char *p = v;
1014         char abuf[16];
1015         (void)fprintf(stderr, "%.4x: ", 0);
1016         for (i = 0, j = 0; i < len; i++, p++) {
1017                 (void)fprintf(stderr, "%.2x ", *p);
1018                 abuf[j++] = isprint(*p) ? *p : '.';
1019                 if (j == 16) {
1020                         j = 0;
1021                         abuf[15] = '\0';
1022                         (void)fprintf(stderr, "%s\n%.4x: ", abuf, i + 1);
1023                 }
1024         }
1025         (void)fprintf(stderr, "\n");
1026 }
1027
1028 void
1029 cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
1030 {
1031         size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
1032             CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
1033         cdf_dump(sst->sst_tab, ss * sst->sst_len);
1034 }
1035
1036 void
1037 cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
1038     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
1039     const cdf_dir_t *dir)
1040 {
1041         size_t i, j;
1042         cdf_directory_t *d;
1043         char name[__arraycount(d->d_name)];
1044         cdf_stream_t scn;
1045         struct timespec ts;
1046
1047         static const char *types[] = { "empty", "user storage",
1048             "user stream", "lockbytes", "property", "root storage" };
1049
1050         for (i = 0; i < dir->dir_len; i++) {
1051                 d = &dir->dir_tab[i];
1052                 for (j = 0; j < sizeof(name); j++)
1053                         name[j] = (char)CDF_TOLE2(d->d_name[j]);
1054                 (void)fprintf(stderr, "Directory %zu: %s\n", i, name);
1055                 if (d->d_type < __arraycount(types))
1056                         (void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
1057                 else
1058                         (void)fprintf(stderr, "Type: %d\n", d->d_type);
1059                 (void)fprintf(stderr, "Color: %s\n",
1060                     d->d_color ? "black" : "red");
1061                 (void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
1062                 (void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
1063                 (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags);
1064                 cdf_timestamp_to_timespec(&ts, d->d_created);
1065                 (void)fprintf(stderr, "Created %s", ctime(&ts.tv_sec));
1066                 cdf_timestamp_to_timespec(&ts, d->d_modified);
1067                 (void)fprintf(stderr, "Modified %s", ctime(&ts.tv_sec));
1068                 (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
1069                 (void)fprintf(stderr, "Size %d\n", d->d_size);
1070                 switch (d->d_type) {
1071                 case CDF_DIR_TYPE_USER_STORAGE:
1072                         (void)fprintf(stderr, "Storage: %d\n", d->d_storage);
1073                         break;
1074                 case CDF_DIR_TYPE_USER_STREAM:
1075                         if (sst == NULL)
1076                                 break;
1077                         if (cdf_read_sector_chain(info, h, sat, ssat, sst,
1078                             d->d_stream_first_sector, d->d_size, &scn) == -1) {
1079                                 warn("Can't read stream for %s at %d len %d",
1080                                     name, d->d_stream_first_sector, d->d_size);
1081                                 break;
1082                         }
1083                         cdf_dump_stream(h, &scn);
1084                         free(scn.sst_tab);
1085                         break;
1086                 default:
1087                         break;
1088                 }
1089                         
1090         }
1091 }
1092
1093 void
1094 cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
1095 {
1096         cdf_timestamp_t tp;
1097         struct timespec ts;
1098         char buf[64];
1099         size_t i;
1100
1101         for (i = 0; i < count; i++) {
1102                 cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
1103                 (void)fprintf(stderr, "%zu) %s: ", i, buf); 
1104                 switch (info[i].pi_type) {
1105                 case CDF_SIGNED16:
1106                         (void)fprintf(stderr, "signed 16 [%hd]\n",
1107                             info[i].pi_s16);
1108                         break;
1109                 case CDF_SIGNED32:
1110                         (void)fprintf(stderr, "signed 32 [%d]\n",
1111                             info[i].pi_s32);
1112                         break;
1113                 case CDF_UNSIGNED32:
1114                         (void)fprintf(stderr, "unsigned 32 [%u]\n",
1115                             info[i].pi_u32);
1116                         break;
1117                 case CDF_LENGTH32_STRING:
1118                         (void)fprintf(stderr, "string %u [%.*s]\n",
1119                             info[i].pi_str.s_len,
1120                             info[i].pi_str.s_len, info[i].pi_str.s_buf);
1121                         break;
1122                 case CDF_FILETIME:
1123                         tp = info[i].pi_tp;
1124                         if (tp < 1000000000000000LL) {
1125                                 cdf_print_elapsed_time(buf, sizeof(buf), tp);
1126                                 (void)fprintf(stderr, "timestamp %s\n", buf);
1127                         } else {
1128                                 cdf_timestamp_to_timespec(&ts, tp);
1129                                 (void)fprintf(stderr, "timestamp %s",
1130                                     ctime(&ts.tv_sec));
1131                         }
1132                         break;
1133                 case CDF_CLIPBOARD:
1134                         (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
1135                         break;
1136                 default:
1137                         DPRINTF(("Don't know how to deal with %x\n",
1138                             info[i].pi_type));
1139                         break;
1140                 }
1141         }
1142 }
1143
1144
1145 void
1146 cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
1147 {
1148         char buf[128];
1149         cdf_summary_info_header_t ssi;
1150         cdf_property_info_t *info;
1151         size_t count;
1152
1153         (void)&h;
1154         if (cdf_unpack_summary_info(sst, &ssi, &info, &count) == -1)
1155                 return;
1156         (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
1157         (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
1158                 ssi.si_os_version >> 8);
1159         (void)fprintf(stderr, "Os %d\n", ssi.si_os);
1160         cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
1161         (void)fprintf(stderr, "Class %s\n", buf);
1162         (void)fprintf(stderr, "Count %d\n", ssi.si_count);
1163         cdf_dump_property_info(info, count);
1164         free(info);
1165 }
1166
1167 #endif
1168
1169 #ifdef TEST
1170 int
1171 main(int argc, char *argv[])
1172 {
1173         int i;
1174         cdf_header_t h;
1175         cdf_sat_t sat, ssat;
1176         cdf_stream_t sst, scn;
1177         cdf_dir_t dir;
1178         cdf_info_t info;
1179
1180         if (argc < 2) {
1181                 (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
1182                 return -1;
1183         }
1184
1185         info.i_buf = NULL;
1186         info.i_len = 0;
1187         for (i = 1; i < argc; i++) {
1188                 if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
1189                         err(1, "Cannot open `%s'", argv[1]);
1190
1191                 if (cdf_read_header(&info, &h) == -1)
1192                         err(1, "Cannot read header");
1193 #ifdef CDF_DEBUG
1194                 cdf_dump_header(&h);
1195 #endif
1196
1197                 if (cdf_read_sat(&info, &h, &sat) == -1)
1198                         err(1, "Cannot read sat");
1199 #ifdef CDF_DEBUG
1200                 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
1201 #endif
1202
1203                 if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
1204                         err(1, "Cannot read ssat");
1205 #ifdef CDF_DEBUG
1206                 cdf_dump_sat("SSAT", &h, &ssat, CDF_SHORT_SEC_SIZE(&h));
1207 #endif
1208
1209                 if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
1210                         err(1, "Cannot read dir");
1211
1212                 if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
1213                         err(1, "Cannot read short stream");
1214 #ifdef CDF_DEBUG
1215                 cdf_dump_stream(&h, &sst);
1216 #endif
1217
1218 #ifdef CDF_DEBUG
1219                 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
1220 #endif
1221
1222
1223                 if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
1224                     &scn) == -1)
1225                         err(1, "Cannot read summary info");
1226 #ifdef CDF_DEBUG
1227                 cdf_dump_summary_info(&h, &scn);
1228 #endif
1229
1230                 (void)close(info.i_fd);
1231         }
1232
1233         return 0;
1234 }
1235 #endif