libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

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 }