Annotation of embedaddon/php/ext/fileinfo/libmagic/cdf.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>