2002-07-10 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         /* If we are to save IFD 0 or 1, we need some extra entries. */
267         if (ifd == data->ifd0) {
268                 if (data->ifd_exif->count)
269                         n_ptr++;
270                 if (data->ifd_gps->count)
271                         n_ptr++;
272         } else if (ifd == data->ifd1) {
273                 if (data->ifd_interoperability->count)
274                         n_ptr++;
275         }
276
277         /*
278          * If we are to save IFD 1, we can point to the thumbnail if it
279          * exists.
280          */
281         if ((ifd == data->ifd1) && data->data)
282                 n_thumb = 2;
283
284         /*
285          * Allocate enough memory for all entries
286          * and the number of entries.
287          */
288         *ds += (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4);
289         *d = realloc (*d, sizeof (char) * *ds);
290
291         /* Save the number of entries */
292         exif_set_short (*d + 6 + offset, data->priv->order,
293                         ifd->count + n_ptr + n_thumb);
294         offset += 2;
295 #ifdef DEBUG
296         printf ("Saving %i entries (offset: %i)...\n", ifd->count, offset);
297 #endif
298
299         /* Save each entry */
300         for (i = 0; i < ifd->count; i++)
301                 exif_data_save_data_entry (data, ifd->entries[i],
302                                 d, ds, offset + 12 * i);
303         offset += 12 * ifd->count;
304
305         /* Save special entries */
306         if (ifd == data->ifd0 && data->ifd_exif->count) {
307
308                 /* EXIF_TAG_EXIF_IFD_POINTER */
309                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
310                                 EXIF_TAG_EXIF_IFD_POINTER);
311                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
312                                 EXIF_FORMAT_LONG);
313                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
314                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
315                                 *ds - 6);
316                 exif_data_save_data_content (data, data->ifd_exif, d, ds,
317                                              *ds - 6);
318                 offset += 12;
319         }
320
321         if (ifd == data->ifd0 && data->ifd_gps->count) {
322
323                 /* EXIF_TAG_GPS_INFO_IFD_POINTER */
324                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
325                                 EXIF_TAG_GPS_INFO_IFD_POINTER);
326                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
327                                 EXIF_FORMAT_LONG);
328                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
329                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
330                                 *ds - 6);
331                 exif_data_save_data_content (data, data->ifd_gps, d, ds,
332                                              *ds - 6);
333                 offset += 12;
334         }
335
336         if (ifd == data->ifd1 && data->ifd_interoperability->count) {
337
338                 /* EXIF_TAG_INTEROPERABILITY_IFD_POINTER */
339                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
340                                 EXIF_TAG_INTEROPERABILITY_IFD_POINTER);
341                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
342                                 EXIF_FORMAT_LONG);
343                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
344                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
345                                 *ds - 6);
346                 exif_data_save_data_content (data, data->ifd_interoperability,
347                                              d, ds, *ds - 6);
348                 offset += 12;
349         }
350
351         if (n_thumb) {
352
353                 /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */
354                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
355                                 EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
356                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
357                                 EXIF_FORMAT_LONG);
358                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
359                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
360                                 data->size);
361                 offset += 12;
362                 
363                 /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */
364                 exif_set_short (*d + 6 + offset + 0, data->priv->order,
365                                 EXIF_TAG_JPEG_INTERCHANGE_FORMAT);
366                 exif_set_short (*d + 6 + offset + 2, data->priv->order,
367                                 EXIF_FORMAT_LONG);
368                 exif_set_long  (*d + 6 + offset + 4, data->priv->order, 1);
369                 exif_set_long  (*d + 6 + offset + 8, data->priv->order,
370                                 *ds - 6);
371                 *ds += data->size;
372                 *d = realloc (*d, sizeof (char) * *ds);
373                 memcpy (*d + *ds - data->size, data->data, data->size);
374                 offset += 12;
375         }
376
377         if (ifd == data->ifd0 && (data->ifd1->count ||
378                                   data->ifd_interoperability->count)) {
379                 /*
380                  * We are saving IFD 0. Tell where IFD 1 starts and save
381                  * IFD 1.
382                  */
383                 exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6);
384                 exif_data_save_data_content (data, data->ifd1, d, ds,
385                                              *ds - 6);
386         } else
387                 exif_set_long (*d + 6 + offset, data->priv->order, 0);
388 }
389
390 void
391 exif_data_load_data (ExifData *data, const unsigned char *d, unsigned int size)
392 {
393         unsigned int l, len = size;
394         ExifLong offset;
395         ExifShort n;
396
397         if (!data)
398                 return;
399         if (!d || !size)
400                 return;
401
402 #ifdef DEBUG
403         printf ("Parsing %i byte(s) EXIF data...\n", size);
404 #endif
405
406         /*
407          * It can be that the data starts with the EXIF header. If it does
408          * not, search the EXIF marker.
409          */
410         if (size < 6) {
411 #ifdef DEBUG
412                 printf ("Size too small.\n");
413 #endif
414                 return;
415         }
416         if (!memcmp (d, ExifHeader, 6)) {
417 #ifdef DEBUG
418                 printf ("Found EXIF header.\n");
419 #endif
420         } else {
421 #ifdef DEBUG
422                 printf ("Data begins with 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x "
423                         "0x%x...\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6]);
424 #endif
425                 while (1) {
426                         while ((d[0] == 0xff) && size) {
427                                 d++;
428                                 size--;
429                         }
430
431                         /* JPEG_MARKER_SOI */
432                         if (d[0] == JPEG_MARKER_SOI) {
433                                 d++;
434                                 size--;
435                                 continue;
436                         }
437
438                         /* JPEG_MARKER_APP0 */
439                         if (d[0] == JPEG_MARKER_APP0) {
440                                 d++;
441                                 size--;
442                                 l = (d[0] << 8) | d[1];
443                                 if (l > size)
444                                         return;
445                                 d += l;
446                                 size -= l;
447                                 continue;
448                         }
449
450                         /* JPEG_MARKER_APP1 */
451                         if (d[0] == JPEG_MARKER_APP1)
452                                 break;
453
454                         /* Unknown marker or data. Give up. */
455 #ifdef DEBUG
456                         printf ("EXIF marker not found.\n");
457 #endif
458                         return;
459                 }
460                 d++;
461                 size--;
462                 if (size < 2) {
463 #ifdef DEBUG
464                         printf ("Size too small.\n");
465 #endif
466                         return;
467                 }
468                 len = (d[0] << 8) | d[1];
469 #ifdef DEBUG
470                 printf ("We have to deal with %i byte(s) of EXIF data.\n", len);
471 #endif
472                 d += 2;
473                 size -= 2;
474         }
475
476         /*
477          * Verify the exif header
478          * (offset 2, length 6).
479          */
480         if (size < 6) {
481 #ifdef DEBUG
482                 printf ("Size too small.\n");
483 #endif
484                 return;
485         }
486         if (memcmp (d, ExifHeader, 6)) {
487 #ifdef DEBUG
488                 printf ("EXIF header not found.\n");
489 #endif
490                 return;
491         }
492
493 #ifdef DEBUG
494         printf ("Found EXIF header.\n");
495 #endif
496
497         /* Byte order (offset 6, length 2) */
498         if (size < 12)
499                 return;
500         if (!memcmp (d + 6, "II", 2))
501                 data->priv->order = EXIF_BYTE_ORDER_INTEL;
502         else if (!memcmp (d + 6, "MM", 2))
503                 data->priv->order = EXIF_BYTE_ORDER_MOTOROLA;
504         else
505                 return;
506
507         /* Fixed value */
508         if (exif_get_short (d + 8, data->priv->order) != 0x002a)
509                 return;
510
511         /* IFD 0 offset */
512         offset = exif_get_long (d + 10, data->priv->order);
513 #ifdef DEBUG
514         printf ("IFD 0 at %i.\n", (int) offset);
515 #endif
516
517         /* Parse the actual exif data (offset 14) */
518         exif_data_load_data_content (data, data->ifd0, d + 6,
519                                      size - 6, offset);
520
521         /* IFD 1 offset */
522         n = exif_get_short (d + 6 + offset, data->priv->order);
523         offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order);
524         if (offset) {
525 #ifdef DEBUG
526                 printf ("IFD 1 at %i.\n", (int) offset);
527 #endif
528                 exif_data_load_data_content (data, data->ifd1, d + 6,
529                                              size - 6, offset);
530         }
531 }
532
533 void
534 exif_data_save_data (ExifData *data, unsigned char **d, unsigned int *ds)
535 {
536         if (!data)
537                 return;
538         if (!d || !ds)
539                 return;
540
541         /* Header */
542         *ds = 6;
543         *d = malloc (sizeof (char) * *ds);
544         memcpy (*d, ExifHeader, 6);
545
546         /* Order (offset 6) */
547         *ds += 2;
548         *d = realloc (*d, sizeof (char) * *ds);
549         if (data->priv->order == EXIF_BYTE_ORDER_INTEL) {
550                 memcpy (*d + 6, "II", 2);
551         } else {
552                 memcpy (*d + 6, "MM", 2);
553         }
554
555         /* Fixed value (2 bytes, offset 8) */
556         *ds += 2;
557         *d = realloc (*d, sizeof (char) * *ds);
558         exif_set_short (*d + 8, data->priv->order, 0x002a);
559
560         /*
561          * IFD 0 offset (4 bytes, offset 10).
562          * We will start 8 bytes after the
563          * EXIF header (2 bytes for order, another 2 for the test, and 
564          * 4 bytes for the IFD 0 offset make 8 bytes together).
565          */
566         *ds += 4;
567         *d = realloc (*d, sizeof (char) * *ds);
568         exif_set_long (*d + 10, data->priv->order, 8);
569
570         /* Now save IFD 0. IFD 1 will be saved automatically. */
571 #ifdef DEBUG
572         printf ("Saving IFDs...\n");
573 #endif
574         exif_data_save_data_content (data, data->ifd0, d, ds, *ds - 6);
575
576 #ifdef DEBUG
577         printf ("Saved %i byte(s) EXIF data.\n", *ds);
578 #endif
579 }
580
581 ExifData *
582 exif_data_new_from_file (const char *path)
583 {
584         FILE *f;
585         unsigned int size;
586         unsigned char *data;
587         ExifData *edata;
588         int marker, ll, lh;
589
590         f = fopen (path, "rb");
591         if (!f)
592                 return (NULL);
593
594         while (1) {
595                 while ((marker = fgetc (f)) == 0xff);
596
597                 /* JPEG_MARKER_SOI */
598                 if (marker == JPEG_MARKER_SOI)
599                         continue;
600
601                 /* JPEG_MARKER_APP0 */
602                 if (marker == JPEG_MARKER_APP0) {
603                         lh = fgetc (f);
604                         ll = fgetc (f);
605                         size = (lh << 8) | ll;
606                         if (fseek (f, size - 2, SEEK_CUR) < 0)
607                                 return (NULL);
608                         continue;
609                 }
610
611                 /* JPEG_MARKER_APP1 */
612                 if (marker == JPEG_MARKER_APP1)
613                         break;
614
615                 /* Unknown marker or data. Give up. */
616                 return (NULL);
617         }
618
619         /* EXIF data found. Allocate the necessary memory and read the data. */
620         lh = fgetc (f);
621         ll = fgetc (f);
622         size = (lh << 8) | ll;
623         data = malloc (sizeof (char) * size);
624         if (!data)
625                 return (NULL);
626         if (fread (data, 1, size, f) != size) {
627                 free (data);
628                 return (NULL);
629         }
630
631         edata = exif_data_new_from_data (data, size);
632         free (data);
633
634         fclose (f);
635
636         return (edata);
637 }
638
639 void
640 exif_data_ref (ExifData *data)
641 {
642         if (!data)
643                 return;
644
645         data->priv->ref_count++;
646 }
647
648 void
649 exif_data_unref (ExifData *data)
650 {
651         if (!data)
652                 return;
653
654         data->priv->ref_count--;
655         if (!data->priv->ref_count)
656                 exif_data_free (data);
657 }
658
659 void
660 exif_data_free (ExifData *data)
661 {
662         if (data->ifd0)
663                 exif_content_unref (data->ifd0);
664         if (data->ifd1)
665                 exif_content_unref (data->ifd1);
666         if (data->data)
667                 free (data->data);
668         free (data->priv);
669         free (data);
670 }
671
672 void
673 exif_data_dump (ExifData *data)
674 {
675         if (!data)
676                 return;
677
678         if (data->ifd0->count) {
679                 printf ("Dumping IFD 0...\n");
680                 exif_content_dump (data->ifd0, 0);
681         }
682
683         if (data->ifd1->count) {
684                 printf ("Dumping IFD 1...\n");
685                 exif_content_dump (data->ifd1, 0);
686         }
687
688         if (data->ifd_exif->count) {
689                 printf ("Dumping IFD EXIF...\n");
690                 exif_content_dump (data->ifd_exif, 0);
691         }
692
693         if (data->ifd_gps->count) {
694                 printf ("Dumping IFD GPS...\n");
695                 exif_content_dump (data->ifd_gps, 0);
696         }
697
698         if (data->ifd_interoperability->count) {
699                 printf ("Dumping IFD Interoperability...\n");
700                 exif_content_dump (data->ifd_interoperability, 0);
701         }
702
703         if (data->data) {
704                 printf ("%i byte(s) thumbnail data available.", data->size);
705                 if (data->size >= 4) {
706                         printf ("0x%02x 0x%02x ... 0x%02x 0x%02x\n",
707                                 data->data[0], data->data[1],
708                                 data->data[data->size - 2],
709                                 data->data[data->size - 1]);
710                 }
711         }
712 }
713
714 ExifByteOrder
715 exif_data_get_byte_order (ExifData *data)
716 {
717         if (!data)
718                 return (0);
719
720         return (data->priv->order);
721 }
722
723 void
724 exif_data_foreach_content (ExifData *data, ExifDataForeachContentFunc func,
725                            void *user_data)
726 {
727         if (!data || !func)
728                 return;
729
730         func (data->ifd0,                 user_data);
731         func (data->ifd1,                 user_data);
732         func (data->ifd_exif,             user_data);
733         func (data->ifd_gps,              user_data);
734         func (data->ifd_interoperability, user_data);
735 }
736
737 typedef struct _ByteOrderChangeData ByteOrderChangeData;
738 struct _ByteOrderChangeData {
739         ExifByteOrder old, new;
740 };
741
742 static void
743 entry_set_byte_order (ExifEntry *e, void *data)
744 {
745         ByteOrderChangeData *d = data;
746         unsigned int i;
747         ExifShort s;
748         ExifLong l;
749         ExifSLong sl;
750         ExifRational r;
751         ExifSRational sr;
752
753         if (!e)
754                 return;
755
756         switch (e->format) {
757         case EXIF_FORMAT_SHORT:
758                 for (i = 0; i < e->components; i++) {
759                         s = exif_get_short (e->data +
760                                 (i * exif_format_get_size (e->format)),
761                                 d->old);
762                         exif_set_short (e->data + 
763                                 (i * exif_format_get_size (e->format)),
764                                 d->new, s);
765                 }
766                 break;
767         case EXIF_FORMAT_LONG:
768                 for (i = 0; i < e->components; i++) {
769                         l = exif_get_long (e->data +
770                                 (i * exif_format_get_size (e->format)),
771                                 d->old);
772                         exif_set_long (e->data +
773                                 (i * exif_format_get_size (e->format)),
774                                 d->new, l);
775                 }
776                 break;
777         case EXIF_FORMAT_RATIONAL:
778                 for (i = 0; i < e->components; i++) {
779                         r = exif_get_rational (e->data +
780                                 (i * exif_format_get_size (e->format)),
781                                 d->old);
782                         exif_set_rational (e->data +
783                                 (i * exif_format_get_size (e->format)),
784                                 d->new, r);
785                 }
786                 break;
787         case EXIF_FORMAT_SLONG:
788                 for (i = 0; i < e->components; i++) {
789                         sl = exif_get_slong (e->data +
790                                 (i * exif_format_get_size (e->format)),
791                                 d->old);
792                         exif_set_slong (e->data +
793                                 (i * exif_format_get_size (e->format)),
794                                 d->new, sl);
795                 }
796                 break;
797         case EXIF_FORMAT_SRATIONAL:
798                 for (i = 0; i < e->components; i++) {
799                         sr = exif_get_srational (e->data +
800                                 (i * exif_format_get_size (e->format)),
801                                 d->old);
802                         exif_set_srational (e->data +
803                                 (i * exif_format_get_size (e->format)),
804                                 d->new, sr);
805                 }
806                 break;
807         case EXIF_FORMAT_UNDEFINED:
808         case EXIF_FORMAT_BYTE:
809         case EXIF_FORMAT_ASCII:
810         default:
811                 /* Nothing here. */
812                 break;
813         }
814 }
815
816 static void
817 content_set_byte_order (ExifContent *content, void *data)
818 {
819         exif_content_foreach_entry (content, entry_set_byte_order, data);
820 }
821
822 void
823 exif_data_set_byte_order (ExifData *data, ExifByteOrder order)
824 {
825         ByteOrderChangeData d;
826
827         if (!data || (order == data->priv->order))
828                 return;
829
830         d.old = data->priv->order;
831         d.new = order;
832         exif_data_foreach_content (data, content_set_byte_order, &d);
833         data->priv->order = order;
834 }