1/* $NetBSD: readcdf.c,v 1.6.4.1 2012/03/07 23:18:29 riz Exp $ */ 2 3/*- 4 * Copyright (c) 2008 Christos Zoulas 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28#include "file.h" 29 30#ifndef lint 31#if 0 32FILE_RCSID("@(#)$File: readcdf.c,v 1.29 2012/02/20 20:04:58 christos Exp $") 33#else 34__RCSID("$NetBSD: readcdf.c,v 1.6.4.1 2012/03/07 23:18:29 riz Exp $"); 35#endif 36#endif 37 38#include <stdlib.h> 39#include <unistd.h> 40#include <string.h> 41#include <time.h> 42#include <ctype.h> 43 44#include "cdf.h" 45#include "magic.h" 46 47#ifndef __arraycount 48#define __arraycount(a) (sizeof(a) / sizeof(a[0])) 49#endif 50 51#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) 52 53private int 54cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, 55 size_t count) 56{ 57 size_t i; 58 cdf_timestamp_t tp; 59 struct timespec ts; 60 char buf[64]; 61 const char *str = NULL; 62 const char *s; 63 int len; 64 65 for (i = 0; i < count; i++) { 66 cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 67 switch (info[i].pi_type) { 68 case CDF_NULL: 69 break; 70 case CDF_SIGNED16: 71 if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, 72 info[i].pi_s16) == -1) 73 return -1; 74 break; 75 case CDF_SIGNED32: 76 if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, 77 info[i].pi_s32) == -1) 78 return -1; 79 break; 80 case CDF_UNSIGNED32: 81 if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, 82 info[i].pi_u32) == -1) 83 return -1; 84 break; 85 case CDF_FLOAT: 86 if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 87 info[i].pi_f) == -1) 88 return -1; 89 break; 90 case CDF_DOUBLE: 91 if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf, 92 info[i].pi_d) == -1) 93 return -1; 94 break; 95 case CDF_LENGTH32_STRING: 96 case CDF_LENGTH32_WSTRING: 97 len = info[i].pi_str.s_len; 98 if (len > 1) { 99 char vbuf[1024]; 100 size_t j, k = 1; 101 102 if (info[i].pi_type == CDF_LENGTH32_WSTRING) 103 k++; 104 s = info[i].pi_str.s_buf; 105 for (j = 0; j < sizeof(vbuf) && len--; 106 j++, s += k) { 107 if (*s == '\0') 108 break; 109 if (isprint((unsigned char)*s)) 110 vbuf[j] = *s; 111 } 112 if (j == sizeof(vbuf)) 113 --j; 114 vbuf[j] = '\0'; 115 if (NOTMIME(ms)) { 116 if (vbuf[0]) { 117 if (file_printf(ms, ", %s: %s", 118 buf, vbuf) == -1) 119 return -1; 120 } 121 } else if (info[i].pi_id == 122 CDF_PROPERTY_NAME_OF_APPLICATION) { 123 if (strstr(vbuf, "Word")) 124 str = "msword"; 125 else if (strstr(vbuf, "Excel")) 126 str = "vnd.ms-excel"; 127 else if (strstr(vbuf, "Powerpoint")) 128 str = "vnd.ms-powerpoint"; 129 else if (strstr(vbuf, 130 "Crystal Reports")) 131 str = "x-rpt"; 132 } 133 } 134 break; 135 case CDF_FILETIME: 136 tp = info[i].pi_tp; 137 if (tp != 0) { 138 if (tp < 1000000000000000LL) { 139 char tbuf[64]; 140 cdf_print_elapsed_time(tbuf, 141 sizeof(tbuf), tp); 142 if (NOTMIME(ms) && file_printf(ms, 143 ", %s: %s", buf, tbuf) == -1) 144 return -1; 145 } else { 146 char *c, *ec; 147 cdf_timestamp_to_timespec(&ts, tp); 148 c = cdf_ctime(&ts.tv_sec); 149 if ((ec = strchr(c, '\n')) != NULL) 150 *ec = '\0'; 151 152 if (NOTMIME(ms) && file_printf(ms, 153 ", %s: %s", buf, c) == -1) 154 return -1; 155 } 156 } 157 break; 158 case CDF_CLIPBOARD: 159 break; 160 default: 161 return -1; 162 } 163 } 164 if (!NOTMIME(ms)) { 165 if (str == NULL) 166 return 0; 167 if (file_printf(ms, "application/%s", str) == -1) 168 return -1; 169 } 170 return 1; 171} 172 173private int 174cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, 175 const cdf_stream_t *sst) 176{ 177 cdf_summary_info_header_t si; 178 cdf_property_info_t *info; 179 size_t count; 180 int m; 181 182 if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) 183 return -1; 184 185 if (NOTMIME(ms)) { 186 if (file_printf(ms, "Composite Document File V2 Document") 187 == -1) 188 return -1; 189 190 if (file_printf(ms, ", %s Endian", 191 si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 192 return -2; 193 switch (si.si_os) { 194 case 2: 195 if (file_printf(ms, ", Os: Windows, Version %d.%d", 196 si.si_os_version & 0xff, 197 (uint32_t)si.si_os_version >> 8) == -1) 198 return -2; 199 break; 200 case 1: 201 if (file_printf(ms, ", Os: MacOS, Version %d.%d", 202 (uint32_t)si.si_os_version >> 8, 203 si.si_os_version & 0xff) == -1) 204 return -2; 205 break; 206 default: 207 if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 208 si.si_os_version & 0xff, 209 (uint32_t)si.si_os_version >> 8) == -1) 210 return -2; 211 break; 212 } 213 } 214 215 m = cdf_file_property_info(ms, info, count); 216 free(info); 217 218 return m == -1 ? -2 : m; 219} 220 221protected int 222file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, 223 size_t nbytes) 224{ 225 cdf_info_t info; 226 cdf_header_t h; 227 cdf_sat_t sat, ssat; 228 cdf_stream_t sst, scn; 229 cdf_dir_t dir; 230 int i; 231 const char *expn = ""; 232 const char *corrupt = "corrupt: "; 233 234 info.i_fd = fd; 235 info.i_buf = buf; 236 info.i_len = nbytes; 237 if (ms->flags & MAGIC_APPLE) 238 return 0; 239 if (cdf_read_header(&info, &h) == -1) 240 return 0; 241#ifdef CDF_DEBUG 242 cdf_dump_header(&h); 243#endif 244 245 if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 246 expn = "Can't read SAT"; 247 goto out0; 248 } 249#ifdef CDF_DEBUG 250 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 251#endif 252 253 if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 254 expn = "Can't read SSAT"; 255 goto out1; 256 } 257#ifdef CDF_DEBUG 258 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 259#endif 260 261 if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 262 expn = "Can't read directory"; 263 goto out2; 264 } 265 266 if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) { 267 expn = "Cannot read short stream"; 268 goto out3; 269 } 270#ifdef CDF_DEBUG 271 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 272#endif 273 274 if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 275 &scn)) == -1) { 276 if (errno == ESRCH) { 277 corrupt = expn; 278 expn = "No summary info"; 279 } else { 280 expn = "Cannot read summary info"; 281 } 282 goto out4; 283 } 284#ifdef CDF_DEBUG 285 cdf_dump_summary_info(&h, &scn); 286#endif 287 if ((i = cdf_file_summary_info(ms, &h, &scn)) < 0) 288 expn = "Can't expand summary_info"; 289 if (i == 0) { 290 const char *str = "vnd.ms-office"; 291 cdf_directory_t *d; 292 char name[__arraycount(d->d_name)]; 293 size_t j, k; 294 for (j = 0; j < dir.dir_len; j++) { 295 d = &dir.dir_tab[j]; 296 for (k = 0; k < sizeof(name); k++) 297 name[k] = (char)cdf_tole2(d->d_name[k]); 298 if (strstr(name, "WordDocument") == 0) { 299 str = "msword"; 300 break; 301 } 302 } 303 if (file_printf(ms, "application/%s", str) == -1) 304 return -1; 305 i = 1; 306 } 307 free(scn.sst_tab); 308out4: 309 free(sst.sst_tab); 310out3: 311 free(dir.dir_tab); 312out2: 313 free(ssat.sat_tab); 314out1: 315 free(sat.sat_tab); 316out0: 317 if (i != 1) { 318 if (i == -1) 319 if (file_printf(ms, "Composite Document File V2 Document") 320 == -1) 321 return -1; 322 if (*expn) 323 if (file_printf(ms, ", %s%s", corrupt, expn) == -1) 324 return -1; 325 i = 1; 326 } 327 return i; 328} 329