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

libexif Generated by doxygen