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