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