Back to index

php5  5.3.10
cdf.c
Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 2008 Christos Zoulas
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  *
00014  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
00015  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00016  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00017  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
00018  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00019  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00020  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00021  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00022  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00023  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00024  * POSSIBILITY OF SUCH DAMAGE.
00025  */
00026 /*
00027  * Parse composite document files, the format used in Microsoft Office
00028  * document files before they switched to zipped xml.
00029  * Info from: http://sc.openoffice.org/compdocfileformat.pdf
00030  */
00031 
00032 #include "file.h"
00033 
00034 #ifndef lint
00035 FILE_RCSID("@(#)$File: cdf.c,v 1.30 2009/05/06 14:29:47 christos Exp $")
00036 #endif
00037 
00038 #include <assert.h>
00039 #ifdef CDF_DEBUG
00040 #include <err.h>
00041 #endif
00042 #include <stdlib.h>
00043 
00044 #ifdef PHP_WIN32
00045 #include "win32/unistd.h"
00046 #else
00047 #include <unistd.h>
00048 #endif
00049 
00050 #ifndef UINT32_MAX
00051 # define UINT32_MAX (0xffffffff)
00052 #endif
00053 
00054 #include <string.h>
00055 #include <time.h>
00056 #include <ctype.h>
00057 
00058 #ifndef EFTYPE
00059 #define EFTYPE EINVAL
00060 #endif
00061 
00062 #include "cdf.h"
00063 
00064 #ifndef __arraycount
00065 #define __arraycount(a) (sizeof(a) / sizeof(a[0]))
00066 #endif
00067 
00068 #ifdef CDF_DEBUG
00069 #define DPRINTF(a) printf a, fflush(stdout)
00070 #else
00071 #define DPRINTF(a)
00072 #endif
00073 
00074 static union {
00075        char s[4];
00076        uint32_t u;
00077 } cdf_bo;
00078 
00079 #define NEED_SWAP    (cdf_bo.u == (uint32_t)0x01020304)
00080 
00081 #define CDF_TOLE8(x) (NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x))
00082 #define CDF_TOLE4(x) (NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x))
00083 #define CDF_TOLE2(x) (NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x))
00084 
00085 /*
00086  * swap a short
00087  */
00088 uint16_t
00089 cdf_tole2(uint16_t sv)
00090 {
00091        uint16_t rv;
00092        uint8_t *s = (uint8_t *)(void *)&sv; 
00093        uint8_t *d = (uint8_t *)(void *)&rv; 
00094        d[0] = s[1];
00095        d[1] = s[0];
00096        return rv;
00097 }
00098 
00099 /*
00100  * swap an int
00101  */
00102 uint32_t
00103 cdf_tole4(uint32_t sv)
00104 {
00105        uint32_t rv;
00106        uint8_t *s = (uint8_t *)(void *)&sv; 
00107        uint8_t *d = (uint8_t *)(void *)&rv; 
00108        d[0] = s[3];
00109        d[1] = s[2];
00110        d[2] = s[1];
00111        d[3] = s[0];
00112        return rv;
00113 }
00114 
00115 /*
00116  * swap a quad
00117  */
00118 uint64_t
00119 cdf_tole8(uint64_t sv)
00120 {
00121        uint64_t rv;
00122        uint8_t *s = (uint8_t *)(void *)&sv; 
00123        uint8_t *d = (uint8_t *)(void *)&rv; 
00124        d[0] = s[7];
00125        d[1] = s[6];
00126        d[2] = s[5];
00127        d[3] = s[4];
00128        d[4] = s[3];
00129        d[5] = s[2];
00130        d[6] = s[1];
00131        d[7] = s[0];
00132        return rv;
00133 }
00134 
00135 #define CDF_UNPACK(a)       \
00136     (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
00137 #define CDF_UNPACKA(a)      \
00138     (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
00139 
00140 void
00141 cdf_swap_header(cdf_header_t *h)
00142 {
00143        size_t i;
00144 
00145        h->h_magic = CDF_TOLE8(h->h_magic);
00146        h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]);
00147        h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]);
00148        h->h_revision = CDF_TOLE2(h->h_revision);
00149        h->h_version = CDF_TOLE2(h->h_version);
00150        h->h_byte_order = CDF_TOLE2(h->h_byte_order);
00151        h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2);
00152        h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2);
00153        h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat);
00154        h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory);
00155        h->h_min_size_standard_stream =
00156            CDF_TOLE4(h->h_min_size_standard_stream);
00157        h->h_secid_first_sector_in_short_sat =
00158            CDF_TOLE4(h->h_secid_first_sector_in_short_sat);
00159        h->h_num_sectors_in_short_sat =
00160            CDF_TOLE4(h->h_num_sectors_in_short_sat);
00161        h->h_secid_first_sector_in_master_sat =
00162            CDF_TOLE4(h->h_secid_first_sector_in_master_sat);
00163        h->h_num_sectors_in_master_sat =
00164            CDF_TOLE4(h->h_num_sectors_in_master_sat);
00165        for (i = 0; i < __arraycount(h->h_master_sat); i++)
00166               h->h_master_sat[i] = CDF_TOLE4(h->h_master_sat[i]);
00167 }
00168 
00169 void
00170 cdf_unpack_header(cdf_header_t *h, char *buf)
00171 {
00172        size_t i;
00173        size_t len = 0;
00174 
00175        CDF_UNPACK(h->h_magic);
00176        CDF_UNPACKA(h->h_uuid);
00177        CDF_UNPACK(h->h_revision);
00178        CDF_UNPACK(h->h_version);
00179        CDF_UNPACK(h->h_byte_order);
00180        CDF_UNPACK(h->h_sec_size_p2);
00181        CDF_UNPACK(h->h_short_sec_size_p2);
00182        CDF_UNPACKA(h->h_unused0);
00183        CDF_UNPACK(h->h_num_sectors_in_sat);
00184        CDF_UNPACK(h->h_secid_first_directory);
00185        CDF_UNPACKA(h->h_unused1);
00186        CDF_UNPACK(h->h_min_size_standard_stream);
00187        CDF_UNPACK(h->h_secid_first_sector_in_short_sat);
00188        CDF_UNPACK(h->h_num_sectors_in_short_sat);
00189        CDF_UNPACK(h->h_secid_first_sector_in_master_sat);
00190        CDF_UNPACK(h->h_num_sectors_in_master_sat);
00191        for (i = 0; i < __arraycount(h->h_master_sat); i++)
00192               CDF_UNPACK(h->h_master_sat[i]);
00193 }
00194 
00195 void
00196 cdf_swap_dir(cdf_directory_t *d)
00197 {
00198        d->d_namelen = CDF_TOLE2(d->d_namelen);
00199        d->d_left_child = CDF_TOLE4(d->d_left_child);
00200        d->d_right_child = CDF_TOLE4(d->d_right_child);
00201        d->d_storage = CDF_TOLE4(d->d_storage);
00202        d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]);
00203        d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]);
00204        d->d_flags = CDF_TOLE4(d->d_flags);
00205        d->d_created = CDF_TOLE8(d->d_created);
00206        d->d_modified = CDF_TOLE8(d->d_modified);
00207        d->d_stream_first_sector = CDF_TOLE4(d->d_stream_first_sector);
00208        d->d_size = CDF_TOLE4(d->d_size);
00209 }
00210 
00211 void
00212 cdf_swap_class(cdf_classid_t *d)
00213 {
00214        d->cl_dword = CDF_TOLE4(d->cl_dword);
00215        d->cl_word[0] = CDF_TOLE2(d->cl_word[0]);
00216        d->cl_word[1] = CDF_TOLE2(d->cl_word[1]);
00217 }
00218 
00219 void
00220 cdf_unpack_dir(cdf_directory_t *d, char *buf)
00221 {
00222        size_t len = 0;
00223 
00224        CDF_UNPACKA(d->d_name);
00225        CDF_UNPACK(d->d_namelen);
00226        CDF_UNPACK(d->d_type);
00227        CDF_UNPACK(d->d_color);
00228        CDF_UNPACK(d->d_left_child);
00229        CDF_UNPACK(d->d_right_child);
00230        CDF_UNPACK(d->d_storage);
00231        CDF_UNPACKA(d->d_storage_uuid);
00232        CDF_UNPACK(d->d_flags);
00233        CDF_UNPACK(d->d_created);
00234        CDF_UNPACK(d->d_modified);
00235        CDF_UNPACK(d->d_stream_first_sector);
00236        CDF_UNPACK(d->d_size);
00237        CDF_UNPACK(d->d_unused0);
00238 }
00239 
00240 static int
00241 cdf_check_stream_offset(const cdf_stream_t *sst, const void *p, size_t tail)
00242 {
00243        const char *b = (const char *)sst->sst_tab;
00244        const char *e = ((const char *)p) + tail;
00245        if (e >= b && (size_t)(e - b) < sst->sst_dirlen * sst->sst_len)
00246               return 0;
00247        DPRINTF((stderr, "offset begin %p end %p %zu >= %zu\n", b, e,
00248            (size_t)(e - b), sst->sst_dirlen * sst->sst_len));
00249        errno = EFTYPE;
00250        return -1;
00251 }
00252 
00253 static ssize_t
00254 cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
00255 {
00256        size_t siz = (size_t)off + len;
00257 
00258        if ((off_t)(off + len) != (off_t)siz) {
00259               errno = EINVAL;
00260               return -1;
00261        }
00262 
00263        if (info->i_buf != NULL && info->i_len >= siz) {
00264               (void)memcpy(buf, &info->i_buf[off], len);
00265               return (ssize_t)len;
00266        }
00267 
00268        if (info->i_fd == -1)
00269               return -1;
00270 
00271        if (lseek(info->i_fd, off, SEEK_SET) == (off_t)-1)
00272               return -1;
00273 
00274        if (read(info->i_fd, buf, len) != (ssize_t)len)
00275               return -1;
00276 
00277        return (ssize_t)len;
00278 }
00279 
00280 int
00281 cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
00282 {
00283        char buf[512];
00284 
00285        (void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
00286        if (cdf_read(info, (off_t)0, buf, sizeof(buf)) == -1)
00287               return -1;
00288        cdf_unpack_header(h, buf);
00289        cdf_swap_header(h);
00290        if (h->h_magic != CDF_MAGIC) {
00291               DPRINTF(("Bad magic 0x%llx != 0x%llx\n",
00292                   (unsigned long long)h->h_magic,
00293                   (unsigned long long)CDF_MAGIC));
00294               goto out;
00295        }
00296        if (h->h_sec_size_p2 > 20) {
00297               DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
00298               goto out;
00299        }
00300        if (h->h_short_sec_size_p2 > 20) {
00301               DPRINTF(("Bad short sector size 0x%u\n",
00302                   h->h_short_sec_size_p2));
00303               goto out;
00304        }
00305        return 0;
00306 out:
00307        errno = EFTYPE;
00308        return -1;
00309 }
00310 
00311 
00312 ssize_t
00313 cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
00314     const cdf_header_t *h, cdf_secid_t id)
00315 {
00316        assert((size_t)CDF_SEC_SIZE(h) == len);
00317        return cdf_read(info, (off_t)CDF_SEC_POS(h, id),
00318            ((char *)buf) + offs, len);
00319 }
00320 
00321 ssize_t
00322 cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
00323     size_t len, const cdf_header_t *h, cdf_secid_t id)
00324 {
00325        assert((size_t)CDF_SHORT_SEC_SIZE(h) == len);
00326        (void)memcpy(((char *)buf) + offs,
00327            ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len);
00328        return len;
00329 }
00330 
00331 /*
00332  * Read the sector allocation table.
00333  */
00334 int
00335 cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
00336 {
00337        size_t i, j, k;
00338        size_t ss = CDF_SEC_SIZE(h);
00339        cdf_secid_t *msa, mid, sec;
00340        size_t nsatpersec = (ss / sizeof(mid)) - 1;
00341 
00342        for (i = 0; i < __arraycount(h->h_master_sat); i++)
00343               if (h->h_master_sat[i] == CDF_SECID_FREE)
00344                      break;
00345 
00346 #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
00347        if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec ||
00348            i > CDF_SEC_LIMIT) {
00349               DPRINTF(("Number of sectors in master SAT too big %u %zu\n",
00350                   h->h_num_sectors_in_master_sat, i));
00351               errno = EFTYPE;
00352               return -1;
00353        }
00354 
00355        sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
00356        DPRINTF(("sat_len = %zu ss = %zu\n", sat->sat_len, ss));
00357        if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL)
00358               return -1;
00359 
00360        for (i = 0; i < __arraycount(h->h_master_sat); i++) {
00361               if (h->h_master_sat[i] < 0)
00362                      break;
00363               if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
00364                   h->h_master_sat[i]) != (ssize_t)ss) {
00365                      DPRINTF(("Reading sector %d", h->h_master_sat[i]));
00366                      goto out1;
00367               }
00368        }
00369 
00370        if ((msa = calloc(1, ss)) == NULL)
00371               goto out1;
00372 
00373        mid = h->h_secid_first_sector_in_master_sat;
00374        for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
00375               if (mid < 0)
00376                      goto out;
00377               if (j >= CDF_LOOP_LIMIT) {
00378                      DPRINTF(("Reading master sector loop limit"));
00379                      errno = EFTYPE;
00380                      goto out2;
00381               }
00382               if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
00383                      DPRINTF(("Reading master sector %d", mid));
00384                      goto out2;
00385               }
00386               for (k = 0; k < nsatpersec; k++, i++) {
00387                      sec = CDF_TOLE4(msa[k]);
00388                      if (sec < 0)
00389                             goto out;
00390                      if (i >= sat->sat_len) {
00391                          DPRINTF(("Out of bounds reading MSA %u >= %u",
00392                             i, sat->sat_len));
00393                          errno = EFTYPE;
00394                          goto out2;
00395                      }
00396                      if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
00397                          sec) != (ssize_t)ss) {
00398                             DPRINTF(("Reading sector %d",
00399                                 CDF_TOLE4(msa[k])));
00400                             goto out2;
00401                      }
00402               }
00403               mid = CDF_TOLE4(msa[nsatpersec]);
00404        }
00405 out:
00406        sat->sat_len = i;
00407        free(msa);
00408        return 0;
00409 out2:
00410        free(msa);
00411 out1:
00412        free(sat->sat_tab);
00413        return -1;
00414 }
00415 
00416 size_t
00417 cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
00418 {
00419        size_t i, j;
00420        cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * size);
00421 
00422        DPRINTF(("Chain:"));
00423        for (j = i = 0; sid >= 0; i++, j++) {
00424               DPRINTF((" %d", sid));
00425               if (j >= CDF_LOOP_LIMIT) {
00426                      DPRINTF(("Counting chain loop limit"));
00427                      errno = EFTYPE;
00428                      return (size_t)-1;
00429               }
00430               if (sid > maxsector) {
00431                      DPRINTF(("Sector %d > %d\n", sid, maxsector));
00432                      errno = EFTYPE;
00433                      return (size_t)-1;
00434               }
00435               sid = CDF_TOLE4(sat->sat_tab[sid]);
00436        }
00437        DPRINTF(("\n"));
00438        return i;
00439 }
00440 
00441 int
00442 cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
00443     const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn)
00444 {
00445        size_t ss = CDF_SEC_SIZE(h), i, j;
00446        ssize_t nr;
00447        scn->sst_len = cdf_count_chain(sat, sid, ss);
00448        scn->sst_dirlen = len;
00449 
00450        if (scn->sst_len == (size_t)-1)
00451               return -1;
00452 
00453        scn->sst_tab = calloc(scn->sst_len, ss);
00454        if (scn->sst_tab == NULL)
00455               return -1;
00456 
00457        for (j = i = 0; sid >= 0; i++, j++) {
00458               if (j >= CDF_LOOP_LIMIT) {
00459                      DPRINTF(("Read long sector chain loop limit"));
00460                      errno = EFTYPE;
00461                      goto out;
00462               }
00463               if (i >= scn->sst_len) {
00464                      DPRINTF(("Out of bounds reading long sector chain "
00465                          "%u > %u\n", i, scn->sst_len));
00466                      errno = EFTYPE;
00467                      goto out;
00468               }
00469               if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
00470                   sid)) != (ssize_t)ss) {
00471                      if (i == scn->sst_len - 1 && nr > 0) {
00472                             /* Last sector might be truncated */
00473                             return 0;
00474                      }
00475                      DPRINTF(("Reading long sector chain %d", sid));
00476                      goto out;
00477               }
00478               sid = CDF_TOLE4(sat->sat_tab[sid]);
00479        }
00480        return 0;
00481 out:
00482        free(scn->sst_tab);
00483        return -1;
00484 }
00485 
00486 int
00487 cdf_read_short_sector_chain(const cdf_header_t *h,
00488     const cdf_sat_t *ssat, const cdf_stream_t *sst,
00489     cdf_secid_t sid, size_t len, cdf_stream_t *scn)
00490 {
00491        size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
00492        scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
00493        scn->sst_dirlen = len;
00494 
00495        if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
00496               return -1;
00497 
00498        scn->sst_tab = calloc(scn->sst_len, ss);
00499        if (scn->sst_tab == NULL)
00500               return -1;
00501 
00502        for (j = i = 0; sid >= 0; i++, j++) {
00503               if (j >= CDF_LOOP_LIMIT) {
00504                      DPRINTF(("Read short sector chain loop limit"));
00505                      errno = EFTYPE;
00506                      goto out;
00507               }
00508               if (i >= scn->sst_len) {
00509                      DPRINTF(("Out of bounds reading short sector chain "
00510                          "%u > %u\n", i, scn->sst_len));
00511                      errno = EFTYPE;
00512                      goto out;
00513               }
00514               if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
00515                   sid) != (ssize_t)ss) {
00516                      DPRINTF(("Reading short sector chain %d", sid));
00517                      goto out;
00518               }
00519               sid = CDF_TOLE4(ssat->sat_tab[sid]);
00520        }
00521        return 0;
00522 out:
00523        free(scn->sst_tab);
00524        return -1;
00525 }
00526 
00527 int
00528 cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
00529     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
00530     cdf_secid_t sid, size_t len, cdf_stream_t *scn)
00531 {
00532 
00533        if (len < h->h_min_size_standard_stream)
00534               return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
00535                   scn);
00536        else
00537               return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
00538 }
00539 
00540 int
00541 cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
00542     const cdf_sat_t *sat, cdf_dir_t *dir)
00543 {
00544        size_t i, j;
00545        size_t ss = CDF_SEC_SIZE(h), ns, nd;
00546        char *buf;
00547        cdf_secid_t sid = h->h_secid_first_directory;
00548 
00549        ns = cdf_count_chain(sat, sid, ss);
00550        if (ns == (size_t)-1)
00551               return -1;
00552 
00553        nd = ss / CDF_DIRECTORY_SIZE;
00554 
00555        dir->dir_len = ns * nd;
00556        dir->dir_tab = calloc(dir->dir_len, sizeof(dir->dir_tab[0]));
00557        if (dir->dir_tab == NULL)
00558               return -1;
00559 
00560        if ((buf = malloc(ss)) == NULL) {
00561               free(dir->dir_tab);
00562               return -1;
00563        }
00564 
00565        for (j = i = 0; i < ns; i++, j++) {
00566               if (j >= CDF_LOOP_LIMIT) {
00567                      DPRINTF(("Read dir loop limit"));
00568                      errno = EFTYPE;
00569                      goto out;
00570               }
00571               if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
00572                      DPRINTF(("Reading directory sector %d", sid));
00573                      goto out;
00574               }
00575               for (j = 0; j < nd; j++) {
00576                      cdf_unpack_dir(&dir->dir_tab[i * nd + j],
00577                          &buf[j * CDF_DIRECTORY_SIZE]);
00578               }
00579               sid = CDF_TOLE4(sat->sat_tab[sid]);
00580        }
00581        if (NEED_SWAP)
00582               for (i = 0; i < dir->dir_len; i++)
00583                      cdf_swap_dir(&dir->dir_tab[i]);
00584        free(buf);
00585        return 0;
00586 out:
00587        free(dir->dir_tab);
00588        free(buf);
00589        return -1;
00590 }
00591 
00592 
00593 int
00594 cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
00595     const cdf_sat_t *sat, cdf_sat_t *ssat)
00596 {
00597        size_t i, j;
00598        size_t ss = CDF_SEC_SIZE(h);
00599        cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
00600 
00601        ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h));
00602        if (ssat->sat_len == (size_t)-1)
00603               return -1;
00604 
00605        ssat->sat_tab = calloc(ssat->sat_len, ss);
00606        if (ssat->sat_tab == NULL)
00607               return -1;
00608 
00609        for (j = i = 0; sid >= 0; i++, j++) {
00610               if (j >= CDF_LOOP_LIMIT) {
00611                      DPRINTF(("Read short sat sector loop limit"));
00612                      errno = EFTYPE;
00613                      goto out;
00614               }
00615               if (i >= ssat->sat_len) {
00616                      DPRINTF(("Out of bounds reading short sector chain "
00617                          "%u > %u\n", i, ssat->sat_len));
00618                      errno = EFTYPE;
00619                      goto out;
00620               }
00621               if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
00622                   (ssize_t)ss) {
00623                      DPRINTF(("Reading short sat sector %d", sid));
00624                      goto out;
00625               }
00626               sid = CDF_TOLE4(sat->sat_tab[sid]);
00627        }
00628        return 0;
00629 out:
00630        free(ssat->sat_tab);
00631        return -1;
00632 }
00633 
00634 int
00635 cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
00636     const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn)
00637 {
00638        size_t i;
00639        const cdf_directory_t *d;
00640 
00641        for (i = 0; i < dir->dir_len; i++)
00642               if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
00643                      break;
00644 
00645        /* If the it is not there, just fake it; some docs don't have it */
00646        if (i == dir->dir_len)
00647               goto out;
00648        d = &dir->dir_tab[i];
00649 
00650        /* If the it is not there, just fake it; some docs don't have it */
00651        if (d->d_stream_first_sector < 0)
00652               goto out;
00653 
00654        return  cdf_read_long_sector_chain(info, h, sat,
00655            d->d_stream_first_sector, d->d_size, scn);
00656 out:
00657        scn->sst_tab = NULL;
00658        scn->sst_len = 0;
00659        scn->sst_dirlen = 0;
00660        return 0;
00661 }
00662 
00663 static int
00664 cdf_namecmp(const char *d, const uint16_t *s, size_t l)
00665 {
00666        for (; l--; d++, s++)
00667               if (*d != CDF_TOLE2(*s))
00668                      return (unsigned char)*d - CDF_TOLE2(*s);
00669        return 0;
00670 }
00671 
00672 int
00673 cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
00674     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
00675     const cdf_dir_t *dir, cdf_stream_t *scn)
00676 {
00677        size_t i;
00678        const cdf_directory_t *d;
00679        static const char name[] = "\05SummaryInformation";
00680 
00681        for (i = 0; i < dir->dir_len; i++)
00682               if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_USER_STREAM &&
00683                   cdf_namecmp(name, dir->dir_tab[i].d_name, sizeof(name))
00684                   == 0)
00685                      break;
00686 
00687        if (i == dir->dir_len) {
00688               DPRINTF(("Cannot find summary information section\n"));
00689               errno = EFTYPE;
00690               return -1;
00691        }
00692        d = &dir->dir_tab[i];
00693        return cdf_read_sector_chain(info, h, sat, ssat, sst,
00694            d->d_stream_first_sector, d->d_size, scn);
00695 }
00696 
00697 int
00698 cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
00699     cdf_property_info_t **info, size_t *count, size_t *maxcount)
00700 {
00701        const cdf_section_header_t *shp;
00702        cdf_section_header_t sh;
00703        const uint32_t *p, *q, *e;
00704        int16_t s16;
00705        int32_t s32;
00706        uint32_t u32;
00707        int64_t s64;
00708        uint64_t u64;
00709        cdf_timestamp_t tp;
00710        size_t i, o, nelements, j;
00711        cdf_property_info_t *inp;
00712 
00713        if (offs > UINT32_MAX / 4) {
00714               errno = EFTYPE;
00715               goto out;
00716        }
00717        shp = (const void *)((const char *)sst->sst_tab + offs);
00718        if (cdf_check_stream_offset(sst, shp, sizeof(*shp)) == -1)
00719               goto out;
00720        sh.sh_len = CDF_TOLE4(shp->sh_len);
00721 #define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
00722        if (sh.sh_len > CDF_SHLEN_LIMIT) {
00723               errno = EFTYPE;
00724               goto out;
00725        }
00726        sh.sh_properties = CDF_TOLE4(shp->sh_properties);
00727 #define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
00728        if (sh.sh_properties > CDF_PROP_LIMIT)
00729               goto out;
00730        DPRINTF(("section len: %u properties %u\n", sh.sh_len,
00731            sh.sh_properties));
00732        if (*maxcount) {
00733               if (*maxcount > CDF_PROP_LIMIT)
00734                      goto out;
00735               *maxcount += sh.sh_properties;
00736               inp = realloc(*info, *maxcount * sizeof(*inp));
00737        } else {
00738               *maxcount = sh.sh_properties;
00739               inp = malloc(*maxcount * sizeof(*inp));
00740        }
00741        if (inp == NULL)
00742               goto out;
00743        *info = inp;
00744        inp += *count;
00745        *count += sh.sh_properties;
00746        p = (const void *)((const char *)sst->sst_tab + offs + sizeof(sh));
00747        e = (const void *)(((const char *)shp) + sh.sh_len);
00748        if (cdf_check_stream_offset(sst, e, 0) == -1)
00749               goto out;
00750        for (i = 0; i < sh.sh_properties; i++) {
00751               q = (const uint32_t *)((const char *)p +
00752                   CDF_TOLE4(p[(i << 1) + 1])) - 2;
00753               if (q > e) {
00754                      DPRINTF(("Ran of the end %p > %p\n", q, e));
00755                      goto out;
00756               }
00757               inp[i].pi_id = CDF_TOLE4(p[i << 1]);
00758               inp[i].pi_type = CDF_TOLE4(q[0]);
00759               DPRINTF(("%d) id=%x type=%x offs=%x\n", i, inp[i].pi_id,
00760                   inp[i].pi_type, (const char *)q - (const char *)p));
00761               if (inp[i].pi_type & CDF_VECTOR) {
00762                      nelements = CDF_TOLE4(q[1]);
00763                      o = 2;
00764               } else {
00765                      nelements = 1;
00766                      o = 1;
00767               }
00768               if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
00769                      goto unknown;
00770               switch (inp[i].pi_type & CDF_TYPEMASK) {
00771               case CDF_EMPTY:
00772                      break;
00773               case CDF_SIGNED16:
00774                      if (inp[i].pi_type & CDF_VECTOR)
00775                             goto unknown;
00776                      (void)memcpy(&s16, &q[o], sizeof(s16));
00777                      inp[i].pi_s16 = CDF_TOLE2(s16);
00778                      break;
00779               case CDF_SIGNED32:
00780                      if (inp[i].pi_type & CDF_VECTOR)
00781                             goto unknown;
00782                      (void)memcpy(&s32, &q[o], sizeof(s32));
00783                      inp[i].pi_s32 = CDF_TOLE4(s32);
00784                      break;
00785               case CDF_BOOL:
00786               case CDF_UNSIGNED32:
00787                      if (inp[i].pi_type & CDF_VECTOR)
00788                             goto unknown;
00789                      (void)memcpy(&u32, &q[o], sizeof(u32));
00790                      inp[i].pi_u32 = CDF_TOLE4(u32);
00791                      break;
00792               case CDF_SIGNED64:
00793                      if (inp[i].pi_type & CDF_VECTOR)
00794                             goto unknown;
00795                      (void)memcpy(&s64, &q[o], sizeof(s64));
00796                      inp[i].pi_s64 = CDF_TOLE4(s64);
00797                      break;
00798               case CDF_UNSIGNED64:
00799                      if (inp[i].pi_type & CDF_VECTOR)
00800                             goto unknown;
00801                      (void)memcpy(&u64, &q[o], sizeof(u64));
00802                      inp[i].pi_u64 = CDF_TOLE4(u64);
00803                      break;
00804               case CDF_LENGTH32_STRING:
00805                      if (nelements > 1) {
00806                             size_t nelem = inp - *info;
00807                             if (*maxcount > CDF_PROP_LIMIT
00808                                 || nelements > CDF_PROP_LIMIT)
00809                                    goto out;
00810                             *maxcount += nelements;
00811                             inp = realloc(*info, *maxcount * sizeof(*inp));
00812                             if (inp == NULL)
00813                                    goto out;
00814                             *info = inp;
00815                             inp = *info + nelem;
00816                      }
00817                      DPRINTF(("nelements = %d\n", nelements));
00818                      for (j = 0; j < nelements; j++, i++) {
00819                             uint32_t l = CDF_TOLE4(q[o]);
00820                             inp[i].pi_str.s_len = l;
00821                             inp[i].pi_str.s_buf = (const char *)(&q[o+1]);
00822                             DPRINTF(("l = %d, r = %d, s = %s\n", l,
00823                                 CDF_ROUND(l, sizeof(l)),
00824                                 inp[i].pi_str.s_buf));
00825                             l = 4 + CDF_ROUND(l, sizeof(l));
00826                             o += l >> 2;
00827                      }
00828                      i--;
00829                      break;
00830               case CDF_FILETIME:
00831                      if (inp[i].pi_type & CDF_VECTOR)
00832                             goto unknown;
00833                      (void)memcpy(&tp, &q[o], sizeof(tp));
00834                      inp[i].pi_tp = CDF_TOLE8(tp);
00835                      break;
00836               case CDF_CLIPBOARD:
00837                      if (inp[i].pi_type & CDF_VECTOR)
00838                             goto unknown;
00839                      break;
00840               default:
00841               unknown:
00842                      DPRINTF(("Don't know how to deal with %x\n",
00843                          inp[i].pi_type));
00844                      goto out;
00845               }
00846        }
00847        return 0;
00848 out:
00849        free(*info);
00850        return -1;
00851 }
00852 
00853 int
00854 cdf_unpack_summary_info(const cdf_stream_t *sst, cdf_summary_info_header_t *ssi,
00855     cdf_property_info_t **info, size_t *count)
00856 {
00857        size_t i, maxcount;
00858        const cdf_summary_info_header_t *si = sst->sst_tab;
00859        const cdf_section_declaration_t *sd = (const void *)
00860            ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET);
00861 
00862        if (cdf_check_stream_offset(sst, si, sizeof(*si)) == -1 ||
00863            cdf_check_stream_offset(sst, sd, sizeof(*sd)) == -1)
00864               return -1;
00865        ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
00866        ssi->si_os_version = CDF_TOLE2(si->si_os_version);
00867        ssi->si_os = CDF_TOLE2(si->si_os);
00868        ssi->si_class = si->si_class;
00869        cdf_swap_class(&ssi->si_class);
00870        ssi->si_count = CDF_TOLE2(si->si_count);
00871        *count = 0;
00872        maxcount = 0;
00873        *info = NULL;
00874        for (i = 0; i < CDF_TOLE4(si->si_count); i++) {
00875               if (i >= CDF_LOOP_LIMIT) {
00876                      DPRINTF(("Unpack summary info loop limit"));
00877                      errno = EFTYPE;
00878                      return -1;
00879               }
00880               if (cdf_read_property_info(sst, CDF_TOLE4(sd->sd_offset),
00881                   info, count, &maxcount) == -1)
00882                      return -1;
00883        }
00884        return 0;
00885 }
00886 
00887 
00888 
00889 int
00890 cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
00891 {
00892        return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
00893            "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
00894            id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
00895            id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
00896            id->cl_six[5]);
00897 }
00898 
00899 static const struct {
00900        uint32_t v;
00901        const char *n;
00902 } vn[] = {
00903        { CDF_PROPERTY_CODE_PAGE, "Code page" },
00904        { CDF_PROPERTY_TITLE, "Title" },
00905        { CDF_PROPERTY_SUBJECT, "Subject" },
00906        { CDF_PROPERTY_AUTHOR, "Author" },
00907        { CDF_PROPERTY_KEYWORDS, "Keywords" },
00908        { CDF_PROPERTY_COMMENTS, "Comments" },
00909        { CDF_PROPERTY_TEMPLATE, "Template" },
00910        { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
00911        { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
00912        { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
00913        { CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
00914        { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
00915        { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
00916        { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
00917        { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
00918        { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
00919        { CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
00920        { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
00921        { CDF_PROPERTY_SECURITY, "Security" },
00922        { CDF_PROPERTY_LOCALE_ID, "Locale ID" },
00923 };
00924 
00925 int
00926 cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
00927 {
00928        size_t i;
00929 
00930        for (i = 0; i < __arraycount(vn); i++)
00931               if (vn[i].v == p)
00932                      return snprintf(buf, bufsiz, "%s", vn[i].n);
00933        return snprintf(buf, bufsiz, "0x%x", p);
00934 }
00935 
00936 int
00937 cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
00938 {
00939        size_t len = 0;
00940        int days, hours, mins, secs;
00941 
00942        ts /= CDF_TIME_PREC;
00943        secs = ts % 60;
00944        ts /= 60;
00945        mins = ts % 60;
00946        ts /= 60;
00947        hours = ts % 24;
00948        ts /= 24;
00949        days = ts;
00950 
00951        if (days) {
00952               len += snprintf(buf + len, bufsiz - len, "%dd+", days);
00953               if (len >= bufsiz)
00954                      return len;
00955        }
00956 
00957        if (days || hours) {
00958               len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
00959               if (len >= bufsiz)
00960                      return len;
00961        }
00962 
00963        len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
00964        if (len >= bufsiz)
00965               return len;
00966 
00967        len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
00968        return len;
00969 }
00970 
00971 
00972 #ifdef CDF_DEBUG
00973 void
00974 cdf_dump_header(const cdf_header_t *h)
00975 {
00976        size_t i;
00977 
00978 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
00979 #define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
00980     h->h_ ## b, 1 << h->h_ ## b)
00981        DUMP("%d", revision);
00982        DUMP("%d", version);
00983        DUMP("0x%x", byte_order);
00984        DUMP2("%d", sec_size_p2);
00985        DUMP2("%d", short_sec_size_p2);
00986        DUMP("%d", num_sectors_in_sat);
00987        DUMP("%d", secid_first_directory);
00988        DUMP("%d", min_size_standard_stream);
00989        DUMP("%d", secid_first_sector_in_short_sat);
00990        DUMP("%d", num_sectors_in_short_sat);
00991        DUMP("%d", secid_first_sector_in_master_sat);
00992        DUMP("%d", num_sectors_in_master_sat);
00993        for (i = 0; i < __arraycount(h->h_master_sat); i++) {
00994               if (h->h_master_sat[i] == CDF_SECID_FREE)
00995                      break;
00996               (void)fprintf(stderr, "%35.35s[%.3zu] = %d\n",
00997                   "master_sat", i, h->h_master_sat[i]);
00998        }
00999 }
01000 
01001 void
01002 cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
01003 {
01004        size_t i, j, s = size / sizeof(cdf_secid_t);
01005 
01006        for (i = 0; i < sat->sat_len; i++) {
01007               (void)fprintf(stderr, "%s[%zu]:\n%.6d: ", prefix, i, i * s);
01008               for (j = 0; j < s; j++) {
01009                      (void)fprintf(stderr, "%5d, ",
01010                          CDF_TOLE4(sat->sat_tab[s * i + j]));
01011                      if ((j + 1) % 10 == 0)
01012                             (void)fprintf(stderr, "\n%.6d: ",
01013                                 i * s + j + 1);
01014               }
01015               (void)fprintf(stderr, "\n");
01016        }
01017 }
01018 
01019 void
01020 cdf_dump(void *v, size_t len)
01021 {
01022        size_t i, j;
01023        unsigned char *p = v;
01024        char abuf[16];
01025        (void)fprintf(stderr, "%.4x: ", 0);
01026        for (i = 0, j = 0; i < len; i++, p++) {
01027               (void)fprintf(stderr, "%.2x ", *p);
01028               abuf[j++] = isprint(*p) ? *p : '.';
01029               if (j == 16) {
01030                      j = 0;
01031                      abuf[15] = '\0';
01032                      (void)fprintf(stderr, "%s\n%.4x: ", abuf, i + 1);
01033               }
01034        }
01035        (void)fprintf(stderr, "\n");
01036 }
01037 
01038 void
01039 cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
01040 {
01041        size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
01042            CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
01043        cdf_dump(sst->sst_tab, ss * sst->sst_len);
01044 }
01045 
01046 void
01047 cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
01048     const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
01049     const cdf_dir_t *dir)
01050 {
01051        size_t i, j;
01052        cdf_directory_t *d;
01053        char name[__arraycount(d->d_name)];
01054        cdf_stream_t scn;
01055        struct timeval ts;
01056 
01057        static const char *types[] = { "empty", "user storage",
01058            "user stream", "lockbytes", "property", "root storage" };
01059 
01060        for (i = 0; i < dir->dir_len; i++) {
01061               d = &dir->dir_tab[i];
01062               for (j = 0; j < sizeof(name); j++)
01063                      name[j] = (char)CDF_TOLE2(d->d_name[j]);
01064               (void)fprintf(stderr, "Directory %zu: %s\n", i, name);
01065               if (d->d_type < __arraycount(types))
01066                      (void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
01067               else
01068                      (void)fprintf(stderr, "Type: %d\n", d->d_type);
01069               (void)fprintf(stderr, "Color: %s\n",
01070                   d->d_color ? "black" : "red");
01071               (void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
01072               (void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
01073               (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags);
01074               cdf_timestamp_to_timespec(&ts, d->d_created);
01075               (void)fprintf(stderr, "Created %s", ctime(&ts.tv_sec));
01076               cdf_timestamp_to_timespec(&ts, d->d_modified);
01077               (void)fprintf(stderr, "Modified %s", ctime(&ts.tv_sec));
01078               (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
01079               (void)fprintf(stderr, "Size %d\n", d->d_size);
01080               switch (d->d_type) {
01081               case CDF_DIR_TYPE_USER_STORAGE:
01082                      (void)fprintf(stderr, "Storage: %d\n", d->d_storage);
01083                      break;
01084               case CDF_DIR_TYPE_USER_STREAM:
01085                      if (sst == NULL)
01086                             break;
01087                      if (cdf_read_sector_chain(info, h, sat, ssat, sst,
01088                          d->d_stream_first_sector, d->d_size, &scn) == -1) {
01089                             warn("Can't read stream for %s at %d len %d",
01090                                 name, d->d_stream_first_sector, d->d_size);
01091                             break;
01092                      }
01093                      cdf_dump_stream(h, &scn);
01094                      free(scn.sst_tab);
01095                      break;
01096               default:
01097                      break;
01098               }
01099                      
01100        }
01101 }
01102 
01103 void
01104 cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
01105 {
01106        cdf_timestamp_t tp;
01107        struct timeval ts;
01108        char buf[64];
01109        size_t i;
01110 
01111        for (i = 0; i < count; i++) {
01112               cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
01113               (void)fprintf(stderr, "%zu) %s: ", i, buf);
01114               switch (info[i].pi_type) {
01115               case CDF_SIGNED16:
01116                      (void)fprintf(stderr, "signed 16 [%hd]\n",
01117                          info[i].pi_s16);
01118                      break;
01119               case CDF_SIGNED32:
01120                      (void)fprintf(stderr, "signed 32 [%d]\n",
01121                          info[i].pi_s32);
01122                      break;
01123               case CDF_UNSIGNED32:
01124                      (void)fprintf(stderr, "unsigned 32 [%u]\n",
01125                          info[i].pi_u32);
01126                      break;
01127               case CDF_LENGTH32_STRING:
01128                      (void)fprintf(stderr, "string %u [%.*s]\n",
01129                          info[i].pi_str.s_len,
01130                          info[i].pi_str.s_len, info[i].pi_str.s_buf);
01131                      break;
01132               case CDF_FILETIME:
01133                      tp = info[i].pi_tp;
01134 #if defined(PHP_WIN32) && _MSC_VER <= 1500
01135               if (tp < 1000000000000000i64) {
01136 #else
01137                      if (tp < 1000000000000000LL) {
01138 #endif
01139                             cdf_print_elapsed_time(buf, sizeof(buf), tp);
01140                             (void)fprintf(stderr, "timestamp %s\n", buf);
01141                      } else {
01142                             cdf_timestamp_to_timespec(&ts, tp);
01143                             (void)fprintf(stderr, "timestamp %s",
01144                                    ctime(&ts.tv_sec));
01145                      }
01146                      break;
01147               case CDF_CLIPBOARD:
01148                      (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
01149                      break;
01150               default:
01151                      DPRINTF(("Don't know how to deal with %x\n",
01152                          info[i].pi_type));
01153                      break;
01154               }
01155        }
01156 }
01157 
01158 
01159 void
01160 cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
01161 {
01162        char buf[128];
01163        cdf_summary_info_header_t ssi;
01164        cdf_property_info_t *info;
01165        size_t count;
01166 
01167        (void)&h;
01168        if (cdf_unpack_summary_info(sst, &ssi, &info, &count) == -1)
01169               return;
01170        (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
01171        (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
01172               ssi.si_os_version >> 8);
01173        (void)fprintf(stderr, "Os %d\n", ssi.si_os);
01174        cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
01175        (void)fprintf(stderr, "Class %s\n", buf);
01176        (void)fprintf(stderr, "Count %d\n", ssi.si_count);
01177        cdf_dump_property_info(info, count);
01178        free(info);
01179 }
01180 
01181 #endif
01182 
01183 #ifdef TEST
01184 int
01185 main(int argc, char *argv[])
01186 {
01187        int i;
01188        cdf_header_t h;
01189        cdf_sat_t sat, ssat;
01190        cdf_stream_t sst, scn;
01191        cdf_dir_t dir;
01192        cdf_info_t info;
01193 
01194        if (argc < 2) {
01195               (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
01196               return -1;
01197        }
01198 
01199        info.i_buf = NULL;
01200        info.i_len = 0;
01201        for (i = 1; i < argc; i++) {
01202               if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
01203                      err(1, "Cannot open `%s'", argv[1]);
01204 
01205               if (cdf_read_header(&info, &h) == -1)
01206                      err(1, "Cannot read header");
01207 #ifdef CDF_DEBUG
01208               cdf_dump_header(&h);
01209 #endif
01210 
01211               if (cdf_read_sat(&info, &h, &sat) == -1)
01212                      err(1, "Cannot read sat");
01213 #ifdef CDF_DEBUG
01214               cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
01215 #endif
01216 
01217               if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
01218                      err(1, "Cannot read ssat");
01219 #ifdef CDF_DEBUG
01220               cdf_dump_sat("SSAT", &h, &ssat, CDF_SHORT_SEC_SIZE(&h));
01221 #endif
01222 
01223               if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
01224                      err(1, "Cannot read dir");
01225 
01226               if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
01227                      err(1, "Cannot read short stream");
01228 #ifdef CDF_DEBUG
01229               cdf_dump_stream(&h, &sst);
01230 #endif
01231 
01232 #ifdef CDF_DEBUG
01233               cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
01234 #endif
01235 
01236 
01237               if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
01238                   &scn) == -1)
01239                      err(1, "Cannot read summary info");
01240 #ifdef CDF_DEBUG
01241               cdf_dump_summary_info(&h, &scn);
01242 #endif
01243 
01244               (void)close(info.i_fd);
01245        }
01246 
01247        return 0;
01248 }
01249 #endif