"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/cdf.c" (15 Oct 2018, 41585 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cdf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

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