"Fossies" - the Fresh Open Source Software Archive

Member "libextractor-1.11/src/plugins/png_extractor.c" (30 Jan 2021, 12990 Bytes) of package /linux/privat/libextractor-1.11.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "png_extractor.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5_vs_1.6.

    1 /*
    2      This file is part of libextractor.
    3      Copyright (C) 2002, 2003, 2004, 2005, 2009, 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/png_extractor.c
   22  * @brief plugin to support PNG files
   23  * @author Christian Grothoff
   24  */
   25 #include "platform.h"
   26 #include <zlib.h>
   27 #include "extractor.h"
   28 #include "convert.h"
   29 
   30 /**
   31  * Header that every PNG file must start with.
   32  */
   33 #define PNG_HEADER "\211PNG\r\n\032\n"
   34 
   35 
   36 /**
   37  * Function to create 0-terminated string from the
   38  * first n characters of the given input.
   39  *
   40  * @param str input string
   41  * @param n length of the input
   42  * @return n-bytes from str followed by 0-termination, NULL on error
   43  */
   44 static char *
   45 stndup (const char *str,
   46         size_t n)
   47 {
   48   char *tmp;
   49 
   50   if (n + 1 < n)
   51     return NULL;
   52   if (NULL == (tmp = malloc (n + 1)))
   53     return NULL;
   54   tmp[n] = '\0';
   55   memcpy (tmp, str, n);
   56   return tmp;
   57 }
   58 
   59 
   60 /**
   61  * strnlen is GNU specific, let's redo it here to be
   62  * POSIX compliant.
   63  *
   64  * @param str input string
   65  * @param maxlen maximum length of str
   66  * @return first position of 0-terminator in str, or maxlen
   67  */
   68 static size_t
   69 stnlen (const char *str,
   70         size_t maxlen)
   71 {
   72   size_t ret;
   73 
   74   ret = 0;
   75   while ( (ret < maxlen) &&
   76           ('\0' != str[ret]) )
   77     ret++;
   78   return ret;
   79 }
   80 
   81 
   82 /**
   83  * Interpret the 4 bytes in 'buf' as a big-endian
   84  * encoded 32-bit integer, convert and return.
   85  *
   86  * @param pos (unaligned) pointer to 4 byte integer
   87  * @return converted integer in host byte order
   88  */
   89 static uint32_t
   90 get_int_at (const void *pos)
   91 {
   92   uint32_t i;
   93 
   94   memcpy (&i, pos, sizeof (i));
   95   return htonl (i);
   96 }
   97 
   98 
   99 /**
  100  * Map from PNG meta data descriptor strings
  101  * to LE types.
  102  */
  103 static struct
  104 {
  105   /**
  106    * PNG name.
  107    */
  108   const char *name;
  109 
  110   /**
  111    * Corresponding LE type.
  112    */
  113   enum EXTRACTOR_MetaType type;
  114 } tagmap[] = {
  115   { "Author", EXTRACTOR_METATYPE_AUTHOR_NAME },
  116   { "Description", EXTRACTOR_METATYPE_DESCRIPTION },
  117   { "Comment", EXTRACTOR_METATYPE_COMMENT },
  118   { "Copyright", EXTRACTOR_METATYPE_COPYRIGHT },
  119   { "Source", EXTRACTOR_METATYPE_SOURCE_DEVICE },
  120   { "Creation Time", EXTRACTOR_METATYPE_CREATION_DATE },
  121   { "Title", EXTRACTOR_METATYPE_TITLE },
  122   { "Software", EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE },
  123   { "Disclaimer", EXTRACTOR_METATYPE_DISCLAIMER },
  124   { "Warning", EXTRACTOR_METATYPE_WARNING },
  125   { "Signature", EXTRACTOR_METATYPE_UNKNOWN },
  126   { NULL, EXTRACTOR_METATYPE_RESERVED }
  127 };
  128 
  129 
  130 /**
  131  * Give the given metadata to LE.  Set "ret" to 1 and
  132  * goto 'FINISH' if LE says we are done.
  133  *
  134  * @param t type of the metadata
  135  * @param s utf8 string with the metadata
  136  */
  137 #define ADD(t,s) do { if (0 != (ret = ec->proc (ec->cls, "png", t, \
  138                                                 EXTRACTOR_METAFORMAT_UTF8, \
  139                                                 "text/plain", s, strlen (s) \
  140                                                 + 1))) goto FINISH; \
  141 } while (0)
  142 
  143 
  144 /**
  145  * Give the given metadata to LE and free the memory.  Set "ret" to 1 and
  146  * goto 'FINISH' if LE says we are done.
  147  *
  148  * @param t type of the metadata
  149  * @param s utf8 string with the metadata, to be freed afterwards
  150  */
  151 #define ADDF(t,s) do { if ( (NULL != s) && (0 != (ret = ec->proc (ec->cls, \
  152                                                                   "png", t, \
  153                                                                   EXTRACTOR_METAFORMAT_UTF8, \
  154                                                                   "text/plain", \
  155                                                                   s, strlen (s) \
  156                                                                   + 1))) ) { \
  157                          free (s); goto FINISH; } if (NULL != s) free (s); \
  158 } while (0)
  159 
  160 
  161 /**
  162  * Process EXt tag.
  163  *
  164  * @param ec extraction context
  165  * @param length length of the tag
  166  * @return 0 to continue extracting, 1 if we are done
  167  */
  168 static int
  169 processtEXt (struct EXTRACTOR_ExtractContext *ec,
  170              uint32_t length)
  171 {
  172   void *ptr;
  173   unsigned char *data;
  174   char *keyword;
  175   size_t off;
  176   unsigned int i;
  177   int ret;
  178 
  179   if (length != ec->read (ec->cls, &ptr, length))
  180     return 1;
  181   data = ptr;
  182   off = stnlen ((char*) data, length) + 1;
  183   if (off >= length)
  184     return 0;                /* failed to find '\0' */
  185   if (NULL == (keyword = EXTRACTOR_common_convert_to_utf8 ((char*) &data[off],
  186                                                            length - off,
  187                                                            "ISO-8859-1")))
  188     return 0;
  189   ret = 0;
  190   for (i = 0; NULL != tagmap[i].name; i++)
  191     if (0 == strcmp (tagmap[i].name, (char*) data))
  192     {
  193       ADDF (tagmap[i].type, keyword);
  194       return 0;
  195     }
  196   ADDF (EXTRACTOR_METATYPE_KEYWORDS, keyword);
  197 FINISH:
  198   return ret;
  199 }
  200 
  201 
  202 /**
  203  * Process iTXt tag.
  204  *
  205  * @param ec extraction context
  206  * @param length length of the tag
  207  * @return 0 to continue extracting, 1 if we are done
  208  */
  209 static int
  210 processiTXt (struct EXTRACTOR_ExtractContext *ec,
  211              uint32_t length)
  212 {
  213   void *ptr;
  214   unsigned char *data;
  215   size_t pos;
  216   char *keyword;
  217   const char *language;
  218   const char *translated;
  219   unsigned int i;
  220   int compressed;
  221   char *buf;
  222   char *lan;
  223   uLongf bufLen;
  224   int ret;
  225   int zret;
  226 
  227   if (length != ec->read (ec->cls, &ptr, length))
  228     return 1;
  229   data = ptr;
  230   pos = stnlen ((char *) data, length) + 1;
  231   if (pos >= length)
  232     return 0;
  233   compressed = data[pos++];
  234   if (compressed && (0 != data[pos++]))
  235     return 0;                /* bad compression method */
  236   if (pos > length)
  237     return 0;
  238   language = (char *) &data[pos];
  239   ret = 0;
  240   if ( (stnlen (language, length - pos) > 0) &&
  241        (NULL != (lan = stndup (language, length - pos))) )
  242     ADDF (EXTRACTOR_METATYPE_LANGUAGE, lan);
  243   pos += stnlen (language, length - pos) + 1;
  244   if (pos + 1 >= length)
  245     return 0;
  246   translated = (char*) &data[pos];      /* already in utf-8! */
  247   if ( (stnlen (translated, length - pos) > 0) &&
  248        (NULL != (lan = stndup (translated, length - pos))) )
  249     ADDF (EXTRACTOR_METATYPE_KEYWORDS, lan);
  250   pos += stnlen (translated, length - pos) + 1;
  251   if (pos >= length)
  252     return 0;
  253 
  254   if (compressed)
  255   {
  256     bufLen = 1024 + 2 * (length - pos);
  257     while (1)
  258     {
  259       if (bufLen * 2 < bufLen)
  260         return 0;
  261       bufLen *= 2;
  262       if (bufLen > 50 * (length - pos))
  263       {
  264         /* printf("zlib problem"); */
  265         return 0;
  266       }
  267       if (NULL == (buf = malloc (bufLen)))
  268       {
  269         /* printf("out of memory"); */
  270         return 0;            /* out of memory */
  271       }
  272       if (Z_OK ==
  273           (zret = uncompress ((Bytef *) buf,
  274                               &bufLen,
  275                               (const Bytef *) &data[pos], length - pos)))
  276       {
  277         /* printf("zlib ok"); */
  278         break;
  279       }
  280       free (buf);
  281       if (Z_BUF_ERROR != zret)
  282         return 0;            /* unknown error, abort */
  283     }
  284     keyword = stndup (buf, bufLen);
  285     free (buf);
  286   }
  287   else
  288   {
  289     keyword = stndup ((char *) &data[pos], length - pos);
  290   }
  291   if (NULL == keyword)
  292     return ret;
  293   for (i = 0; NULL != tagmap[i].name; i++)
  294     if (0 == strcmp (tagmap[i].name, (char*) data))
  295     {
  296       ADDF (tagmap[i].type, keyword /* already in utf8 */);
  297       return 0;
  298     }
  299   ADDF (EXTRACTOR_METATYPE_COMMENT, keyword);
  300 FINISH:
  301   return ret;
  302 }
  303 
  304 
  305 /**
  306  * Process IHDR tag.
  307  *
  308  * @param ec extraction context
  309  * @param length length of the tag
  310  * @return 0 to continue extracting, 1 if we are done
  311  */
  312 static int
  313 processIHDR (struct EXTRACTOR_ExtractContext *ec,
  314              uint32_t length)
  315 {
  316   void *ptr;
  317   unsigned char *data;
  318   char tmp[128];
  319   int ret;
  320 
  321   if (length < 12)
  322     return 0;
  323   if (length != ec->read (ec->cls, &ptr, length))
  324     return 1;
  325   data = ptr;
  326   ret = 0;
  327   snprintf (tmp,
  328             sizeof (tmp),
  329             "%ux%u",
  330             get_int_at (data), get_int_at (&data[4]));
  331   ADD (EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, tmp);
  332 FINISH:
  333   return ret;
  334 }
  335 
  336 
  337 /**
  338  * Process zTXt tag.
  339  *
  340  * @param ec extraction context
  341  * @param length length of the tag
  342  * @return 0 to continue extracting, 1 if we are done
  343  */
  344 static int
  345 processzTXt (struct EXTRACTOR_ExtractContext *ec,
  346              uint32_t length)
  347 {
  348   void *ptr;
  349   unsigned char *data;
  350   char *keyword;
  351   size_t off;
  352   unsigned int i;
  353   char *buf;
  354   uLongf bufLen;
  355   int zret;
  356   int ret;
  357 
  358   if (length != ec->read (ec->cls, &ptr, length))
  359     return 1;
  360   data = ptr;
  361   off = stnlen ((char *) data, length) + 1;
  362   if (off >= length)
  363     return 0;                /* failed to find '\0' */
  364   if (0 != data[off])
  365     return 0;                /* compression method must be 0 */
  366   off++;
  367   ret = 0;
  368   bufLen = 1024 + 2 * (length - off);
  369   while (1)
  370   {
  371     if (bufLen * 2 < bufLen)
  372       return 0;
  373     bufLen *= 2;
  374     if (bufLen > 50 * (length - off))
  375     {
  376       /* printf("zlib problem"); */
  377       return 0;
  378     }
  379     if (NULL == (buf = malloc (bufLen)))
  380     {
  381       /* printf("out of memory"); */
  382       return 0;              /* out of memory */
  383     }
  384     if (Z_OK ==
  385         (zret = uncompress ((Bytef *) buf,
  386                             &bufLen,
  387                             (const Bytef *) &data[off],
  388                             length - off)))
  389     {
  390       /* printf("zlib ok"); */
  391       break;
  392     }
  393     free (buf);
  394     if (Z_BUF_ERROR != zret)
  395       return 0;              /* unknown error, abort */
  396   }
  397   keyword = EXTRACTOR_common_convert_to_utf8 (buf,
  398                                               bufLen,
  399                                               "ISO-8859-1");
  400   free (buf);
  401   for (i = 0; NULL != tagmap[i].name; i++)
  402     if (0 == strcmp (tagmap[i].name, (char*)  data))
  403     {
  404       ADDF (tagmap[i].type, keyword);
  405       return 0;
  406     }
  407   ADDF (EXTRACTOR_METATYPE_COMMENT, keyword);
  408 FINISH:
  409   return ret;
  410 }
  411 
  412 
  413 /**
  414  * Process IME tag.
  415  *
  416  * @param ec extraction context
  417  * @param length length of the tag
  418  * @return 0 to continue extracting, 1 if we are done
  419  */
  420 static int
  421 processtIME (struct EXTRACTOR_ExtractContext *ec,
  422              uint32_t length)
  423 {
  424   void *ptr;
  425   unsigned char *data;
  426   unsigned short y;
  427   unsigned int year;
  428   unsigned int mo;
  429   unsigned int day;
  430   unsigned int h;
  431   unsigned int m;
  432   unsigned int s;
  433   char val[256];
  434   int ret;
  435 
  436   if (length != 7)
  437     return 0;
  438   if (length != ec->read (ec->cls, &ptr, length))
  439     return 1;
  440   data = ptr;
  441   ret = 0;
  442   memcpy (&y, data, sizeof (uint16_t));
  443   year = ntohs (y);
  444   mo = (unsigned char) data[6];
  445   day = (unsigned char) data[7];
  446   h = (unsigned char) data[8];
  447   m = (unsigned char) data[9];
  448   s = (unsigned char) data[10];
  449   snprintf (val,
  450             sizeof (val),
  451             "%04u-%02u-%02u %02d:%02d:%02d",
  452             year, mo, day, h, m, s);
  453   ADD (EXTRACTOR_METATYPE_MODIFICATION_DATE, val);
  454 FINISH:
  455   return ret;
  456 }
  457 
  458 
  459 /**
  460  * Main entry method for the 'image/png' extraction plugin.
  461  *
  462  * @param ec extraction context provided to the plugin
  463  */
  464 void
  465 EXTRACTOR_png_extract_method (struct EXTRACTOR_ExtractContext *ec)
  466 {
  467   void *data;
  468   uint32_t length;
  469   int64_t pos;
  470   int ret;
  471   ssize_t len;
  472 
  473   len = strlen (PNG_HEADER);
  474   if (len != ec->read (ec->cls, &data, len))
  475     return;
  476   if (0 != strncmp ((const char*) data, PNG_HEADER, len))
  477     return;
  478   ADD (EXTRACTOR_METATYPE_MIMETYPE, "image/png");
  479   ret = 0;
  480   while (0 == ret)
  481   {
  482     if (sizeof (uint32_t) + 4 != ec->read (ec->cls,
  483                                            &data,
  484                                            sizeof (uint32_t) + 4))
  485       break;
  486     length = get_int_at (data);
  487     if (0 > (pos = ec->seek (ec->cls, 0, SEEK_CUR)))
  488       break;
  489     pos += length + 4;   /* Chunk type, data, crc */
  490     if (0 == strncmp ((char*) data + sizeof (uint32_t), "IHDR", 4))
  491       ret = processIHDR (ec, length);
  492     if (0 == strncmp ((char*) data + sizeof (uint32_t), "iTXt", 4))
  493       ret = processiTXt (ec, length);
  494     if (0 == strncmp ((char*) data + sizeof (uint32_t), "tEXt", 4))
  495       ret = processtEXt (ec, length);
  496     if (0 == strncmp ((char*) data + sizeof (uint32_t), "zTXt", 4))
  497       ret = processzTXt (ec, length);
  498     if (0 == strncmp ((char*) data + sizeof (uint32_t), "tIME", 4))
  499       ret = processtIME (ec, length);
  500     if (ret != 0)
  501       break;
  502     if (pos != ec->seek (ec->cls, pos, SEEK_SET))
  503       break;
  504   }
  505 FINISH:
  506   return;
  507 }
  508 
  509 
  510 /* end of png_extractor.c */