1 /* $NetBSD: readcdf.c,v 1.3 2011/05/13 01:52:13 christos 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 32 FILE_RCSID("@(#)$File: readcdf.c,v 1.25 2011/02/10 21:35:05 christos Exp $") 33 #else 34 __RCSID("$NetBSD: readcdf.c,v 1.3 2011/05/13 01:52:13 christos 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 #define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0) 48 49 private int 50 cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info, 51 size_t count) 52 { 53 size_t i; 54 cdf_timestamp_t tp; 55 struct timespec ts; 56 char buf[64]; 57 const char *str = "vnd.ms-office"; 58 const char *s; 59 int len; 60 61 for (i = 0; i < count; i++) { 62 cdf_print_property_name(buf, sizeof(buf), info[i].pi_id); 63 switch (info[i].pi_type) { 64 case CDF_NULL: 65 break; 66 case CDF_SIGNED16: 67 if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf, 68 info[i].pi_s16) == -1) 69 return -1; 70 break; 71 case CDF_SIGNED32: 72 if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf, 73 info[i].pi_s32) == -1) 74 return -1; 75 break; 76 case CDF_UNSIGNED32: 77 if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf, 78 info[i].pi_u32) == -1) 79 return -1; 80 break; 81 case CDF_LENGTH32_STRING: 82 case CDF_LENGTH32_WSTRING: 83 len = info[i].pi_str.s_len; 84 if (len > 1) { 85 char vbuf[1024]; 86 size_t j, k = 1; 87 88 if (info[i].pi_type == CDF_LENGTH32_WSTRING) 89 k++; 90 s = info[i].pi_str.s_buf; 91 for (j = 0; j < sizeof(vbuf) && len--; 92 j++, s += k) { 93 if (*s == '\0') 94 break; 95 if (isprint((unsigned char)*s)) 96 vbuf[j] = *s; 97 } 98 if (j == sizeof(vbuf)) 99 --j; 100 vbuf[j] = '\0'; 101 if (NOTMIME(ms)) { 102 if (vbuf[0]) { 103 if (file_printf(ms, ", %s: %s", 104 buf, vbuf) == -1) 105 return -1; 106 } 107 } else if (info[i].pi_id == 108 CDF_PROPERTY_NAME_OF_APPLICATION) { 109 if (strstr(vbuf, "Word")) 110 str = "msword"; 111 else if (strstr(vbuf, "Excel")) 112 str = "vnd.ms-excel"; 113 else if (strstr(vbuf, "Powerpoint")) 114 str = "vnd.ms-powerpoint"; 115 else if (strstr(vbuf, 116 "Crystal Reports")) 117 str = "x-rpt"; 118 } 119 } 120 break; 121 case CDF_FILETIME: 122 tp = info[i].pi_tp; 123 if (tp != 0) { 124 if (tp < 1000000000000000LL) { 125 char tbuf[64]; 126 cdf_print_elapsed_time(tbuf, 127 sizeof(tbuf), tp); 128 if (NOTMIME(ms) && file_printf(ms, 129 ", %s: %s", buf, tbuf) == -1) 130 return -1; 131 } else { 132 char *c, *ec; 133 cdf_timestamp_to_timespec(&ts, tp); 134 c = cdf_ctime(&ts.tv_sec); 135 if ((ec = strchr(c, '\n')) != NULL) 136 *ec = '\0'; 137 138 if (NOTMIME(ms) && file_printf(ms, 139 ", %s: %s", buf, c) == -1) 140 return -1; 141 } 142 } 143 break; 144 case CDF_CLIPBOARD: 145 break; 146 default: 147 return -1; 148 } 149 } 150 if (!NOTMIME(ms)) { 151 if (file_printf(ms, "application/%s", str) == -1) 152 return -1; 153 } 154 return 1; 155 } 156 157 private int 158 cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h, 159 const cdf_stream_t *sst) 160 { 161 cdf_summary_info_header_t si; 162 cdf_property_info_t *info; 163 size_t count; 164 int m; 165 166 if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1) 167 return -1; 168 169 if (NOTMIME(ms)) { 170 if (file_printf(ms, "Composite Document File V2 Document") == -1) 171 return -1; 172 173 if (file_printf(ms, ", %s Endian", 174 si.si_byte_order == 0xfffe ? "Little" : "Big") == -1) 175 return -1; 176 switch (si.si_os) { 177 case 2: 178 if (file_printf(ms, ", Os: Windows, Version %d.%d", 179 si.si_os_version & 0xff, 180 (uint32_t)si.si_os_version >> 8) == -1) 181 return -1; 182 break; 183 case 1: 184 if (file_printf(ms, ", Os: MacOS, Version %d.%d", 185 (uint32_t)si.si_os_version >> 8, 186 si.si_os_version & 0xff) == -1) 187 return -1; 188 break; 189 default: 190 if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os, 191 si.si_os_version & 0xff, 192 (uint32_t)si.si_os_version >> 8) == -1) 193 return -1; 194 break; 195 } 196 } 197 198 m = cdf_file_property_info(ms, info, count); 199 free(info); 200 201 return m; 202 } 203 204 protected int 205 file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf, 206 size_t nbytes) 207 { 208 cdf_info_t info; 209 cdf_header_t h; 210 cdf_sat_t sat, ssat; 211 cdf_stream_t sst, scn; 212 cdf_dir_t dir; 213 int i; 214 const char *expn = ""; 215 const char *corrupt = "corrupt: "; 216 217 info.i_fd = fd; 218 info.i_buf = buf; 219 info.i_len = nbytes; 220 if (ms->flags & MAGIC_APPLE) 221 return 0; 222 if (cdf_read_header(&info, &h) == -1) 223 return 0; 224 #ifdef CDF_DEBUG 225 cdf_dump_header(&h); 226 #endif 227 228 if ((i = cdf_read_sat(&info, &h, &sat)) == -1) { 229 expn = "Can't read SAT"; 230 goto out0; 231 } 232 #ifdef CDF_DEBUG 233 cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h)); 234 #endif 235 236 if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) { 237 expn = "Can't read SSAT"; 238 goto out1; 239 } 240 #ifdef CDF_DEBUG 241 cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h)); 242 #endif 243 244 if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) { 245 expn = "Can't read directory"; 246 goto out2; 247 } 248 249 if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst)) == -1) { 250 expn = "Cannot read short stream"; 251 goto out3; 252 } 253 #ifdef CDF_DEBUG 254 cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir); 255 #endif 256 257 if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir, 258 &scn)) == -1) { 259 if (errno == ESRCH) { 260 corrupt = expn; 261 expn = "No summary info"; 262 } else { 263 expn = "Cannot read summary info"; 264 } 265 goto out4; 266 } 267 #ifdef CDF_DEBUG 268 cdf_dump_summary_info(&h, &scn); 269 #endif 270 if ((i = cdf_file_summary_info(ms, &h, &scn)) == -1) 271 expn = "Can't expand summary_info"; 272 free(scn.sst_tab); 273 out4: 274 free(sst.sst_tab); 275 out3: 276 free(dir.dir_tab); 277 out2: 278 free(ssat.sat_tab); 279 out1: 280 free(sat.sat_tab); 281 out0: 282 if (i != 1) { 283 if (file_printf(ms, "Composite Document File V2 Document") == -1) 284 return -1; 285 if (*expn) 286 if (file_printf(ms, ", %s%s", corrupt, expn) == -1) 287 return -1; 288 i = 1; 289 } 290 return i; 291 } 292