summaryrefslogtreecommitdiff
path: root/src/cdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cdf.c')
-rw-r--r--src/cdf.c593
1 files changed, 376 insertions, 217 deletions
diff --git a/src/cdf.c b/src/cdf.c
index 9e3cf9f..accfb32 100644
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -35,7 +35,7 @@
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.69 2014/12/04 15:56:46 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.106 2017/04/30 17:05:02 christos Exp $")
#endif
#include <assert.h>
@@ -73,10 +73,41 @@ static union {
#define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x)))
#define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x)))
#define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x)))
-#define CDF_TOLE(x) (sizeof(x) == 2 ? CDF_TOLE2(x) : (sizeof(x) == 4 ? \
- CDF_TOLE4(x) : CDF_TOLE8(x)))
+#define CDF_TOLE(x) (/*CONSTCOND*/sizeof(x) == 2 ? \
+ CDF_TOLE2(CAST(uint16_t, x)) : \
+ (/*CONSTCOND*/sizeof(x) == 4 ? \
+ CDF_TOLE4(CAST(uint32_t, x)) : \
+ CDF_TOLE8(CAST(uint64_t, x))))
#define CDF_GETUINT32(x, y) cdf_getuint32(x, y)
+#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n))
+#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n))
+#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u))
+
+
+static void *
+cdf_malloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), size_t n)
+{
+ DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n));
+ return malloc(n);
+}
+
+static void *
+cdf_realloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), void *p, size_t n)
+{
+ DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n));
+ return realloc(p, n);
+}
+
+static void *
+cdf_calloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), size_t n, size_t u)
+{
+ DPRINTF(("%s,%zu: %s %zu %zu\n", file, line, __func__, n, u));
+ return calloc(n, u);
+}
/*
* swap a short
@@ -263,15 +294,34 @@ cdf_unpack_dir(cdf_directory_t *d, char *buf)
CDF_UNPACK(d->d_unused0);
}
+int
+cdf_zero_stream(cdf_stream_t *scn)
+{
+ scn->sst_len = 0;
+ scn->sst_dirlen = 0;
+ scn->sst_ss = 0;
+ free(scn->sst_tab);
+ scn->sst_tab = NULL;
+ return -1;
+}
+
+static size_t
+cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h)
+{
+ size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
+ CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ assert(ss == sst->sst_ss);
+ return sst->sst_ss;
+}
+
static int
cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h,
const void *p, size_t tail, int line)
{
const char *b = (const char *)sst->sst_tab;
const char *e = ((const char *)p) + tail;
- size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
- CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
- (void)&line;
+ size_t ss = cdf_check_stream(sst, h);
+ /*LINTED*/(void)&line;
if (e >= b && (size_t)(e - b) <= ss * sst->sst_len)
return 0;
DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u"
@@ -287,10 +337,8 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
{
size_t siz = (size_t)off + len;
- if ((off_t)(off + len) != (off_t)siz) {
- errno = EINVAL;
- return -1;
- }
+ if ((off_t)(off + len) != (off_t)siz)
+ goto out;
if (info->i_buf != NULL && info->i_len >= siz) {
(void)memcpy(buf, &info->i_buf[off], len);
@@ -298,12 +346,15 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
}
if (info->i_fd == -1)
- return -1;
+ goto out;
if (pread(info->i_fd, buf, len, off) != (ssize_t)len)
return -1;
return (ssize_t)len;
+out:
+ errno = EINVAL;
+ return -1;
}
int
@@ -317,18 +368,18 @@ cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
cdf_unpack_header(h, buf);
cdf_swap_header(h);
if (h->h_magic != CDF_MAGIC) {
- DPRINTF(("Bad magic 0x%" INT64_T_FORMAT "x != 0x%"
+ DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#"
INT64_T_FORMAT "x\n",
(unsigned long long)h->h_magic,
(unsigned long long)CDF_MAGIC));
goto out;
}
if (h->h_sec_size_p2 > 20) {
- DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
+ DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2));
goto out;
}
if (h->h_short_sec_size_p2 > 20) {
- DPRINTF(("Bad short sector size 0x%u\n",
+ DPRINTF(("Bad short sector size %hu\n",
h->h_short_sec_size_p2));
goto out;
}
@@ -360,11 +411,14 @@ cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %"
SIZE_T_FORMAT "u\n",
pos + len, CDF_SEC_SIZE(h) * sst->sst_len));
- return -1;
+ goto out;
}
(void)memcpy(((char *)buf) + offs,
((const char *)sst->sst_tab) + pos, len);
return len;
+out:
+ errno = EFTYPE;
+ return -1;
}
/*
@@ -382,7 +436,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
if (h->h_master_sat[i] == CDF_SECID_FREE)
break;
-#define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
+#define CDF_SEC_LIMIT (UINT32_MAX / (8 * ss))
if ((nsatpersec > 0 &&
h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) ||
i > CDF_SEC_LIMIT) {
@@ -395,7 +449,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n",
sat->sat_len, ss));
- if ((sat->sat_tab = CAST(cdf_secid_t *, calloc(sat->sat_len, ss)))
+ if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss)))
== NULL)
return -1;
@@ -409,7 +463,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
}
}
- if ((msa = CAST(cdf_secid_t *, calloc(1, ss))) == NULL)
+ if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL)
goto out1;
mid = h->h_secid_first_sector_in_master_sat;
@@ -418,8 +472,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
goto out;
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Reading master sector loop limit"));
- errno = EFTYPE;
- goto out2;
+ goto out3;
}
if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
DPRINTF(("Reading master sector %d", mid));
@@ -432,8 +485,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
if (i >= sat->sat_len) {
DPRINTF(("Out of bounds reading MSA %" SIZE_T_FORMAT
"u >= %" SIZE_T_FORMAT "u", i, sat->sat_len));
- errno = EFTYPE;
- goto out2;
+ goto out3;
}
if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
sec) != (ssize_t)ss) {
@@ -448,6 +500,8 @@ out:
sat->sat_len = i;
free(msa);
return 0;
+out3:
+ errno = EFTYPE;
out2:
free(msa);
out1:
@@ -473,23 +527,24 @@ cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
DPRINTF((" %d", sid));
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Counting chain loop limit"));
- errno = EFTYPE;
- return (size_t)-1;
+ goto out;
}
if (sid >= maxsector) {
DPRINTF(("Sector %d >= %d\n", sid, maxsector));
- errno = EFTYPE;
- return (size_t)-1;
+ goto out;
}
sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
}
if (i == 0) {
DPRINTF((" none, sid: %d\n", sid));
- return (size_t)-1;
+ goto out;
}
DPRINTF(("\n"));
return i;
+out:
+ errno = EFTYPE;
+ return (size_t)-1;
}
int
@@ -498,27 +553,30 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
{
size_t ss = CDF_SEC_SIZE(h), i, j;
ssize_t nr;
+ scn->sst_tab = NULL;
scn->sst_len = cdf_count_chain(sat, sid, ss);
- scn->sst_dirlen = len;
+ scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len);
+ scn->sst_ss = ss;
+
+ if (sid == CDF_SECID_END_OF_CHAIN || len == 0)
+ return cdf_zero_stream(scn);
if (scn->sst_len == (size_t)-1)
- return -1;
+ goto out;
- scn->sst_tab = calloc(scn->sst_len, ss);
+ scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
if (scn->sst_tab == NULL)
- return -1;
+ return cdf_zero_stream(scn);
for (j = i = 0; sid >= 0; i++, j++) {
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Read long sector chain loop limit"));
- errno = EFTYPE;
goto out;
}
if (i >= scn->sst_len) {
DPRINTF(("Out of bounds reading long sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
scn->sst_len));
- errno = EFTYPE;
goto out;
}
if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
@@ -534,8 +592,8 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
}
return 0;
out:
- free(scn->sst_tab);
- return -1;
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
}
int
@@ -544,27 +602,27 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
cdf_secid_t sid, size_t len, cdf_stream_t *scn)
{
size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
+ scn->sst_tab = NULL;
scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
scn->sst_dirlen = len;
+ scn->sst_ss = ss;
- if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
- return -1;
+ if (scn->sst_len == (size_t)-1)
+ goto out;
- scn->sst_tab = calloc(scn->sst_len, ss);
+ scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
if (scn->sst_tab == NULL)
- return -1;
+ return cdf_zero_stream(scn);
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 (i >= scn->sst_len) {
DPRINTF(("Out of bounds reading short sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n",
i, scn->sst_len));
- errno = EFTYPE;
goto out;
}
if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
@@ -576,8 +634,8 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
}
return 0;
out:
- free(scn->sst_tab);
- return -1;
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
}
int
@@ -610,11 +668,11 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
dir->dir_len = ns * nd;
dir->dir_tab = CAST(cdf_directory_t *,
- calloc(dir->dir_len, sizeof(dir->dir_tab[0])));
+ CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0])));
if (dir->dir_tab == NULL)
return -1;
- if ((buf = CAST(char *, malloc(ss))) == NULL) {
+ if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) {
free(dir->dir_tab);
return -1;
}
@@ -622,7 +680,6 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
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(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
@@ -643,6 +700,7 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
out:
free(dir->dir_tab);
free(buf);
+ errno = EFTYPE;
return -1;
}
@@ -655,36 +713,37 @@ cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
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(sat, sid, CDF_SEC_SIZE(h));
+ ssat->sat_tab = NULL;
+ ssat->sat_len = cdf_count_chain(sat, sid, ss);
if (ssat->sat_len == (size_t)-1)
- return -1;
+ goto out;
- ssat->sat_tab = CAST(cdf_secid_t *, calloc(ssat->sat_len, ss));
+ ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss));
if (ssat->sat_tab == NULL)
- return -1;
+ goto out1;
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 (i >= ssat->sat_len) {
DPRINTF(("Out of bounds reading short sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
ssat->sat_len));
- errno = EFTYPE;
goto out;
}
if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
(ssize_t)ss) {
DPRINTF(("Reading short sat sector %d", sid));
- goto out;
+ goto out1;
}
sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
}
return 0;
out:
+ errno = EFTYPE;
+out1:
free(ssat->sat_tab);
return -1;
}
@@ -703,21 +762,24 @@ cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
break;
/* If the it is not there, just fake it; some docs don't have it */
- if (i == dir->dir_len)
+ if (i == dir->dir_len) {
+ DPRINTF(("Cannot find root storage dir\n"));
goto out;
+ }
d = &dir->dir_tab[i];
*root = d;
/* If the it is not there, just fake it; some docs don't have it */
- if (d->d_stream_first_sector < 0)
+ if (d->d_stream_first_sector < 0) {
+ DPRINTF(("No first secror in dir\n"));
goto out;
+ }
- return cdf_read_long_sector_chain(info, h, sat,
+ return cdf_read_long_sector_chain(info, h, sat,
d->d_stream_first_sector, d->d_size, scn);
out:
scn->sst_tab = NULL;
- scn->sst_len = 0;
- scn->sst_dirlen = 0;
+ (void)cdf_zero_stream(scn);
return 0;
}
@@ -731,6 +793,15 @@ cdf_namecmp(const char *d, const uint16_t *s, size_t l)
}
int
+cdf_read_doc_summary_info(const cdf_info_t *info, 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)
+{
+ return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
+ "\05DocumentSummaryInformation", scn);
+}
+
+int
cdf_read_summary_info(const cdf_info_t *info, 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)
@@ -744,24 +815,129 @@ cdf_read_user_stream(const cdf_info_t *info, 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, const char *name, cdf_stream_t *scn)
{
- size_t i;
const cdf_directory_t *d;
- size_t name_len = strlen(name) + 1;
+ int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM);
+
+ if (i <= 0) {
+ memset(scn, 0, sizeof(*scn));
+ return -1;
+ }
+
+ d = &dir->dir_tab[i - 1];
+ return cdf_read_sector_chain(info, h, sat, ssat, sst,
+ d->d_stream_first_sector, d->d_size, scn);
+}
+
+int
+cdf_find_stream(const cdf_dir_t *dir, const char *name, int type)
+{
+ size_t i, name_len = strlen(name) + 1;
for (i = dir->dir_len; i > 0; i--)
- if (dir->dir_tab[i - 1].d_type == CDF_DIR_TYPE_USER_STREAM &&
+ if (dir->dir_tab[i - 1].d_type == type &&
cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len)
== 0)
break;
+ if (i > 0)
+ return CAST(int, i);
- if (i == 0) {
- DPRINTF(("Cannot find user stream `%s'\n", name));
- errno = ESRCH;
- return -1;
+ DPRINTF(("Cannot find type %d `%s'\n", type, name));
+ errno = ESRCH;
+ return 0;
+}
+
+#define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
+#define CDF_PROP_LIMIT (UINT32_MAX / (8 * sizeof(cdf_property_info_t)))
+
+static const void *
+cdf_offset(const void *p, size_t l)
+{
+ return CAST(const void *, CAST(const uint8_t *, p) + l);
+}
+
+static const uint8_t *
+cdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h,
+ const uint8_t *p, const uint8_t *e, size_t i)
+{
+ size_t tail = (i << 1) + 1;
+ size_t ofs;
+ const uint8_t *q;
+
+ if (p >= e) {
+ DPRINTF(("Past end %p < %p\n", e, p));
+ return NULL;
}
- d = &dir->dir_tab[i - 1];
- return cdf_read_sector_chain(info, h, sat, ssat, sst,
- d->d_stream_first_sector, d->d_size, scn);
+ if (cdf_check_stream_offset(sst, h, p, (tail + 1) * sizeof(uint32_t),
+ __LINE__) == -1)
+ return NULL;
+ ofs = CDF_GETUINT32(p, tail);
+ q = CAST(const uint8_t *, cdf_offset(CAST(const void *, p),
+ ofs - 2 * sizeof(uint32_t)));
+
+ if (q < p) {
+ DPRINTF(("Wrapped around %p < %p\n", q, p));
+ return NULL;
+ }
+
+ if (q >= e) {
+ DPRINTF(("Ran off the end %p >= %p\n", q, e));
+ return NULL;
+ }
+ return q;
+}
+
+static cdf_property_info_t *
+cdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr)
+{
+ cdf_property_info_t *inp;
+ size_t newcount = *maxcount + incr;
+
+ if (newcount > CDF_PROP_LIMIT) {
+ DPRINTF(("exceeded property limit %zu > %zu\n",
+ newcount, CDF_PROP_LIMIT));
+ goto out;
+ }
+ inp = CAST(cdf_property_info_t *,
+ CDF_REALLOC(*info, newcount * sizeof(*inp)));
+ if (inp == NULL)
+ goto out;
+
+ *info = inp;
+ *maxcount = newcount;
+ return inp;
+out:
+ free(*info);
+ *maxcount = 0;
+ *info = NULL;
+ return NULL;
+}
+
+static int
+cdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e,
+ size_t len)
+{
+ if (inp->pi_type & CDF_VECTOR)
+ return 0;
+
+ if ((size_t)(CAST(const char *, e) - CAST(const char *, p)) < len)
+ return 0;
+
+ (void)memcpy(&inp->pi_val, p, len);
+
+ switch (len) {
+ case 2:
+ inp->pi_u16 = CDF_TOLE2(inp->pi_u16);
+ break;
+ case 4:
+ inp->pi_u32 = CDF_TOLE4(inp->pi_u32);
+ break;
+ case 8:
+ inp->pi_u64 = CDF_TOLE8(inp->pi_u64);
+ break;
+ default:
+ abort();
+ }
+ return 1;
}
int
@@ -771,92 +947,69 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
const cdf_section_header_t *shp;
cdf_section_header_t sh;
const uint8_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, o4, nelements, j;
+ size_t i, o4, nelements, j, slen, left;
cdf_property_info_t *inp;
if (offs > UINT32_MAX / 4) {
errno = EFTYPE;
goto out;
}
- shp = CAST(const cdf_section_header_t *, (const void *)
- ((const char *)sst->sst_tab + offs));
+ shp = CAST(const cdf_section_header_t *,
+ cdf_offset(sst->sst_tab, offs));
if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1)
goto out;
sh.sh_len = CDF_TOLE4(shp->sh_len);
-#define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
if (sh.sh_len > CDF_SHLEN_LIMIT) {
errno = EFTYPE;
goto out;
}
- sh.sh_properties = CDF_TOLE4(shp->sh_properties);
-#define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp)))
- if (sh.sh_properties > CDF_PROP_LIMIT)
+
+ if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1)
goto out;
+
+ sh.sh_properties = CDF_TOLE4(shp->sh_properties);
DPRINTF(("section len: %u properties %u\n", sh.sh_len,
sh.sh_properties));
- if (*maxcount) {
- if (*maxcount > CDF_PROP_LIMIT)
- goto out;
- *maxcount += sh.sh_properties;
- inp = CAST(cdf_property_info_t *,
- realloc(*info, *maxcount * sizeof(*inp)));
- } else {
- *maxcount = sh.sh_properties;
- inp = CAST(cdf_property_info_t *,
- malloc(*maxcount * sizeof(*inp)));
- }
+ if (sh.sh_properties > CDF_PROP_LIMIT)
+ goto out;
+ inp = cdf_grow_info(info, maxcount, sh.sh_properties);
if (inp == NULL)
goto out;
- *info = inp;
inp += *count;
*count += sh.sh_properties;
- p = CAST(const uint8_t *, (const void *)
- ((const char *)(const void *)sst->sst_tab +
- offs + sizeof(sh)));
- e = CAST(const uint8_t *, (const void *)
- (((const char *)(const void *)shp) + sh.sh_len));
- if (cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1)
+ p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh)));
+ e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len));
+ if (p >= e || cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1)
goto out;
+
for (i = 0; i < sh.sh_properties; i++) {
- size_t tail = (i << 1) + 1;
- size_t ofs;
- if (cdf_check_stream_offset(sst, h, p, tail * sizeof(uint32_t),
- __LINE__) == -1)
+ if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL)
goto out;
- ofs = CDF_GETUINT32(p, tail);
- q = (const uint8_t *)(const void *)
- ((const char *)(const void *)p + ofs
- - 2 * sizeof(uint32_t));
- if (q < p) {
- DPRINTF(("Wrapped around %p < %p\n", q, p));
- goto out;
- }
- if (q > e) {
- DPRINTF(("Ran of the end %p > %p\n", q, e));
+ inp[i].pi_id = CDF_GETUINT32(p, i << 1);
+ left = CAST(size_t, e - q);
+ if (left < sizeof(uint32_t)) {
+ DPRINTF(("short info (no type)_\n"));
goto out;
}
- inp[i].pi_id = CDF_GETUINT32(p, i << 1);
inp[i].pi_type = CDF_GETUINT32(q, 0);
- DPRINTF(("%" SIZE_T_FORMAT "u) id=%x type=%x offs=0x%tx,0x%x\n",
+ DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n",
i, inp[i].pi_id, inp[i].pi_type, q - p, offs));
if (inp[i].pi_type & CDF_VECTOR) {
+ if (left < sizeof(uint32_t) * 2) {
+ DPRINTF(("missing CDF_VECTOR length\n"));
+ goto out;
+ }
nelements = CDF_GETUINT32(q, 1);
if (nelements == 0) {
DPRINTF(("CDF_VECTOR with nelements == 0\n"));
goto out;
}
- o = 2;
+ slen = 2;
} else {
nelements = 1;
- o = 1;
+ slen = 1;
}
- o4 = o * sizeof(uint32_t);
+ o4 = slen * sizeof(uint32_t);
if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
goto unknown;
switch (inp[i].pi_type & CDF_TYPEMASK) {
@@ -864,100 +1017,72 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
case CDF_EMPTY:
break;
case CDF_SIGNED16:
- if (inp[i].pi_type & CDF_VECTOR)
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t)))
goto unknown;
- (void)memcpy(&s16, &q[o4], 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[o4], sizeof(s32));
- inp[i].pi_s32 = CDF_TOLE4((uint32_t)s32);
- break;
case CDF_BOOL:
case CDF_UNSIGNED32:
- if (inp[i].pi_type & CDF_VECTOR)
+ case CDF_FLOAT:
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t)))
goto unknown;
- (void)memcpy(&u32, &q[o4], 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[o4], sizeof(s64));
- inp[i].pi_s64 = CDF_TOLE8((uint64_t)s64);
- break;
case CDF_UNSIGNED64:
- if (inp[i].pi_type & CDF_VECTOR)
- goto unknown;
- (void)memcpy(&u64, &q[o4], sizeof(u64));
- inp[i].pi_u64 = CDF_TOLE8((uint64_t)u64);
- break;
- case CDF_FLOAT:
- if (inp[i].pi_type & CDF_VECTOR)
- goto unknown;
- (void)memcpy(&u32, &q[o4], sizeof(u32));
- u32 = CDF_TOLE4(u32);
- memcpy(&inp[i].pi_f, &u32, sizeof(inp[i].pi_f));
- break;
case CDF_DOUBLE:
- if (inp[i].pi_type & CDF_VECTOR)
+ case CDF_FILETIME:
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t)))
goto unknown;
- (void)memcpy(&u64, &q[o4], sizeof(u64));
- u64 = CDF_TOLE8((uint64_t)u64);
- memcpy(&inp[i].pi_d, &u64, sizeof(inp[i].pi_d));
break;
case CDF_LENGTH32_STRING:
case CDF_LENGTH32_WSTRING:
if (nelements > 1) {
size_t nelem = inp - *info;
- if (*maxcount > CDF_PROP_LIMIT
- || nelements > CDF_PROP_LIMIT)
- goto out;
- *maxcount += nelements;
- inp = CAST(cdf_property_info_t *,
- realloc(*info, *maxcount * sizeof(*inp)));
+ inp = cdf_grow_info(info, maxcount, nelements);
if (inp == NULL)
goto out;
- *info = inp;
- inp = *info + nelem;
+ inp += nelem;
}
DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n",
nelements));
for (j = 0; j < nelements && i < sh.sh_properties;
j++, i++)
{
- uint32_t l = CDF_GETUINT32(q, o);
+ uint32_t l;
+
+ if (o4 + sizeof(uint32_t) > left)
+ goto out;
+
+ l = CDF_GETUINT32(q, slen);
+ o4 += sizeof(uint32_t);
+ if (o4 + l > left)
+ goto out;
+
inp[i].pi_str.s_len = l;
- inp[i].pi_str.s_buf = (const char *)
- (const void *)(&q[o4 + sizeof(l)]);
- DPRINTF(("l = %d, r = %" SIZE_T_FORMAT
- "u, s = %s\n", l,
- CDF_ROUND(l, sizeof(l)),
+ inp[i].pi_str.s_buf = CAST(const char *,
+ CAST(const void *, &q[o4]));
+
+ DPRINTF(("o=%zu l=%d(%" SIZE_T_FORMAT
+ "u), t=%zu s=%s\n", o4, l,
+ CDF_ROUND(l, sizeof(l)), left,
inp[i].pi_str.s_buf));
+
if (l & 1)
l++;
- o += l >> 1;
- if (q + o >= e)
- goto out;
- o4 = o * sizeof(uint32_t);
+
+ slen += l >> 1;
+ o4 = slen * sizeof(uint32_t);
}
i--;
break;
- case CDF_FILETIME:
- if (inp[i].pi_type & CDF_VECTOR)
- goto unknown;
- (void)memcpy(&tp, &q[o4], sizeof(tp));
- inp[i].pi_tp = CDF_TOLE8((uint64_t)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",
+ memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val));
+ DPRINTF(("Don't know how to deal with %#x\n",
inp[i].pi_type));
break;
}
@@ -965,6 +1090,10 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
return 0;
out:
free(*info);
+ *info = NULL;
+ *count = 0;
+ *maxcount = 0;
+ errno = EFTYPE;
return -1;
}
@@ -998,52 +1127,79 @@ cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
}
-#define extract_catalog_field(f, l) \
- memcpy(&ce[i].f, b + (l), sizeof(ce[i].f)); \
- ce[i].f = CDF_TOLE(ce[i].f)
+#define extract_catalog_field(t, f, l) \
+ if (b + l + sizeof(cep->f) > eb) { \
+ cep->ce_namlen = 0; \
+ break; \
+ } \
+ memcpy(&cep->f, b + (l), sizeof(cep->f)); \
+ ce[i].f = CAST(t, CDF_TOLE(cep->f))
int
cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
cdf_catalog_t **cat)
{
- size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
- CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ size_t ss = cdf_check_stream(sst, h);
const char *b = CAST(const char *, sst->sst_tab);
- const char *eb = b + ss * sst->sst_len;
- size_t nr, i, k;
+ const char *nb, *eb = b + ss * sst->sst_len;
+ size_t nr, i, j, k;
cdf_catalog_entry_t *ce;
uint16_t reclen;
const uint16_t *np;
- for (nr = 0; b < eb; nr++) {
+ for (nr = 0;; nr++) {
memcpy(&reclen, b, sizeof(reclen));
reclen = CDF_TOLE2(reclen);
if (reclen == 0)
break;
b += reclen;
+ if (b > eb)
+ break;
}
+ if (nr == 0)
+ return -1;
+ nr--;
*cat = CAST(cdf_catalog_t *,
- malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
- (*cat)->cat_num = nr;
+ CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
+ if (*cat == NULL)
+ return -1;
ce = (*cat)->cat_e;
+ memset(ce, 0, nr * sizeof(*ce));
b = CAST(const char *, sst->sst_tab);
- for (i = 0; i < nr; i++) {
- extract_catalog_field(ce_namlen, 0);
- extract_catalog_field(ce_num, 2);
- extract_catalog_field(ce_timestamp, 6);
- reclen = ce[i].ce_namlen;
- ce[i].ce_namlen =
- sizeof(ce[i].ce_name) / sizeof(ce[i].ce_name[0]) - 1;
- if (ce[i].ce_namlen > reclen - 14)
- ce[i].ce_namlen = reclen - 14;
- np = CAST(const uint16_t *, (b + 16));
- for (k = 0; k < ce[i].ce_namlen; k++) {
- ce[i].ce_name[k] = np[k];
- CDF_TOLE2(ce[i].ce_name[k]);
+ for (j = i = 0; i < nr; b += reclen) {
+ cdf_catalog_entry_t *cep = &ce[j];
+ uint16_t rlen;
+
+ extract_catalog_field(uint16_t, ce_namlen, 0);
+ extract_catalog_field(uint16_t, ce_num, 4);
+ extract_catalog_field(uint64_t, ce_timestamp, 8);
+ reclen = cep->ce_namlen;
+
+ if (reclen < 14) {
+ cep->ce_namlen = 0;
+ continue;
}
- ce[i].ce_name[ce[i].ce_namlen] = 0;
- b += reclen;
+
+ cep->ce_namlen = __arraycount(cep->ce_name) - 1;
+ rlen = reclen - 14;
+ if (cep->ce_namlen > rlen)
+ cep->ce_namlen = rlen;
+
+ np = CAST(const uint16_t *, CAST(const void *, (b + 16)));
+ nb = CAST(const char *, CAST(const void *,
+ (np + cep->ce_namlen)));
+ if (nb > eb) {
+ cep->ce_namlen = 0;
+ break;
+ }
+
+ for (k = 0; k < cep->ce_namlen; k++)
+ cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */
+ cep->ce_name[cep->ce_namlen] = 0;
+ j = i;
+ i++;
}
+ (*cat)->cat_num = j;
return 0;
}
@@ -1091,7 +1247,7 @@ cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
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);
+ return snprintf(buf, bufsiz, "%#x", p);
}
int
@@ -1150,7 +1306,7 @@ cdf_dump_header(const cdf_header_t *h)
h->h_ ## b, 1 << h->h_ ## b)
DUMP("%d", revision);
DUMP("%d", version);
- DUMP("0x%x", byte_order);
+ DUMP("%#x", byte_order);
DUMP2("%d", sec_size_p2);
DUMP2("%d", short_sec_size_p2);
DUMP("%d", num_sectors_in_sat);
@@ -1188,11 +1344,12 @@ cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
}
void
-cdf_dump(void *v, size_t len)
+cdf_dump(const void *v, size_t len)
{
size_t i, j;
- unsigned char *p = v;
+ const unsigned char *p = v;
char abuf[16];
+
(void)fprintf(stderr, "%.4x: ", 0);
for (i = 0, j = 0; i < len; i++, p++) {
(void)fprintf(stderr, "%.2x ", *p);
@@ -1208,10 +1365,9 @@ cdf_dump(void *v, size_t len)
}
void
-cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
+cdf_dump_stream(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);
+ size_t ss = sst->sst_ss;
cdf_dump(sst->sst_tab, ss * sst->sst_len);
}
@@ -1244,7 +1400,7 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
d->d_color ? "black" : "red");
(void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
(void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
- (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags);
+ (void)fprintf(stderr, "Flags: %#x\n", d->d_flags);
cdf_timestamp_to_timespec(&ts, d->d_created);
(void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf));
cdf_timestamp_to_timespec(&ts, d->d_modified);
@@ -1265,7 +1421,7 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
name, d->d_stream_first_sector, d->d_size);
break;
}
- cdf_dump_stream(h, &scn);
+ cdf_dump_stream(&scn);
free(scn.sst_tab);
break;
default:
@@ -1327,17 +1483,17 @@ cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
cdf_print_elapsed_time(buf, sizeof(buf), tp);
(void)fprintf(stderr, "timestamp %s\n", buf);
} else {
- char buf[26];
+ char tbuf[26];
cdf_timestamp_to_timespec(&ts, tp);
(void)fprintf(stderr, "timestamp %s",
- cdf_ctime(&ts.tv_sec, buf));
+ cdf_ctime(&ts.tv_sec, tbuf));
}
break;
case CDF_CLIPBOARD:
(void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
break;
default:
- DPRINTF(("Don't know how to deal with %x\n",
+ DPRINTF(("Don't know how to deal with %#x\n",
info[i].pi_type));
break;
}
@@ -1356,7 +1512,7 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
(void)&h;
if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1)
return;
- (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order);
+ (void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order);
(void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
ssi.si_os_version >> 8);
(void)fprintf(stderr, "Os %d\n", ssi.si_os);
@@ -1401,7 +1557,10 @@ main(int argc, char *argv[])
cdf_dir_t dir;
cdf_info_t info;
const cdf_directory_t *root;
-
+#ifdef __linux__
+#define getprogname() __progname
+ extern char *__progname;
+#endif
if (argc < 2) {
(void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
return -1;
@@ -1438,7 +1597,7 @@ main(int argc, char *argv[])
== -1)
err(1, "Cannot read short stream");
#ifdef CDF_DEBUG
- cdf_dump_stream(&h, &sst);
+ cdf_dump_stream(&sst);
#endif
#ifdef CDF_DEBUG
@@ -1453,8 +1612,8 @@ main(int argc, char *argv[])
else
cdf_dump_summary_info(&h, &scn);
#endif
- if (cdf_read_catalog(&info, &h, &sat, &ssat, &sst, &dir,
- &scn) == -1)
+ if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst,
+ &dir, "Catalog", &scn) == -1)
warn("Cannot read catalog");
#ifdef CDF_DEBUG
else