1 /* jpeg-data.c
2 *
3 * Copyright (c) 2001 Lutz Mueller <lutz@users.sourceforge.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA.
19 */
20
21 #include "config.h"
22 #include "jpeg-data.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <errno.h>
28
29 /* This refers to the exif-i18n.h file from the "exif" package and is
30 * NOT to be confused with the libexif/i18n.h file.
31 */
32 #include "exif/exif-i18n.h"
33
34 /* realloc that cleans up on memory failure and returns to caller */
35 #define CLEANUP_REALLOC(p,s) { \
36 unsigned char *cleanup_ptr = realloc((p),(s)); \
37 if (!cleanup_ptr) { free(p); (p) = NULL; return; } \
38 (p) = cleanup_ptr; \
39 }
40
41 struct _JPEGDataPrivate
42 {
43 unsigned int ref_count;
44
45 ExifLog *log;
46 };
47
48 JPEGData *
jpeg_data_new(void)49 jpeg_data_new (void)
50 {
51 JPEGData *data;
52
53 data = malloc (sizeof (JPEGData));
54 if (!data)
55 return (NULL);
56 memset (data, 0, sizeof (JPEGData));
57 data->priv = malloc (sizeof (JPEGDataPrivate));
58 if (!data->priv) {
59 free (data);
60 return (NULL);
61 }
62 memset (data->priv, 0, sizeof (JPEGDataPrivate));
63 data->priv->ref_count = 1;
64
65 return (data);
66 }
67
68 void
jpeg_data_append_section(JPEGData * data)69 jpeg_data_append_section (JPEGData *data)
70 {
71 JPEGSection *s;
72
73 if (!data) return;
74
75 if (!data->count)
76 s = malloc (sizeof (JPEGSection));
77 else
78 s = realloc (data->sections,
79 sizeof (JPEGSection) * (data->count + 1));
80 if (!s) {
81 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data",
82 sizeof (JPEGSection) * (data->count + 1));
83 return;
84 }
85 memset(s + data->count, 0, sizeof (JPEGSection));
86 data->sections = s;
87 data->count++;
88 }
89
90 /*! jpeg_data_save_file returns 1 on success, 0 on failure */
91 int
jpeg_data_save_file(JPEGData * data,const char * path)92 jpeg_data_save_file (JPEGData *data, const char *path)
93 {
94 FILE *f;
95 unsigned char *d = NULL;
96 unsigned int size = 0, written;
97
98 jpeg_data_save_data (data, &d, &size);
99 if (!d)
100 return 0;
101
102 f = fopen (path, "wb");
103 if (!f) {
104 free (d);
105 return 0;
106 }
107 written = fwrite (d, 1, size, f);
108 free (d);
109 if (fclose (f) == EOF)
110 return 0;
111 if (written == size) {
112 return 1;
113 }
114 return 0;
115 }
116
117 void
jpeg_data_save_data(JPEGData * data,unsigned char ** d,unsigned int * ds)118 jpeg_data_save_data (JPEGData *data, unsigned char **d, unsigned int *ds)
119 {
120 unsigned int i, eds = 0;
121 JPEGSection s;
122 unsigned char *ed = NULL;
123
124 if (!data)
125 return;
126 if (!d)
127 return;
128 if (!ds)
129 return;
130
131 for (*ds = i = 0; i < data->count; i++) {
132 s = data->sections[i];
133
134 /* Write the marker */
135 CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2));
136 (*d)[*ds + 0] = 0xff;
137 (*d)[*ds + 1] = s.marker;
138 *ds += 2;
139
140 switch (s.marker) {
141 case JPEG_MARKER_SOI:
142 case JPEG_MARKER_EOI:
143 break;
144 case JPEG_MARKER_APP1:
145 ed = NULL;
146 exif_data_save_data (s.content.app1, &ed, &eds);
147 if (!ed) break;
148 CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2));
149 (*d)[*ds + 0] = (eds + 2) >> 8;
150 (*d)[*ds + 1] = (eds + 2) >> 0;
151 *ds += 2;
152 CLEANUP_REALLOC (*d, sizeof (char) * (*ds + eds));
153 memcpy (*d + *ds, ed, eds);
154 *ds += eds;
155 free (ed);
156 break;
157 default:
158 CLEANUP_REALLOC (*d, sizeof (char) *
159 (*ds + s.content.generic.size + 2));
160 (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8;
161 (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0;
162 *ds += 2;
163 memcpy (*d + *ds, s.content.generic.data,
164 s.content.generic.size);
165 *ds += s.content.generic.size;
166
167 /* In case of SOS, we need to write the data. */
168 if (s.marker == JPEG_MARKER_SOS) {
169 CLEANUP_REALLOC (*d, *ds + data->size);
170 memcpy (*d + *ds, data->data, data->size);
171 *ds += data->size;
172 }
173 break;
174 }
175 }
176 }
177
178 JPEGData *
jpeg_data_new_from_data(const unsigned char * d,unsigned int size)179 jpeg_data_new_from_data (const unsigned char *d,
180 unsigned int size)
181 {
182 JPEGData *data;
183
184 data = jpeg_data_new ();
185 jpeg_data_load_data (data, d, size);
186 return (data);
187 }
188
189 void
jpeg_data_load_data(JPEGData * data,const unsigned char * d,unsigned int size)190 jpeg_data_load_data (JPEGData *data, const unsigned char *d,
191 unsigned int size)
192 {
193 unsigned int i, o, len;
194 JPEGSection *s;
195 JPEGMarker marker;
196
197 if (!data) return;
198 if (!d) return;
199 if (!size) return;
200
201 for (o = 0; o < size;) {
202
203 /*
204 * JPEG sections start with 0xff. The first byte that is
205 * not 0xff is a marker (hopefully).
206 */
207 for (i = 0; i < MIN(7, size - o); i++)
208 if (d[o + i] != 0xff)
209 break;
210 if (o+i == 0) /* ignore if its the first byte, otherwise 0xff is at -1 */
211 continue;
212 if ((i >= size - o) || !JPEG_IS_MARKER (d[o + i])) {
213 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
214 _("Data does not follow JPEG specification."));
215 return;
216 }
217 marker = d[o + i];
218
219 /* Append this section */
220 jpeg_data_append_section (data);
221 if (!data->count) return;
222 s = &data->sections[data->count - 1];
223 s->marker = marker;
224 o += i + 1;
225
226 switch (s->marker) {
227 case JPEG_MARKER_SOI:
228 case JPEG_MARKER_EOI:
229 break;
230 default:
231
232 /* Read the length of the section */
233 if (2 > size - o) { o = size; break; }
234 len = ((d[o] << 8) | d[o + 1]) - 2;
235 if (len > size) { o = size; break; }
236 o += 2;
237 if (len > size - o) { o = size; break; }
238
239 switch (s->marker) {
240 case JPEG_MARKER_APP1:
241 s->content.app1 = exif_data_new_from_data (
242 d + o - 4, len + 4);
243 break;
244 default:
245 s->content.generic.data =
246 malloc (sizeof (char) * len);
247 if (!s->content.generic.data) {
248 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * len);
249 return;
250 }
251 s->content.generic.size = len;
252 memcpy (s->content.generic.data, &d[o], len);
253
254 /* In case of SOS, image data will follow. */
255 if (s->marker == JPEG_MARKER_SOS) {
256 data->size = size - o - len;
257 if (data->size >= 2) {
258 /* -2 means 'take all but the last 2 bytes which are
259 hoped to be JPEG_MARKER_EOI */
260 data->size -= 2;
261 if (d[o + len + data->size] != 0xFF) {
262 /* A truncated file (i.e. w/o JPEG_MARKER_EOI at the end).
263 Instead of trying to use the last two bytes as marker,
264 touching memory beyond allocated memory and posssibly saving
265 back screwed file, we rather take the rest of the file. */
266 data->size += 2;
267 }
268 }
269 data->data = malloc (
270 sizeof (char) * data->size);
271 if (!data->data) {
272 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * data->size);
273 data->size = 0;
274 return;
275 }
276 memcpy (data->data, d + o + len,
277 data->size);
278 o += data->size;
279 }
280 break;
281 }
282 o += len;
283 break;
284 }
285 }
286 }
287
288 JPEGData *
jpeg_data_new_from_file(const char * path)289 jpeg_data_new_from_file (const char *path)
290 {
291 JPEGData *data;
292
293 data = jpeg_data_new ();
294 jpeg_data_load_file (data, path);
295 return (data);
296 }
297
298 void
jpeg_data_load_file(JPEGData * data,const char * path)299 jpeg_data_load_file (JPEGData *data, const char *path)
300 {
301 FILE *f;
302 unsigned char *d;
303 long size;
304
305 if (!data) return;
306 if (!path) return;
307
308 f = fopen (path, "rb");
309 if (!f) {
310 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
311 _("Could not open '%s' (%s)!"), path, strerror (errno));
312 return;
313 }
314
315 /* For now, we read the data into memory. Patches welcome... */
316 if (fseek (f, 0, SEEK_END) < 0) {
317 fclose (f);
318 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
319 _("Could not determine size of '%s' (%s)."), path, strerror (errno));
320 return;
321 }
322 size = ftell (f);
323 if (size < 0) {
324 fclose (f);
325 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
326 _("Could not determine size of '%s' (%s)."), path, strerror (errno));
327 return;
328 }
329 if (fseek (f, 0, SEEK_SET) < 0) {
330 fclose (f);
331 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
332 _("Could not determine size of '%s' (%s)."), path, strerror (errno));
333 return;
334 }
335
336 d = malloc (size);
337 if (!d) {
338 fclose (f);
339 EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", size);
340 return;
341 }
342 if (fread (d, 1, size, f) != (size_t) size) {
343 free (d);
344 fclose (f);
345 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
346 _("Could not read '%s' (%s)."), path, strerror (errno));
347 return;
348 }
349 if (fclose (f) == EOF)
350 exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
351 _("Could not read '%s' (%s)."), path, strerror (errno));
352
353 jpeg_data_load_data (data, d, size);
354 free (d);
355 }
356
357 void
jpeg_data_ref(JPEGData * data)358 jpeg_data_ref (JPEGData *data)
359 {
360 if (!data)
361 return;
362
363 data->priv->ref_count++;
364 }
365
366 void
jpeg_data_unref(JPEGData * data)367 jpeg_data_unref (JPEGData *data)
368 {
369 if (!data)
370 return;
371
372 if (data->priv) {
373 data->priv->ref_count--;
374 if (!data->priv->ref_count)
375 jpeg_data_free (data);
376 }
377 }
378
379 void
jpeg_data_free(JPEGData * data)380 jpeg_data_free (JPEGData *data)
381 {
382 unsigned int i;
383 JPEGSection s;
384
385 if (!data)
386 return;
387
388 if (data->count) {
389 for (i = 0; i < data->count; i++) {
390 s = data->sections[i];
391 switch (s.marker) {
392 case JPEG_MARKER_SOI:
393 case JPEG_MARKER_EOI:
394 break;
395 case JPEG_MARKER_APP1:
396 exif_data_unref (s.content.app1);
397 break;
398 default:
399 free (s.content.generic.data);
400 break;
401 }
402 }
403 free (data->sections);
404 }
405
406 if (data->data)
407 free (data->data);
408
409 if (data->priv) {
410 if (data->priv->log) {
411 exif_log_unref (data->priv->log);
412 data->priv->log = NULL;
413 }
414 free (data->priv);
415 }
416
417 free (data);
418 }
419
420 void
jpeg_data_dump(JPEGData * data)421 jpeg_data_dump (JPEGData *data)
422 {
423 unsigned int i;
424 JPEGContent content;
425 JPEGMarker marker;
426
427 if (!data)
428 return;
429
430 printf ("Dumping JPEG data (%i bytes of data)...\n", data->size);
431 for (i = 0; i < data->count; i++) {
432 marker = data->sections[i].marker;
433 content = data->sections[i].content;
434 printf ("Section %i (marker 0x%x - %s):\n", i, marker,
435 jpeg_marker_get_name (marker));
436 printf (" Description: %s\n",
437 jpeg_marker_get_description (marker));
438 switch (marker) {
439 case JPEG_MARKER_SOI:
440 case JPEG_MARKER_EOI:
441 break;
442 case JPEG_MARKER_APP1:
443 exif_data_dump (content.app1);
444 break;
445 default:
446 printf (" Size: %i\n", content.generic.size);
447 printf (" Unknown content.\n");
448 break;
449 }
450 }
451 }
452
453 static JPEGSection *
jpeg_data_get_section(JPEGData * data,JPEGMarker marker)454 jpeg_data_get_section (JPEGData *data, JPEGMarker marker)
455 {
456 unsigned int i;
457
458 if (!data)
459 return (NULL);
460
461 for (i = 0; i < data->count; i++)
462 if (data->sections[i].marker == marker)
463 return (&data->sections[i]);
464 return (NULL);
465 }
466
467 ExifData *
jpeg_data_get_exif_data(JPEGData * data)468 jpeg_data_get_exif_data (JPEGData *data)
469 {
470 JPEGSection *section;
471
472 if (!data)
473 return NULL;
474
475 section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
476 if (section) {
477 exif_data_ref (section->content.app1);
478 return (section->content.app1);
479 }
480
481 return (NULL);
482 }
483
484 void
jpeg_data_set_exif_data(JPEGData * data,ExifData * exif_data)485 jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data)
486 {
487 JPEGSection *section;
488
489 if (!data) return;
490
491 section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
492 if (!section) {
493 jpeg_data_append_section (data);
494 if (data->count < 2) return;
495 memmove (&data->sections[2], &data->sections[1],
496 sizeof (JPEGSection) * (data->count - 2));
497 section = &data->sections[1];
498 } else {
499 exif_data_unref (section->content.app1);
500 }
501 section->marker = JPEG_MARKER_APP1;
502 section->content.app1 = exif_data;
503 exif_data_ref (exif_data);
504 }
505
506 void
jpeg_data_log(JPEGData * data,ExifLog * log)507 jpeg_data_log (JPEGData *data, ExifLog *log)
508 {
509 if (!data || !data->priv) return;
510 if (data->priv->log) exif_log_unref (data->priv->log);
511 data->priv->log = log;
512 exif_log_ref (log);
513 }
514