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
no_emit(j_common_ptr cinfo,int msg_level)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
no_output(j_common_ptr cinfo)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
no_exit(j_common_ptr cinfo)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
EXTRACTOR_jpeg_extract_method(struct EXTRACTOR_ExtractContext * ec)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
161 if (JPEG_COM != mptr->marker)
162 continue;
163 off = 0;
164 while ( (off < mptr->data_length) &&
165 (isspace (((const unsigned char *) mptr->data)[mptr->data_length
166 - 1 - off])) )
167 off++;
168 if (0 !=
169 ec->proc (ec->cls,
170 "jpeg",
171 EXTRACTOR_METATYPE_COMMENT,
172 EXTRACTOR_METAFORMAT_C_STRING,
173 "text/plain",
174 (const char *) mptr->data,
175 mptr->data_length - off))
176 goto EXIT;
177 }
178
179 EXIT:
180 jpeg_destroy_decompress (&jds);
181 }
182
183
184 /* end of jpeg_extractor.c */
185