#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.62 2014/06/04 17:26:07 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.63 2014/06/09 13:04:37 christos Exp $")
#endif
#include <assert.h>
#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_GETUINT32(x, y) cdf_getuint32(x, y)
"\05SummaryInformation", scn);
}
+int
+cdf_read_catalog(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,
+ "Catalog", scn);
+}
+
int
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,
}
+#define extract_catalog_field(f, l) \
+ memcpy(&ce[i].f, b + (l), sizeof(ce[i].f)); \
+ ce[i].f = CDF_TOLE(ce[i].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);
+ const char *b = CAST(const char *, sst->sst_tab);
+ const char *eb = b + ss * sst->sst_len;
+ size_t nr, i, k;
+ cdf_catalog_entry_t *ce;
+ uint16_t reclen;
+ const uint16_t *np;
+
+ for (nr = 0; b < eb; nr++) {
+ memcpy(&reclen, b, sizeof(reclen));
+ reclen = CDF_TOLE2(reclen);
+ if (reclen == 0)
+ break;
+ b += reclen;
+ }
+ *cat = CAST(cdf_catalog_t *,
+ malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
+ (*cat)->cat_num = nr;
+ ce = (*cat)->cat_e;
+ 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]);
+ }
+ ce[i].ce_name[ce[i].ce_namlen] = 0;
+ b += reclen;
+ }
+ return 0;
+}
int
cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
return len;
}
+char *
+cdf_u16tos8(char *buf, size_t len, const uint16_t *p)
+{
+ size_t i;
+ for (i = 0; i < len && p[i]; i++)
+ buf[i] = (char)p[i];
+ buf[i] = '\0';
+ return buf;
+}
#ifdef CDF_DEBUG
void
return;
(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);
+ ssi.si_os_version >> 8);
(void)fprintf(stderr, "Os %d\n", ssi.si_os);
cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
(void)fprintf(stderr, "Class %s\n", buf);
free(info);
}
+
+void
+cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst)
+{
+ cdf_catalog_t *cat;
+ cdf_unpack_catalog(h, sst, &cat);
+ const cdf_catalog_entry_t *ce = cat->cat_e;
+ struct timespec ts;
+ char tbuf[64], sbuf[256];
+ size_t i;
+
+ printf("Catalog:\n");
+ for (i = 0; i < cat->cat_num; i++) {
+ cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp);
+ printf("\t%d %s %s", ce[i].ce_num,
+ cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name),
+ cdf_ctime(&ts.tv_sec, tbuf));
+ }
+ free(cat);
+}
+
#endif
#ifdef TEST
cdf_stream_t sst, scn;
cdf_dir_t dir;
cdf_info_t info;
+ const cdf_directory_t *root;
if (argc < 2) {
(void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
err(1, "Cannot read dir");
- if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst) == -1)
+ if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root)
+ == -1)
err(1, "Cannot read short stream");
#ifdef CDF_DEBUG
cdf_dump_stream(&h, &sst);
if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
&scn) == -1)
- err(1, "Cannot read summary info");
+ warn("Cannot read summary info");
+#ifdef CDF_DEBUG
+ else
+ cdf_dump_summary_info(&h, &scn);
+#endif
+ if (cdf_read_catalog(&info, &h, &sat, &ssat, &sst, &dir,
+ &scn) == -1)
+ warn("Cannot read catalog");
#ifdef CDF_DEBUG
- cdf_dump_summary_info(&h, &scn);
+ else
+ cdf_dump_catalog(&h, &scn);
#endif
(void)close(info.i_fd);
size_t i_len;
} cdf_info_t;
+
+typedef struct {
+ uint16_t ce_namlen;
+ uint32_t ce_num;
+ uint64_t ce_timestamp;
+ uint16_t ce_name[256];
+} cdf_catalog_entry_t;
+
+typedef struct {
+ size_t cat_num;
+ cdf_catalog_entry_t cat_e[0];
+} cdf_catalog_t;
+
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_user_stream(const cdf_info_t *, const cdf_header_t *,
const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
const cdf_dir_t *, const char *, cdf_stream_t *);
+int cdf_read_catalog(cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
+ const cdf_dir_t *, cdf_stream_t *);
int cdf_read_summary_info(const cdf_info_t *, const cdf_header_t *,
const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
const cdf_dir_t *, cdf_stream_t *);
int cdf_unpack_summary_info(const cdf_stream_t *, const cdf_header_t *,
cdf_summary_info_header_t *, cdf_property_info_t **, size_t *);
+int cdf_unpack_catalog(const cdf_header_t *, const cdf_stream_t *,
+ cdf_catalog_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);
uint32_t cdf_tole4(uint32_t);
uint64_t cdf_tole8(uint64_t);
char *cdf_ctime(const time_t *, char *);
+char *cdf_u16tos8(char *, size_t, const uint16_t *);
#ifdef CDF_DEBUG
void cdf_dump_header(const cdf_header_t *);
const cdf_sat_t *, const cdf_stream_t *, const cdf_dir_t *);
void cdf_dump_property_info(const cdf_property_info_t *, size_t);
void cdf_dump_summary_info(const cdf_header_t *, const cdf_stream_t *);
+void cdf_dump_catalog(const cdf_header_t *, const cdf_stream_t *);
#endif
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: readcdf.c,v 1.43 2014/05/07 21:26:06 christos Exp $")
+FILE_RCSID("@(#)$File: readcdf.c,v 1.44 2014/05/14 23:22:48 christos Exp $")
#endif
#include <assert.h>
return 1;
}
+private int
+cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
+ const cdf_stream_t *sst)
+{
+ cdf_catalog_t *cat;
+ size_t i;
+ char buf[256];
+ cdf_catalog_entry_t *ce;
+
+ if (NOTMIME(ms)) {
+ if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
+ return -1;
+ if (cdf_unpack_catalog(h, sst, &cat) == -1)
+ return -1;
+ ce = cat->cat_e;
+ /* skip first entry since it has a , or paren */
+ for (i = 1; i < cat->cat_num; i++)
+ if (file_printf(ms, "%s%s",
+ cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
+ i == cat->cat_num - 1 ? "]" : ", ") == -1) {
+ free(cat);
+ return -1;
+ }
+ free(cat);
+ } else {
+ if (file_printf(ms, "application/CDFV2") == -1)
+ return -1;
+ }
+ return 1;
+}
+
private int
cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
const cdf_stream_t *sst, const cdf_directory_t *root_storage)
if (root_storage) {
str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
clsid2desc);
- if (str)
+ if (str) {
if (file_printf(ms, ", %s", str) == -1)
return -2;
}
}
+ }
m = cdf_file_property_info(ms, info, count, root_storage);
free(info);
if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
&scn)) == -1) {
if (errno == ESRCH) {
- corrupt = expn;
- expn = "No summary info";
+ if ((i = cdf_read_catalog(&info, &h, &sat, &ssat, &sst,
+ &dir, &scn)) == -1) {
+ corrupt = expn;
+ expn = "No summary info";
+ goto out4;
+ }
+#ifdef CDF_DEBUG
+ cdf_dump_catalog(&h, &scn);
+#endif
+ if ((i = cdf_file_catalog(ms, &h, &scn))
+ < 0)
+ expn = "Can't expand catalog";
} else {
expn = "Cannot read summary info";
}