cdf.c revision 191739
1191739Sobrien/*- 2191739Sobrien * Copyright (c) 2008 Christos Zoulas 3191739Sobrien * All rights reserved. 4191739Sobrien * 5191739Sobrien * Redistribution and use in source and binary forms, with or without 6191739Sobrien * modification, are permitted provided that the following conditions 7191739Sobrien * are met: 8191739Sobrien * 1. Redistributions of source code must retain the above copyright 9191739Sobrien * notice, this list of conditions and the following disclaimer. 10191739Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11191739Sobrien * notice, this list of conditions and the following disclaimer in the 12191739Sobrien * documentation and/or other materials provided with the distribution. 13191739Sobrien * 14191739Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 15191739Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16191739Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17191739Sobrien * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18191739Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19191739Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20191739Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21191739Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22191739Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23191739Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24191739Sobrien * POSSIBILITY OF SUCH DAMAGE. 25191739Sobrien */ 26191739Sobrien/* 27191739Sobrien * Parse composite document files, the format used in Microsoft Office 28191739Sobrien * document files before they switched to zipped xml. 29191739Sobrien * Info from: http://sc.openoffice.org/compdocfileformat.pdf 30191739Sobrien */ 31191739Sobrien 32191739Sobrien#include "file.h" 33191739Sobrien 34191739Sobrien#ifndef lint 35191739SobrienFILE_RCSID("@(#)$File: cdf.c,v 1.17 2009/02/03 20:27:51 christos Exp $") 36191739Sobrien#endif 37191739Sobrien 38191739Sobrien#include <assert.h> 39191739Sobrien#ifdef CDF_DEBUG 40191739Sobrien#include <err.h> 41191739Sobrien#endif 42191739Sobrien#include <stdlib.h> 43191739Sobrien#include <unistd.h> 44191739Sobrien#include <string.h> 45191739Sobrien#include <time.h> 46191739Sobrien#include <ctype.h> 47191739Sobrien 48191739Sobrien#ifndef EFTYPE 49191739Sobrien#define EFTYPE EINVAL 50191739Sobrien#endif 51191739Sobrien 52191739Sobrien#include "cdf.h" 53191739Sobrien 54191739Sobrien#ifndef __arraycount 55191739Sobrien#define __arraycount(a) (sizeof(a) / sizeof(a[0])) 56191739Sobrien#endif 57191739Sobrien 58191739Sobrien#ifdef CDF_DEBUG 59191739Sobrien#define DPRINTF(a) printf a 60191739Sobrien#else 61191739Sobrien#define DPRINTF(a) 62191739Sobrien#endif 63191739Sobrien 64191739Sobrienstatic union { 65191739Sobrien char s[4]; 66191739Sobrien uint32_t u; 67191739Sobrien} cdf_bo; 68191739Sobrien 69191739Sobrien#define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304) 70191739Sobrien 71191739Sobrien#define CDF_TOLE8(x) (NEED_SWAP ? cdf_tole8(x) : (uint64_t)(x)) 72191739Sobrien#define CDF_TOLE4(x) (NEED_SWAP ? cdf_tole4(x) : (uint32_t)(x)) 73191739Sobrien#define CDF_TOLE2(x) (NEED_SWAP ? cdf_tole2(x) : (uint16_t)(x)) 74191739Sobrien 75191739Sobrien/* 76191739Sobrien * swap a short 77191739Sobrien */ 78191739Sobrienuint16_t 79191739Sobriencdf_tole2(uint16_t sv) 80191739Sobrien{ 81191739Sobrien uint16_t rv; 82191739Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 83191739Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 84191739Sobrien d[0] = s[1]; 85191739Sobrien d[1] = s[0]; 86191739Sobrien return rv; 87191739Sobrien} 88191739Sobrien 89191739Sobrien/* 90191739Sobrien * swap an int 91191739Sobrien */ 92191739Sobrienuint32_t 93191739Sobriencdf_tole4(uint32_t sv) 94191739Sobrien{ 95191739Sobrien uint32_t rv; 96191739Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 97191739Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 98191739Sobrien d[0] = s[3]; 99191739Sobrien d[1] = s[2]; 100191739Sobrien d[2] = s[1]; 101191739Sobrien d[3] = s[0]; 102191739Sobrien return rv; 103191739Sobrien} 104191739Sobrien 105191739Sobrien/* 106191739Sobrien * swap a quad 107191739Sobrien */ 108191739Sobrienuint64_t 109191739Sobriencdf_tole8(uint64_t sv) 110191739Sobrien{ 111191739Sobrien uint64_t rv; 112191739Sobrien uint8_t *s = (uint8_t *)(void *)&sv; 113191739Sobrien uint8_t *d = (uint8_t *)(void *)&rv; 114191739Sobrien d[0] = s[7]; 115191739Sobrien d[1] = s[6]; 116191739Sobrien d[2] = s[5]; 117191739Sobrien d[3] = s[4]; 118191739Sobrien d[4] = s[3]; 119191739Sobrien d[5] = s[2]; 120191739Sobrien d[6] = s[1]; 121191739Sobrien d[7] = s[0]; 122191739Sobrien return rv; 123191739Sobrien} 124191739Sobrien 125191739Sobrien#define CDF_UNPACK(a) \ 126191739Sobrien (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a) 127191739Sobrien#define CDF_UNPACKA(a) \ 128191739Sobrien (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a) 129191739Sobrien 130191739Sobrienvoid 131191739Sobriencdf_swap_header(cdf_header_t *h) 132191739Sobrien{ 133191739Sobrien size_t i; 134191739Sobrien 135191739Sobrien h->h_magic = CDF_TOLE8(h->h_magic); 136191739Sobrien h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]); 137191739Sobrien h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]); 138191739Sobrien h->h_revision = CDF_TOLE2(h->h_revision); 139191739Sobrien h->h_version = CDF_TOLE2(h->h_version); 140191739Sobrien h->h_byte_order = CDF_TOLE2(h->h_byte_order); 141191739Sobrien h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2); 142191739Sobrien h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2); 143191739Sobrien h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat); 144191739Sobrien h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory); 145191739Sobrien h->h_min_size_standard_stream = 146191739Sobrien CDF_TOLE4(h->h_min_size_standard_stream); 147191739Sobrien h->h_secid_first_sector_in_short_sat = 148191739Sobrien CDF_TOLE4(h->h_secid_first_sector_in_short_sat); 149191739Sobrien h->h_num_sectors_in_short_sat = 150191739Sobrien CDF_TOLE4(h->h_num_sectors_in_short_sat); 151191739Sobrien h->h_secid_first_sector_in_master_sat = 152191739Sobrien CDF_TOLE4(h->h_secid_first_sector_in_master_sat); 153191739Sobrien h->h_num_sectors_in_master_sat = 154191739Sobrien CDF_TOLE4(h->h_num_sectors_in_master_sat); 155191739Sobrien for (i = 0; i < __arraycount(h->h_master_sat); i++) 156191739Sobrien h->h_master_sat[i] = CDF_TOLE4(h->h_master_sat[i]); 157191739Sobrien} 158191739Sobrien 159191739Sobrienvoid 160191739Sobriencdf_unpack_header(cdf_header_t *h, char *buf) 161191739Sobrien{ 162191739Sobrien size_t i; 163191739Sobrien size_t len = 0; 164191739Sobrien 165191739Sobrien CDF_UNPACK(h->h_magic); 166191739Sobrien CDF_UNPACKA(h->h_uuid); 167191739Sobrien CDF_UNPACK(h->h_revision); 168191739Sobrien CDF_UNPACK(h->h_version); 169191739Sobrien CDF_UNPACK(h->h_byte_order); 170191739Sobrien CDF_UNPACK(h->h_sec_size_p2); 171191739Sobrien CDF_UNPACK(h->h_short_sec_size_p2); 172191739Sobrien CDF_UNPACKA(h->h_unused0); 173191739Sobrien CDF_UNPACK(h->h_num_sectors_in_sat); 174191739Sobrien CDF_UNPACK(h->h_secid_first_directory); 175191739Sobrien CDF_UNPACKA(h->h_unused1); 176191739Sobrien CDF_UNPACK(h->h_min_size_standard_stream); 177191739Sobrien CDF_UNPACK(h->h_secid_first_sector_in_short_sat); 178191739Sobrien CDF_UNPACK(h->h_num_sectors_in_short_sat); 179191739Sobrien CDF_UNPACK(h->h_secid_first_sector_in_master_sat); 180191739Sobrien CDF_UNPACK(h->h_num_sectors_in_master_sat); 181191739Sobrien for (i = 0; i < __arraycount(h->h_master_sat); i++) 182191739Sobrien CDF_UNPACK(h->h_master_sat[i]); 183191739Sobrien} 184191739Sobrien 185191739Sobrienvoid 186191739Sobriencdf_swap_dir(cdf_directory_t *d) 187191739Sobrien{ 188191739Sobrien d->d_namelen = CDF_TOLE2(d->d_namelen); 189191739Sobrien d->d_left_child = CDF_TOLE4(d->d_left_child); 190191739Sobrien d->d_right_child = CDF_TOLE4(d->d_right_child); 191191739Sobrien d->d_storage = CDF_TOLE4(d->d_storage); 192191739Sobrien d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]); 193191739Sobrien d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]); 194191739Sobrien d->d_flags = CDF_TOLE4(d->d_flags); 195191739Sobrien d->d_created = CDF_TOLE8(d->d_created); 196191739Sobrien d->d_modified = CDF_TOLE8(d->d_modified); 197191739Sobrien d->d_stream_first_sector = CDF_TOLE4(d->d_stream_first_sector); 198191739Sobrien d->d_size = CDF_TOLE4(d->d_size); 199191739Sobrien} 200191739Sobrien 201191739Sobrienvoid 202191739Sobriencdf_swap_class(cdf_classid_t *d) 203191739Sobrien{ 204191739Sobrien d->cl_dword = CDF_TOLE4(d->cl_dword); 205191739Sobrien d->cl_word[0] = CDF_TOLE2(d->cl_word[0]); 206191739Sobrien d->cl_word[1] = CDF_TOLE2(d->cl_word[1]); 207191739Sobrien} 208191739Sobrien 209191739Sobrienvoid 210191739Sobriencdf_unpack_dir(cdf_directory_t *d, char *buf) 211191739Sobrien{ 212191739Sobrien size_t len = 0; 213191739Sobrien 214191739Sobrien CDF_UNPACKA(d->d_name); 215191739Sobrien CDF_UNPACK(d->d_namelen); 216191739Sobrien CDF_UNPACK(d->d_type); 217191739Sobrien CDF_UNPACK(d->d_color); 218191739Sobrien CDF_UNPACK(d->d_left_child); 219191739Sobrien CDF_UNPACK(d->d_right_child); 220191739Sobrien CDF_UNPACK(d->d_storage); 221191739Sobrien CDF_UNPACKA(d->d_storage_uuid); 222191739Sobrien CDF_UNPACK(d->d_flags); 223191739Sobrien CDF_UNPACK(d->d_created); 224191739Sobrien CDF_UNPACK(d->d_modified); 225191739Sobrien CDF_UNPACK(d->d_stream_first_sector); 226191739Sobrien CDF_UNPACK(d->d_size); 227191739Sobrien CDF_UNPACK(d->d_unused0); 228191739Sobrien} 229191739Sobrien 230191739Sobrienint 231191739Sobriencdf_read_header(int fd, cdf_header_t *h) 232191739Sobrien{ 233191739Sobrien (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); 234191739Sobrien char buf[512]; 235191739Sobrien if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) 236191739Sobrien return -1; 237191739Sobrien if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 238191739Sobrien return -1; 239191739Sobrien cdf_unpack_header(h, buf); 240191739Sobrien cdf_swap_header(h); 241191739Sobrien if (h->h_magic != CDF_MAGIC) { 242191739Sobrien DPRINTF(("Bad magic 0x%x != 0x$x\n", h->h_magic, CDF_MAGIC)); 243191739Sobrien errno = EFTYPE; 244191739Sobrien return -1; 245191739Sobrien } 246191739Sobrien return 0; 247191739Sobrien} 248191739Sobrien 249191739Sobrien 250191739Sobrienssize_t 251191739Sobriencdf_read_sector(int fd, void *buf, size_t offs, size_t len, 252191739Sobrien const cdf_header_t *h, cdf_secid_t id) 253191739Sobrien{ 254191739Sobrien assert((size_t)CDF_SEC_SIZE(h) == len); 255191739Sobrien if (lseek(fd, (off_t)CDF_SEC_POS(h, id), SEEK_SET) == (off_t)-1) 256191739Sobrien return -1; 257191739Sobrien return read(fd, ((char *)buf) + offs, len); 258191739Sobrien} 259191739Sobrien 260191739Sobrienssize_t 261191739Sobriencdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, 262191739Sobrien size_t len, const cdf_header_t *h, cdf_secid_t id) 263191739Sobrien{ 264191739Sobrien assert((size_t)CDF_SHORT_SEC_SIZE(h) == len); 265191739Sobrien (void)memcpy(((char *)buf) + offs, 266191739Sobrien ((const char *)sst->sst_tab) + CDF_SHORT_SEC_POS(h, id), len); 267191739Sobrien return len; 268191739Sobrien} 269191739Sobrien 270191739Sobrien/* 271191739Sobrien * Read the sector allocation table. 272191739Sobrien */ 273191739Sobrienint 274191739Sobriencdf_read_sat(int fd, cdf_header_t *h, cdf_sat_t *sat) 275191739Sobrien{ 276191739Sobrien size_t i, j, k; 277191739Sobrien size_t ss = CDF_SEC_SIZE(h); 278191739Sobrien cdf_secid_t *msa, mid; 279191739Sobrien 280191739Sobrien for (i = 0; i < __arraycount(h->h_master_sat); i++) 281191739Sobrien if (h->h_master_sat[i] == CDF_SECID_FREE) 282191739Sobrien break; 283191739Sobrien 284191739Sobrien sat->sat_len = (h->h_num_sectors_in_master_sat + i); 285191739Sobrien if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL) 286191739Sobrien return -1; 287191739Sobrien 288191739Sobrien for (i = 0; i < __arraycount(h->h_master_sat); i++) { 289191739Sobrien if (h->h_master_sat[i] < 0) 290191739Sobrien break; 291191739Sobrien if (cdf_read_sector(fd, sat->sat_tab, ss * i, ss, h, 292191739Sobrien h->h_master_sat[i]) != (ssize_t)ss) { 293191739Sobrien DPRINTF(("Reading sector %d", h->h_master_sat[i])); 294191739Sobrien goto out1; 295191739Sobrien } 296191739Sobrien } 297191739Sobrien 298191739Sobrien if ((msa = calloc(1, ss)) == NULL) 299191739Sobrien goto out1; 300191739Sobrien 301191739Sobrien mid = h->h_secid_first_sector_in_master_sat; 302191739Sobrien for (j = 0; j < h->h_num_sectors_in_master_sat; j++) { 303191739Sobrien if (j >= CDF_LOOP_LIMIT) { 304191739Sobrien DPRINTF(("Reading master sector loop limit")); 305191739Sobrien errno = EFTYPE; 306191739Sobrien goto out2; 307191739Sobrien } 308191739Sobrien if (cdf_read_sector(fd, msa, 0, ss, h, mid) != (ssize_t)ss) { 309191739Sobrien DPRINTF(("Reading master sector %d", mid)); 310191739Sobrien goto out2; 311191739Sobrien } 312191739Sobrien for (k = 0; k < (ss / sizeof(mid)) - 1; k++, i++) 313191739Sobrien if (cdf_read_sector(fd, sat->sat_tab, ss * i, ss, h, 314191739Sobrien CDF_TOLE4(msa[k])) != (ssize_t)ss) { 315191739Sobrien DPRINTF(("Reading sector %d", 316191739Sobrien CDF_TOLE4(msa[k]))); 317191739Sobrien goto out2; 318191739Sobrien } 319191739Sobrien mid = CDF_TOLE4(msa[(ss / sizeof(mid)) - 1]); 320191739Sobrien } 321191739Sobrien free(msa); 322191739Sobrien return 0; 323191739Sobrienout2: 324191739Sobrien free(msa); 325191739Sobrienout1: 326191739Sobrien free(sat->sat_tab); 327191739Sobrien return -1; 328191739Sobrien} 329191739Sobrien 330191739Sobriensize_t 331191739Sobriencdf_count_chain(const cdf_header_t *h, const cdf_sat_t *sat, 332191739Sobrien cdf_secid_t sid) 333191739Sobrien{ 334191739Sobrien size_t i, j, s = CDF_SEC_SIZE(h) / sizeof(cdf_secid_t); 335191739Sobrien cdf_secid_t maxsector = (cdf_secid_t)(sat->sat_len * s); 336191739Sobrien 337191739Sobrien DPRINTF(("Chain:")); 338191739Sobrien for (j = i = 0; sid >= 0; i++, j++) { 339191739Sobrien DPRINTF((" %d", sid)); 340191739Sobrien if (j >= CDF_LOOP_LIMIT) { 341191739Sobrien DPRINTF(("Counting chain loop limit")); 342191739Sobrien errno = EFTYPE; 343191739Sobrien return (size_t)-1; 344191739Sobrien } 345191739Sobrien if (sid > maxsector) { 346191739Sobrien DPRINTF(("Sector %d > %d\n", sid, maxsector)); 347191739Sobrien errno = EFTYPE; 348191739Sobrien return (size_t)-1; 349191739Sobrien } 350191739Sobrien sid = CDF_TOLE4(sat->sat_tab[sid]); 351191739Sobrien } 352191739Sobrien DPRINTF(("\n")); 353191739Sobrien return i; 354191739Sobrien} 355191739Sobrien 356191739Sobrienint 357191739Sobriencdf_read_long_sector_chain(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 358191739Sobrien cdf_secid_t sid, size_t len, cdf_stream_t *scn) 359191739Sobrien{ 360191739Sobrien size_t ss = CDF_SEC_SIZE(h), i, j; 361191739Sobrien ssize_t nr; 362191739Sobrien scn->sst_len = cdf_count_chain(h, sat, sid); 363191739Sobrien scn->sst_dirlen = len; 364191739Sobrien 365191739Sobrien if (scn->sst_len == (size_t)-1) 366191739Sobrien return -1; 367191739Sobrien 368191739Sobrien scn->sst_tab = calloc(scn->sst_len, ss); 369191739Sobrien if (scn->sst_tab == NULL) 370191739Sobrien return -1; 371191739Sobrien 372191739Sobrien for (j = i = 0; sid >= 0; i++, j++) { 373191739Sobrien if ((nr = cdf_read_sector(fd, scn->sst_tab, i * ss, ss, h, 374191739Sobrien sid)) != (ssize_t)ss) { 375191739Sobrien if (i == scn->sst_len - 1 && nr > 0) { 376191739Sobrien /* Last sector might be truncated */ 377191739Sobrien return 0; 378191739Sobrien } 379191739Sobrien DPRINTF(("Reading long sector chain %d", sid)); 380191739Sobrien goto out; 381191739Sobrien } 382191739Sobrien sid = CDF_TOLE4(sat->sat_tab[sid]); 383191739Sobrien if (j >= CDF_LOOP_LIMIT) { 384191739Sobrien DPRINTF(("Read long sector chain loop limit")); 385191739Sobrien errno = EFTYPE; 386191739Sobrien goto out; 387191739Sobrien } 388191739Sobrien } 389191739Sobrien return 0; 390191739Sobrienout: 391191739Sobrien free(scn->sst_tab); 392191739Sobrien return (size_t)-1; 393191739Sobrien} 394191739Sobrien 395191739Sobrienint 396191739Sobriencdf_read_short_sector_chain(const cdf_header_t *h, 397191739Sobrien const cdf_sat_t *ssat, const cdf_stream_t *sst, 398191739Sobrien cdf_secid_t sid, size_t len, cdf_stream_t *scn) 399191739Sobrien{ 400191739Sobrien size_t ss = CDF_SHORT_SEC_SIZE(h), i, j; 401191739Sobrien scn->sst_len = cdf_count_chain(h, ssat, sid); 402191739Sobrien scn->sst_dirlen = len; 403191739Sobrien 404191739Sobrien if (scn->sst_len == (size_t)-1) 405191739Sobrien return -1; 406191739Sobrien 407191739Sobrien scn->sst_tab = calloc(scn->sst_len, ss); 408191739Sobrien if (scn->sst_tab == NULL) 409191739Sobrien return -1; 410191739Sobrien 411191739Sobrien for (j = i = 0; sid >= 0; i++, j++) { 412191739Sobrien if (j >= CDF_LOOP_LIMIT) { 413191739Sobrien DPRINTF(("Read short sector chain loop limit")); 414191739Sobrien errno = EFTYPE; 415191739Sobrien goto out; 416191739Sobrien } 417191739Sobrien if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h, 418191739Sobrien sid) != (ssize_t)ss) { 419191739Sobrien DPRINTF(("Reading short sector chain %d", sid)); 420191739Sobrien goto out; 421191739Sobrien } 422191739Sobrien sid = CDF_TOLE4(ssat->sat_tab[sid]); 423191739Sobrien } 424191739Sobrien return 0; 425191739Sobrienout: 426191739Sobrien free(scn->sst_tab); 427191739Sobrien return (size_t)-1; 428191739Sobrien} 429191739Sobrien 430191739Sobrienint 431191739Sobriencdf_read_sector_chain(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 432191739Sobrien const cdf_sat_t *ssat, const cdf_stream_t *sst, 433191739Sobrien cdf_secid_t sid, size_t len, cdf_stream_t *scn) 434191739Sobrien{ 435191739Sobrien 436191739Sobrien if (len < h->h_min_size_standard_stream) 437191739Sobrien return cdf_read_short_sector_chain(h, ssat, sst, sid, len, 438191739Sobrien scn); 439191739Sobrien else 440191739Sobrien return cdf_read_long_sector_chain(fd, h, sat, sid, len, scn); 441191739Sobrien} 442191739Sobrien 443191739Sobrienint 444191739Sobriencdf_read_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 445191739Sobrien cdf_dir_t *dir) 446191739Sobrien{ 447191739Sobrien size_t i, j; 448191739Sobrien size_t ss = CDF_SEC_SIZE(h), ns, nd; 449191739Sobrien char *buf; 450191739Sobrien cdf_secid_t sid = h->h_secid_first_directory; 451191739Sobrien 452191739Sobrien ns = cdf_count_chain(h, sat, sid); 453191739Sobrien if (ns == (size_t)-1) 454191739Sobrien return -1; 455191739Sobrien 456191739Sobrien nd = ss / CDF_DIRECTORY_SIZE; 457191739Sobrien 458191739Sobrien dir->dir_len = ns * nd; 459191739Sobrien dir->dir_tab = calloc(dir->dir_len, sizeof(dir->dir_tab[0])); 460191739Sobrien if (dir->dir_tab == NULL) 461191739Sobrien return -1; 462191739Sobrien 463191739Sobrien if ((buf = malloc(ss)) == NULL) { 464191739Sobrien free(dir->dir_tab); 465191739Sobrien return -1; 466191739Sobrien } 467191739Sobrien 468191739Sobrien for (j = i = 0; i < ns; i++, j++) { 469191739Sobrien if (j >= CDF_LOOP_LIMIT) { 470191739Sobrien DPRINTF(("Read dir loop limit")); 471191739Sobrien errno = EFTYPE; 472191739Sobrien goto out; 473191739Sobrien } 474191739Sobrien if (cdf_read_sector(fd, buf, 0, ss, h, sid) != (ssize_t)ss) { 475191739Sobrien DPRINTF(("Reading directory sector %d", sid)); 476191739Sobrien goto out; 477191739Sobrien } 478191739Sobrien for (j = 0; j < nd; j++) { 479191739Sobrien cdf_unpack_dir(&dir->dir_tab[i * nd + j], 480191739Sobrien &buf[j * CDF_DIRECTORY_SIZE]); 481191739Sobrien } 482191739Sobrien sid = CDF_TOLE4(sat->sat_tab[sid]); 483191739Sobrien } 484191739Sobrien if (NEED_SWAP) 485191739Sobrien for (i = 0; i < dir->dir_len; i++) 486191739Sobrien cdf_swap_dir(&dir->dir_tab[i]); 487191739Sobrien free(buf); 488191739Sobrien return 0; 489191739Sobrienout: 490191739Sobrien free(dir->dir_tab); 491191739Sobrien free(buf); 492191739Sobrien return -1; 493191739Sobrien} 494191739Sobrien 495191739Sobrien 496191739Sobrienint 497191739Sobriencdf_read_ssat(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 498191739Sobrien cdf_sat_t *ssat) 499191739Sobrien{ 500191739Sobrien size_t i, j; 501191739Sobrien size_t ss = CDF_SEC_SIZE(h); 502191739Sobrien cdf_secid_t sid = h->h_secid_first_sector_in_short_sat; 503191739Sobrien 504191739Sobrien ssat->sat_len = cdf_count_chain(h, sat, sid); 505191739Sobrien if (ssat->sat_len == (size_t)-1) 506191739Sobrien return -1; 507191739Sobrien 508191739Sobrien ssat->sat_tab = calloc(ssat->sat_len, ss); 509191739Sobrien if (ssat->sat_tab == NULL) 510191739Sobrien return -1; 511191739Sobrien 512191739Sobrien for (j = i = 0; sid >= 0; i++, j++) { 513191739Sobrien if (j >= CDF_LOOP_LIMIT) { 514191739Sobrien DPRINTF(("Read short sat sector loop limit")); 515191739Sobrien errno = EFTYPE; 516191739Sobrien goto out; 517191739Sobrien } 518191739Sobrien if (cdf_read_sector(fd, ssat->sat_tab, i * ss, ss, h, sid) != 519191739Sobrien (ssize_t)ss) { 520191739Sobrien DPRINTF(("Reading short sat sector %d", sid)); 521191739Sobrien goto out; 522191739Sobrien } 523191739Sobrien sid = CDF_TOLE4(sat->sat_tab[sid]); 524191739Sobrien } 525191739Sobrien return 0; 526191739Sobrienout: 527191739Sobrien free(ssat->sat_tab); 528191739Sobrien return -1; 529191739Sobrien} 530191739Sobrien 531191739Sobrienint 532191739Sobriencdf_read_short_stream(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 533191739Sobrien const cdf_dir_t *dir, cdf_stream_t *scn) 534191739Sobrien{ 535191739Sobrien size_t i; 536191739Sobrien const cdf_directory_t *d; 537191739Sobrien 538191739Sobrien for (i = 0; i < dir->dir_len; i++) 539191739Sobrien if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE) 540191739Sobrien break; 541191739Sobrien 542191739Sobrien if (i == dir->dir_len) { 543191739Sobrien DPRINTF(("Cannot find root storage node\n")); 544191739Sobrien errno = EFTYPE; 545191739Sobrien return -1; 546191739Sobrien } 547191739Sobrien d = &dir->dir_tab[i]; 548191739Sobrien 549191739Sobrien /* If the it is not there, just fake it; some docs don't have it */ 550191739Sobrien if (d->d_stream_first_sector < 0) { 551191739Sobrien scn->sst_tab = NULL; 552191739Sobrien scn->sst_len = 0; 553191739Sobrien return 0; 554191739Sobrien } 555191739Sobrien 556191739Sobrien return cdf_read_long_sector_chain(fd, h, sat, 557191739Sobrien d->d_stream_first_sector, d->d_size, scn); 558191739Sobrien} 559191739Sobrien 560191739Sobrienstatic int 561191739Sobriencdf_namecmp(const char *d, const uint16_t *s, size_t l) 562191739Sobrien{ 563191739Sobrien for (; l--; d++, s++) 564191739Sobrien if (*d != CDF_TOLE2(*s)) 565191739Sobrien return (unsigned char)*d - CDF_TOLE2(*s); 566191739Sobrien return 0; 567191739Sobrien} 568191739Sobrien 569191739Sobrienint 570191739Sobriencdf_read_summary_info(int fd, const cdf_header_t *h, 571191739Sobrien const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, 572191739Sobrien const cdf_dir_t *dir, cdf_stream_t *scn) 573191739Sobrien{ 574191739Sobrien size_t i; 575191739Sobrien const cdf_directory_t *d; 576191739Sobrien static const char name[] = "\05SummaryInformation"; 577191739Sobrien 578191739Sobrien for (i = 0; i < dir->dir_len; i++) 579191739Sobrien if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_USER_STREAM && 580191739Sobrien cdf_namecmp(name, dir->dir_tab[i].d_name, sizeof(name)) 581191739Sobrien == 0) 582191739Sobrien break; 583191739Sobrien 584191739Sobrien if (i == dir->dir_len) { 585191739Sobrien DPRINTF(("Cannot find summary information section\n")); 586191739Sobrien errno = EFTYPE; 587191739Sobrien return -1; 588191739Sobrien } 589191739Sobrien d = &dir->dir_tab[i]; 590191739Sobrien return cdf_read_sector_chain(fd, h, sat, ssat, sst, 591191739Sobrien d->d_stream_first_sector, d->d_size, scn); 592191739Sobrien} 593191739Sobrien 594191739Sobrienint 595191739Sobriencdf_read_property_info(const cdf_stream_t *sst, uint32_t offs, 596191739Sobrien cdf_property_info_t **info, size_t *count, size_t *maxcount) 597191739Sobrien{ 598191739Sobrien const cdf_section_header_t *shp; 599191739Sobrien cdf_section_header_t sh; 600191739Sobrien const uint32_t *p, *q, *e; 601191739Sobrien int16_t s16; 602191739Sobrien int32_t s32; 603191739Sobrien uint32_t u32; 604191739Sobrien int64_t s64; 605191739Sobrien uint64_t u64; 606191739Sobrien cdf_timestamp_t tp; 607191739Sobrien size_t i, o, nelements, j; 608191739Sobrien cdf_property_info_t *inp; 609191739Sobrien 610191739Sobrien shp = (const void *)((const char *)sst->sst_tab + offs); 611191739Sobrien sh.sh_len = CDF_TOLE4(shp->sh_len); 612191739Sobrien sh.sh_properties = CDF_TOLE4(shp->sh_properties); 613191739Sobrien DPRINTF(("section len: %d properties %d\n", sh.sh_len, 614191739Sobrien sh.sh_properties)); 615191739Sobrien if (*maxcount) { 616191739Sobrien *maxcount += sh.sh_properties; 617191739Sobrien inp = realloc(*info, *maxcount * sizeof(*inp)); 618191739Sobrien } else { 619191739Sobrien *maxcount = sh.sh_properties; 620191739Sobrien inp = malloc(*maxcount * sizeof(*inp)); 621191739Sobrien } 622191739Sobrien if (inp == NULL) 623191739Sobrien goto out; 624191739Sobrien *info = inp; 625191739Sobrien inp += *count; 626191739Sobrien *count += sh.sh_properties; 627191739Sobrien p = (const void *)((const char *)sst->sst_tab + offs + sizeof(sh)); 628191739Sobrien e = (const void *)(((const char *)shp) + sh.sh_len); 629191739Sobrien for (i = 0; i < sh.sh_properties; i++) { 630191739Sobrien q = (const uint32_t *)((const char *)p + 631191739Sobrien CDF_TOLE4(p[(i << 1) + 1])) - 2; 632191739Sobrien if (q > e) { 633191739Sobrien DPRINTF(("Ran of the end %p > %p\n", q, e)); 634191739Sobrien goto out; 635191739Sobrien } 636191739Sobrien inp[i].pi_id = CDF_TOLE4(p[i << 1]); 637191739Sobrien inp[i].pi_type = CDF_TOLE4(q[0]); 638191739Sobrien DPRINTF(("%d) id=%x type=%x offs=%x\n", i, inp[i].pi_id, 639191739Sobrien inp[i].pi_type, (const char *)q - (const char *)p)); 640191739Sobrien if (inp[i].pi_type & CDF_VECTOR) { 641191739Sobrien nelements = CDF_TOLE4(q[1]); 642191739Sobrien o = 2; 643191739Sobrien } else { 644191739Sobrien nelements = 1; 645191739Sobrien o = 1; 646191739Sobrien } 647191739Sobrien if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED)) 648191739Sobrien goto unknown; 649191739Sobrien switch (inp[i].pi_type & CDF_TYPEMASK) { 650191739Sobrien case CDF_EMPTY: 651191739Sobrien break; 652191739Sobrien case CDF_SIGNED16: 653191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 654191739Sobrien goto unknown; 655191739Sobrien (void)memcpy(&s16, &q[o], sizeof(s16)); 656191739Sobrien inp[i].pi_s16 = CDF_TOLE2(s16); 657191739Sobrien break; 658191739Sobrien case CDF_SIGNED32: 659191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 660191739Sobrien goto unknown; 661191739Sobrien (void)memcpy(&s32, &q[o], sizeof(s32)); 662191739Sobrien inp[i].pi_s32 = CDF_TOLE4(s32); 663191739Sobrien break; 664191739Sobrien case CDF_BOOL: 665191739Sobrien case CDF_UNSIGNED32: 666191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 667191739Sobrien goto unknown; 668191739Sobrien (void)memcpy(&u32, &q[o], sizeof(u32)); 669191739Sobrien inp[i].pi_u32 = CDF_TOLE4(u32); 670191739Sobrien break; 671191739Sobrien case CDF_SIGNED64: 672191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 673191739Sobrien goto unknown; 674191739Sobrien (void)memcpy(&s64, &q[o], sizeof(s64)); 675191739Sobrien inp[i].pi_s64 = CDF_TOLE4(s64); 676191739Sobrien break; 677191739Sobrien case CDF_UNSIGNED64: 678191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 679191739Sobrien goto unknown; 680191739Sobrien (void)memcpy(&u64, &q[o], sizeof(u64)); 681191739Sobrien inp[i].pi_u64 = CDF_TOLE4(u64); 682191739Sobrien break; 683191739Sobrien case CDF_LENGTH32_STRING: 684191739Sobrien if (nelements > 1) { 685191739Sobrien size_t nelem = inp - *info; 686191739Sobrien *maxcount += nelements; 687191739Sobrien inp = realloc(*info, *maxcount * sizeof(*inp)); 688191739Sobrien if (inp == NULL) 689191739Sobrien goto out; 690191739Sobrien *info = inp; 691191739Sobrien inp = *info + nelem; 692191739Sobrien } 693191739Sobrien DPRINTF(("nelements = %d\n", nelements)); 694191739Sobrien for (j = 0; j < nelements; j++, i++) { 695191739Sobrien uint32_t l = CDF_TOLE4(q[o]); 696191739Sobrien inp[i].pi_str.s_len = l; 697191739Sobrien inp[i].pi_str.s_buf = (const char *)(&q[o+1]); 698191739Sobrien DPRINTF(("l = %d, r = %d, s = %s\n", l, 699191739Sobrien CDF_ROUND(l, sizeof(l)), 700191739Sobrien inp[i].pi_str.s_buf)); 701191739Sobrien l = 4 + CDF_ROUND(l, sizeof(l)); 702191739Sobrien o += l >> 2; 703191739Sobrien } 704191739Sobrien i--; 705191739Sobrien break; 706191739Sobrien case CDF_FILETIME: 707191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 708191739Sobrien goto unknown; 709191739Sobrien (void)memcpy(&tp, &q[o], sizeof(tp)); 710191739Sobrien inp[i].pi_tp = CDF_TOLE8(tp); 711191739Sobrien break; 712191739Sobrien case CDF_CLIPBOARD: 713191739Sobrien if (inp[i].pi_type & CDF_VECTOR) 714191739Sobrien goto unknown; 715191739Sobrien break; 716191739Sobrien default: 717191739Sobrien unknown: 718191739Sobrien DPRINTF(("Don't know how to deal with %x\n", 719191739Sobrien inp[i].pi_type)); 720191739Sobrien goto out; 721191739Sobrien } 722191739Sobrien } 723191739Sobrien return 0; 724191739Sobrienout: 725191739Sobrien free(*info); 726191739Sobrien return -1; 727191739Sobrien} 728191739Sobrien 729191739Sobrienint 730191739Sobriencdf_unpack_summary_info(const cdf_stream_t *sst, cdf_summary_info_header_t *ssi, 731191739Sobrien cdf_property_info_t **info, size_t *count) 732191739Sobrien{ 733191739Sobrien size_t i, maxcount; 734191739Sobrien const cdf_summary_info_header_t *si = sst->sst_tab; 735191739Sobrien const cdf_section_declaration_t *sd = (const void *) 736191739Sobrien ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET); 737191739Sobrien 738191739Sobrien ssi->si_byte_order = CDF_TOLE2(si->si_byte_order); 739191739Sobrien ssi->si_os_version = CDF_TOLE2(si->si_os_version); 740191739Sobrien ssi->si_os = CDF_TOLE2(si->si_os); 741191739Sobrien ssi->si_class = si->si_class; 742191739Sobrien cdf_swap_class(&ssi->si_class); 743191739Sobrien ssi->si_count = CDF_TOLE2(si->si_count); 744191739Sobrien *count = 0; 745191739Sobrien maxcount = 0; 746191739Sobrien *info = NULL; 747191739Sobrien for (i = 0; i < CDF_TOLE4(si->si_count); i++) { 748191739Sobrien if (i >= CDF_LOOP_LIMIT) { 749191739Sobrien DPRINTF(("Unpack summary info loop limit")); 750191739Sobrien errno = EFTYPE; 751191739Sobrien return -1; 752191739Sobrien } 753191739Sobrien if (cdf_read_property_info(sst, CDF_TOLE4(sd->sd_offset), 754191739Sobrien info, count, &maxcount) == -1) 755191739Sobrien return -1; 756191739Sobrien } 757191739Sobrien return 0; 758191739Sobrien} 759191739Sobrien 760191739Sobrien 761191739Sobrien 762191739Sobrienint 763191739Sobriencdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id) 764191739Sobrien{ 765191739Sobrien return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-" 766191739Sobrien "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0], 767191739Sobrien id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0], 768191739Sobrien id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4], 769191739Sobrien id->cl_six[5]); 770191739Sobrien} 771191739Sobrien 772191739Sobrienstatic const struct { 773191739Sobrien uint32_t v; 774191739Sobrien const char *n; 775191739Sobrien} vn[] = { 776191739Sobrien { CDF_PROPERTY_CODE_PAGE, "Code page" }, 777191739Sobrien { CDF_PROPERTY_TITLE, "Title" }, 778191739Sobrien { CDF_PROPERTY_SUBJECT, "Subject" }, 779191739Sobrien { CDF_PROPERTY_AUTHOR, "Author" }, 780191739Sobrien { CDF_PROPERTY_KEYWORDS, "Keywords" }, 781191739Sobrien { CDF_PROPERTY_COMMENTS, "Comments" }, 782191739Sobrien { CDF_PROPERTY_TEMPLATE, "Template" }, 783191739Sobrien { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" }, 784191739Sobrien { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" }, 785191739Sobrien { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" }, 786191739Sobrien { CDF_PROPERTY_LAST_PRINTED, "Last Printed" }, 787191739Sobrien { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" }, 788191739Sobrien { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" }, 789191739Sobrien { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" }, 790191739Sobrien { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" }, 791191739Sobrien { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" }, 792191739Sobrien { CDF_PROPERTY_THUMBNAIL, "Thumbnail" }, 793191739Sobrien { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" }, 794191739Sobrien { CDF_PROPERTY_SECURITY, "Security" }, 795191739Sobrien { CDF_PROPERTY_LOCALE_ID, "Locale ID" }, 796191739Sobrien}; 797191739Sobrien 798191739Sobrienint 799191739Sobriencdf_print_property_name(char *buf, size_t bufsiz, uint32_t p) 800191739Sobrien{ 801191739Sobrien size_t i; 802191739Sobrien 803191739Sobrien for (i = 0; i < __arraycount(vn); i++) 804191739Sobrien if (vn[i].v == p) 805191739Sobrien return snprintf(buf, bufsiz, "%s", vn[i].n); 806191739Sobrien return snprintf(buf, bufsiz, "0x%x", p); 807191739Sobrien} 808191739Sobrien 809191739Sobrienint 810191739Sobriencdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts) 811191739Sobrien{ 812191739Sobrien size_t len = 0; 813191739Sobrien int days, hours, mins, secs; 814191739Sobrien 815191739Sobrien ts /= CDF_TIME_PREC; 816191739Sobrien secs = ts % 60; 817191739Sobrien ts /= 60; 818191739Sobrien mins = ts % 60; 819191739Sobrien ts /= 60; 820191739Sobrien hours = ts % 24; 821191739Sobrien ts /= 24; 822191739Sobrien days = ts; 823191739Sobrien 824191739Sobrien if (days) { 825191739Sobrien len += snprintf(buf + len, bufsiz - len, "%dd+", days); 826191739Sobrien if (len >= bufsiz) 827191739Sobrien return len; 828191739Sobrien } 829191739Sobrien 830191739Sobrien if (days || hours) { 831191739Sobrien len += snprintf(buf + len, bufsiz - len, "%.2d:", hours); 832191739Sobrien if (len >= bufsiz) 833191739Sobrien return len; 834191739Sobrien } 835191739Sobrien 836191739Sobrien len += snprintf(buf + len, bufsiz - len, "%.2d:", mins); 837191739Sobrien if (len >= bufsiz) 838191739Sobrien return len; 839191739Sobrien 840191739Sobrien len += snprintf(buf + len, bufsiz - len, "%.2d", secs); 841191739Sobrien return len; 842191739Sobrien} 843191739Sobrien 844191739Sobrien 845191739Sobrien#ifdef CDF_DEBUG 846191739Sobrienvoid 847191739Sobriencdf_dump_header(const cdf_header_t *h) 848191739Sobrien{ 849191739Sobrien size_t i; 850191739Sobrien 851191739Sobrien#define DUMP(a, b) printf("%40.40s = " a "\n", # b, h->h_ ## b) 852191739Sobrien DUMP("%d", revision); 853191739Sobrien DUMP("%d", version); 854191739Sobrien DUMP("0x%x", byte_order); 855191739Sobrien DUMP("%d", sec_size_p2); 856191739Sobrien DUMP("%d", short_sec_size_p2); 857191739Sobrien DUMP("%d", num_sectors_in_sat); 858191739Sobrien DUMP("%d", secid_first_directory); 859191739Sobrien DUMP("%d", min_size_standard_stream); 860191739Sobrien DUMP("%d", secid_first_sector_in_short_sat); 861191739Sobrien DUMP("%d", num_sectors_in_short_sat); 862191739Sobrien DUMP("%d", secid_first_sector_in_master_sat); 863191739Sobrien DUMP("%d", num_sectors_in_master_sat); 864191739Sobrien for (i = 0; i < __arraycount(h->h_master_sat); i++) { 865191739Sobrien if (h->h_master_sat[i] == CDF_SECID_FREE) 866191739Sobrien break; 867191739Sobrien printf("%35.35s[%.3zu] = %d\n", 868191739Sobrien "master_sat", i, h->h_master_sat[i]); 869191739Sobrien } 870191739Sobrien} 871191739Sobrien 872191739Sobrienvoid 873191739Sobriencdf_dump_sat(const char *prefix, const cdf_header_t *h, const cdf_sat_t *sat) 874191739Sobrien{ 875191739Sobrien size_t i, j, s = CDF_SEC_SIZE(h) / sizeof(cdf_secid_t); 876191739Sobrien 877191739Sobrien for (i = 0; i < sat->sat_len; i++) { 878191739Sobrien printf("%s[%zu]:\n", prefix, i); 879191739Sobrien for (j = 0; j < s; j++) { 880191739Sobrien printf("%5d, ", CDF_TOLE4(sat->sat_tab[s * i + j])); 881191739Sobrien if ((j + 1) % 10 == 0) 882191739Sobrien printf("\n"); 883191739Sobrien } 884191739Sobrien printf("\n"); 885191739Sobrien } 886191739Sobrien} 887191739Sobrien 888191739Sobrienvoid 889191739Sobriencdf_dump(void *v, size_t len) 890191739Sobrien{ 891191739Sobrien size_t i, j; 892191739Sobrien unsigned char *p = v; 893191739Sobrien char abuf[16]; 894191739Sobrien printf("%.4x: ", 0); 895191739Sobrien for (i = 0, j = 0; i < len; i++, p++) { 896191739Sobrien printf("%.2x ", *p); 897191739Sobrien abuf[j++] = isprint(*p) ? *p : '.'; 898191739Sobrien if (j == 16) { 899191739Sobrien j = 0; 900191739Sobrien abuf[15] = '\0'; 901191739Sobrien printf("%s\n%.4x: ", abuf, i + 1); 902191739Sobrien } 903191739Sobrien } 904191739Sobrien printf("\n"); 905191739Sobrien} 906191739Sobrien 907191739Sobrienvoid 908191739Sobriencdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst) 909191739Sobrien{ 910191739Sobrien size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? 911191739Sobrien CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); 912191739Sobrien cdf_dump(sst->sst_tab, ss * sst->sst_len); 913191739Sobrien} 914191739Sobrien 915191739Sobrienvoid 916191739Sobriencdf_dump_dir(int fd, const cdf_header_t *h, const cdf_sat_t *sat, 917191739Sobrien const cdf_sat_t *ssat, const cdf_stream_t *sst, 918191739Sobrien const cdf_dir_t *dir) 919191739Sobrien{ 920191739Sobrien size_t i, j; 921191739Sobrien cdf_directory_t *d; 922191739Sobrien char name[__arraycount(d->d_name)]; 923191739Sobrien cdf_stream_t scn; 924191739Sobrien struct timespec ts; 925191739Sobrien 926191739Sobrien static const char *types[] = { "empty", "user storage", 927191739Sobrien "user stream", "lockbytes", "property", "root storage" }; 928191739Sobrien 929191739Sobrien for (i = 0; i < dir->dir_len; i++) { 930191739Sobrien d = &dir->dir_tab[i]; 931191739Sobrien for (j = 0; j < sizeof(name); j++) 932191739Sobrien name[j] = (char)CDF_TOLE2(d->d_name[j]); 933191739Sobrien printf("Directory %zu: %s\n", i, name); 934191739Sobrien if (d->d_type < __arraycount(types)) 935191739Sobrien printf("Type: %s\n", types[d->d_type]); 936191739Sobrien else 937191739Sobrien printf("Type: %d\n", d->d_type); 938191739Sobrien printf("Color: %s\n", d->d_color ? "black" : "red"); 939191739Sobrien printf("Left child: %d\n", d->d_left_child); 940191739Sobrien printf("Right child: %d\n", d->d_right_child); 941191739Sobrien printf("Flags: 0x%x\n", d->d_flags); 942191739Sobrien cdf_timestamp_to_timespec(&ts, d->d_created); 943191739Sobrien printf("Created %s", ctime(&ts.tv_sec)); 944191739Sobrien cdf_timestamp_to_timespec(&ts, d->d_modified); 945191739Sobrien printf("Modified %s", ctime(&ts.tv_sec)); 946191739Sobrien printf("Stream %d\n", d->d_stream_first_sector); 947191739Sobrien printf("Size %d\n", d->d_size); 948191739Sobrien switch (d->d_type) { 949191739Sobrien case CDF_DIR_TYPE_USER_STORAGE: 950191739Sobrien printf("Storage: %d\n", d->d_storage); 951191739Sobrien break; 952191739Sobrien case CDF_DIR_TYPE_USER_STREAM: 953191739Sobrien if (sst == NULL) 954191739Sobrien break; 955191739Sobrien if (cdf_read_sector_chain(fd, h, sat, ssat, sst, 956191739Sobrien d->d_stream_first_sector, d->d_size, &scn) == -1) { 957191739Sobrien warn("Can't read stream for %s at %d len %d", 958191739Sobrien name, d->d_stream_first_sector, d->d_size); 959191739Sobrien break; 960191739Sobrien } 961191739Sobrien cdf_dump_stream(h, &scn); 962191739Sobrien free(scn.sst_tab); 963191739Sobrien break; 964191739Sobrien default: 965191739Sobrien break; 966191739Sobrien } 967191739Sobrien 968191739Sobrien } 969191739Sobrien} 970191739Sobrien 971191739Sobrienvoid 972191739Sobriencdf_dump_property_info(const cdf_property_info_t *info, size_t count) 973191739Sobrien{ 974191739Sobrien cdf_timestamp_t tp; 975191739Sobrien struct timespec ts; 976191739Sobrien char buf[64]; 977191739Sobrien size_t i; 978191739Sobrien 979191739Sobrien for (i = 0; i < count; i++) { 980191739Sobrien cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 981191739Sobrien printf("%zu) %s: ", i, buf); 982191739Sobrien switch (info[i].pi_type) { 983191739Sobrien case CDF_SIGNED16: 984191739Sobrien printf("signed 16 [%hd]\n", info[i].pi_s16); 985191739Sobrien break; 986191739Sobrien case CDF_SIGNED32: 987191739Sobrien printf("signed 32 [%d]\n", info[i].pi_s32); 988191739Sobrien break; 989191739Sobrien case CDF_UNSIGNED32: 990191739Sobrien printf("unsigned 32 [%u]\n", info[i].pi_u32); 991191739Sobrien break; 992191739Sobrien case CDF_LENGTH32_STRING: 993191739Sobrien printf("string %u [%.*s]\n", info[i].pi_str.s_len, 994191739Sobrien info[i].pi_str.s_len, info[i].pi_str.s_buf); 995191739Sobrien break; 996191739Sobrien case CDF_FILETIME: 997191739Sobrien tp = info[i].pi_tp; 998191739Sobrien if (tp < 1000000000000000LL) { 999191739Sobrien cdf_print_elapsed_time(buf, sizeof(buf), tp); 1000191739Sobrien printf("timestamp %s\n", buf); 1001191739Sobrien } else { 1002191739Sobrien cdf_timestamp_to_timespec(&ts, tp); 1003191739Sobrien printf("timestamp %s", ctime(&ts.tv_sec)); 1004191739Sobrien } 1005191739Sobrien break; 1006191739Sobrien case CDF_CLIPBOARD: 1007191739Sobrien printf("CLIPBOARD %u\n", info[i].pi_u32); 1008191739Sobrien break; 1009191739Sobrien default: 1010191739Sobrien DPRINTF(("Don't know how to deal with %x\n", 1011191739Sobrien info[i].pi_type)); 1012191739Sobrien break; 1013191739Sobrien } 1014191739Sobrien } 1015191739Sobrien} 1016191739Sobrien 1017191739Sobrien 1018191739Sobrienvoid 1019191739Sobriencdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) 1020191739Sobrien{ 1021191739Sobrien char buf[128]; 1022191739Sobrien cdf_summary_info_header_t ssi; 1023191739Sobrien cdf_property_info_t *info; 1024191739Sobrien size_t count; 1025191739Sobrien 1026191739Sobrien (void)&h; 1027191739Sobrien if (cdf_unpack_summary_info(sst, &ssi, &info, &count) == -1) 1028191739Sobrien return; 1029191739Sobrien printf("Endian: %x\n", ssi.si_byte_order); 1030191739Sobrien printf("Os Version %d.%d\n", ssi.si_os_version & 0xff, 1031191739Sobrien ssi.si_os_version >> 8); 1032191739Sobrien printf("Os %d\n", ssi.si_os); 1033191739Sobrien cdf_print_classid(buf, sizeof(buf), &ssi.si_class); 1034191739Sobrien printf("Class %s\n", buf); 1035191739Sobrien printf("Count %d\n", ssi.si_count); 1036191739Sobrien cdf_dump_property_info(info, count); 1037191739Sobrien free(info); 1038191739Sobrien} 1039191739Sobrien 1040191739Sobrien#endif 1041191739Sobrien 1042191739Sobrien#ifdef TEST 1043191739Sobrienint 1044191739Sobrienmain(int argc, char *argv[]) 1045191739Sobrien{ 1046191739Sobrien int fd, i; 1047191739Sobrien cdf_header_t h; 1048191739Sobrien cdf_sat_t sat, ssat; 1049191739Sobrien cdf_stream_t sst, scn; 1050191739Sobrien cdf_dir_t dir; 1051191739Sobrien 1052191739Sobrien if (argc < 2) { 1053191739Sobrien (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname()); 1054191739Sobrien return -1; 1055191739Sobrien } 1056191739Sobrien 1057191739Sobrien for (i = 1; i < argc; i++) { 1058191739Sobrien if ((fd = open(argv[1], O_RDONLY)) == -1) 1059191739Sobrien err(1, "Cannot open `%s'", argv[1]); 1060191739Sobrien 1061191739Sobrien if (cdf_read_header(fd, &h) == -1) 1062191739Sobrien err(1, "Cannot read header"); 1063191739Sobrien#ifdef CDF_DEBUG 1064191739Sobrien cdf_dump_header(&h); 1065191739Sobrien#endif 1066191739Sobrien 1067191739Sobrien if (cdf_read_sat(fd, &h, &sat) == -1) 1068191739Sobrien err(1, "Cannot read sat"); 1069191739Sobrien#ifdef CDF_DEBUG 1070191739Sobrien cdf_dump_sat("SAT", &h, &sat); 1071191739Sobrien#endif 1072191739Sobrien 1073191739Sobrien if (cdf_read_ssat(fd, &h, &sat, &ssat) == -1) 1074191739Sobrien err(1, "Cannot read ssat"); 1075191739Sobrien#ifdef CDF_DEBUG 1076191739Sobrien cdf_dump_sat("SSAT", &h, &ssat); 1077191739Sobrien#endif 1078191739Sobrien 1079191739Sobrien if (cdf_read_dir(fd, &h, &sat, &dir) == -1) 1080191739Sobrien err(1, "Cannot read dir"); 1081191739Sobrien 1082191739Sobrien if (cdf_read_short_stream(fd, &h, &sat, &dir, &sst) == -1) 1083191739Sobrien err(1, "Cannot read short stream"); 1084191739Sobrien#ifdef CDF_DEBUG 1085191739Sobrien cdf_dump_stream(&h, &sst); 1086191739Sobrien#endif 1087191739Sobrien 1088191739Sobrien#ifdef CDF_DEBUG 1089191739Sobrien cdf_dump_dir(fd, &h, &sat, &ssat, &sst, &dir); 1090191739Sobrien#endif 1091191739Sobrien 1092191739Sobrien 1093191739Sobrien if (cdf_read_summary_info(fd, &h, &sat, &ssat, &sst, &dir, 1094191739Sobrien &scn) == -1) 1095191739Sobrien err(1, "Cannot read summary info"); 1096191739Sobrien#ifdef CDF_DEBUG 1097191739Sobrien cdf_dump_summary_info(&h, &scn); 1098191739Sobrien#endif 1099191739Sobrien 1100191739Sobrien (void)close(fd); 1101191739Sobrien } 1102191739Sobrien 1103191739Sobrien return 0; 1104191739Sobrien} 1105191739Sobrien#endif 1106