2002-07-25 Lutz Müller <lutz@users.sourceforge.net>
[platform/upstream/libexif.git] / libexif / exif-data.c
1 /* exif-data.c
2  *
3  * Copyright (C) 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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 #include <config.h>
21 #include "exif-data.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include <libjpeg/jpeg-marker.h>
28
29 #include <libexif/exif-utils.h>
30
31 #undef MAX
32 #define MAX(a, b)  (((a) > (b)) ? (a) : (b))
33
34 //#define DEBUG
35
36 static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
37
38 struct _ExifDataPrivate
39 {
40         ExifByteOrder order;
41
42         unsigned int ref_count;
43 };
44
45 ExifData *
46 exif_data_new (void)
47 {
48         ExifData *data;
49
50         data = malloc (sizeof (ExifData));
51         if (!data)
52                 return (NULL);
53         memset (data, 0, sizeof (ExifData));
54         data->priv = malloc (sizeof (ExifDataPrivate));
55         if (!data->priv) {
56                 free (data);
57                 return (NULL);
58         }
59         memset (data->priv, 0, sizeof (ExifDataPrivate));
60         data->priv->ref_count = 1;
61
62         data->ifd0                 = exif_content_new ();
63         data->ifd1                 = exif_content_new ();
64         data->ifd_exif             = exif_content_new ();
65         data->ifd_gps              = exif_content_new ();
66         data->ifd_interoperability = exif_content_new ();
67         if (!data->ifd_exif || !data->ifd_gps || !data->ifd_interoperability ||
68             !data->ifd0 || !data->ifd1) {
69                 exif_data_free (data);
70                 return (NULL);
71         }
72         data->ifd0->parent                 = data;
73         data->ifd1->parent                 = data;
74         data->ifd_exif->parent             = data;
75         data->ifd_gps->parent              = data;
76         data->ifd_interoperability->parent = data;
77
78         return (data);
79 }
80
81 ExifData *
82 exif_data_new_from_data (const unsigned char *data, unsigned int size)
83 {
84         ExifData *edata;
85
86         edata = exif_data_new ();
87         exif_data_load_data (edata, data, size);
88         return (edata);
89 }
90
91 static void
92 exif_data_load_data_entry (ExifData *data, ExifEntry *entry,
93                            const unsigned char *d,
94                            unsigned int size, unsigned int offset)
95 {
96         unsigned int s, doff;
97
98         entry->tag        = exif_get_short (d + offset + 0, data->priv->order);
99         entry->format     = exif_get_short (d + offset + 2, data->priv->order);
100         entry->components = exif_get_long  (d + offset + 4, data->priv->order);
101
102         /*
103          * Size? If bigger than 4 bytes, the actual data is not
104          * in the entry but somewhere else (offset).
105          */
106         s = exif_format_get_size (entry->format) * entry->components;
107         if (!s)
108                 return;
109         if (s > 4)
110                 doff = exif_get_long (d + offset + 8, data->priv->order);
111         else
112                 doff = offset + 8;
113
114         /* Sanity check */
115         if (size < doff + s)
116                 return;
117
118         entry->data = malloc (sizeof (char) * s);
119         if (!entry->data)
120                 return;
121         entry->size = s;
122         memcpy (entry->data, d + doff, s);
123 }
124
125 static void
126 exif_data_save_data_entry (ExifData *data, ExifEntry *entry,
127                            unsigned char **d, unsigned int *ds,
128                            unsigned int offset)
129 {
130         unsigned int doff, s;
131
132         /*
133          * Each entry is 12 bytes long. The memory for the entry has
134          * already been allocated.
135          */
136         exif_set_short (*d + 6 + offset + 0,
137                         data->priv->order, entry->tag);
138         exif_set_short (*d + 6 + offset + 2,
139                         data->priv->order, entry->format);
140         exif_set_long  (*d + 6 + offset + 4,
141                         data->priv->order, entry->components);
142
143         /*
144          * Size? If bigger than 4 bytes, the actual data is not in
145          * the entry but somewhere else.
146          */
147         s = exif_format_get_size (entry->format) * entry->components;
148         if (!s)
149                 return;
150         if (s > 4) {
151                 *ds += entry->size;
152                 *d = realloc (*d, sizeof (char) * *ds);
153                 doff = *ds - 6 - entry->size;
154                 exif_set_long (*d + 6 + offset + 8,
155                                data->priv->order, doff);
156         } else
157                 doff = offset + 8;
158         memcpy (*d + 6 + doff, entry->data, entry->size);
159 }
160
161 static void
162 exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d,
163                                unsigned int ds, ExifLong offset, ExifLong size)
164 {
165         if (ds < offset + size) {
166 #ifdef DEBUG
167                 printf ("Bogus thumbnail offset and size: %i < %i + %i.\n",
168                         (int) ds, (int) offset, (int) size);
169 #endif
170                 return;
171         }
172         if (data->data)
173                 free (data->data);
174         data->size = size;
175         data->data = malloc (sizeof (char) * data->size);
176         memcpy (data->data, d + offset, data->size);
177 }
178
179 static void
180 exif_data_load_data_content (ExifData *data, ExifContent *ifd,
181                              const unsigned char *d,
182                              unsigned int ds, unsigned int offset)
183 {
184         ExifLong o, thumbnail_offset = 0, thumbnail_length = 0;
185         ExifShort n;
186         ExifEntry *entry;
187         unsigned int i;
188         ExifTag tag;
189
190         /* Read the number of entries */
191         n = exif_get_short (d + offset, data->priv->order);
192 #ifdef DEBUG
193         printf ("Loading %i entries...\n", n);
194 #endif
195         offset += 2;
196         for (i = 0; i < n; i++) {
197
198                 tag = exif_get_short (d + offset + 12 * i, data->priv->order);
199 #ifdef DEBUG
200                 printf ("Loading entry '%s' (%i of %i)...\n",
201                         exif_tag_get_name (tag), i + 1, n);
202 #endif
203                 switch (tag) {
204                 case EXIF_TAG_EXIF_IFD_POINTER:
205                 case EXIF_TAG_GPS_INFO_IFD_POINTER:
206                 case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
207                 case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
208                 case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
209                         o = exif_get_long (d + offset + 12 * i + 8,
210                                            data->priv->order);
211                         switch (tag) {
212                         case EXIF_TAG_EXIF_IFD_POINTER:
213                                 exif_data_load_data_content (data,
214                                         data->ifd_exif, d, ds, o);
215                                 break;
216                         case EXIF_TAG_GPS_INFO_IFD_POINTER:
217                                 exif_data_load_data_content (data,
218                                         data->ifd_gps, d, ds, o);
219                                 break;
220                         case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
221                                 exif_data_load_data_content (data,
222                                         data->ifd_interoperability, d, ds, o);
223                                 break;
224                         case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
225 #ifdef DEBUG
226                                 printf ("Thumbnail at %i.\n", (int) o);
227 #endif
228                                 thumbnail_offset = o;
229                                 if (thumbnail_offset && thumbnail_length)
230                                         exif_data_load_data_thumbnail (data, d,
231                                                 ds, thumbnail_offset,
232                                                 thumbnail_length);
233                                 break;
234                         case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH:
235 #ifdef DEBUG
236                                 printf ("Thumbnail size: %i.\n", (int) o);
237 #endif
238                                 thumbnail_length = o;
239                                 if (thumbnail_offset && thumbnail_length)
240                                         exif_data_load_data_thumbnail (data, d,
241                                                 ds, thumbnail_offset,
242                                                 thumbnail_length);
243                                 break;
244                         default:
245                                 return;
246                         }
247                         break;
248                 default:
249                         entry = exif_entry_new ();
250                         exif_content_add_entry (ifd, entry);
251                         exif_data_load_data_entry (data, entry, d, ds,
252                                                    offset + 12 * i);
253                         exif_entry_unref (entry);
254                         break;
255                 }
256         }
257 }
258
259 static void
260 exif_data_save_data_content (ExifData *data, ExifContent *ifd,
261                              unsigned char **d, unsigned int *ds,
262                              unsigned int offset)
263 {
264         unsigned int i, n_ptr = 0, n_thumb = 0;
265
266         /*
267          * Check if we need some extra entries for pointers or the thumbnail.
268          */
269         if (ifd == data->ifd0) {
270                 if (data->ifd_exif->count || data->ifd_interoperability->count)
271                         n_ptr++;
272                 if (data->ifd_gps->count)
273                         n_ptr++;
274         } else if (ifd == data->ifd1) {
275                 if (data->size)
276                         n_thumb = 2;
277         } else if (ifd == data->ifd_exif) {
278                 if (data->ifd_interoperability->count)
279                         n_ptr++;
280         }
281
282         /*
283          * Allocate enough memory for all entries
284          * and the number of entries.
285          */
286         *ds += (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4);
287         *d = realloc (*d, sizeof (char) * *ds);
288
289         /* Save the number of entries */
290         exif_set_short (*d + 6 + offset, data->priv->order,
291                         ifd->count + n_ptr + n_thumb);
292         offset += 2;
293 #ifdef DEBUG
294         printf ("Saving %i entries (offset: %i)...\n", ifd->count, offset);
295 #endif
296
297         /* Save each entry */
298         for (i = 0; i < ifd->count; i++)
299                 exif_data_save_data_entry (data, ifd->entries[i],
300                                 d, ds, offset + 12 * i);
301         offset += 12 * ifd->count;
302
303         /* Save special entries */
304         if (ifd == data->ifd0 && (data->ifd_exif->count ||
305                                   data->ifd_interoperability->count)) {
306
307                 /* EXIF_TAG_EXIF_IFD_POINTER */
308                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
309                                 EXIF_TAG_EXIF_IFD_POINTER);
310                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
311                                 EXIF_FORMAT_LONG);
312                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
313                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
314                                 *ds - 6);
315                 exif_data_save_data_content (data, data->ifd_exif, d, ds,
316                                              *ds - 6);
317                 offset += 12;
318         }
319
320         if (ifd == data->ifd0 && data->ifd_gps->count) {
321
322                 /* EXIF_TAG_GPS_INFO_IFD_POINTER */
323                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
324                                 EXIF_TAG_GPS_INFO_IFD_POINTER);
325                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
326                                 EXIF_FORMAT_LONG);
327                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
328                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
329                                 *ds - 6);
330                 exif_data_save_data_content (data, data->ifd_gps, d, ds,
331                                              *ds - 6);
332                 offset += 12;
333         }
334
335         if (ifd == data->ifd_exif && data->ifd_interoperability->count) {
336
337                 /* EXIF_TAG_INTEROPERABILITY_IFD_POINTER */
338                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
339                                 EXIF_TAG_INTEROPERABILITY_IFD_POINTER);
340                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
341                                 EXIF_FORMAT_LONG);
342                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
343                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
344                                 *ds - 6);
345                 exif_data_save_data_content (data, data->ifd_interoperability,
346                                              d, ds, *ds - 6);
347                 offset += 12;
348         }
349
350         if (n_thumb) {
351
352                 /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */
353                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
354                                 EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
355                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
356                                 EXIF_FORMAT_LONG);
357                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
358                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
359                                 data->size);
360                 offset += 12;
361                 
362                 /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */
363                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
364                                 EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
365                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
366                                 EXIF_FORMAT_LONG);
367                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
368                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
369                                 *ds - 6);
370                 *ds += data->size;
371                 *d = realloc (*d, sizeof (char) * *ds);
372                 memcpy (*d + *ds - data->size, data->data, data->size);
373                 offset += 12;
374         }
375
376         if (ifd == data->ifd0 && data->ifd1->count) {
377
378                 /*
379                  * We are saving IFD 0. Tell where IFD 1 starts and save
380                  * IFD 1.
381                  */
382                 exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6);
383                 exif_data_save_data_content (data, data->ifd1, d, ds,
384                                              *ds - 6);
385         } else
386                 exif_set_long (*d + 6 + offset, data->priv->order, 0);
387 }
388
389 void
390 exif_data_load_data (ExifData *data, const unsigned char *d, unsigned int size)
391 {
392         unsigned int l, len = size;
393         ExifLong offset;
394         ExifShort n;
395
396         if (!data)
397                 return;
398         if (!d || !size)
399                 return;
400
401 #ifdef DEBUG
402         printf ("Parsing %i byte(s) EXIF data...\n", size);
403 #endif
404
405         /*
406          * It can be that the data starts with the EXIF header. If it does
407          * not, search the EXIF marker.
408          */
409         if (size < 6) {
410 #ifdef DEBUG
411                 printf ("Size too small.\n");
412 #endif
413                 return;
414         }
415         if (!memcmp (d, ExifHeader, 6)) {
416 #ifdef DEBUG
417                 printf ("Found EXIF header.\n");
418 #endif
419         } else {
420 #ifdef DEBUG
421                 printf ("Data begins with 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
422                         "0x%x...\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
423 #endif
424                 while (1) {
425                         while ((d[0] == 0xff) && size) {
426                                 d++;
427                                 size--;
428                         }
429
430                         /* JPEG_MARKER_SOI */
431                         if (d[0] == JPEG_MARKER_SOI) {
432                                 d++;
433                                 size--;
434                                 continue;
435                         }
436
437                         /* JPEG_MARKER_APP0 */
438                         if (d[0] == JPEG_MARKER_APP0) {
439                                 d++;
440                                 size--;
441                                 l = (d[0] << 8) | d[1];
442                                 if (l > size)
443                                         return;
444                                 d += l;
445                                 size -= l;
446                                 continue;
447                         }
448
449                         /* JPEG_MARKER_APP1 */
450                         if (d[0] == JPEG_MARKER_APP1)
451                                 break;
452
453                         /* Unknown marker or data. Give up. */
454 #ifdef DEBUG
455                         printf ("EXIF marker not found.\n");
456 #endif
457                         return;
458                 }
459                 d++;
460                 size--;
461                 if (size < 2) {
462 #ifdef DEBUG
463                         printf ("Size too small.\n");
464 #endif
465                         return;
466                 }
467                 len = (d[0] << 8) | d[1];
468 #ifdef DEBUG
469                 printf ("We have to deal with %i byte(s) of EXIF data.\n", len);
470 #endif
471                 d += 2;
472                 size -= 2;
473         }
474
475         /*
476          * Verify the exif header
477          * (offset 2, length 6).
478          */
479         if (size < 6) {
480 #ifdef DEBUG
481                 printf ("Size too small.\n");
482 #endif
483                 return;
484         }
485         if (memcmp (d, ExifHeader, 6)) {
486 #ifdef DEBUG
487                 printf ("EXIF header not found.\n");
488 #endif
489                 return;
490         }
491
492 #ifdef DEBUG
493         printf ("Found EXIF header.\n");
494 #endif
495
496         /* Byte order (offset 6, length 2) */
497         if (size < 12)
498                 return;
499         if (!memcmp (d + 6, "II", 2))
500                 data->priv->order = EXIF_BYTE_ORDER_INTEL;
501         else if (!memcmp (d + 6, "MM", 2))
502                 data->priv->order = EXIF_BYTE_ORDER_MOTOROLA;
503         else
504                 return;
505
506         /* Fixed value */
507         if (exif_get_short (d + 8, data->priv->order) != 0x002a)
508                 return;
509
510         /* IFD 0 offset */
511         offset = exif_get_long (d + 10, data->priv->order);
512 #ifdef DEBUG
513         printf ("IFD 0 at %i.\n", (int) offset);
514 #endif
515
516         /* Parse the actual exif data (offset 14) */
517         exif_data_load_data_content (data, data->ifd0, d + 6,
518                                      size - 6, offset);
519
520         /* IFD 1 offset */
521         n = exif_get_short (d + 6 + offset, data->priv->order);
522         offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order);
523         if (offset) {
524 #ifdef DEBUG
525                 printf ("IFD 1 at %i.\n", (int) offset);
526 #endif
527                 exif_data_load_data_content (data, data->ifd1, d + 6,
528                                              size - 6, offset);
529         }
530 }
531
532 void
533 exif_data_save_data (ExifData *data, unsigned char **d, unsigned int *ds)
534 {
535         if (!data)
536                 return;
537         if (!d || !ds)
538                 return;
539
540         /* Header */
541         *ds = 6;
542         *d = malloc (sizeof (char) * *ds);
543         memcpy (*d, ExifHeader, 6);
544
545         /* Order (offset 6) */
546         *ds += 2;
547         *d = realloc (*d, sizeof (char) * *ds);
548         if (data->priv->order == EXIF_BYTE_ORDER_INTEL) {
549                 memcpy (*d + 6, "II", 2);
550         } else {
551                 memcpy (*d + 6, "MM", 2);
552         }
553
554         /* Fixed value (2 bytes, offset 8) */
555         *ds += 2;
556         *d = realloc (*d, sizeof (char) * *ds);
557         exif_set_short (*d + 8, data->priv->order, 0x002a);
558
559         /*
560          * IFD 0 offset (4 bytes, offset 10).
561          * We will start 8 bytes after the
562          * EXIF header (2 bytes for order, another 2 for the test, and 
563          * 4 bytes for the IFD 0 offset make 8 bytes together).
564          */
565         *ds += 4;
566         *d = realloc (*d, sizeof (char) * *ds);
567         exif_set_long (*d + 10, data->priv->order, 8);
568
569         /* Now save IFD 0. IFD 1 will be saved automatically. */
570 #ifdef DEBUG
571         printf ("Saving IFDs...\n");
572 #endif
573         exif_data_save_data_content (data, data->ifd0, d, ds, *ds - 6);
574
575 #ifdef DEBUG
576         printf ("Saved %i byte(s) EXIF data.\n", *ds);
577 #endif
578 }
579
580 ExifData *
581 exif_data_new_from_file (const char *path)
582 {
583         FILE *f;
584         unsigned int size;
585         unsigned char *data;
586         ExifData *edata;
587         int marker, ll, lh;
588
589         f = fopen (path, "rb");
590         if (!f)
591                 return (NULL);
592
593         while (1) {
594                 while ((marker = fgetc (f)) == 0xff);
595
596                 /* JPEG_MARKER_SOI */
597                 if (marker == JPEG_MARKER_SOI)
598                         continue;
599
600                 /* JPEG_MARKER_APP0 */
601                 if (marker == JPEG_MARKER_APP0) {
602                         lh = fgetc (f);
603                         ll = fgetc (f);
604                         size = (lh << 8) | ll;
605                         if (fseek (f, size - 2, SEEK_CUR) < 0)
606                                 return (NULL);
607                         continue;
608                 }
609
610                 /* JPEG_MARKER_APP1 */
611                 if (marker == JPEG_MARKER_APP1)
612                         break;
613
614                 /* Unknown marker or data. Give up. */
615                 return (NULL);
616         }
617
618         /* EXIF data found. Allocate the necessary memory and read the data. */
619         lh = fgetc (f);
620         ll = fgetc (f);
621         size = (lh << 8) | ll;
622         data = malloc (sizeof (char) * size);
623         if (!data)
624                 return (NULL);
625         if (fread (data, 1, size, f) != size) {
626                 free (data);
627                 return (NULL);
628         }
629
630         edata = exif_data_new_from_data (data, size);
631         free (data);
632
633         fclose (f);
634
635         return (edata);
636 }
637
638 void
639 exif_data_ref (ExifData *data)
640 {
641         if (!data)
642                 return;
643
644         data->priv->ref_count++;
645 }
646
647 void
648 exif_data_unref (ExifData *data)
649 {
650         if (!data)
651                 return;
652
653         data->priv->ref_count--;
654         if (!data->priv->ref_count)
655                 exif_data_free (data);
656 }
657
658 void
659 exif_data_free (ExifData *data)
660 {
661         if (!data)
662                 return;
663
664         if (data->ifd0) {
665                 exif_content_unref (data->ifd0);
666                 data->ifd0 = NULL;
667         }
668         if (data->ifd1) {
669                 exif_content_unref (data->ifd1);
670                 data->ifd1 = NULL;
671         }
672         if (data->ifd_exif) {
673                 exif_content_unref (data->ifd_exif);
674                 data->ifd_exif = NULL;
675         }
676         if (data->ifd_gps) {
677                 exif_content_unref (data->ifd_gps);
678                 data->ifd_gps = NULL;
679         }
680         if (data->ifd_interoperability) {
681                 exif_content_unref (data->ifd_interoperability);
682                 data->ifd_interoperability = NULL;
683         }
684         if (data->data) {
685                 free (data->data);
686                 data->data = NULL;
687         }
688         if (data->priv) {
689                 free (data->priv);
690                 data->priv = NULL;
691         }
692         free (data);
693 }
694
695 void
696 exif_data_dump (ExifData *data)
697 {
698         if (!data)
699                 return;
700
701         if (data->ifd0->count) {
702                 printf ("Dumping IFD 0...\n");
703                 exif_content_dump (data->ifd0, 0);
704         }
705
706         if (data->ifd1->count) {
707                 printf ("Dumping IFD 1...\n");
708                 exif_content_dump (data->ifd1, 0);
709         }
710
711         if (data->ifd_exif->count) {
712                 printf ("Dumping IFD EXIF...\n");
713                 exif_content_dump (data->ifd_exif, 0);
714         }
715
716         if (data->ifd_gps->count) {
717                 printf ("Dumping IFD GPS...\n");
718                 exif_content_dump (data->ifd_gps, 0);
719         }
720
721         if (data->ifd_interoperability->count) {
722                 printf ("Dumping IFD Interoperability...\n");
723                 exif_content_dump (data->ifd_interoperability, 0);
724         }
725
726         if (data->data) {
727                 printf ("%i byte(s) thumbnail data available.", data->size);
728                 if (data->size >= 4) {
729                         printf ("0x%02x 0x%02x ... 0x%02x 0x%02x\n",
730                                 data->data[0], data->data[1],
731                                 data->data[data->size - 2],
732                                 data->data[data->size - 1]);
733                 }
734         }
735 }
736
737 ExifByteOrder
738 exif_data_get_byte_order (ExifData *data)
739 {
740         if (!data)
741                 return (0);
742
743         return (data->priv->order);
744 }
745
746 void
747 exif_data_foreach_content (ExifData *data, ExifDataForeachContentFunc func,
748                            void *user_data)
749 {
750         if (!data || !func)
751                 return;
752
753         func (data->ifd0,                 user_data);
754         func (data->ifd1,                 user_data);
755         func (data->ifd_exif,             user_data);
756         func (data->ifd_gps,              user_data);
757         func (data->ifd_interoperability, user_data);
758 }
759
760 typedef struct _ByteOrderChangeData ByteOrderChangeData;
761 struct _ByteOrderChangeData {
762         ExifByteOrder old, new;
763 };
764
765 static void
766 entry_set_byte_order (ExifEntry *e, void *data)
767 {
768         ByteOrderChangeData *d = data;
769         unsigned int i;
770         ExifShort s;
771         ExifLong l;
772         ExifSLong sl;
773         ExifRational r;
774         ExifSRational sr;
775
776         if (!e)
777                 return;
778
779         switch (e->format) {
780         case EXIF_FORMAT_SHORT:
781                 for (i = 0; i < e->components; i++) {
782                         s = exif_get_short (e->data +
783                                 (i * exif_format_get_size (e->format)),
784                                 d->old);
785                         exif_set_short (e->data + 
786                                 (i * exif_format_get_size (e->format)),
787                                 d->new, s);
788                 }
789                 break;
790         case EXIF_FORMAT_LONG:
791                 for (i = 0; i < e->components; i++) {
792                         l = exif_get_long (e->data +
793                                 (i * exif_format_get_size (e->format)),
794                                 d->old);
795                         exif_set_long (e->data +
796                                 (i * exif_format_get_size (e->format)),
797                                 d->new, l);
798                 }
799                 break;
800         case EXIF_FORMAT_RATIONAL:
801                 for (i = 0; i < e->components; i++) {
802                         r = exif_get_rational (e->data +
803                                 (i * exif_format_get_size (e->format)),
804                                 d->old);
805                         exif_set_rational (e->data +
806                                 (i * exif_format_get_size (e->format)),
807                                 d->new, r);
808                 }
809                 break;
810         case EXIF_FORMAT_SLONG:
811                 for (i = 0; i < e->components; i++) {
812                         sl = exif_get_slong (e->data +
813                                 (i * exif_format_get_size (e->format)),
814                                 d->old);
815                         exif_set_slong (e->data +
816                                 (i * exif_format_get_size (e->format)),
817                                 d->new, sl);
818                 }
819                 break;
820         case EXIF_FORMAT_SRATIONAL:
821                 for (i = 0; i < e->components; i++) {
822                         sr = exif_get_srational (e->data +
823                                 (i * exif_format_get_size (e->format)),
824                                 d->old);
825                         exif_set_srational (e->data +
826                                 (i * exif_format_get_size (e->format)),
827                                 d->new, sr);
828                 }
829                 break;
830         case EXIF_FORMAT_UNDEFINED:
831         case EXIF_FORMAT_BYTE:
832         case EXIF_FORMAT_ASCII:
833         default:
834                 /* Nothing here. */
835                 break;
836         }
837 }
838
839 static void
840 content_set_byte_order (ExifContent *content, void *data)
841 {
842         exif_content_foreach_entry (content, entry_set_byte_order, data);
843 }
844
845 void
846 exif_data_set_byte_order (ExifData *data, ExifByteOrder order)
847 {
848         ByteOrderChangeData d;
849
850         if (!data || (order == data->priv->order))
851                 return;
852
853         d.old = data->priv->order;
854         d.new = order;
855         exif_data_foreach_content (data, content_set_byte_order, &d);
856         data->priv->order = order;
857 }