exif 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+ }