From owner-svn-src-vendor@FreeBSD.ORG Sat May 2 08:22:51 2009 Return-Path: Delivered-To: svn-src-vendor@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 21F00106564A; Sat, 2 May 2009 08:22:51 +0000 (UTC) (envelope-from obrien@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 0DB098FC21; Sat, 2 May 2009 08:22:51 +0000 (UTC) (envelope-from obrien@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n428MnS7077092; Sat, 2 May 2009 08:22:49 GMT (envelope-from obrien@svn.freebsd.org) Received: (from obrien@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n428MntB077088; Sat, 2 May 2009 08:22:49 GMT (envelope-from obrien@svn.freebsd.org) Message-Id: <200905020822.n428MntB077088@svn.freebsd.org> From: "David E. O'Brien" Date: Sat, 2 May 2009 08:22:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org X-SVN-Group: vendor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r191739 - in vendor/file/dist: . Magdir tests X-BeenThere: svn-src-vendor@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the vendor work area tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 02 May 2009 08:22:51 -0000 Author: obrien Date: Sat May 2 08:22:49 2009 New Revision: 191739 URL: http://svn.freebsd.org/changeset/base/191739 Log: Virgin import of Christos Zoulas's FILE 5.00. Added: vendor/file/dist/Magdir/wireless vendor/file/dist/Makefile.am-src (contents, props changed) vendor/file/dist/cdf.c (contents, props changed) vendor/file/dist/cdf.h (contents, props changed) vendor/file/dist/cdf_time.c (contents, props changed) vendor/file/dist/encoding.c (contents, props changed) vendor/file/dist/readcdf.c (contents, props changed) Modified: vendor/file/dist/asprintf.c (props changed) vendor/file/dist/elfclass.h (props changed) vendor/file/dist/getopt_long.c (props changed) vendor/file/dist/mygetopt.h (props changed) vendor/file/dist/tests/Makefile.am (props changed) vendor/file/dist/tests/Makefile.in (props changed) vendor/file/dist/tests/test.c (props changed) vendor/file/dist/vasprintf.c (props changed) Added: vendor/file/dist/Magdir/wireless ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/file/dist/Magdir/wireless Sat May 2 08:22:49 2009 (r191739) @@ -0,0 +1,5 @@ +#------------------------------------------------------------------------------ +# wireless-regdb: file(1) magic for CRDA wireless-regdb file format +# +0 string RGDB CRDA wireless regulatory database file +>4 belong 19 (Version 1) Added: vendor/file/dist/Makefile.am-src ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/file/dist/Makefile.am-src Sat May 2 08:22:49 2009 (r191739) @@ -0,0 +1,18 @@ +MAGIC = $(pkgdatadir)/magic +lib_LTLIBRARIES = libmagic.la +include_HEADERS = magic.h + +bin_PROGRAMS = file + +AM_CPPFLAGS = -DMAGIC='"$(MAGIC)"' +AM_CFLAGS = @WARNINGS@ + +libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \ + encoding.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 cdf.c cdf_time.c readcdf.c cdf.h +libmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0 +libmagic_la_LIBADD = $(LTLIBOBJS) + +file_SOURCES = file.c +file_LDADD = libmagic.la Added: vendor/file/dist/cdf.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ vendor/file/dist/cdf.c Sat May 2 08:22:49 2009 (r191739) @@ -0,0 +1,1105 @@ +/*- + * 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. + */ +/* + * Parse composite document files, the format used in Microsoft Office + * document files before they switched to zipped xml. + * Info from: http://sc.openoffice.org/compdocfileformat.pdf + */ + +#include "file.h" + +#ifndef lint +FILE_RCSID("@(#)$File: cdf.c,v 1.17 2009/02/03 20:27:51 christos Exp $") +#endif + +#include +#ifdef CDF_DEBUG +#include +#endif +#include +#include +#include +#include +#include + +#ifndef EFTYPE +#define EFTYPE EINVAL +#endif + +#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 + +static union { + char s[4]; + uint32_t u; +} cdf_bo; + +#define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304) + +#define CDF_TOLE8(x) (NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x)) +#define CDF_TOLE4(x) (NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x)) +#define CDF_TOLE2(x) (NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x)) + +/* + * swap a short + */ +uint16_t +cdf_tole2(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 + */ +uint32_t +cdf_tole4(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; +} + +/* + * swap a quad + */ +uint64_t +cdf_tole8(uint64_t sv) +{ + uint64_t rv; + uint8_t *s = (uint8_t *)(void *)&sv; + uint8_t *d = (uint8_t *)(void *)&rv; + 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]; + return rv; +} + +#define CDF_UNPACK(a) \ + (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a) +#define CDF_UNPACKA(a) \ + (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a) + +void +cdf_swap_header(cdf_header_t *h) +{ + size_t i; + + h->h_magic = CDF_TOLE8(h->h_magic); + h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]); + h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]); + h->h_revision = CDF_TOLE2(h->h_revision); + h->h_version = CDF_TOLE2(h->h_version); + h->h_byte_order = CDF_TOLE2(h->h_byte_order); + h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2); + h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2); + h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat); + h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory); + h->h_min_size_standard_stream = + CDF_TOLE4(h->h_min_size_standard_stream); + h->h_secid_first_sector_in_short_sat = + CDF_TOLE4(h->h_secid_first_sector_in_short_sat); + h->h_num_sectors_in_short_sat = + CDF_TOLE4(h->h_num_sectors_in_short_sat); + h->h_secid_first_sector_in_master_sat = + CDF_TOLE4(h->h_secid_first_sector_in_master_sat); + h->h_num_sectors_in_master_sat = + CDF_TOLE4(h->h_num_sectors_in_master_sat); + for (i = 0; i < __arraycount(h->h_master_sat); i++) + h->h_master_sat[i] = CDF_TOLE4(h->h_master_sat[i]); +} + +void +cdf_unpack_header(cdf_header_t *h, char *buf) +{ + size_t i; + size_t len = 0; + + CDF_UNPACK(h->h_magic); + CDF_UNPACKA(h->h_uuid); + CDF_UNPACK(h->h_revision); + CDF_UNPACK(h->h_version); + CDF_UNPACK(h->h_byte_order); + CDF_UNPACK(h->h_sec_size_p2); + CDF_UNPACK(h->h_short_sec_size_p2); + CDF_UNPACKA(h->h_unused0); + CDF_UNPACK(h->h_num_sectors_in_sat); + CDF_UNPACK(h->h_secid_first_directory); + CDF_UNPACKA(h->h_unused1); + CDF_UNPACK(h->h_min_size_standard_stream); + CDF_UNPACK(h->h_secid_first_sector_in_short_sat); + CDF_UNPACK(h->h_num_sectors_in_short_sat); + CDF_UNPACK(h->h_secid_first_sector_in_master_sat); + CDF_UNPACK(h->h_num_sectors_in_master_sat); + for (i = 0; i < __arraycount(h->h_master_sat); i++) + CDF_UNPACK(h->h_master_sat[i]); +} + +void +cdf_swap_dir(cdf_directory_t *d) +{ + d->d_namelen = CDF_TOLE2(d->d_namelen); + d->d_left_child = CDF_TOLE4(d->d_left_child); + d->d_right_child = CDF_TOLE4(d->d_right_child); + d->d_storage = CDF_TOLE4(d->d_storage); + d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]); + d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]); + d->d_flags = CDF_TOLE4(d->d_flags); + d->d_created = CDF_TOLE8(d->d_created); + d->d_modified = CDF_TOLE8(d->d_modified); + d->d_stream_first_sector = CDF_TOLE4(d->d_stream_first_sector); + d->d_size = CDF_TOLE4(d->d_size); +} + +void +cdf_swap_class(cdf_classid_t *d) +{ + d->cl_dword = CDF_TOLE4(d->cl_dword); + d->cl_word[0] = CDF_TOLE2(d->cl_word[0]); + d->cl_word[1] = CDF_TOLE2(d->cl_word[1]); +} + +void +cdf_unpack_dir(cdf_directory_t *d, char *buf) +{ + size_t len = 0; + + CDF_UNPACKA(d->d_name); + CDF_UNPACK(d->d_namelen); + CDF_UNPACK(d->d_type); + CDF_UNPACK(d->d_color); + CDF_UNPACK(d->d_left_child); + CDF_UNPACK(d->d_right_child); + CDF_UNPACK(d->d_storage); + CDF_UNPACKA(d->d_storage_uuid); + CDF_UNPACK(d->d_flags); + CDF_UNPACK(d->d_created); + CDF_UNPACK(d->d_modified); + CDF_UNPACK(d->d_stream_first_sector); + CDF_UNPACK(d->d_size); + CDF_UNPACK(d->d_unused0); +} + +int +cdf_read_header(int fd, cdf_header_t *h) +{ + (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); + char buf[512]; + if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) + return -1; + if (read(fd, buf, sizeof(buf)) != sizeof(buf)) + return -1; + cdf_unpack_header(h, buf); + cdf_swap_header(h); + if (h->h_magic != CDF_MAGIC) { + DPRINTF(("Bad magic 0x%x != 0x$x\n", 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; + return read(fd, ((char *)buf) + offs, len); +} + +ssize_t +cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, + size_t len, const cdf_header_t *h, cdf_secid_t id) +{ + assert((size_t)CDF_SHORT_SEC_SIZE(h) == len); + (void)memcpy(((char *)buf) + offs, + ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len); + 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) { + DPRINTF(("Reading sector %d", h->h_master_sat[i])); + goto out1; + } + } + + if ((msa = calloc(1, ss)) == NULL) + goto out1; + + mid = h->h_secid_first_sector_in_master_sat; + for (j = 0; j < h->h_num_sectors_in_master_sat; j++) { + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Reading master sector loop limit")); + errno = EFTYPE; + goto out2; + } + if (cdf_read_sector(fd, msa, 0, ss, h, mid) != (ssize_t)ss) { + DPRINTF(("Reading master sector %d", mid)); + goto out2; + } + for (k = 0; k < (ss / sizeof(mid)) - 1; k++, i++) + if (cdf_read_sector(fd, sat->sat_tab, ss * i, ss, h, + CDF_TOLE4(msa[k])) != (ssize_t)ss) { + DPRINTF(("Reading sector %d", + CDF_TOLE4(msa[k]))); + goto out2; + } + mid = CDF_TOLE4(msa[(ss / sizeof(mid)) - 1]); + } + free(msa); + return 0; +out2: + free(msa); +out1: + free(sat->sat_tab); + return -1; +} + +size_t +cdf_count_chain(const cdf_header_t *h, const cdf_sat_t *sat, + cdf_secid_t sid) +{ + size_t i, j, s = CDF_SEC_SIZE(h) / sizeof(cdf_secid_t); + cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * s); + + DPRINTF(("Chain:")); + for (j = i = 0; sid >= 0; i++, j++) { + DPRINTF((" %d", sid)); + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Counting chain loop limit")); + errno = EFTYPE; + return (size_t)-1; + } + if (sid > maxsector) { + DPRINTF(("Sector %d > %d\n", sid, maxsector)); + errno = EFTYPE; + return (size_t)-1; + } + sid = CDF_TOLE4(sat->sat_tab[sid]); + } + DPRINTF(("\n")); + return i; +} + +int +cdf_read_long_sector_chain(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_secid_t sid, size_t len, cdf_stream_t *scn) +{ + size_t ss = CDF_SEC_SIZE(h), i, j; + ssize_t nr; + scn->sst_len = cdf_count_chain(h, sat, sid); + scn->sst_dirlen = len; + + if (scn->sst_len == (size_t)-1) + return -1; + + scn->sst_tab = calloc(scn->sst_len, ss); + if (scn->sst_tab == NULL) + return -1; + + for (j = i = 0; sid >= 0; i++, j++) { + if ((nr = cdf_read_sector(fd, scn->sst_tab, i * ss, ss, h, + sid)) != (ssize_t)ss) { + if (i == scn->sst_len - 1 && nr > 0) { + /* Last sector might be truncated */ + return 0; + } + DPRINTF(("Reading long sector chain %d", sid)); + goto out; + } + sid = CDF_TOLE4(sat->sat_tab[sid]); + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Read long sector chain loop limit")); + errno = EFTYPE; + goto out; + } + } + return 0; +out: + free(scn->sst_tab); + return (size_t)-1; +} + +int +cdf_read_short_sector_chain(const cdf_header_t *h, + const cdf_sat_t *ssat, const cdf_stream_t *sst, + cdf_secid_t sid, size_t len, cdf_stream_t *scn) +{ + size_t ss = CDF_SHORT_SEC_SIZE(h), i, j; + scn->sst_len = cdf_count_chain(h, ssat, sid); + scn->sst_dirlen = len; + + if (scn->sst_len == (size_t)-1) + return -1; + + scn->sst_tab = calloc(scn->sst_len, ss); + if (scn->sst_tab == NULL) + return -1; + + for (j = i = 0; sid >= 0; i++, j++) { + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Read short sector chain loop limit")); + errno = EFTYPE; + goto out; + } + if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h, + sid) != (ssize_t)ss) { + DPRINTF(("Reading short sector chain %d", sid)); + goto out; + } + sid = CDF_TOLE4(ssat->sat_tab[sid]); + } + return 0; +out: + free(scn->sst_tab); + return (size_t)-1; +} + +int +cdf_read_sector_chain(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + const cdf_sat_t *ssat, const cdf_stream_t *sst, + cdf_secid_t sid, size_t len, cdf_stream_t *scn) +{ + + if (len < h->h_min_size_standard_stream) + return cdf_read_short_sector_chain(h, ssat, sst, sid, len, + scn); + else + return cdf_read_long_sector_chain(fd, h, sat, sid, len, scn); +} + +int +cdf_read_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_dir_t *dir) +{ + size_t i, j; + size_t ss = CDF_SEC_SIZE(h), ns, nd; + char *buf; + cdf_secid_t sid = h->h_secid_first_directory; + + ns = cdf_count_chain(h, sat, sid); + if (ns == (size_t)-1) + return -1; + + nd = ss / CDF_DIRECTORY_SIZE; + + dir->dir_len = ns * nd; + dir->dir_tab = calloc(dir->dir_len, sizeof(dir->dir_tab[0])); + if (dir->dir_tab == NULL) + return -1; + + if ((buf = malloc(ss)) == NULL) { + free(dir->dir_tab); + return -1; + } + + for (j = i = 0; i < ns; i++, j++) { + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Read dir loop limit")); + errno = EFTYPE; + goto out; + } + if (cdf_read_sector(fd, buf, 0, ss, h, sid) != (ssize_t)ss) { + DPRINTF(("Reading directory sector %d", sid)); + goto out; + } + for (j = 0; j < nd; j++) { + cdf_unpack_dir(&dir->dir_tab[i * nd + j], + &buf[j * CDF_DIRECTORY_SIZE]); + } + sid = CDF_TOLE4(sat->sat_tab[sid]); + } + if (NEED_SWAP) + for (i = 0; i < dir->dir_len; i++) + cdf_swap_dir(&dir->dir_tab[i]); + free(buf); + return 0; +out: + free(dir->dir_tab); + free(buf); + return -1; +} + + +int +cdf_read_ssat(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + cdf_sat_t *ssat) +{ + size_t i, j; + 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 (ssat->sat_len == (size_t)-1) + return -1; + + ssat->sat_tab = calloc(ssat->sat_len, ss); + if (ssat->sat_tab == NULL) + return -1; + + for (j = i = 0; sid >= 0; i++, j++) { + if (j >= CDF_LOOP_LIMIT) { + DPRINTF(("Read short sat sector loop limit")); + errno = EFTYPE; + goto out; + } + if (cdf_read_sector(fd, ssat->sat_tab, i * ss, ss, h, sid) != + (ssize_t)ss) { + DPRINTF(("Reading short sat sector %d", sid)); + goto out; + } + sid = CDF_TOLE4(sat->sat_tab[sid]); + } + return 0; +out: + free(ssat->sat_tab); + return -1; +} + +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 *scn) +{ + 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) { + DPRINTF(("Cannot find root storage node\n")); + errno = EFTYPE; + return -1; + } + d = &dir->dir_tab[i]; + + /* If the it is not there, just fake it; some docs don't have it */ + if (d->d_stream_first_sector < 0) { + scn->sst_tab = NULL; + scn->sst_len = 0; + return 0; + } + + return cdf_read_long_sector_chain(fd, h, sat, + d->d_stream_first_sector, d->d_size, scn); +} + +static int +cdf_namecmp(const char *d, const uint16_t *s, size_t l) +{ + for (; l--; d++, s++) + if (*d != CDF_TOLE2(*s)) + return (unsigned char)*d - CDF_TOLE2(*s); + return 0; +} + +int +cdf_read_summary_info(int fd, const cdf_header_t *h, + const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, + const cdf_dir_t *dir, cdf_stream_t *scn) +{ + 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) { + DPRINTF(("Cannot find summary information section\n")); + errno = EFTYPE; + return -1; + } + d = &dir->dir_tab[i]; + return cdf_read_sector_chain(fd, h, sat, ssat, sst, + d->d_stream_first_sector, d->d_size, scn); +} + +int +cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs, + cdf_property_info_t **info, size_t *count, size_t *maxcount) +{ + const cdf_section_header_t *shp; + cdf_section_header_t sh; + const uint32_t *p, *q, *e; + int16_t s16; + int32_t s32; + uint32_t u32; + int64_t s64; + uint64_t u64; + cdf_timestamp_t tp; + size_t i, o, nelements, j; + cdf_property_info_t *inp; + + shp = (const void *)((const char *)sst->sst_tab + offs); + sh.sh_len = CDF_TOLE4(shp->sh_len); + sh.sh_properties = CDF_TOLE4(shp->sh_properties); + DPRINTF(("section len: %d properties %d\n", sh.sh_len, + sh.sh_properties)); + if (*maxcount) { + *maxcount += sh.sh_properties; + inp = realloc(*info, *maxcount * sizeof(*inp)); + } else { + *maxcount = sh.sh_properties; + inp = malloc(*maxcount * sizeof(*inp)); + } + if (inp == NULL) + goto out; + *info = inp; + inp += *count; + *count += sh.sh_properties; + p = (const void *)((const char *)sst->sst_tab + offs + sizeof(sh)); + e = (const void *)(((const char *)shp) + sh.sh_len); + for (i = 0; i < sh.sh_properties; i++) { + q = (const uint32_t *)((const char *)p + + CDF_TOLE4(p[(i << 1) + 1])) - 2; + if (q > e) { + DPRINTF(("Ran of the end %p > %p\n", q, e)); + goto out; + } + inp[i].pi_id = CDF_TOLE4(p[i << 1]); + inp[i].pi_type = CDF_TOLE4(q[0]); + DPRINTF(("%d) id=%x type=%x offs=%x\n", i, inp[i].pi_id, + inp[i].pi_type, (const char *)q - (const char *)p)); + if (inp[i].pi_type & CDF_VECTOR) { + nelements = CDF_TOLE4(q[1]); + o = 2; + } else { + nelements = 1; + o = 1; + } + if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED)) + goto unknown; + switch (inp[i].pi_type & CDF_TYPEMASK) { + case CDF_EMPTY: + break; + case CDF_SIGNED16: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&s16, &q[o], sizeof(s16)); + inp[i].pi_s16 = CDF_TOLE2(s16); + break; + case CDF_SIGNED32: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&s32, &q[o], sizeof(s32)); + inp[i].pi_s32 = CDF_TOLE4(s32); + break; + case CDF_BOOL: + case CDF_UNSIGNED32: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&u32, &q[o], sizeof(u32)); + inp[i].pi_u32 = CDF_TOLE4(u32); + break; + case CDF_SIGNED64: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&s64, &q[o], sizeof(s64)); + inp[i].pi_s64 = CDF_TOLE4(s64); + break; + case CDF_UNSIGNED64: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&u64, &q[o], sizeof(u64)); + inp[i].pi_u64 = CDF_TOLE4(u64); + break; + case CDF_LENGTH32_STRING: + if (nelements > 1) { + size_t nelem = inp - *info; + *maxcount += nelements; + inp = realloc(*info, *maxcount * sizeof(*inp)); + if (inp == NULL) + goto out; + *info = inp; + inp = *info + nelem; + } + DPRINTF(("nelements = %d\n", nelements)); + for (j = 0; j < nelements; j++, i++) { + uint32_t l = CDF_TOLE4(q[o]); + inp[i].pi_str.s_len = l; + inp[i].pi_str.s_buf = (const char *)(&q[o+1]); + DPRINTF(("l = %d, r = %d, s = %s\n", l, + CDF_ROUND(l, sizeof(l)), + inp[i].pi_str.s_buf)); + l = 4 + CDF_ROUND(l, sizeof(l)); + o += l >> 2; + } + i--; + break; + case CDF_FILETIME: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + (void)memcpy(&tp, &q[o], sizeof(tp)); + inp[i].pi_tp = CDF_TOLE8(tp); + break; + case CDF_CLIPBOARD: + if (inp[i].pi_type & CDF_VECTOR) + goto unknown; + break; + default: + unknown: + DPRINTF(("Don't know how to deal with %x\n", + inp[i].pi_type)); + goto out; + } + } + return 0; +out: + free(*info); + return -1; +} + +int +cdf_unpack_summary_info(const cdf_stream_t *sst, cdf_summary_info_header_t *ssi, + cdf_property_info_t **info, size_t *count) +{ + size_t i, maxcount; + 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); + + ssi->si_byte_order = CDF_TOLE2(si->si_byte_order); + ssi->si_os_version = CDF_TOLE2(si->si_os_version); + ssi->si_os = CDF_TOLE2(si->si_os); + ssi->si_class = si->si_class; + cdf_swap_class(&ssi->si_class); + ssi->si_count = CDF_TOLE2(si->si_count); + *count = 0; + maxcount = 0; + *info = NULL; + for (i = 0; i < CDF_TOLE4(si->si_count); i++) { + if (i >= CDF_LOOP_LIMIT) { + DPRINTF(("Unpack summary info loop limit")); + errno = EFTYPE; + return -1; + } + if (cdf_read_property_info(sst, CDF_TOLE4(sd->sd_offset), + info, count, &maxcount) == -1) + return -1; + } + return 0; +} + + + +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, ", CDF_TOLE4(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, j; + unsigned char *p = v; + char abuf[16]; + printf("%.4x: ", 0); + for (i = 0, j = 0; i < len; i++, p++) { + printf("%.2x ", *p); + abuf[j++] = isprint(*p) ? *p : '.'; + if (j == 16) { + j = 0; + abuf[15] = '\0'; + printf("%s\n%.4x: ", abuf, i + 1); + } + } + printf("\n"); +} + +void +cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst) +{ + size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? + CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); + cdf_dump(sst->sst_tab, ss * sst->sst_len); +} + +void +cdf_dump_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, + const cdf_sat_t *ssat, const cdf_stream_t *sst, + const cdf_dir_t *dir) +{ + size_t i, j; + cdf_directory_t *d; + char name[__arraycount(d->d_name)]; + cdf_stream_t scn; + 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)CDF_TOLE2(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); + 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); + 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 (sst == NULL) + break; + if (cdf_read_sector_chain(fd, h, sat, ssat, sst, + d->d_stream_first_sector, d->d_size, &scn) == -1) { + warn("Can't read stream for %s at %d len %d", + name, d->d_stream_first_sector, d->d_size); + break; + } + cdf_dump_stream(h, &scn); + free(scn.sst_tab); + break; + default: + break; + } + + } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***