libextractor

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

jpeg_extractor.c (5343B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2002, 2003, 2004, 2012 Vidyut Samanta and Christian Grothoff
      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 3, 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  * @file plugins/jpeg_extractor.c
     22  * @brief plugin to support JPEG files
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include "extractor.h"
     27 #if WINDOWS || DARWIN
     28 #if DARWIN
     29 typedef int boolean;
     30 #endif
     31 #define HAVE_BOOLEAN
     32 #endif
     33 #include <jpeglib.h>
     34 #include <setjmp.h>
     35 
     36 
     37 /**
     38  * Context for custom functions.
     39  */
     40 struct Context
     41 {
     42   /**
     43    * Environment for longjmp from within error_exit handler.
     44    */
     45   jmp_buf env;
     46 };
     47 
     48 
     49 /**
     50  * Function used to avoid having libjpeg write error messages to the console.
     51  */
     52 static void
     53 no_emit (j_common_ptr cinfo, int msg_level)
     54 {
     55   /* do nothing */
     56 }
     57 
     58 
     59 /**
     60  * Function used to avoid having libjpeg write error messages to the console.
     61  */
     62 static void
     63 no_output (j_common_ptr cinfo)
     64 {
     65   /* do nothing */
     66 }
     67 
     68 
     69 /**
     70  * Function used to avoid having libjpeg kill our process.
     71  */
     72 static void
     73 no_exit (j_common_ptr cinfo)
     74 {
     75   struct Context *ctx = cinfo->client_data;
     76 
     77   /* we're not allowed to return (by API definition),
     78      and we don't want to abort/exit.  So we longjmp
     79      to our cleanup code instead. */
     80   longjmp (ctx->env, 1);
     81 }
     82 
     83 
     84 /**
     85  * Main entry method for the 'image/jpeg' extraction plugin.
     86  *
     87  * @param ec extraction context provided to the plugin
     88  */
     89 void
     90 EXTRACTOR_jpeg_extract_method (struct EXTRACTOR_ExtractContext *ec)
     91 {
     92   struct jpeg_decompress_struct jds;
     93   struct jpeg_error_mgr em;
     94   void *buf;
     95   ssize_t size;
     96   int is_jpeg;
     97   unsigned int rounds;
     98   char format[128];
     99   struct jpeg_marker_struct *mptr;
    100   struct Context ctx;
    101 
    102   is_jpeg = 0;
    103   rounds = 0; /* used to avoid going on forever for non-jpeg files */
    104   jpeg_std_error (&em);
    105   em.emit_message = &no_emit;
    106   em.output_message = &no_output;
    107   em.error_exit = &no_exit;
    108   jds.client_data = &ctx;
    109   if (1 == setjmp (ctx.env))
    110     goto EXIT; /* we get here if libjpeg calls 'no_exit' because it wants to die */
    111   jds.err = &em;
    112   jpeg_create_decompress (&jds);
    113   jpeg_save_markers (&jds, JPEG_COM, 1024 * 8);
    114   while ( (1 == is_jpeg) || (rounds++ < 8) )
    115   {
    116     if (-1 == (size = ec->read (ec->cls,
    117                                 &buf,
    118                                 16 * 1024)))
    119       break;
    120     if (0 == size)
    121       break;
    122     jpeg_mem_src (&jds, buf, size);
    123     if (0 == is_jpeg)
    124     {
    125       if (JPEG_HEADER_OK == jpeg_read_header (&jds, 1))
    126         is_jpeg = 1; /* ok, really a jpeg, keep going until the end */
    127       continue;
    128     }
    129     jpeg_consume_input (&jds);
    130   }
    131 
    132   if (1 != is_jpeg)
    133     goto EXIT;
    134   if (0 !=
    135       ec->proc (ec->cls,
    136                 "jpeg",
    137                 EXTRACTOR_METATYPE_MIMETYPE,
    138                 EXTRACTOR_METAFORMAT_UTF8,
    139                 "text/plain",
    140                 "image/jpeg",
    141                 strlen ("image/jpeg") + 1))
    142     goto EXIT;
    143   snprintf (format,
    144             sizeof (format),
    145             "%ux%u",
    146             (unsigned int) jds.image_width,
    147             (unsigned int) jds.image_height);
    148   if (0 !=
    149       ec->proc (ec->cls,
    150                 "jpeg",
    151                 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS,
    152                 EXTRACTOR_METAFORMAT_UTF8,
    153                 "text/plain",
    154                 format,
    155                 strlen (format) + 1))
    156     goto EXIT;
    157   for (mptr = jds.marker_list; NULL != mptr; mptr = mptr->next)
    158   {
    159     size_t off;
    160     size_t clen;
    161     char *comment;
    162 
    163     if (JPEG_COM != mptr->marker)
    164       continue;
    165     off = 0;
    166     while ( (off < mptr->data_length) &&
    167             (isspace (((const unsigned char *) mptr->data)[mptr->data_length
    168                                                            - 1 - off])) )
    169       off++;
    170     clen = mptr->data_length - off;
    171     if (0 == clen)
    172       continue;
    173     /* libjpeg hands out the raw marker payload, which is neither
    174        0-terminated nor guaranteed to be free of 0 bytes; C_STRING
    175        promises "data_len == strlen (data) + 1", so terminate a copy
    176        and measure that. */
    177     if (NULL == (comment = malloc (clen + 1)))
    178       goto EXIT;
    179     memcpy (comment,
    180             mptr->data,
    181             clen);
    182     comment[clen] = '\0';
    183     if (0 == strlen (comment))
    184     {
    185       free (comment);
    186       continue;
    187     }
    188     if (0 !=
    189         ec->proc (ec->cls,
    190                   "jpeg",
    191                   EXTRACTOR_METATYPE_COMMENT,
    192                   EXTRACTOR_METAFORMAT_C_STRING,
    193                   "text/plain",
    194                   comment,
    195                   strlen (comment) + 1))
    196     {
    197       free (comment);
    198       goto EXIT;
    199     }
    200     free (comment);
    201   }
    202 
    203 EXIT:
    204   jpeg_destroy_decompress (&jds);
    205 }
    206 
    207 
    208 /* end of jpeg_extractor.c */