root/ext/fileinfo/libmagic/cdf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _cdf_tole2
  2. _cdf_tole4
  3. _cdf_tole8
  4. cdf_getuint32
  5. cdf_tole2
  6. cdf_tole4
  7. cdf_tole8
  8. cdf_swap_header
  9. cdf_unpack_header
  10. cdf_swap_dir
  11. cdf_swap_class
  12. cdf_unpack_dir
  13. cdf_check_stream_offset
  14. cdf_read
  15. cdf_read_header
  16. cdf_read_sector
  17. cdf_read_short_sector
  18. cdf_read_sat
  19. cdf_count_chain
  20. cdf_read_long_sector_chain
  21. cdf_read_short_sector_chain
  22. cdf_read_sector_chain
  23. cdf_read_dir
  24. cdf_read_ssat
  25. cdf_read_short_stream
  26. cdf_namecmp
  27. cdf_read_summary_info
  28. cdf_read_user_stream
  29. cdf_find_stream
  30. cdf_read_property_info
  31. cdf_unpack_summary_info
  32. cdf_unpack_catalog
  33. cdf_print_classid
  34. cdf_print_property_name
  35. cdf_print_elapsed_time
  36. cdf_u16tos8
  37. cdf_dump_header
  38. cdf_dump_sat
  39. cdf_dump
  40. cdf_dump_stream
  41. cdf_dump_dir
  42. cdf_dump_property_info
  43. cdf_dump_summary_info
  44. cdf_dump_catalog
  45. main

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

/* [<][>][^][v][top][bottom][index][help] */