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

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

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