From: Christos Zoulas Date: Sun, 12 Oct 2008 15:38:51 +0000 (+0000) Subject: add cdf support. X-Git-Tag: FILE5_05~318 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=39d700267df7815c381107f881766780efcd0989;p=file add cdf support. --- diff --git a/src/Makefile.am b/src/Makefile.am index 308eb7f5..1bc60c0c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ AM_CFLAGS = @WARNINGS@ libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ compress.c is_tar.c readelf.c print.c fsmagic.c \ funcs.c file.h names.h patchlevel.h readelf.h tar.h apptype.c \ - file_opts.h elfclass.h mygetopt.h + file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0 libmagic_la_LIBADD = $(LTLIBOBJS) diff --git a/src/cdf.c b/src/cdf.c new file mode 100644 index 00000000..07f6d951 --- /dev/null +++ b/src/cdf.c @@ -0,0 +1,710 @@ +/*- + * Copyright (c) 2008 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdf.h" + +#ifndef __arraycount +#define __arraycount(a) (sizeof(a) / sizeof(a[0])) +#endif + +#ifdef CDF_DEBUG +#define DPRINTF(a) printf a +#else +#define DPRINTF(a) +#endif + +#ifdef notyet +/* + * swap a short + */ +static uint16_t +swap2(uint16_t sv) +{ + uint16_t rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; + d[0] = s[1]; + d[1] = s[0]; + return rv; +} + +/* + * swap an int + */ +static uint32_t +swap4(uint32_t sv) +{ + uint32_t rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; + d[0] = s[3]; + d[1] = s[2]; + d[2] = s[1]; + d[3] = s[0]; + return rv; +} +#endif + +/* + * swap a quad + */ +static uint64_t +swap8(uint64_t sv) +{ + uint64_t rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; +#if 0 + d[0] = s[3]; + d[1] = s[2]; + d[2] = s[1]; + d[3] = s[0]; + d[4] = s[7]; + d[5] = s[6]; + d[6] = s[5]; + d[7] = s[4]; +#else + d[0] = s[7]; + d[1] = s[6]; + d[2] = s[5]; + d[3] = s[4]; + d[4] = s[3]; + d[5] = s[2]; + d[6] = s[1]; + d[7] = s[0]; +#endif + return rv; +} + +int +cdf_read_header(int fd, cdf_header_t *h) +{ + assert(sizeof(*h) == 512); + if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) + return -1; + if (read(fd, h, sizeof(*h)) != sizeof(*h)) + return -1; + if (swap8(h->h_magic) != CDF_MAGIC) { + errno = EFTYPE; + return -1; + } + return 0; +} + + +ssize_t +cdf_read_sector(int fd, void *buf, size_t offs, size_t len, + const cdf_header_t *h, cdf_secid_t id) +{ + assert((size_t)CDF_SEC_SIZE(h) == len); + if (lseek(fd, (off_t)CDF_SEC_POS(h, id), SEEK_SET) == (off_t)-1) + return -1; + if (read(fd, ((char *)buf) + offs, len) != (ssize_t)len) + return -1; + return len; +} + +/* + * Read the sector allocation table. + */ +int +cdf_read_sat(int fd, cdf_header_t *h, cdf_sat_t *sat) +{ + size_t i, j, k; + size_t ss = CDF_SEC_SIZE(h); + cdf_secid_t *msa, mid; + + for (i = 0; i < __arraycount(h->h_master_sat); i++) + if (h->h_master_sat[i] == CDF_SECID_FREE) + break; + + sat->sat_len = (h->h_num_sectors_in_master_sat + i); + if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL) + return -1; + + for (i = 0; i < __arraycount(h->h_master_sat); i++) { + if (h->h_master_sat[i] < 0) + break; + if (cdf_read_sector(fd, sat->sat_tab, ss * i, ss, h, + h->h_master_sat[i]) != (ssize_t)ss) { + warnx("Reading sector %d", h->h_master_sat[i]); + free(sat->sat_tab); + return -1; + } + } + + if ((msa = calloc(1, ss)) == NULL) + return -1; + + mid = h->h_secid_first_sector_in_master_sat; + for (j = 0; j < h->h_num_sectors_in_master_sat; j++) { + if (cdf_read_sector(fd, msa, 0, ss, h, mid) != (ssize_t)ss) { + warnx("Reading master sector %d", mid); + free(sat->sat_tab); + free(msa); + return -1; + } + for (k = 0; k < (ss / sizeof(mid)) - 1; k++, i++) + if (cdf_read_sector(fd, sat->sat_tab, ss * i, ss, h, + msa[k]) != (ssize_t)ss) { + warnx("Reading sector %d", msa[k]); + free(sat->sat_tab); + free(msa); + return -1; + } + mid = msa[(ss / sizeof(mid)) - 1]; + } + free(msa); + return 0; +} + +size_t +cdf_count_chain(const cdf_header_t *h, const cdf_sat_t *sat, cdf_secid_t sid) +{ + size_t i, s = CDF_SEC_SIZE(h) / sizeof(cdf_secid_t); + + DPRINTF(("Chain:")); + for (i = 0; sid >= 0; i++) { + DPRINTF((" %d", sid)); + if (sid > (cdf_secid_t)(sat->sat_len * s)) { + errno = EFTYPE; + return (size_t)-1; + } + sid = sat->sat_tab[sid]; + } + DPRINTF(("\n")); + return i; +} + +int +cdf_read_stream(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_secid_t sid, size_t len, cdf_stream_t *sst) +{ + size_t ss = CDF_SEC_SIZE(h), i; + + sst->sst_len = cdf_count_chain(h, sat, sid); + sst->sst_dirlen = len; + + if (sst->sst_len == (size_t)-1) + return -1; + + sst->sst_tab = calloc(sst->sst_len, ss); + if (sst->sst_tab == NULL) + return -1; + + for (i = 0; sid >= 0; i++) { + if (cdf_read_sector(fd, sst->sst_tab, i * ss, ss, h, sid) + != (ssize_t)ss) { + warnx("Reading short stream sector %d", sid); + free(sst->sst_tab); + return -1; + } + sid = sat->sat_tab[sid]; + } + return 0; +} + + +int +cdf_read_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_dir_t *dir) +{ + size_t i; + size_t ss = CDF_SEC_SIZE(h), ns; + cdf_secid_t sid = h->h_secid_first_directory; + + ns = cdf_count_chain(h, sat, sid); + if (ns == (size_t)-1) + return -1; + + dir->dir_tab = calloc(ns, sizeof(dir->dir_tab[0])); + if (dir->dir_tab == NULL) + return -1; + dir->dir_len = ns * ss / sizeof(dir->dir_tab[0]); + + for (i = 0; i < ns; i++) { + if (cdf_read_sector(fd, dir->dir_tab, i * ss, ss, h, sid) != + (ssize_t)ss) { + warnx("Reading directory sector %d", sid); + free(dir->dir_tab); + return -1; + } + sid = sat->sat_tab[sid]; + } + return 0; +} + + +int +cdf_read_ssat(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_sat_t *ssat) +{ + size_t i; + size_t ss = CDF_SEC_SIZE(h); + cdf_secid_t sid = h->h_secid_first_sector_in_short_sat; + + ssat->sat_len = cdf_count_chain(h, sat, sid); + if (sat->sat_len == (size_t)-1) + return -1; + + ssat->sat_tab = calloc(ssat->sat_len, ss); + if (sat->sat_tab == NULL) + return -1; + + for (i = 0; sid >= 0; i++) { + if (cdf_read_sector(fd, ssat->sat_tab, i * ss, ss, h, sid) != + (ssize_t)ss) { + warnx("Reading short sat sector %d", sid); + free(sat->sat_tab); + return -1; + } + sid = sat->sat_tab[sid]; + } + return 0; +} + +int +cdf_read_short_stream(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + const cdf_dir_t *dir, cdf_stream_t *sst) +{ + size_t i; + const cdf_directory_t *d; + + for (i = 0; i < dir->dir_len; i++) + if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE) + break; + + if (i == dir->dir_len) { + errno = EFTYPE; + return -1; + } + d = &dir->dir_tab[i]; + + return cdf_read_stream(fd, h, sat, d->d_stream_first_sector, d->d_size, + sst); +} + +static int +cdf_namecmp(const char *d, const uint16_t *s, size_t l) +{ + for (; l--; d++, s++) + if (*d != *s) + return (unsigned char)*d - *s; + return 0; +} + +int +cdf_read_summary_info(int fd, const cdf_header_t *h, + const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *sst) +{ + size_t i; + const cdf_directory_t *d; + static const char name[] = "\05SummaryInformation"; + + for (i = 0; i < dir->dir_len; i++) + if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_USER_STREAM && + cdf_namecmp(name, dir->dir_tab[i].d_name, sizeof(name)) == 0) + break; + + if (i == dir->dir_len) { + errno = EFTYPE; + return -1; + } + d = &dir->dir_tab[i]; + return cdf_read_stream(fd, h, sat, d->d_stream_first_sector, d->d_size, + sst); +} + + +int +cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id) +{ + return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-" + "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0], + id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0], + id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4], + id->cl_six[5]); +} + +static const struct { + uint32_t v; + const char *n; +} vn[] = { + { CDF_PROPERTY_CODE_PAGE, "Code page" }, + { CDF_PROPERTY_TITLE, "Title" }, + { CDF_PROPERTY_SUBJECT, "Subject" }, + { CDF_PROPERTY_AUTHOR, "Author" }, + { CDF_PROPERTY_KEYWORDS, "Keywords" }, + { CDF_PROPERTY_COMMENTS, "Comments" }, + { CDF_PROPERTY_TEMPLATE, "Template" }, + { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" }, + { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" }, + { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" }, + { CDF_PROPERTY_LAST_PRINTED, "Last Printed" }, + { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" }, + { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" }, + { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" }, + { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" }, + { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" }, + { CDF_PROPERTY_THUMBNAIL, "Thumbnail" }, + { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" }, + { CDF_PROPERTY_SECURITY, "Security" }, + { CDF_PROPERTY_LOCALE_ID, "Locale ID" }, +}; + +int +cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p) +{ + size_t i; + + for (i = 0; i < __arraycount(vn); i++) + if (vn[i].v == p) + return snprintf(buf, bufsiz, "%s", vn[i].n); + return snprintf(buf, bufsiz, "0x%x", p); +} + +int +cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts) +{ + size_t len = 0; + int days, hours, mins, secs; + + ts /= CDF_TIME_PREC; + secs = ts % 60; + ts /= 60; + mins = ts % 60; + ts /= 60; + hours = ts % 24; + ts /= 24; + days = ts; + + if (days) { + len += snprintf(buf + len, bufsiz - len, "%dd+", days); + if (len >= bufsiz) + return len; + } + + if (days || hours) { + len += snprintf(buf + len, bufsiz - len, "%.2d:", hours); + if (len >= bufsiz) + return len; + } + + len += snprintf(buf + len, bufsiz - len, "%.2d:", mins); + if (len >= bufsiz) + return len; + + len += snprintf(buf + len, bufsiz - len, "%.2d", secs); + return len; +} + + +#ifdef CDF_DEBUG +void +cdf_dump_header(const cdf_header_t *h) +{ + size_t i; + +#define DUMP(a, b) printf("%40.40s = " a "\n", # b, h->h_ ## b) + DUMP("%d", revision); + DUMP("%d", version); + DUMP("0x%x", byte_order); + DUMP("%d", sec_size_p2); + DUMP("%d", short_sec_size_p2); + DUMP("%d", num_sectors_in_sat); + DUMP("%d", secid_first_directory); + DUMP("%d", min_size_standard_stream); + DUMP("%d", secid_first_sector_in_short_sat); + DUMP("%d", num_sectors_in_short_sat); + DUMP("%d", secid_first_sector_in_master_sat); + DUMP("%d", num_sectors_in_master_sat); + for (i = 0; i < __arraycount(h->h_master_sat); i++) { + if (h->h_master_sat[i] == CDF_SECID_FREE) + break; + printf("%35.35s[%.3zu] = %d\n", + "master_sat", i, h->h_master_sat[i]); + } +} + +void +cdf_dump_sat(const char *prefix, const cdf_header_t *h, const cdf_sat_t *sat) +{ + size_t i, j, s = CDF_SEC_SIZE(h) / sizeof(cdf_secid_t); + + for (i = 0; i < sat->sat_len; i++) { + printf("%s[%zu]:\n", prefix, i); + for (j = 0; j < s; j++) { + printf("%5d, ", sat->sat_tab[s * i + j]); + if ((j + 1) % 10 == 0) + printf("\n"); + } + printf("\n"); + } +} + +void +cdf_dump(void *v, size_t len) +{ + size_t i; + unsigned char *p = v; + for (i = 0; i < len; i++, p++) { + if (0 && *p == 0) + continue; + if (isprint(*p)) + printf("%c ", *p); + else + printf("0x%x ", *p); + } +} + +void +cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst) +{ + cdf_dump(sst->sst_tab, CDF_SEC_SIZE(h) * sst->sst_len); +} + +void +cdf_dump_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + const cdf_dir_t *dir) +{ + size_t i, j; + cdf_directory_t *d; + char name[__arraycount(d->d_name)]; + cdf_stream_t sst; + struct timespec ts; + + static const char *types[] = { "empty", "user storage", + "user stream", "lockbytes", "property", "root storage" }; + + for (i = 0; i < dir->dir_len; i++) { + d = &dir->dir_tab[i]; + for (j = 0; j < sizeof(name); j++) + name[j] = (char)d->d_name[j]; + printf("Directory %zu: %s\n", i, name); + if (d->d_type < __arraycount(types)) + printf("Type: %s\n", types[d->d_type]); + else + printf("Type: %d\n", d->d_type); + printf("Color: %s\n", d->d_color ? "black" : "red"); + printf("Left child: %d\n", d->d_left_child); + printf("Right child: %d\n", d->d_right_child); + switch (d->d_type) { + case CDF_DIR_TYPE_USER_STORAGE: + printf("Storage: %d\n", d->d_storage); + break; + case CDF_DIR_TYPE_USER_STREAM: + if (cdf_read_stream(fd, h, sat, + d->d_stream_first_sector, d->d_size, &sst) == -1) { + warn("Can't read stream"); + break; + } + cdf_dump_stream(h, &sst); + free(sst.sst_tab); + break; + default: + break; + } + + printf("Flags: 0x%x\n", d->d_flags); + cdf_timestamp_to_timespec(&ts, d->d_created); + printf("Created %s", ctime(&ts.tv_sec)); + cdf_timestamp_to_timespec(&ts, d->d_modified); + printf("Modified %s", ctime(&ts.tv_sec)); + printf("Stream %d\n", d->d_stream_first_sector); + printf("Size %d\n", d->d_size); + } +} + +void +cdf_dump_section_info(const cdf_stream_t *sst, uint32_t offs) +{ + const cdf_section_header_t *sh; + const uint32_t *p, *q, *e; + size_t i, len; + uint32_t u32; + int32_t s32; + int16_t s16; + cdf_timestamp_t tp; + struct timespec ts; + char buf[64]; + + sh = (const void *)((const char *)sst->sst_tab + offs); + printf("Length %d, Properties %d\n", sh->sh_len, sh->sh_properties); + p = (const void *)((const char *)sst->sst_tab + offs + sizeof(*sh)); + q = p + (sh->sh_properties << 1); + e = (void *)(((char *)sh) + sh->sh_len); + for (i = 0; i < sh->sh_properties; i++) { + cdf_print_property_name(buf, sizeof(buf), p[i << 1]); + printf("%zu) %s: ", i, buf); + switch (q[0]) { + case CDF_SIGNED16: + (void)memcpy(&s16, &q[1], sizeof(s16)); + printf("signed 16 [%hd]\n", s16); + len = 2; + break; + case CDF_SIGNED32: + (void)memcpy(&s32, &q[1], sizeof(s32)); + printf("signed 32 [%d]\n", s32); + len = 4; + break; + case CDF_UNSIGNED32: + (void)memcpy(&u32, &q[1], sizeof(u32)); + printf("unsigned 32 [%u]\n", u32); + len = 4; + break; + case CDF_LENGTH32_STRING: + printf("string %u [%.*s]\n", q[1], q[1], + (const char *)(&q[2])); + len = 4 + q[1]; + break; + case CDF_FILETIME: + (void)memcpy(&tp, &q[1], sizeof(tp)); + if (tp < 1000000000000000LL) { + cdf_print_elapsed_time(buf, sizeof(buf), tp); + printf("timestamp %s\n", buf); + } else { + cdf_timestamp_to_timespec(&ts, tp); + printf("timestamp %s", ctime(&ts.tv_sec)); + } + len = 8; + break; + case CDF_CLIPBOARD: + printf("\n"); + len = 4 + q[1]; + break; + default: + len = 4; + DPRINTF(("Don't know how to deal with %x\n", q[0])); + break; + } + q++; + q = (void *)(((char *)q) + CDF_ROUND(len, sizeof(*q))); + if (q > e) { + DPRINTF(("Ran of the end %p > %p\n", q, e)); + return; + } + } +} + + + +void +cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) +{ + char buf[128]; + size_t i; + const cdf_summary_info_header_t *si = sst->sst_tab; + const cdf_section_declaration_t *sd = (const void *) + ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET); + + printf("Endian: %x\n", si->si_byte_order); + printf("Os Version %d.%d\n", si->si_os_version & 0xff, + si->si_os_version >> 8); + printf("Os %d\n", si->si_os); + cdf_print_classid(buf, sizeof(buf), &si->si_class); + printf("Class %s\n", buf); + printf("Count %d\n", si->si_count); + for (i = 0; i < si->si_count; i++) { + cdf_print_classid(buf, sizeof(buf), &sd->sd_class); + printf("Section %zu: %s %x\n", i, buf, sd->sd_offset); + cdf_dump_section_info(sst, sd->sd_offset); + } +} +#endif + +#ifdef TEST +int +main(int argc, char *argv[]) +{ + int fd, i; + cdf_header_t h; + cdf_sat_t sat, ssat; + cdf_stream_t sst; + cdf_dir_t dir; + + if (argc < 2) { + (void)fprintf(stderr, "Usage: %s \n", getprogname()); + return -1; + } + + for (i = 1; i < argc; i++) { + if ((fd = open(argv[1], O_RDONLY)) == -1) + err(1, "Cannot open `%s'", argv[1]); + + if (cdf_read_header(fd, &h) == -1) + err(1, "Cannot read header"); +#ifdef CDF_DEBUG + cdf_dump_header(&h); +#endif + + if (cdf_read_sat(fd, &h, &sat) == -1) + err(1, "Cannot read sat"); +#ifdef CDF_DEBUG + cdf_dump_sat("SAT", &h, &sat); +#endif + + if (cdf_read_ssat(fd, &h, &sat, &ssat) == -1) + err(1, "Cannot read ssat"); +#ifdef CDF_DEBUG + cdf_dump_sat("SSAT", &h, &ssat); +#endif + + if (cdf_read_dir(fd, &h, &sat, &dir) == -1) + err(1, "Cannot read dir"); +#ifdef CDF_DEBUG + cdf_dump_dir(fd, &h, &sat, &dir); +#endif + + if (cdf_read_short_stream(fd, &h, &sat, &dir, &sst) == -1) + err(1, "Cannot read short stream"); +#ifdef CDF_DEBUG + cdf_dump_stream(&h, &sst); +#endif + + if (cdf_read_summary_info(fd, &h, &sat, &dir, &sst) + == -1) + err(1, "Cannot read summary info"); +#ifdef CDF_DEBUG + cdf_dump_summary_info(&h, &sst); +#endif + + (void)close(fd); + } + + return 0; +} +#endif diff --git a/src/cdf.h b/src/cdf.h new file mode 100644 index 00000000..adc2cc4e --- /dev/null +++ b/src/cdf.h @@ -0,0 +1,204 @@ +/*- + * Copyright (c) 2008 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Info from: http://sc.openoffice.org/compdocfileformat.pdf + */ + +#ifndef _H_CDF_ +#define _H_CDF_ + +typedef int32_t cdf_secid_t; + +#define CDF_SECID_NULL 0 +#define CDF_SECID_FREE -1 +#define CDF_SECID_END_OF_CHAIN -2 +#define CDF_SECID_SECTOR_ALLOCATION_TABLE -3 +#define CDF_SECID_MASTER_SECTOR_ALLOCATION_TABLE -4 + +typedef struct { + uint64_t h_magic; +#define CDF_MAGIC 0xD0CF11E0A1B11AE1LL + uint64_t h_uuid[2]; + uint16_t h_revision; + uint16_t h_version; + uint16_t h_byte_order; + uint16_t h_sec_size_p2; + uint16_t h_short_sec_size_p2; + uint8_t h_unused0[10]; + uint32_t h_num_sectors_in_sat; + uint32_t h_secid_first_directory; + uint8_t h_unused1[4]; + uint32_t h_min_size_standard_stream; + cdf_secid_t h_secid_first_sector_in_short_sat; + uint32_t h_num_sectors_in_short_sat; + cdf_secid_t h_secid_first_sector_in_master_sat; + uint32_t h_num_sectors_in_master_sat; + cdf_secid_t h_master_sat[436/4]; +} cdf_header_t; + +#define CDF_SEC_SIZE(h) (1 << (h)->h_sec_size_p2) +#define CDF_SEC_POS(h, secid) (512 + (secid) * CDF_SEC_SIZE(h)) +#define CDF_SHORT_SEC_SIZE(h) (1 << (h)->h_short_sec_size_p2) +#define CDF_SHORT_SEC_POS(h, secid) ((secid) * CDF_SHORT_SEC_SIZE(h)) + +typedef int32_t cdf_dirid_t; +#define CDF_DIRID_NULL -1 + +typedef int64_t cdf_timestamp_t; +#define CDF_BASE_YEAR 1601 +#define CDF_TIME_PREC 10000000 + +typedef struct { + uint16_t d_name[32]; + uint16_t d_namelen; + uint8_t d_type; +#define CDF_DIR_TYPE_EMPTY 0 +#define CDF_DIR_TYPE_USER_STORAGE 1 +#define CDF_DIR_TYPE_USER_STREAM 2 +#define CDF_DIR_TYPE_LOCKBYTES 3 +#define CDF_DIR_TYPE_PROPERTY 4 +#define CDF_DIR_TYPE_ROOT_STORAGE 5 + uint8_t d_color; +#define CDF_DIR_COLOR_READ 0 +#define CDF_DIR_COLOR_BLACK 1 + cdf_dirid_t d_left_child; + cdf_dirid_t d_right_child; + cdf_dirid_t d_storage; + uint64_t d_storage_uuid[2]; + uint32_t d_flags; + cdf_timestamp_t d_created; + cdf_timestamp_t d_modified; + cdf_secid_t d_stream_first_sector; + uint32_t d_size; + uint32_t d_unused0; +} cdf_directory_t; + +typedef struct { + cdf_secid_t *sat_tab; + size_t sat_len; +} cdf_sat_t; + +typedef struct { + cdf_directory_t *dir_tab; + size_t dir_len; +} cdf_dir_t; + +typedef struct { + void *sst_tab; + size_t sst_len; + size_t sst_dirlen; +} cdf_stream_t; + +typedef struct { + uint32_t cl_dword; + uint16_t cl_word[2]; + uint8_t cl_two[2]; + uint8_t cl_six[6]; +} cdf_classid_t; + +typedef struct { + uint16_t si_byte_order; + uint16_t si_zero; + uint16_t si_os_version; + uint16_t si_os; + cdf_classid_t si_class; + uint32_t si_count; +} cdf_summary_info_header_t; + +#define CDF_SECTION_DECLARATION_OFFSET 0x1c + +typedef struct { + cdf_classid_t sd_class; + uint32_t sd_offset; +} cdf_section_declaration_t; + +typedef struct { + uint32_t sh_len; + uint32_t sh_properties; +} cdf_section_header_t; + +#define CDF_ROUND(val, by) (((val) + (by) - 1) & ~((by) - 1)) + +#define CDF_SIGNED16 0x00000002 +#define CDF_SIGNED32 0x00000003 +#define CDF_UNSIGNED32 0x00000013 +#define CDF_LENGTH32_STRING 0x0000001e +#define CDF_FILETIME 0x00000040 +#define CDF_CLIPBOARD 0x00000047 + +#define CDF_PROPERTY_CODE_PAGE 0x00000001 +#define CDF_PROPERTY_TITLE 0x00000002 +#define CDF_PROPERTY_SUBJECT 0x00000003 +#define CDF_PROPERTY_AUTHOR 0x00000004 +#define CDF_PROPERTY_KEYWORDS 0x00000005 +#define CDF_PROPERTY_COMMENTS 0x00000006 +#define CDF_PROPERTY_TEMPLATE 0x00000007 +#define CDF_PROPERTY_LAST_SAVED_BY 0x00000008 +#define CDF_PROPERTY_REVISION_NUMBER 0x00000009 +#define CDF_PROPERTY_TOTAL_EDITING_TIME 0x0000000a +#define CDF_PROPERTY_LAST_PRINTED 0X0000000b +#define CDF_PROPERTY_CREATE_TIME 0x0000000c +#define CDF_PROPERTY_LAST_SAVED_TIME 0x0000000d +#define CDF_PROPERTY_NUMBER_OF_PAGES 0x0000000e +#define CDF_PROPERTY_NUMBER_OF_WORDS 0x0000000f +#define CDF_PROPERTY_NUMBER_OF_CHARACTERS 0x00000010 +#define CDF_PROPERTY_THUMBNAIL 0x00000011 +#define CDF_PROPERTY_NAME_OF_APPLICATION 0x00000012 +#define CDF_PROPERTY_SECURITY 0x00000013 +#define CDF_PROPERTY_LOCALE_ID 0x80000000 + +struct timespec; +int cdf_timestamp_to_timespec(struct timespec *, cdf_timestamp_t); +int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timespec *); +int cdf_read_header(int, cdf_header_t *); +ssize_t cdf_read_sector(int, void *, size_t, size_t, const cdf_header_t *, + cdf_secid_t); +int cdf_read_sat(int, cdf_header_t *, cdf_sat_t *); +size_t cdf_count_chain(const cdf_header_t *, const cdf_sat_t *, cdf_secid_t); +int cdf_read_stream(int, const cdf_header_t *, const cdf_sat_t *, cdf_secid_t, + size_t, cdf_stream_t *); +int cdf_read_dir(int, const cdf_header_t *, const cdf_sat_t *, cdf_dir_t *); +int cdf_read_ssat(int, const cdf_header_t *, const cdf_sat_t *, cdf_sat_t *); +int cdf_read_short_stream(int, const cdf_header_t *, const cdf_sat_t *, + const cdf_dir_t *, cdf_stream_t *); +int cdf_read_summary_info(int, const cdf_header_t *, const cdf_sat_t *, + const cdf_dir_t *, cdf_stream_t *); +int cdf_print_classid(char *, size_t, const cdf_classid_t *); +int cdf_print_property_name(char *, size_t, uint32_t); +int cdf_print_elapsed_time(char *, size_t, cdf_timestamp_t); + +#ifdef CDF_DEBUG +void cdf_dump_header(const cdf_header_t *); +void cdf_dump_sat(const char *, const cdf_header_t *, const cdf_sat_t *); +void cdf_dump(void *, size_t); +void cdf_dump_stream(const cdf_header_t *, const cdf_stream_t *); +void cdf_dump_dir(int, const cdf_header_t *, const cdf_sat_t *, const cdf_dir_t *); +void cdf_dump_section_info(const cdf_stream_t *, uint32_t); +void cdf_dump_summary_info(const cdf_header_t *, const cdf_stream_t *); +#endif + + +#endif /* _H_CDF_ */ diff --git a/src/cdf_time.c b/src/cdf_time.c new file mode 100644 index 00000000..96321fce --- /dev/null +++ b/src/cdf_time.c @@ -0,0 +1,169 @@ +/*- + * Copyright (c) 2008 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include "cdf.h" + +#define isleap(y) ((((y) % 4) == 0) && \ + ((((y) % 100) != 0) || (((y) % 400) == 0))) + +static const int mdays[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * Return the number of days between jan 01 1601 and jan 01 of year. + */ +static int +cdf_getdays(int year) +{ + int days = 0; + int y; + + for (y = CDF_BASE_YEAR; y < year; y++) + days += isleap(y) + 365; + + return days; +} + +/* + * Return the day within the month + */ +static int +cdf_getday(int year, int days) +{ + size_t m; + + for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { + int sub = mdays[m] + (m == 1 && isleap(year)); + if (days < sub) + return days; + days -= sub; + } + return days; +} + +/* + * Return the 0...11 month number. + */ +static int +cdf_getmonth(int year, int days) +{ + size_t m; + + for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) { + days -= mdays[m]; + if (m == 1 && isleap(year)) + days--; + if (days <= 0) + return (int)m; + } + return (int)m; +} + +int +cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t) +{ + struct tm tm; + static char UTC[] = "UTC"; + + /* Unit is 100's of nanoseconds */ + ts->tv_nsec = (t % CDF_TIME_PREC) * 100; + + t /= CDF_TIME_PREC; + tm.tm_sec = t % 60; + t /= 60; + + tm.tm_min = t % 60; + t /= 60; + + tm.tm_hour = t % 24; + t /= 24; + + // XXX: Approx + tm.tm_year = CDF_BASE_YEAR + (t / 365); + + int rdays = cdf_getdays(tm.tm_year); + t -= rdays; + tm.tm_mday = cdf_getday(tm.tm_year, t); + tm.tm_mon = cdf_getmonth(tm.tm_year, t); + tm.tm_wday = 0; + tm.tm_yday = 0; + tm.tm_isdst = 0; + tm.tm_gmtoff = 0; + tm.tm_zone = UTC; + tm.tm_year -= 1900; + ts->tv_sec = mktime(&tm); + if (ts->tv_sec == -1) { + errno = EINVAL; + return -1; + } + return 0; +} + +int +cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts) +{ + (void)&t; + (void)&ts; +#ifdef notyet + struct tm tm; + if (gmtime_r(&ts->ts_sec, &tm) == NULL) { + errno = EINVAL; + return -1; + } + *t = (ts->ts_nsec / 100) * CDF_TIME_PREC; + *t = tm.tm_sec; + *t += tm.tm_min * 60; + *t += tm.tm_hour * 60 * 60; + *t += tm.tm_mday * 60 * 60 * 24; +#endif + return 0; +} + + +#ifdef TEST +int +main(int argc, char *argv[]) +{ + struct timespec ts; + static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL; + static const char *ref = "Sat Apr 23 01:30:00 1977"; + char *p, *q; + + cdf_timestamp_to_timespec(&ts, tst); + p = ctime(&ts.tv_sec); + if ((q = strchr(p, '\n')) != NULL) + *q = '\0'; + if (strcmp(ref, p) != 0) + errx(1, "Error date %s != %s\n", ref, p); + return 0; +} +#endif diff --git a/src/file.c b/src/file.c index d87f0fd4..effa06a0 100644 --- a/src/file.c +++ b/src/file.c @@ -74,7 +74,7 @@ int getopt_long(int argc, char * const *argv, const char *optstring, const struc #include "patchlevel.h" #ifndef lint -FILE_RCSID("@(#)$File: file.c,v 1.124 2008/10/09 17:24:03 christos Exp $") +FILE_RCSID("@(#)$File: file.c,v 1.125 2008/10/12 15:38:51 christos Exp $") #endif /* lint */ @@ -146,6 +146,7 @@ main(int argc, char *argv[]) } nv[] = { { "apptype", MAGIC_NO_CHECK_APPTYPE }, { "ascii", MAGIC_NO_CHECK_ASCII }, + { "cdf", MAGIC_NO_CHECK_CDF }, { "compress", MAGIC_NO_CHECK_COMPRESS }, { "elf", MAGIC_NO_CHECK_ELF }, { "soft", MAGIC_NO_CHECK_SOFT }, diff --git a/src/file.h b/src/file.h index a08fbfd1..668bfb25 100644 --- a/src/file.h +++ b/src/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.109 2008/09/02 07:11:30 christos Exp $ + * @(#)$File: file.h,v 1.110 2008/10/12 15:38:52 christos Exp $ */ #ifndef __file_h__ @@ -348,6 +348,8 @@ protected int file_printf(struct magic_set *, const char *, ...) protected int file_reset(struct magic_set *); protected int file_tryelf(struct magic_set *, int, const unsigned char *, size_t); +protected int file_trycdf(struct magic_set *, int, const unsigned char *, + size_t); protected int file_zmagic(struct magic_set *, int, const char *, const unsigned char *, size_t); protected int file_ascmagic(struct magic_set *, const unsigned char *, size_t); diff --git a/src/funcs.c b/src/funcs.c index af986051..a29ec20d 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -41,7 +41,7 @@ #endif #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.44 2008/07/16 18:00:57 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.45 2008/10/12 15:38:52 christos Exp $") #endif /* lint */ #ifndef SIZE_MAX @@ -194,18 +194,23 @@ file_buffer(struct magic_set *ms, int fd, const char *inname, const void *buf, /* Check if we have a tar file */ if ((ms->flags & MAGIC_NO_CHECK_TAR) != 0 || (m = file_is_tar(ms, ubuf, nb)) == 0) { - /* try tests in /etc/magic (or surrogate magic file) */ - if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 || - (m = file_softmagic(ms, ubuf, nb, BINTEST)) == 0) { - /* try known keywords, check whether it is ASCII */ - if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 || - (m = file_ascmagic(ms, ubuf, nb)) == 0) { - /* abandon hope, all ye who remain here */ - if ((!mime || (mime & MAGIC_MIME_TYPE)) && - file_printf(ms, mime ? "application/octet-stream" : - "data") == -1) - return -1; - m = 1; + /* Check if we have a CDF file */ + if ((ms->flags & MAGIC_NO_CHECK_CDF) != 0 || + (m = file_trycdf(ms, fd, ubuf, nb)) == 0) { + /* try tests in /etc/magic (or surrogate magic file) */ + if ((ms->flags & MAGIC_NO_CHECK_SOFT) != 0 || + (m = file_softmagic(ms, ubuf, nb, BINTEST)) == 0) { + /* try known keywords, check whether it is ASCII */ + if ((ms->flags & MAGIC_NO_CHECK_ASCII) != 0 || + (m = file_ascmagic(ms, ubuf, nb)) == 0) { + /* abandon hope, all ye who remain here */ + if ((!mime || (mime & MAGIC_MIME_TYPE)) && + file_printf(ms, mime ? + "application/octet-stream" : + "data") == -1) + return -1; + m = 1; + } } } } diff --git a/src/magic.h b/src/magic.h index ecdd53c1..2c085701 100644 --- a/src/magic.h +++ b/src/magic.h @@ -48,6 +48,7 @@ #define MAGIC_NO_CHECK_APPTYPE 0x008000 /* Don't check application type */ #define MAGIC_NO_CHECK_ELF 0x010000 /* Don't check for elf details */ #define MAGIC_NO_CHECK_ASCII 0x020000 /* Don't check for ascii files */ +#define MAGIC_NO_CHECK_CDF 0x040000 /* Don't check for cdf files */ #define MAGIC_NO_CHECK_TOKENS 0x100000 /* Don't check ascii/tokens */ /* Defined for backwards compatibility; do nothing */ diff --git a/src/readcdf.c b/src/readcdf.c new file mode 100644 index 00000000..414c4089 --- /dev/null +++ b/src/readcdf.c @@ -0,0 +1,249 @@ +/*- + * Copyright (c) 2008 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "file.h" + +#ifndef lint +FILE_RCSID("@(#)$File: readcdf.c,v 1.1 2008/10/12 15:38:52 christos Exp $") +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdf.h" +#include "magic.h" + +#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) + +private int +cdf_file_section_info(struct magic_set *ms, const cdf_stream_t *sst, + uint32_t offs) +{ + const cdf_section_header_t *sh; + const uint32_t *p, *q, *e; + const char *s; + size_t i, len; + uint32_t u32; + int32_t s32; + int16_t s16; + cdf_timestamp_t tp; + struct timespec ts; + char buf[64]; + const char *str = "vnd.ms-office"; + + sh = (const void *)((const char *)sst->sst_tab + offs); + p = (const void *)((const char *)sst->sst_tab + offs + sizeof(*sh)); + q = p + (sh->sh_properties << 1); + e = (const void *)(((const char *)sh) + sh->sh_len); + for (i = 0; i < sh->sh_properties; i++) { + cdf_print_property_name(buf, sizeof(buf), p[i << 1]); + switch (q[0]) { + case CDF_SIGNED16: + (void)memcpy(&s16, &q[1], sizeof(s16)); + if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, + s16) == -1) + return -1; + len = 2; + break; + case CDF_SIGNED32: + (void)memcpy(&s32, &q[1], sizeof(s32)); + if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, s32) + == -1) + return -1; + len = 4; + break; + case CDF_UNSIGNED32: + (void)memcpy(&u32, &q[1], sizeof(u32)); + if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, u32) + == -1) + return -1; + len = 4; + break; + case CDF_LENGTH32_STRING: + if (q[1] > 1) { + s = (const char *)(&q[2]); + if (NOTMIME(ms)) { + if (file_printf(ms, ", %s: %.*s", buf, + q[1], s) == -1) + return -1; + } else if (p[i << 1] == + CDF_PROPERTY_NAME_OF_APPLICATION) { + if (strstr(s, "Word")) + str = "msword"; + else if (strstr(s, "Excel")) + str = "vnd.ms-excel"; + else if (strstr(s, "Powerpoint")) + str = "vnd.ms-powerpoint"; + } + } + len = 4 + q[1]; + break; + case CDF_FILETIME: + (void)memcpy(&tp, &q[1], sizeof(tp)); + if (tp != 0) { + if (tp < 1000000000000000LL) { + char tbuf[64]; + cdf_print_elapsed_time(tbuf, + sizeof(tbuf), tp); + if (NOTMIME(ms) && file_printf(ms, + ", %s: %s", buf, tbuf) == -1) + return -1; + } else { + char *c, *ec; + cdf_timestamp_to_timespec(&ts, tp); + c = ctime(&ts.tv_sec); + if ((ec = strchr(c, '\n')) != NULL) + *ec = '\0'; + + if (NOTMIME(ms) && file_printf(ms, + ", %s: %s", buf, c) == -1) + return -1; + } + } + len = 8; + break; + case CDF_CLIPBOARD: + len = 4 + q[1]; + break; + default: + len = 4; + file_error(ms, 0, "Internal parsing error"); + return -1; + } + q++; + q = (const void *)(((const char *)q) + + CDF_ROUND(len, sizeof(*q))); + if (q > e) { + file_error(ms, 0, "Internal parsing error"); + return -1; + } + } + if (!NOTMIME(ms)) { + if (file_printf(ms, "application/%s", str) == -1) + return -1; + } + return 0; +} + +private int +cdf_file_summary_info(struct magic_set *ms, const cdf_stream_t *sst) +{ + size_t i; + const cdf_summary_info_header_t *si = sst->sst_tab; + const cdf_section_declaration_t *sd = (const void *) + ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET); + + if (si->si_byte_order != 0xfffe) + return 0; + + if (NOTMIME(ms) && file_printf(ms, "CDF V2 Document") == -1) + return -1; + + if (NOTMIME(ms) && file_printf(ms, ", %s Endian", + si->si_byte_order == 0xfffe ? "Little" : "Big") == -1) + return -1; + + if (NOTMIME(ms) && file_printf(ms, ", Os Version %d.%d", + si->si_os_version & 0xff, si->si_os_version >> 8) == -1) + return -1; + + if (NOTMIME(ms) && file_printf(ms, ", Os %d", si->si_os) == -1) + return -1; + + for (i = 0; i < si->si_count; i++) + if (cdf_file_section_info(ms, sst, sd->sd_offset) == -1) + return -1; + return 1; +} + +protected int +file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, + size_t nbytes) +{ + cdf_header_t h; + cdf_sat_t sat, ssat; + cdf_stream_t sst; + cdf_dir_t dir; + int i; + (void)&nbytes; + (void)&buf; + + if (cdf_read_header(fd, &h) == -1) + return 0; +#ifdef CDF_DEBUG + cdf_dump_header(&h); +#endif + + if (cdf_read_sat(fd, &h, &sat) == -1) { + file_error(ms, errno, "Can't read SAT"); + return -1; + } +#ifdef CDF_DEBUG + cdf_dump_sat("SAT", &h, &sat); +#endif + + if (cdf_read_ssat(fd, &h, &sat, &ssat) == -1) { + file_error(ms, errno, "Can't read SAT"); + free(sat.sat_tab); + return -1; + } +#ifdef CDF_DEBUG + cdf_dump_sat("SSAT", &h, &ssat); +#endif + + if (cdf_read_dir(fd, &h, &sat, &dir) == -1) { + file_error(ms, errno, "Can't read directory"); + free(sat.sat_tab); + free(ssat.sat_tab); + return -1; + } +#ifdef CDF_DEBUG + cdf_dump_dir(fd, &h, &sat, &dir); +#endif + + if (cdf_read_summary_info(fd, &h, &sat, &dir, &sst) == -1) { + file_error(ms, errno, "Can't read summary_info"); + free(sat.sat_tab); + free(ssat.sat_tab); + free(dir.dir_tab); + return -1; + } +#ifdef CDF_DEBUG + cdf_dump_summary_info(&h, &sst); +#endif + i = cdf_file_summary_info(ms, &sst); + free(sat.sat_tab); + free(ssat.sat_tab); + free(dir.dir_tab); + free(sst.sst_tab); + return i; +}