/* This file is part of libextractor. Copyright (C) 2002, 2003, 2004, 2012 Vidyut Samanta and Christian Grothoff libextractor is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. libextractor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libextractor; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file plugins/jpeg_extractor.c * @brief plugin to support JPEG files * @author Christian Grothoff */ #include "platform.h" #include "extractor.h" #if WINDOWS || DARWIN #if DARWIN typedef int boolean; #endif #define HAVE_BOOLEAN #endif #include #include /** * Context for custom functions. */ struct Context { /** * Environment for longjmp from within error_exit handler. */ jmp_buf env; }; /** * Function used to avoid having libjpeg write error messages to the console. */ static void no_emit (j_common_ptr cinfo, int msg_level) { /* do nothing */ } /** * Function used to avoid having libjpeg write error messages to the console. */ static void no_output (j_common_ptr cinfo) { /* do nothing */ } /** * Function used to avoid having libjpeg kill our process. */ static void no_exit (j_common_ptr cinfo) { struct Context *ctx = cinfo->client_data; /* we're not allowed to return (by API definition), and we don't want to abort/exit. So we longjmp to our cleanup code instead. */ longjmp (ctx->env, 1); } /** * Main entry method for the 'image/jpeg' extraction plugin. * * @param ec extraction context provided to the plugin */ void EXTRACTOR_jpeg_extract_method (struct EXTRACTOR_ExtractContext *ec) { struct jpeg_decompress_struct jds; struct jpeg_error_mgr em; void *buf; ssize_t size; int is_jpeg; unsigned int rounds; char format[128]; struct jpeg_marker_struct *mptr; struct Context ctx; is_jpeg = 0; rounds = 0; /* used to avoid going on forever for non-jpeg files */ jpeg_std_error (&em); em.emit_message = &no_emit; em.output_message = &no_output; em.error_exit = &no_exit; jds.client_data = &ctx; if (1 == setjmp (ctx.env)) goto EXIT; /* we get here if libjpeg calls 'no_exit' because it wants to die */ jds.err = &em; jpeg_create_decompress (&jds); jpeg_save_markers (&jds, JPEG_COM, 1024 * 8); while ( (1 == is_jpeg) || (rounds++ < 8) ) { if (-1 == (size = ec->read (ec->cls, &buf, 16 * 1024))) break; if (0 == size) break; jpeg_mem_src (&jds, buf, size); if (0 == is_jpeg) { if (JPEG_HEADER_OK == jpeg_read_header (&jds, 1)) is_jpeg = 1; /* ok, really a jpeg, keep going until the end */ continue; } jpeg_consume_input (&jds); } if (1 != is_jpeg) goto EXIT; if (0 != ec->proc (ec->cls, "jpeg", EXTRACTOR_METATYPE_MIMETYPE, EXTRACTOR_METAFORMAT_UTF8, "text/plain", "image/jpeg", strlen ("image/jpeg") + 1)) goto EXIT; snprintf (format, sizeof (format), "%ux%u", (unsigned int) jds.image_width, (unsigned int) jds.image_height); if (0 != ec->proc (ec->cls, "jpeg", EXTRACTOR_METATYPE_IMAGE_DIMENSIONS, EXTRACTOR_METAFORMAT_UTF8, "text/plain", format, strlen (format) + 1)) goto EXIT; for (mptr = jds.marker_list; NULL != mptr; mptr = mptr->next) { size_t off; if (JPEG_COM != mptr->marker) continue; off = 0; while ( (off < mptr->data_length) && (isspace (((const unsigned char *)mptr->data)[mptr->data_length - 1 - off])) ) off++; if (0 != ec->proc (ec->cls, "jpeg", EXTRACTOR_METATYPE_COMMENT, EXTRACTOR_METAFORMAT_C_STRING, "text/plain", (const char *) mptr->data, mptr->data_length - off)) goto EXIT; } EXIT: jpeg_destroy_decompress (&jds); } /* end of jpeg_extractor.c */