EXIF library (libexif) Internals 0.6.26
exif-loader.c
Go to the documentation of this file.
1/* exif-loader.c
2 *
3 * Copyright (c) 2002 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 * SPDX-License-Identifier: LGPL-2.0-or-later
21 */
22
23#include <config.h>
24
25#include <libexif/exif-loader.h>
26#include <libexif/exif-utils.h>
27#include <libexif/i18n.h>
28
29#include <sys/types.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdio.h>
33
34#undef JPEG_MARKER_DCT
35#define JPEG_MARKER_DCT 0xc0
36#undef JPEG_MARKER_DHT
37#define JPEG_MARKER_DHT 0xc4
38#undef JPEG_MARKER_SOI
39#define JPEG_MARKER_SOI 0xd8
40#undef JPEG_MARKER_DQT
41#define JPEG_MARKER_DQT 0xdb
42#undef JPEG_MARKER_APP0
43#define JPEG_MARKER_APP0 0xe0
44#undef JPEG_MARKER_APP1
45#define JPEG_MARKER_APP1 0xe1
46#undef JPEG_MARKER_APP2
47#define JPEG_MARKER_APP2 0xe2
48#undef JPEG_MARKER_APP3
49#define JPEG_MARKER_APP3 0xe3
50#undef JPEG_MARKER_APP4
51#define JPEG_MARKER_APP4 0xe4
52#undef JPEG_MARKER_APP5
53#define JPEG_MARKER_APP5 0xe5
54#undef JPEG_MARKER_APP10
55#define JPEG_MARKER_APP10 0xea
56#undef JPEG_MARKER_APP11
57#define JPEG_MARKER_APP11 0xeb
58#undef JPEG_MARKER_APP13
59#define JPEG_MARKER_APP13 0xed
60#undef JPEG_MARKER_APP14
61#define JPEG_MARKER_APP14 0xee
62#undef JPEG_MARKER_COM
63#define JPEG_MARKER_COM 0xfe
64
65typedef enum {
74
75typedef enum {
81
86
88 unsigned char b[12];
89
91 unsigned char b_len;
92
93 unsigned int size;
94 unsigned char *buf;
95 unsigned int bytes_read;
96
97 unsigned int ref_count;
98
101};
102
104static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
105
106static void *
107exif_loader_alloc (ExifLoader *l, unsigned int i)
108{
109 void *d;
110
111 if (!l || !i)
112 return NULL;
113
114 d = exif_mem_alloc (l->mem, i);
115 if (d)
116 return d;
117
118 EXIF_LOG_NO_MEMORY (l->log, "ExifLog", i);
119 return NULL;
120}
121
122void
123exif_loader_write_file (ExifLoader *l, const char *path)
124{
125 FILE *f;
126 int size;
127 unsigned char data[1024];
128
129 if (!l || !path)
130 return;
131
132 f = fopen (path, "rb");
133 if (!f) {
134 exif_log (l->log, EXIF_LOG_CODE_NONE, "ExifLoader",
135 _("The file '%s' could not be opened."), path);
136 return;
137 }
138 while (1) {
139 size = fread (data, 1, sizeof (data), f);
140 if (size <= 0)
141 break;
142 if (!exif_loader_write (l, data, size))
143 break;
144 }
145 fclose (f);
146}
147
148static unsigned int
149exif_loader_copy (ExifLoader *eld, unsigned char *buf, unsigned int len)
150{
151 if (!eld || (len && !buf) || (eld->bytes_read >= eld->size))
152 return 0;
153
154 /* If needed, allocate the buffer. */
155 if (!eld->buf)
156 eld->buf = exif_loader_alloc (eld, eld->size);
157 if (!eld->buf)
158 return 0;
159
160 /* Copy memory */
161 len = MIN (len, eld->size - eld->bytes_read);
162 memcpy (eld->buf + eld->bytes_read, buf, len);
163 eld->bytes_read += len;
164
165 return (eld->bytes_read >= eld->size) ? 0 : 1;
166}
167
168unsigned char
169exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len)
170{
171 unsigned int i;
172
173begin:
174 if (!eld || (len && !buf))
175 return 0;
176
177 switch (eld->state) {
178 case EL_EXIF_FOUND:
179 return exif_loader_copy (eld, buf, len);
180 case EL_SKIP_BYTES:
181 if (eld->size > len) {
182 eld->size -= len;
183 return 1;
184 }
185 len -= eld->size;
186 buf += eld->size;
187 eld->size = 0;
188 eld->b_len = 0;
189 switch (eld->data_format) {
192 break;
193 default:
194 eld->state = EL_READ;
195 break;
196 }
197 break;
198
199 case EL_READ:
200 default:
201 break;
202 }
203
204 if (!len)
205 return 1;
206 exif_log (eld->log, EXIF_LOG_CODE_DEBUG, "ExifLoader",
207 "Scanning %i byte(s) of data...", len);
208
209 /*
210 * First fill the small buffer. Only continue if the buffer
211 * is filled. Note that EXIF data contains at least 12 bytes.
212 */
213 i = MIN (len, sizeof (eld->b) - eld->b_len);
214 if (i) {
215 memcpy (&eld->b[eld->b_len], buf, i);
216 eld->b_len += i;
217 if (eld->b_len < sizeof (eld->b))
218 return 1;
219 buf += i;
220 len -= i;
221 }
222
223 switch (eld->data_format) {
225
226 /* Check the small buffer against known formats. */
227 if (!memcmp (eld->b, "FUJIFILM", 8)) {
228
229 /* Skip to byte 84. There is another offset there. */
231 eld->size = 84;
232 eld->state = EL_SKIP_BYTES;
233 eld->size = 84;
234
235 } else if (!memcmp (eld->b + 2, ExifHeader, sizeof (ExifHeader))) {
236
237 /* Read the size (2 bytes). */
240 }
241 default:
242 break;
243 }
244
245 for (i = 0; i < sizeof (eld->b); i++) {
246 switch (eld->state) {
247 case EL_EXIF_FOUND:
248 if (!exif_loader_copy (eld, eld->b + i,
249 sizeof (eld->b) - i))
250 return 0;
251 return exif_loader_copy (eld, buf, len);
252 case EL_SKIP_BYTES:
253 switch (eld->size) {
254 case 0:
255 eld->state = EL_READ;
256 i--; /* reprocess this byte */
257 break;
258 case 1:
259 eld->size = 0;
260 eld->state = EL_READ;
261 break;
262 default:
263 eld->size--;
264 break;
265 }
266 break;
267
269 eld->size |= (unsigned int)eld->b[i] << 24;
271 break;
273 eld->size |= (unsigned int)eld->b[i] << 16;
275 break;
277 eld->size |= (unsigned int)eld->b[i] << 8;
279 break;
281 eld->size |= eld->b[i] << 0;
282 switch (eld->data_format) {
284 eld->state = EL_SKIP_BYTES;
285 if (eld->size < 2) {
286 /* Actually it's malformed... */
287 eld->size = 0;
288 } else
289 eld->size -= 2;
290 break;
293 eld->state = EL_SKIP_BYTES;
294 if (eld->size < 86) {
295 /* Actually it's malformed... */
296 eld->size = 0;
297 } else
298 eld->size -= 86; /* and put this in an else */
299 break;
301 eld->state = EL_EXIF_FOUND;
302 break;
303 default:
304 break;
305 }
306 break;
307
308 default:
309 switch (eld->b[i]) {
310 case JPEG_MARKER_APP1:
311 if (!memcmp (eld->b + i + 3, ExifHeader, MIN((ssize_t)(sizeof(ExifHeader)), MAX(0, ((ssize_t)(sizeof(eld->b))) - ((ssize_t)i) - 3)))) {
313 } else {
314 eld->data_format = EL_DATA_FORMAT_JPEG; /* Probably JFIF - keep searching for APP1 EXIF*/
315 }
316 eld->size = 0;
318 break;
319 case JPEG_MARKER_DCT:
320 case JPEG_MARKER_DHT:
321 case JPEG_MARKER_DQT:
322 case JPEG_MARKER_APP0:
323 case JPEG_MARKER_APP2:
324 case JPEG_MARKER_APP3:
325 case JPEG_MARKER_APP4:
326 case JPEG_MARKER_APP5:
331 case JPEG_MARKER_COM:
333 eld->size = 0;
335 break;
336 case 0xff:
337 case JPEG_MARKER_SOI:
338 break;
339 default:
340 exif_log (eld->log,
342 "ExifLoader", _("The data supplied "
343 "does not seem to contain "
344 "EXIF data. JPEG Marker type 0x%02x"), eld->b[i]);
345 exif_loader_reset (eld);
346 return 0;
347 }
348 }
349 }
350
351 /*
352 * If we reach this point, the buffer has not been big enough
353 * to read all data we need. Fill it with new data.
354 */
355 eld->b_len = 0;
356 goto begin;
357}
358
361{
364
365 exif_mem_unref (mem);
366
367 return l;
368}
369
372{
373 ExifLoader *loader;
374
375 if (!mem)
376 return NULL;
377
378 loader = exif_mem_alloc (mem, sizeof (ExifLoader));
379 if (!loader)
380 return NULL;
381 loader->ref_count = 1;
382
383 loader->mem = mem;
384 exif_mem_ref (mem);
385
386 return loader;
387}
388
389void
391{
392 if (loader)
393 loader->ref_count++;
394}
395
396static void
398{
399 ExifMem *mem;
400
401 if (!loader)
402 return;
403
404 mem = loader->mem;
405 exif_loader_reset (loader);
406 exif_log_unref (loader->log);
407 exif_mem_free (mem, loader);
408 exif_mem_unref (mem);
409}
410
411void
413{
414 if (!loader)
415 return;
416 if (!--loader->ref_count)
417 exif_loader_free (loader);
418}
419
420void
422{
423 if (!loader)
424 return;
425 exif_mem_free (loader->mem, loader->buf); loader->buf = NULL;
426 loader->size = 0;
427 loader->bytes_read = 0;
428 loader->state = 0;
429 loader->b_len = 0;
431}
432
433ExifData *
435{
436 ExifData *ed;
437
438 if (!loader || (loader->data_format == EL_DATA_FORMAT_UNKNOWN) ||
439 !loader->bytes_read)
440 return NULL;
441
442 ed = exif_data_new_mem (loader->mem);
443 exif_data_log (ed, loader->log);
444 exif_data_load_data (ed, loader->buf, loader->bytes_read);
445
446 return ed;
447}
448
449void
450exif_loader_get_buf (ExifLoader *loader, const unsigned char **buf,
451 unsigned int *buf_size)
452{
453 const unsigned char* b = NULL;
454 unsigned int s = 0;
455
456 if (loader) {
457 if (loader->data_format == EL_DATA_FORMAT_UNKNOWN) {
458 exif_log (loader->log, EXIF_LOG_CODE_DEBUG, "ExifLoader",
459 "Loader format unknown");
460 } else {
461 b = loader->buf;
462 s = loader->bytes_read;
463 }
464 }
465
466 if (buf)
467 *buf = b;
468 if (buf_size)
469 *buf_size = s;
470}
471
472void
474{
475 if (!loader)
476 return;
477 exif_log_unref (loader->log);
478 loader->log = log;
479 exif_log_ref (log);
480}
ExifData * exif_data_new_mem(ExifMem *mem)
Allocate a new ExifData using the given memory allocator.
Definition exif-data.c:109
void exif_data_load_data(ExifData *data, const unsigned char *d_orig, unsigned int ds)
Load the ExifData structure from the raw JPEG or EXIF data in the given memory buffer.
Definition exif-data.c:856
void exif_data_log(ExifData *data, ExifLog *log)
Set the log message object for all IFDs.
Definition exif-data.c:1245
unsigned char size
Definition exif-format.c:37
#define JPEG_MARKER_APP1
Definition exif-loader.c:45
void exif_loader_log(ExifLoader *loader, ExifLog *log)
Set the log message object used by this ExifLoader.
void exif_loader_reset(ExifLoader *loader)
Free any data previously loaded and reset the ExifLoader to its newly-initialized state.
#define JPEG_MARKER_DQT
Definition exif-loader.c:41
static void exif_loader_free(ExifLoader *loader)
ExifLoader * exif_loader_new(void)
Allocate a new ExifLoader.
#define JPEG_MARKER_APP0
Definition exif-loader.c:43
ExifLoaderDataFormat
Definition exif-loader.c:75
@ EL_DATA_FORMAT_UNKNOWN
Definition exif-loader.c:76
@ EL_DATA_FORMAT_FUJI_RAW
Definition exif-loader.c:79
@ EL_DATA_FORMAT_EXIF
Definition exif-loader.c:77
@ EL_DATA_FORMAT_JPEG
Definition exif-loader.c:78
#define JPEG_MARKER_APP3
Definition exif-loader.c:49
static void * exif_loader_alloc(ExifLoader *l, unsigned int i)
#define JPEG_MARKER_APP13
Definition exif-loader.c:59
#define JPEG_MARKER_DCT
Definition exif-loader.c:35
#define JPEG_MARKER_APP10
Definition exif-loader.c:55
#define JPEG_MARKER_APP5
Definition exif-loader.c:53
#define JPEG_MARKER_SOI
Definition exif-loader.c:39
static const unsigned char ExifHeader[]
Magic number for EXIF header.
ExifData * exif_loader_get_data(ExifLoader *loader)
Create an ExifData from the data in the loader.
void exif_loader_unref(ExifLoader *loader)
Decrease the refcount of the ExifLoader.
#define JPEG_MARKER_APP2
Definition exif-loader.c:47
ExifLoaderState
Definition exif-loader.c:65
@ EL_READ_SIZE_BYTE_24
Definition exif-loader.c:67
@ EL_SKIP_BYTES
Definition exif-loader.c:71
@ EL_READ_SIZE_BYTE_00
Definition exif-loader.c:70
@ EL_READ_SIZE_BYTE_16
Definition exif-loader.c:68
@ EL_EXIF_FOUND
Definition exif-loader.c:72
@ EL_READ_SIZE_BYTE_08
Definition exif-loader.c:69
@ EL_READ
Definition exif-loader.c:66
#define JPEG_MARKER_APP14
Definition exif-loader.c:61
#define JPEG_MARKER_APP11
Definition exif-loader.c:57
ExifLoader * exif_loader_new_mem(ExifMem *mem)
Allocate a new ExifLoader using the specified memory allocator.
unsigned char exif_loader_write(ExifLoader *eld, unsigned char *buf, unsigned int len)
Load a buffer into the ExifLoader from a memory buffer.
void exif_loader_ref(ExifLoader *loader)
Increase the refcount of the ExifLoader.
static unsigned int exif_loader_copy(ExifLoader *eld, unsigned char *buf, unsigned int len)
void exif_loader_get_buf(ExifLoader *loader, const unsigned char **buf, unsigned int *buf_size)
Return the raw data read by the loader.
#define JPEG_MARKER_DHT
Definition exif-loader.c:37
#define JPEG_MARKER_APP4
Definition exif-loader.c:51
void exif_loader_write_file(ExifLoader *l, const char *path)
Load a file into the given ExifLoader from the filesystem.
#define JPEG_MARKER_COM
Definition exif-loader.c:63
Defines the ExifLoader type.
void exif_log(ExifLog *log, ExifLogCode code, const char *domain, const char *format,...)
Definition exif-log.c:137
void exif_log_unref(ExifLog *log)
Definition exif-log.c:106
void exif_log_ref(ExifLog *log)
Definition exif-log.c:99
@ EXIF_LOG_CODE_NONE
Definition exif-log.h:57
@ EXIF_LOG_CODE_CORRUPT_DATA
Definition exif-log.h:60
@ EXIF_LOG_CODE_DEBUG
Definition exif-log.h:58
#define EXIF_LOG_NO_MEMORY(l, d, s)
Definition exif-log.h:112
void exif_mem_free(ExifMem *mem, void *d)
Definition exif-mem.c:91
void exif_mem_unref(ExifMem *mem)
Unrefcount an ExifMem.
Definition exif-mem.c:83
void * exif_mem_alloc(ExifMem *mem, ExifLong ds)
Definition exif-mem.c:101
ExifMem * exif_mem_new_default(void)
Create a new ExifMem with default values for your convenience.
Definition exif-mem.c:117
void exif_mem_ref(ExifMem *mem)
Refcount an ExifMem.
Definition exif-mem.c:76
EXIF data manipulation functions and types.
#define MIN(a, b)
Definition exif-utils.h:182
#define MAX(a, b)
Definition exif-utils.h:185
#define _(String)
Definition i18n.h:50
Represents the entire EXIF data found in an image.
Definition exif-data.h:48
unsigned char * buf
Definition exif-loader.c:94
unsigned int ref_count
Definition exif-loader.c:97
ExifLoaderDataFormat data_format
Definition exif-loader.c:85
unsigned char b[12]
Small buffer used for detection of format.
Definition exif-loader.c:88
unsigned char b_len
Number of bytes in the small buffer b.
Definition exif-loader.c:91
unsigned int bytes_read
Definition exif-loader.c:95
unsigned int size
Definition exif-loader.c:93
ExifLog * log
Definition exif-loader.c:99
ExifLoaderState state
Definition exif-loader.c:84
ExifMem * mem

libexif Generated by doxygen