aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-08-04 21:46:54 +0000
committerChristian Grothoff <christian@grothoff.org>2012-08-04 21:46:54 +0000
commitc108c43a6e8a3a09fcb7a9d4d74f85076d33ad2f (patch)
treeeaada8a4bd84e072c0b2ab2a56579054361a88c9
parenta1f2f478e5f939c574cc05460030336761177dd9 (diff)
downloadlibextractor-c108c43a6e8a3a09fcb7a9d4d74f85076d33ad2f.tar.gz
libextractor-c108c43a6e8a3a09fcb7a9d4d74f85076d33ad2f.zip
adding test for gif extractor
-rw-r--r--src/plugins/Makefile.am26
-rw-r--r--src/plugins/gif_extractor.c327
-rw-r--r--src/plugins/mime_extractor.c2
-rw-r--r--src/plugins/test_gif.c77
4 files changed, 187 insertions, 245 deletions
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index fe847db..447b674 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -25,9 +25,15 @@ PLUGIN_MIME=libextractor_mime.la
25TEST_MIME=test_mime 25TEST_MIME=test_mime
26endif 26endif
27 27
28if HAVE_GIF
29PLUGIN_GIF=libextractor_gif.la
30TEST_GIF=test_gif
31endif
32
28plugin_LTLIBRARIES = \ 33plugin_LTLIBRARIES = \
29 $(PLUGIN_OGG) \ 34 $(PLUGIN_OGG) \
30 $(PLUGIN_MIME) 35 $(PLUGIN_MIME) \
36 $(PLUGIN_GIF)
31 37
32if HAVE_ZZUF 38if HAVE_ZZUF
33 fuzz_tests=fuzz_default.sh 39 fuzz_tests=fuzz_default.sh
@@ -35,7 +41,8 @@ endif
35 41
36check_PROGRAMS = \ 42check_PROGRAMS = \
37 $(TEST_OGG) \ 43 $(TEST_OGG) \
38 $(TEST_MIME) 44 $(TEST_MIME) \
45 $(TEST_GIF)
39 46
40TESTS = \ 47TESTS = \
41 $(fuzz_tests) \ 48 $(fuzz_tests) \
@@ -81,4 +88,19 @@ test_mime_LDADD = \
81 $(top_builddir)/src/plugins/libtest.la 88 $(top_builddir)/src/plugins/libtest.la
82 89
83 90
91libextractor_gif_la_SOURCES = \
92 gif_extractor.c
93libextractor_gif_la_LDFLAGS = \
94 $(PLUGINFLAGS)
95libextractor_gif_la_LIBADD = \
96 $(top_builddir)/src/main/libextractor.la \
97 $(top_builddir)/src/common/libextractor_common.la \
98 -lgif
99
100test_gif_SOURCES = \
101 test_gif.c
102test_gif_LDADD = \
103 $(top_builddir)/src/plugins/libtest.la
104
105
84 106
diff --git a/src/plugins/gif_extractor.c b/src/plugins/gif_extractor.c
index 055fd9f..1e85f87 100644
--- a/src/plugins/gif_extractor.c
+++ b/src/plugins/gif_extractor.c
@@ -1,10 +1,10 @@
1/* 1/*
2 This file is part of libextractor. 2 This file is part of libextractor.
3 (C) 2002, 2003, 2009 Vidyut Samanta and Christian Grothoff 3 (C) 2012 Vidyut Samanta and Christian Grothoff
4 4
5 libextractor is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 libextractor is distributed in the hope that it will be useful, but 10 libextractor is distributed in the hope that it will be useful, but
@@ -20,261 +20,104 @@
20 20
21#include "platform.h" 21#include "platform.h"
22#include "extractor.h" 22#include "extractor.h"
23#include "pack.h" 23#include <gif_lib.h>
24 24
25#define DEBUG_GIF 0
26#if DEBUG_GIF
27#define PRINT(a,b) fprintf(stderr,a,b)
28#else
29#define PRINT(a,b)
30#endif
31
32struct GifHeader
33{
34 char gif[3];
35 char version[3];
36 uint16_t screen_width;
37 uint16_t screen_height;
38 unsigned char flags;
39#define HEADER_FLAGS__SIZE_OF_GLOBAL_COLOR_TABLE 0x07
40#define HEADER_FLAGS__SORT_FLAG 0x08
41#define HEADER_FLAGS__COLOR_RESOLUTION 0x70
42#define HEADER_FLAGS__GLOBAL_COLOR_TABLE_FLAG 0x80
43 unsigned char background_color_index;
44 unsigned char pixel_aspect_ratio;
45};
46
47#define GIF_HEADER_SIZE 13
48#define GIF_HEADER_SPEC "3b3bhhbbb"
49#define GIF_HEADER_FIELDS(p) \
50 &(p)->gif,\
51 &(p)->version, \
52 &(p)->screen_width, \
53 &(p)->screen_height, \
54 &(p)->flags, \
55 &(p)->background_color_index, \
56 &(p)->pixel_aspect_ratio
57
58struct GifDescriptor
59{
60 unsigned char image_separator;
61 uint16_t image_left;
62 uint16_t image_top;
63 uint16_t image_width;
64 uint16_t image_height;
65 unsigned char flags;
66#define DESCRIPTOR_FLAGS__PIXEL_SIZE 0x07
67#define DESCRIPTOR_FLAGS__RESERVED 0x18
68#define DESCRIPTOR_FLAGS__SORT_FLAG 0x20
69#define DESCRIPTOR_FLAGS__INTERLACE_FLAG 0x40
70#define DESCRIPTOR_FLAGS__LOCAL_COLOR_TABLE_FLAG 0x80
71};
72
73#define GIF_DESCRIPTOR_SIZE 10
74#define GIF_DESCRIPTOR_SPEC "chhhhc"
75#define GIF_DESCRIPTOR_FIELDS(p) \
76 &(p)->image_separator, \
77 &(p)->image_left, \
78 &(p)->image_top, \
79 &(p)->image_width, \
80 &(p)->image_height, \
81 &(p)->flags
82
83struct GifExtension
84{
85 unsigned char extension_introducer;
86 unsigned char graphic_control_label;
87};
88
89/**
90 * Skip a data block.
91 * @return the position after the block
92 */
93static size_t
94skipDataBlock (const unsigned char *data, size_t pos, const size_t size)
95{
96 while ((pos < size) && (data[pos] != 0))
97 pos += data[pos] + 1;
98 return pos + 1;
99}
100 25
101/** 26/**
102 * skip an extention block 27 * Callback invoked by libgif to read data.
103 * @return the position after the block 28 *
29 * @param ft the file handle, including our extract context
30 * @param bt where to write the data
31 * @param arg number of bytes to read
32 * @return -1 on error, otherwise number of bytes read
104 */ 33 */
105static size_t 34static int
106skipExtensionBlock (const unsigned char *data, 35gif_read_func (GifFileType *ft,
107 size_t pos, const size_t size, 36 GifByteType *bt,
108 const struct GifExtension * ext) 37 int arg)
109{ 38{
110 return skipDataBlock (data, pos + sizeof (struct GifExtension), size); 39 struct EXTRACTOR_ExtractContext *ec = ft->UserData;
40 void *data;
41 ssize_t ret;
42
43 ret = ec->read (ec->cls,
44 &data,
45 arg);
46 if (-1 == ret)
47 return -1;
48 memcpy (bt, data, ret);
49 return ret;
111} 50}
112 51
113/**
114 * @return the offset after the global color map
115 */
116static size_t
117skipGlobalColorMap (const unsigned char *data,
118 const size_t size,
119 const struct GifHeader * header)
120{
121 size_t gct_size;
122
123 if ((header->flags & HEADER_FLAGS__GLOBAL_COLOR_TABLE_FLAG) > 0)
124 gct_size =
125 3 *
126 (1 << ((header->flags & HEADER_FLAGS__SIZE_OF_GLOBAL_COLOR_TABLE) + 1));
127 else
128 gct_size = 0;
129 return GIF_HEADER_SIZE + gct_size;
130}
131 52
132/** 53/**
133 * @return the offset after the local color map 54 * Main entry method for the 'image/gif' extraction plugin.
55 *
56 * @param ec extraction context provided to the plugin
134 */ 57 */
135static size_t 58void
136skipLocalColorMap (const unsigned char *data, 59EXTRACTOR_gif_extract_method (struct EXTRACTOR_ExtractContext *ec)
137 size_t pos, const size_t size,
138 const struct GifDescriptor * descriptor)
139{ 60{
140 size_t lct_size; 61 GifFileType *gif_file;
141 62 GifRecordType gif_type;
142 if (pos + GIF_DESCRIPTOR_SIZE > size) 63 GifByteType *ext;
143 return size; 64 int et;
144 if ((descriptor->flags & DESCRIPTOR_FLAGS__LOCAL_COLOR_TABLE_FLAG) > 0) 65 char dims[128];
145 lct_size = 66
146 3 * (1 << ((descriptor->flags & DESCRIPTOR_FLAGS__PIXEL_SIZE) + 1)); 67 if (NULL == (gif_file = DGifOpen (ec, &gif_read_func)))
147 else 68 return; /* not a GIF */
148 lct_size = 0; 69 if (0 !=
149 return pos + GIF_DESCRIPTOR_SIZE + lct_size; 70 ec->proc (ec->cls,
150} 71 "gif",
151 72 EXTRACTOR_METATYPE_MIMETYPE,
152static int 73 EXTRACTOR_METAFORMAT_UTF8,
153parseComment (const unsigned char *data, 74 "text/plain",
154 size_t pos, const size_t size, 75 "image/gif",
155 EXTRACTOR_MetaDataProcessor proc, 76 strlen ("image/gif") + 1))
156 void *proc_cls) 77 return;
157{ 78 snprintf (dims,
158 size_t length; 79 sizeof (dims),
159 size_t off; 80 "%dx%d",
160 size_t curr = pos; 81 gif_file->SHeight,
161 int ret; 82 gif_file->SWidth);
162 83 if (0 !=
163 length = 0; 84 ec->proc (ec->cls,
164 while ( (curr < size) && 85 "gif",
165 (data[curr] != 0) ) 86 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS,
87 EXTRACTOR_METAFORMAT_UTF8,
88 "text/plain",
89 dims,
90 strlen (dims) + 1))
91 return;
92 while (1)
166 { 93 {
167 length += data[curr]; 94 if (GIF_OK !=
168 curr += data[curr] + 1; 95 DGifGetRecordType (gif_file,
169 if (length > 65536) 96 &gif_type))
170 break; 97 break;
171 } 98 if (UNDEFINED_RECORD_TYPE == gif_type)
172 if ( (length < 65536) && 99 break;
173 (curr < size) ) 100 if (EXTENSION_RECORD_TYPE != gif_type)
174 { 101 continue;
175 char comment[length+1]; 102 if (GIF_OK !=
176 103 DGifGetExtension (gif_file, &et, &ext))
177 curr = pos; 104 continue;
178 off = 0; 105 if (COMMENT_EXT_FUNC_CODE == et)
179 while ((data[curr] != 0) && (curr < size))
180 { 106 {
181 if (off + data[curr] >= size) 107 ec->proc (ec->cls,
182 break; 108 "gif",
183 memcpy (&comment[off], 109 EXTRACTOR_METATYPE_COMMENT,
184 &data[curr] + 1, 110 EXTRACTOR_METAFORMAT_C_STRING,
185 data[curr]); 111 "text/plain",
186 off += data[curr]; 112 (char*) &ext[1],
187 curr += data[curr] + 1; 113 (uint8_t) ext[0]);
114 break;
188 } 115 }
189 comment[off] = '\0'; 116 while ( (GIF_ERROR !=
190 ret = proc (proc_cls, 117 DGifGetExtensionNext(gif_file, &ext)) &&
191 "gif", 118 (NULL != ext) ) ; /* keep going */
192 EXTRACTOR_METATYPE_COMMENT,
193 EXTRACTOR_METAFORMAT_UTF8,
194 "text/plain",
195 comment,
196 length+1);
197 } 119 }
198 else 120 DGifCloseFile (gif_file);
199 {
200 /* too big */
201 ret = 0;
202 }
203 return ret;
204} 121}
205 122
206 123/* end of gif_extractor.c */
207int
208EXTRACTOR_gif_extract (const unsigned char *data,
209 size_t size,
210 EXTRACTOR_MetaDataProcessor proc,
211 void *proc_cls,
212 const char *options)
213{
214 size_t pos;
215 struct GifHeader header;
216 struct GifDescriptor gd;
217 char tmp[128];
218
219 if (size < GIF_HEADER_SIZE)
220 return 0;
221 EXTRACTOR_common_cat_unpack (data, GIF_HEADER_SPEC, GIF_HEADER_FIELDS (&header));
222 if (0 != strncmp (&header.gif[0], "GIF", 3))
223 return 0;
224 if (0 != strncmp (&header.version[0], "89a", 3))
225 return 0; /* only 89a has support for comments */
226 if (0 != proc (proc_cls,
227 "gif",
228 EXTRACTOR_METATYPE_MIMETYPE,
229 EXTRACTOR_METAFORMAT_UTF8,
230 "text/plain",
231 "image/gif",
232 strlen ("image/gif")+1))
233 return 1;
234 snprintf (tmp,
235 sizeof(tmp),
236 "%ux%u",
237 header.screen_width, header.screen_height);
238 if (0 != proc (proc_cls,
239 "gif",
240 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS,
241 EXTRACTOR_METAFORMAT_UTF8,
242 "text/plain",
243 tmp,
244 strlen (tmp)+1))
245 return 1;
246 pos = skipGlobalColorMap (data, size, &header);
247 PRINT ("global color map ends at %d\n", pos);
248 while (pos < size)
249 {
250 switch (data[pos])
251 {
252 case ',': /* image descriptor block */
253 PRINT ("skipping local color map %d\n", pos);
254 EXTRACTOR_common_cat_unpack (&data[pos],
255 GIF_DESCRIPTOR_SPEC,
256 GIF_DESCRIPTOR_FIELDS (&gd));
257 pos = skipLocalColorMap (data, pos, size, &gd);
258 break;
259 case '!': /* extension block */
260 PRINT ("skipping extension block %d\n", pos);
261 if (data[pos + 1] == (unsigned char) 0xFE)
262 {
263 if (0 != parseComment (data, pos + 2, size, proc, proc_cls))
264 return 1;
265 }
266 pos = skipExtensionBlock (data, pos, size,
267 (const struct GifExtension *) & data[pos]);
268 break;
269 case ';':
270 PRINT ("hit terminator at %d!\n", pos);
271 return 0; /* terminator! */
272 default: /* raster data block */
273 PRINT ("skipping data block at %d\n", pos);
274 pos = skipDataBlock (data, pos + 1, size);
275 break;
276 }
277 }
278 PRINT ("returning at %d\n", pos);
279 return 0;
280}
diff --git a/src/plugins/mime_extractor.c b/src/plugins/mime_extractor.c
index 392429a..592ba5f 100644
--- a/src/plugins/mime_extractor.c
+++ b/src/plugins/mime_extractor.c
@@ -4,7 +4,7 @@
4 4
5 libextractor is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your 7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version. 8 option) any later version.
9 9
10 libextractor is distributed in the hope that it will be useful, but 10 libextractor is distributed in the hope that it will be useful, but
diff --git a/src/plugins/test_gif.c b/src/plugins/test_gif.c
new file mode 100644
index 0000000..8fa8185
--- /dev/null
+++ b/src/plugins/test_gif.c
@@ -0,0 +1,77 @@
1/*
2 This file is part of libextractor.
3 (C) 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file plugins/test_gif.c
22 * @brief testcase for ogg plugin
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "test_lib.h"
27
28
29
30/**
31 * Main function for the GIF testcase.
32 *
33 * @param argc number of arguments (ignored)
34 * @param argv arguments (ignored)
35 * @return 0 on success
36 */
37int
38main (int argc, char *argv[])
39{
40 struct SolutionData gif_image_sol[] =
41 {
42 {
43 EXTRACTOR_METATYPE_MIMETYPE,
44 EXTRACTOR_METAFORMAT_UTF8,
45 "text/plain",
46 "image/gif",
47 strlen ("image/gif") + 1,
48 0
49 },
50 {
51 EXTRACTOR_METATYPE_IMAGE_DIMENSIONS,
52 EXTRACTOR_METAFORMAT_UTF8,
53 "text/plain",
54 "4x4",
55 strlen ("4x4") + 1,
56 0
57 },
58 {
59 EXTRACTOR_METATYPE_COMMENT,
60 EXTRACTOR_METAFORMAT_C_STRING,
61 "text/plain",
62 "Testing keyword extraction\n",
63 strlen ("Testing keyword extraction\n"),
64 0
65 },
66 { 0, 0, NULL, NULL, 0, -1 }
67 };
68 struct ProblemSet ps[] =
69 {
70 { "testdata/gif_image.gif",
71 gif_image_sol },
72 { NULL, NULL }
73 };
74 return ET_main ("gif", ps);
75}
76
77/* end of test_gif.c */