applefile_extractor.c (7745B)
1 /* 2 This file is part of libextractor. 3 Copyright Copyright (C) 2008 Heikki Lindholm 4 5 libextractor is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 2, or (at your 8 option) any later version. 9 10 libextractor is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with libextractor; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 21 /* 22 * handles AppleSingle and AppleDouble header files 23 * see RFC 1740 24 */ 25 #include "platform.h" 26 #include "extractor.h" 27 #include "pack.h" 28 29 #define DEBUG 0 30 31 #define APPLESINGLE_SIGNATURE "\x00\x05\x16\x00" 32 #define APPLEDOUBLE_SIGNATURE "\x00\x05\x16\x07" 33 34 typedef struct 35 { 36 unsigned char magic[4]; 37 unsigned int version; 38 char homeFileSystem[16]; /* v1: in ASCII v2: zero filler */ 39 unsigned short entries; 40 } ApplefileHeader; 41 42 #define APPLEFILE_HEADER_SIZE 26 43 #define APPLEFILE_HEADER_SPEC "4bW16bH" 44 #define APPLEFILE_HEADER_FIELDS(p) \ 45 & (p)->magic, \ 46 &(p)->version, \ 47 &(p)->homeFileSystem, \ 48 &(p)->entries 49 50 typedef struct 51 { 52 unsigned int id; 53 unsigned int offset; 54 unsigned int length; 55 } ApplefileEntryDescriptor; 56 57 #define APPLEFILE_ENTRY_DESCRIPTOR_SIZE 12 58 #define APPLEFILE_ENTRY_DESCRIPTOR_SPEC "WWW" 59 #define APPLEFILE_ENTRY_DESCRIPTOR_FIELDS(p) \ 60 & (p)->id, \ 61 &(p)->offset, \ 62 &(p)->length 63 64 #define AED_ID_DATA_FORK 1 65 #define AED_ID_RESOURCE_FORK 2 66 #define AED_ID_REAL_NAME 3 67 #define AED_ID_COMMENT 4 68 #define AED_ID_ICON_BW 5 69 #define AED_ID_ICON_COLOUR 6 70 #define AED_ID_FILE_DATES_INFO 8 71 #define AED_ID_FINDER_INFO 9 72 #define AED_ID_MACINTOSH_FILE_INFO 10 73 #define AED_ID_PRODOS_FILE_INFO 11 74 #define AED_ID_MSDOS_FILE_INFO 12 75 #define AED_ID_SHORT_NAME 13 76 #define AED_ID_AFP_FILE_INFO 14 77 #define AED_ID_DIRECTORY_ID 15 78 79 static int 80 readApplefileHeader (const unsigned char *data, 81 size_t *offset, 82 size_t size, 83 ApplefileHeader *hdr) 84 { 85 if ((*offset + APPLEFILE_HEADER_SIZE) > size) 86 return -1; 87 88 EXTRACTOR_common_cat_unpack (data + *offset, 89 APPLEFILE_HEADER_SPEC, 90 APPLEFILE_HEADER_FIELDS (hdr)); 91 *offset += APPLEFILE_HEADER_SIZE; 92 return 0; 93 } 94 95 96 static int 97 readEntryDescriptor (const unsigned char *data, 98 size_t *offset, 99 size_t size, 100 ApplefileEntryDescriptor *dsc) 101 { 102 if ((*offset + APPLEFILE_ENTRY_DESCRIPTOR_SIZE) > size) 103 return -1; 104 105 EXTRACTOR_common_cat_unpack (data + *offset, 106 APPLEFILE_ENTRY_DESCRIPTOR_SPEC, 107 APPLEFILE_ENTRY_DESCRIPTOR_FIELDS (dsc)); 108 *offset += APPLEFILE_ENTRY_DESCRIPTOR_SIZE; 109 return 0; 110 } 111 112 113 /* mimetype = application/applefile */ 114 int 115 EXTRACTOR_applefile_extract (const char *sdata, 116 size_t size, 117 EXTRACTOR_MetaDataProcessor proc, 118 void *proc_cls, 119 const char *options) 120 { 121 const unsigned char *data = (const unsigned char*) sdata; 122 size_t offset; 123 ApplefileHeader header; 124 ApplefileEntryDescriptor dsc; 125 int i; 126 127 offset = 0; 128 if (readApplefileHeader (data, &offset, size, &header) == -1) 129 return 0; 130 if ( (memcmp (header.magic, APPLESINGLE_SIGNATURE, 4) != 0) && 131 (memcmp (header.magic, APPLEDOUBLE_SIGNATURE, 4) != 0) ) 132 return 0; 133 if (0 != proc (proc_cls, 134 "applefile", 135 EXTRACTOR_METATYPE_MIMETYPE, 136 EXTRACTOR_METAFORMAT_UTF8, 137 "text/plain", 138 "application/applefile", 139 strlen ("application/applefile") + 1)) 140 return 1; 141 #if DEBUG 142 fprintf (stderr, 143 "applefile header: %08x %d\n", header.version, header.entries); 144 #endif 145 if ( (header.version != 0x00010000) && 146 (header.version != 0x00020000) ) 147 return 0; 148 149 for (i = 0; i < header.entries; i++) 150 { 151 if (readEntryDescriptor (data, &offset, size, &dsc) == -1) 152 break; 153 154 #if DEBUG 155 fprintf (stderr, 156 "applefile entry: %u %u %u\n", dsc.id, dsc.offset, dsc.length); 157 #endif 158 switch (dsc.id) 159 { 160 case AED_ID_DATA_FORK: 161 { 162 /* same as in filenameextractor.c */ 163 char s[14]; 164 165 if (dsc.length >= 1000000000) 166 snprintf (s, 13, "%.2f %s", dsc.length / 1000000000.0, 167 _ ("GB")); 168 else if (dsc.length >= 1000000) 169 snprintf (s, 13, "%.2f %s", dsc.length / 1000000.0, _ ("MB")); 170 else if (dsc.length >= 1000) 171 snprintf (s, 13, "%.2f %s", dsc.length / 1000.0, _ ("KB")); 172 else 173 snprintf (s, 13, "%.2f %s", (double) dsc.length, _ ("Bytes")); 174 175 if (0 != proc (proc_cls, 176 "applefile", 177 EXTRACTOR_METATYPE_EMBEDDED_FILE_SIZE, 178 EXTRACTOR_METAFORMAT_UTF8, 179 "text/plain", 180 s, 181 strlen (s) + 1)) 182 return 1; 183 } 184 break; 185 case AED_ID_REAL_NAME: 186 { 187 char s[2048]; 188 if ( (dsc.length < sizeof(s)) && 189 ((dsc.offset + dsc.length) < size) ) 190 { 191 memcpy (s, data + dsc.offset, dsc.length); 192 s[dsc.length] = '\0'; 193 if (0 != proc (proc_cls, 194 "applefile", 195 EXTRACTOR_METATYPE_FILENAME, 196 EXTRACTOR_METAFORMAT_UTF8, 197 "text/plain", 198 s, 199 dsc.length + 1)) 200 return 1; 201 } 202 } 203 break; 204 case AED_ID_COMMENT: 205 if ( (dsc.length < 65536) && ((dsc.offset + dsc.length) < size) ) 206 { 207 char *s = malloc (dsc.length + 1); 208 if (s != NULL) 209 { 210 memcpy (s, data + dsc.offset, dsc.length); 211 s[dsc.length] = '\0'; 212 if (0 != proc (proc_cls, 213 "applefile", 214 EXTRACTOR_METATYPE_COMMENT, 215 EXTRACTOR_METAFORMAT_UTF8, 216 "text/plain", 217 s, 218 dsc.length + 1)) 219 { 220 free (s); 221 return 1; 222 } 223 free (s); 224 } 225 } 226 break; 227 case AED_ID_FINDER_INFO: 228 if ((dsc.length >= 16) && ( (dsc.offset + dsc.length) < size) ) 229 { 230 char s[5]; 231 memcpy (s, data + dsc.offset, 4); 232 s[4] = '\0'; 233 if (0 != proc (proc_cls, 234 "applefile", 235 EXTRACTOR_METATYPE_FINDER_FILE_TYPE, 236 EXTRACTOR_METAFORMAT_C_STRING, 237 "text/plain", 238 s, 239 strlen (s) + 1)) 240 return 1; 241 242 memcpy (s, data + dsc.offset + 4, 4); 243 s[4] = '\0'; 244 if (0 != proc (proc_cls, 245 "applefile", 246 EXTRACTOR_METATYPE_FINDER_FILE_CREATOR, 247 EXTRACTOR_METAFORMAT_C_STRING, 248 "text/plain", 249 s, 250 strlen (s) + 1)) 251 return 1; 252 } 253 break; 254 default: 255 break; 256 } 257 } 258 return 0; 259 }