libextractor

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

applefile_extractor.c (8448B)


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