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