exif 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mkmf'
2
4
  $CFLAGS << ' -std=c99 '
3
5
  have_library('exif')
@@ -0,0 +1,490 @@
1
+ /* jpeg-data.c
2
+ *
3
+ * Copyright � 2001 Lutz M�ller <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
+
28
+ /* This refers to the exif-i18n.h file from the "exif" package and is
29
+ * NOT to be confused with the libexif/i18n.h file.
30
+ */
31
+ #include "exif/exif-i18n.h"
32
+
33
+ /* realloc that cleans up on memory failure and returns to caller */
34
+ #define CLEANUP_REALLOC(p,s) { \
35
+ unsigned char *cleanup_ptr = realloc((p),(s)); \
36
+ if (!cleanup_ptr) { free(p); (p) = NULL; return; } \
37
+ (p) = cleanup_ptr; \
38
+ }
39
+
40
+ struct _JPEGDataPrivate
41
+ {
42
+ unsigned int ref_count;
43
+
44
+ ExifLog *log;
45
+ };
46
+
47
+ JPEGData *
48
+ jpeg_data_new (void)
49
+ {
50
+ JPEGData *data;
51
+
52
+ data = malloc (sizeof (JPEGData));
53
+ if (!data)
54
+ return (NULL);
55
+ memset (data, 0, sizeof (JPEGData));
56
+ data->priv = malloc (sizeof (JPEGDataPrivate));
57
+ if (!data->priv) {
58
+ free (data);
59
+ return (NULL);
60
+ }
61
+ memset (data->priv, 0, sizeof (JPEGDataPrivate));
62
+ data->priv->ref_count = 1;
63
+
64
+ return (data);
65
+ }
66
+
67
+ void
68
+ jpeg_data_append_section (JPEGData *data)
69
+ {
70
+ JPEGSection *s;
71
+
72
+ if (!data) return;
73
+
74
+ if (!data->count)
75
+ s = malloc (sizeof (JPEGSection));
76
+ else
77
+ s = realloc (data->sections,
78
+ sizeof (JPEGSection) * (data->count + 1));
79
+ if (!s) {
80
+ EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data",
81
+ sizeof (JPEGSection) * (data->count + 1));
82
+ return;
83
+ }
84
+ memset(s + data->count, 0, sizeof (JPEGSection));
85
+ data->sections = s;
86
+ data->count++;
87
+ }
88
+
89
+ /*! jpeg_data_save_file returns 1 on success, 0 on failure */
90
+ int
91
+ jpeg_data_save_file (JPEGData *data, const char *path)
92
+ {
93
+ FILE *f;
94
+ unsigned char *d = NULL;
95
+ unsigned int size = 0, written;
96
+
97
+ jpeg_data_save_data (data, &d, &size);
98
+ if (!d)
99
+ return 0;
100
+
101
+ remove (path);
102
+ f = fopen (path, "wb");
103
+ if (!f) {
104
+ free (d);
105
+ return 0;
106
+ }
107
+ written = fwrite (d, 1, size, f);
108
+ fclose (f);
109
+ free (d);
110
+ if (written == size) {
111
+ return 1;
112
+ }
113
+ remove(path);
114
+ return 0;
115
+ }
116
+
117
+ void
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
+ exif_data_save_data (s.content.app1, &ed, &eds);
146
+ if (!ed) break;
147
+ CLEANUP_REALLOC (*d, sizeof (char) * (*ds + 2));
148
+ (*d)[*ds + 0] = (eds + 2) >> 8;
149
+ (*d)[*ds + 1] = (eds + 2) >> 0;
150
+ *ds += 2;
151
+ CLEANUP_REALLOC (*d, sizeof (char) * (*ds + eds));
152
+ memcpy (*d + *ds, ed, eds);
153
+ *ds += eds;
154
+ free (ed);
155
+ break;
156
+ default:
157
+ CLEANUP_REALLOC (*d, sizeof (char) *
158
+ (*ds + s.content.generic.size + 2));
159
+ (*d)[*ds + 0] = (s.content.generic.size + 2) >> 8;
160
+ (*d)[*ds + 1] = (s.content.generic.size + 2) >> 0;
161
+ *ds += 2;
162
+ memcpy (*d + *ds, s.content.generic.data,
163
+ s.content.generic.size);
164
+ *ds += s.content.generic.size;
165
+
166
+ /* In case of SOS, we need to write the data. */
167
+ if (s.marker == JPEG_MARKER_SOS) {
168
+ CLEANUP_REALLOC (*d, *ds + data->size);
169
+ memcpy (*d + *ds, data->data, data->size);
170
+ *ds += data->size;
171
+ }
172
+ break;
173
+ }
174
+ }
175
+ }
176
+
177
+ JPEGData *
178
+ jpeg_data_new_from_data (const unsigned char *d,
179
+ unsigned int size)
180
+ {
181
+ JPEGData *data;
182
+
183
+ data = jpeg_data_new ();
184
+ jpeg_data_load_data (data, d, size);
185
+ return (data);
186
+ }
187
+
188
+ void
189
+ jpeg_data_load_data (JPEGData *data, const unsigned char *d,
190
+ unsigned int size)
191
+ {
192
+ unsigned int i, o, len;
193
+ JPEGSection *s;
194
+ JPEGMarker marker;
195
+
196
+ if (!data) return;
197
+ if (!d) return;
198
+
199
+ for (o = 0; o < size;) {
200
+
201
+ /*
202
+ * JPEG sections start with 0xff. The first byte that is
203
+ * not 0xff is a marker (hopefully).
204
+ */
205
+ for (i = 0; i < MIN(7, size - o); i++)
206
+ if (d[o + i] != 0xff)
207
+ break;
208
+ if ((i >= size - o) || !JPEG_IS_MARKER (d[o + i])) {
209
+ exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
210
+ _("Data does not follow JPEG specification."));
211
+ return;
212
+ }
213
+ marker = d[o + i];
214
+
215
+ /* Append this section */
216
+ jpeg_data_append_section (data);
217
+ if (!data->count) return;
218
+ s = &data->sections[data->count - 1];
219
+ s->marker = marker;
220
+ o += i + 1;
221
+
222
+ switch (s->marker) {
223
+ case JPEG_MARKER_SOI:
224
+ case JPEG_MARKER_EOI:
225
+ break;
226
+ default:
227
+
228
+ /* Read the length of the section */
229
+ if (2 > size - o) { o = size; break; }
230
+ len = ((d[o] << 8) | d[o + 1]) - 2;
231
+ if (len > size) { o = size; break; }
232
+ o += 2;
233
+ if (len > size - o) { o = size; break; }
234
+
235
+ switch (s->marker) {
236
+ case JPEG_MARKER_APP1:
237
+ s->content.app1 = exif_data_new_from_data (
238
+ d + o - 4, len + 4);
239
+ break;
240
+ default:
241
+ s->content.generic.data =
242
+ malloc (sizeof (char) * len);
243
+ if (!s->content.generic.data) {
244
+ EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * len);
245
+ return;
246
+ }
247
+ s->content.generic.size = len;
248
+ memcpy (s->content.generic.data, &d[o], len);
249
+
250
+ /* In case of SOS, image data will follow. */
251
+ if (s->marker == JPEG_MARKER_SOS) {
252
+ data->size = size - o - len;
253
+ if (data->size >= 2) {
254
+ /* -2 means 'take all but the last 2 bytes which are
255
+ hoped to be JPEG_MARKER_EOI */
256
+ data->size -= 2;
257
+ if (d[o + len + data->size] != 0xFF) {
258
+ /* A truncated file (i.e. w/o JPEG_MARKER_EOI at the end).
259
+ Instead of trying to use the last two bytes as marker,
260
+ touching memory beyond allocated memory and posssibly saving
261
+ back screwed file, we rather take the rest of the file. */
262
+ data->size += 2;
263
+ }
264
+ }
265
+ data->data = malloc (
266
+ sizeof (char) * data->size);
267
+ if (!data->data) {
268
+ EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", sizeof (char) * data->size);
269
+ data->size = 0;
270
+ return;
271
+ }
272
+ memcpy (data->data, d + o + len,
273
+ data->size);
274
+ o += data->size;
275
+ }
276
+ break;
277
+ }
278
+ o += len;
279
+ break;
280
+ }
281
+ }
282
+ }
283
+
284
+ JPEGData *
285
+ jpeg_data_new_from_file (const char *path)
286
+ {
287
+ JPEGData *data;
288
+
289
+ data = jpeg_data_new ();
290
+ jpeg_data_load_file (data, path);
291
+ return (data);
292
+ }
293
+
294
+ void
295
+ jpeg_data_load_file (JPEGData *data, const char *path)
296
+ {
297
+ FILE *f;
298
+ unsigned char *d;
299
+ unsigned int size;
300
+
301
+ if (!data) return;
302
+ if (!path) return;
303
+
304
+ f = fopen (path, "rb");
305
+ if (!f) {
306
+ exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
307
+ _("Path '%s' invalid."), path);
308
+ return;
309
+ }
310
+
311
+ /* For now, we read the data into memory. Patches welcome... */
312
+ fseek (f, 0, SEEK_END);
313
+ size = ftell (f);
314
+ fseek (f, 0, SEEK_SET);
315
+ d = malloc (size);
316
+ if (!d) {
317
+ EXIF_LOG_NO_MEMORY (data->priv->log, "jpeg-data", size);
318
+ fclose (f);
319
+ return;
320
+ }
321
+ if (fread (d, 1, size, f) != size) {
322
+ free (d);
323
+ fclose (f);
324
+ exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "jpeg-data",
325
+ _("Could not read '%s'."), path);
326
+ return;
327
+ }
328
+ fclose (f);
329
+
330
+ jpeg_data_load_data (data, d, size);
331
+ free (d);
332
+ }
333
+
334
+ void
335
+ jpeg_data_ref (JPEGData *data)
336
+ {
337
+ if (!data)
338
+ return;
339
+
340
+ data->priv->ref_count++;
341
+ }
342
+
343
+ void
344
+ jpeg_data_unref (JPEGData *data)
345
+ {
346
+ if (!data)
347
+ return;
348
+
349
+ if (data->priv) {
350
+ data->priv->ref_count--;
351
+ if (!data->priv->ref_count)
352
+ jpeg_data_free (data);
353
+ }
354
+ }
355
+
356
+ void
357
+ jpeg_data_free (JPEGData *data)
358
+ {
359
+ unsigned int i;
360
+ JPEGSection s;
361
+
362
+ if (!data)
363
+ return;
364
+
365
+ if (data->count) {
366
+ for (i = 0; i < data->count; i++) {
367
+ s = data->sections[i];
368
+ switch (s.marker) {
369
+ case JPEG_MARKER_SOI:
370
+ case JPEG_MARKER_EOI:
371
+ break;
372
+ case JPEG_MARKER_APP1:
373
+ exif_data_unref (s.content.app1);
374
+ break;
375
+ default:
376
+ free (s.content.generic.data);
377
+ break;
378
+ }
379
+ }
380
+ free (data->sections);
381
+ }
382
+
383
+ if (data->data)
384
+ free (data->data);
385
+
386
+ if (data->priv) {
387
+ if (data->priv->log) {
388
+ exif_log_unref (data->priv->log);
389
+ data->priv->log = NULL;
390
+ }
391
+ free (data->priv);
392
+ }
393
+
394
+ free (data);
395
+ }
396
+
397
+ void
398
+ jpeg_data_dump (JPEGData *data)
399
+ {
400
+ unsigned int i;
401
+ JPEGContent content;
402
+ JPEGMarker marker;
403
+
404
+ if (!data)
405
+ return;
406
+
407
+ printf ("Dumping JPEG data (%i bytes of data)...\n", data->size);
408
+ for (i = 0; i < data->count; i++) {
409
+ marker = data->sections[i].marker;
410
+ content = data->sections[i].content;
411
+ printf ("Section %i (marker 0x%x - %s):\n", i, marker,
412
+ jpeg_marker_get_name (marker));
413
+ printf (" Description: %s\n",
414
+ jpeg_marker_get_description (marker));
415
+ switch (marker) {
416
+ case JPEG_MARKER_SOI:
417
+ case JPEG_MARKER_EOI:
418
+ break;
419
+ case JPEG_MARKER_APP1:
420
+ exif_data_dump (content.app1);
421
+ break;
422
+ default:
423
+ printf (" Size: %i\n", content.generic.size);
424
+ printf (" Unknown content.\n");
425
+ break;
426
+ }
427
+ }
428
+ }
429
+
430
+ static JPEGSection *
431
+ jpeg_data_get_section (JPEGData *data, JPEGMarker marker)
432
+ {
433
+ unsigned int i;
434
+
435
+ if (!data)
436
+ return (NULL);
437
+
438
+ for (i = 0; i < data->count; i++)
439
+ if (data->sections[i].marker == marker)
440
+ return (&data->sections[i]);
441
+ return (NULL);
442
+ }
443
+
444
+ ExifData *
445
+ jpeg_data_get_exif_data (JPEGData *data)
446
+ {
447
+ JPEGSection *section;
448
+
449
+ if (!data)
450
+ return NULL;
451
+
452
+ section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
453
+ if (section) {
454
+ exif_data_ref (section->content.app1);
455
+ return (section->content.app1);
456
+ }
457
+
458
+ return (NULL);
459
+ }
460
+
461
+ void
462
+ jpeg_data_set_exif_data (JPEGData *data, ExifData *exif_data)
463
+ {
464
+ JPEGSection *section;
465
+
466
+ if (!data) return;
467
+
468
+ section = jpeg_data_get_section (data, JPEG_MARKER_APP1);
469
+ if (!section) {
470
+ jpeg_data_append_section (data);
471
+ if (data->count < 2) return;
472
+ memmove (&data->sections[2], &data->sections[1],
473
+ sizeof (JPEGSection) * (data->count - 2));
474
+ section = &data->sections[1];
475
+ } else {
476
+ exif_data_unref (section->content.app1);
477
+ }
478
+ section->marker = JPEG_MARKER_APP1;
479
+ section->content.app1 = exif_data;
480
+ exif_data_ref (exif_data);
481
+ }
482
+
483
+ void
484
+ jpeg_data_log (JPEGData *data, ExifLog *log)
485
+ {
486
+ if (!data || !data->priv) return;
487
+ if (data->priv->log) exif_log_unref (data->priv->log);
488
+ data->priv->log = log;
489
+ exif_log_ref (log);
490
+ }