2005-03-30 Lutz Mueller <lutz@users.sourceforge.net>
[platform/upstream/libexif.git] / libexif / exif-data.c
index 497e3fd..92e5857 100644 (file)
@@ -27,8 +27,7 @@
 #include <libexif/exif-utils.h>
 #include <libexif/exif-loader.h>
 #include <libexif/exif-log.h>
-
-#include <libjpeg/jpeg-marker.h>
+#include <libexif/i18n.h>
 
 #include <libexif/olympus/exif-mnote-data-olympus.h>
 #include <libexif/canon/exif-mnote-data-canon.h>
 #      define strncasecmp strnicmp
 #endif
 
+#undef JPEG_MARKER_SOI
+#define JPEG_MARKER_SOI  0xd8
+#undef JPEG_MARKER_APP0
+#define JPEG_MARKER_APP0 0xe0
+#undef JPEG_MARKER_APP1
+#define JPEG_MARKER_APP1 0xe1
+
 static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00};
 
 struct _ExifDataPrivate
@@ -225,13 +231,21 @@ exif_data_save_data_entry (ExifData *data, ExifEntry *e,
        if (s > 4) {
                doff = *ds - 6;
                *ds += s;
+
+               /*
+                * According to the TIFF specification,
+                * the offset must be an even number. If we need to introduce
+                * a padding byte, we set it to 0.
+                */
+               if (s & 1) (*ds)++;
                *d = exif_mem_realloc (data->priv->mem, *d, *ds);
                if (!*d) {
                        EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", *ds);
                        return;
                }
-               exif_set_long (*d + 6 + offset + 8,
-                              data->priv->order, doff);
+               exif_set_long (*d + 6 + offset + 8, data->priv->order, doff);
+               if (s & 1) *(*d + *ds - 1) = '\0';
+
        } else
                doff = offset + 8;
 
@@ -346,7 +360,7 @@ exif_data_load_data_content (ExifData *data, ExifContent *ifd,
                default:
 
                        /*
-                        * If we don't know the tag, changes are high
+                        * If we don't know the tag, chances are high
                         * that the EXIF data does not follow the standard.
                         */
                        if (!exif_tag_get_name (tag)) {
@@ -355,15 +369,38 @@ exif_data_load_data_content (ExifData *data, ExifContent *ifd,
                                return;
                        }
                        entry = exif_entry_new_mem (data->priv->mem);
-                       exif_content_add_entry (ifd, entry);
                        exif_data_load_data_entry (data, entry, d, ds,
                                                   offset + 12 * i);
+                       exif_content_add_entry (ifd, entry);
                        exif_entry_unref (entry);
                        break;
                }
        }
 }
 
+static int
+cmp_func (const unsigned char *p1, const unsigned char *p2, ExifByteOrder o)
+{
+       ExifShort tag1 = exif_get_short (p1, o);
+       ExifShort tag2 = exif_get_short (p2, o);
+
+       return (tag1 < tag2) ? -1 : (tag1 > tag2) ? 1 : 0;
+}
+
+static int
+cmp_func_intel (const void *elem1, const void *elem2)
+{
+       return cmp_func ((const unsigned char *) elem1,
+                       (const unsigned char *) elem2, EXIF_BYTE_ORDER_INTEL);
+}
+
+static int
+cmp_func_motorola (const void *elem1, const void *elem2)
+{
+       return cmp_func ((const unsigned char *) elem1,
+                       (const unsigned char *) elem2, EXIF_BYTE_ORDER_MOTOROLA);
+}
+
 static void
 exif_data_save_data_content (ExifData *data, ExifContent *ifd,
                             unsigned char **d, unsigned int *ds,
@@ -431,8 +468,8 @@ exif_data_save_data_content (ExifData *data, ExifContent *ifd,
                  "Saving %i entries (IFD '%s', offset: %i)...",
                  ifd->count, exif_ifd_get_name (i), offset);
        for (j = 0; j < ifd->count; j++)
-               exif_data_save_data_entry (data, ifd->entries[j],
-                               d, ds, offset + 12 * j);
+               exif_data_save_data_entry (data, ifd->entries[j], d, ds, offset + 12 * j);
+
        offset += 12 * ifd->count;
 
        /* Now save special entries. */
@@ -542,6 +579,11 @@ exif_data_save_data_content (ExifData *data, ExifContent *ifd,
                break;
        }
 
+       /* Sort the directory according to TIFF specification */
+       qsort (*d + 6 + offset - (ifd->count + n_ptr + n_thumb) * 12,
+                       (ifd->count + n_ptr + n_thumb), 12,
+                       data->priv->order == EXIF_BYTE_ORDER_INTEL ? cmp_func_intel : cmp_func_motorola);
+
        /* Correctly terminate the directory */
        if (i == EXIF_IFD_0 && (data->ifd[EXIF_IFD_1]->count ||
                                             data->size)) {
@@ -584,7 +626,7 @@ exif_data_get_type_maker_note (ExifData *d)
        if (!em) return EXIF_DATA_TYPE_MAKER_NOTE_NONE;
 
        /* Canon */
-       if (!strcmp (exif_entry_get_value (em, value, sizeof(value)), "Canon"))
+       if (!strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon"))
                return EXIF_DATA_TYPE_MAKER_NOTE_CANON;
 
        /* Pentax & some variant of Nikon */
@@ -600,6 +642,10 @@ exif_data_get_type_maker_note (ExifData *d)
        return EXIF_DATA_TYPE_MAKER_NOTE_NONE;
 }
 
+#define LOG_TOO_SMALL \
+exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData", \
+               _("Size of data too small to allow for EXIF data."));
+
 void
 exif_data_load_data (ExifData *data, const unsigned char *d_orig,
                     unsigned int ds_orig)
@@ -620,8 +666,7 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
         * not, search the EXIF marker.
         */
        if (ds < 6) {
-               exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
-                         "Size too small.");
+               LOG_TOO_SMALL;
                return;
        }
        if (!memcmp (d, ExifHeader, 6)) {
@@ -658,15 +703,14 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
                                break;
 
                        /* Unknown marker or data. Give up. */
-                       exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
-                                 "ExifData", "EXIF marker not found.");
+                       exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
+                                 "ExifData", _("EXIF marker not found."));
                        return;
                }
                d++;
                ds--;
                if (ds < 2) {
-                       exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG,
-                                 "ExifData", "Size too small.");
+                       LOG_TOO_SMALL;
                        return;
                }
                len = (d[0] << 8) | d[1];
@@ -682,13 +726,12 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
         * (offset 2, length 6).
         */
        if (ds < 6) {
-               exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
-                         "Size too small.");
+               LOG_TOO_SMALL;
                return;
        }
        if (memcmp (d, ExifHeader, 6)) {
-               exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
-                         "EXIF header not found.");
+               exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
+                               "ExifData", _("EXIF header not found."));
                return;
        }
 
@@ -696,14 +739,17 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
                  "Found EXIF header.");
 
        /* Byte order (offset 6, length 2) */
-       if (ds < 12)
+       if (ds < 14)
                return;
        if (!memcmp (d + 6, "II", 2))
                data->priv->order = EXIF_BYTE_ORDER_INTEL;
        else if (!memcmp (d + 6, "MM", 2))
                data->priv->order = EXIF_BYTE_ORDER_MOTOROLA;
-       else
+       else {
+               exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
+                               "ExifData", _("Unknown encoding."));
                return;
+       }
 
        /* Fixed value */
        if (exif_get_short (d + 8, data->priv->order) != 0x002a)
@@ -714,12 +760,18 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
        exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", 
                  "IFD 0 at %i.", (int) offset);
 
-       /* Parse the actual exif data (offset 14) */
+       /* Parse the actual exif data (usually offset 14 from start) */
        exif_data_load_data_content (data, data->ifd[EXIF_IFD_0], d + 6,
                                     ds - 6, offset);
 
        /* IFD 1 offset */
+       if (offset + 6 + 2 > ds) {
+               return;
+       }
        n = exif_get_short (d + 6 + offset, data->priv->order);
+       if (offset + 6 + 2 + 12 * n + 4 > ds) {
+               return;
+       }
        offset = exif_get_long (d + 6 + offset + 2 + 12 * n, data->priv->order);
        if (offset) {
                exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",
@@ -727,8 +779,8 @@ exif_data_load_data (ExifData *data, const unsigned char *d_orig,
 
                /* Sanity check. */
                if (offset > ds - 6) {
-                       exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, 
-                                 "ExifData", "Bogus offset!");
+                       exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA,
+                                 "ExifData", "Bogus offset.");
                        return;
                }
 
@@ -934,75 +986,11 @@ static void
 entry_set_byte_order (ExifEntry *e, void *data)
 {
        ByteOrderChangeData *d = data;
-       unsigned int i;
-       ExifShort s;
-       ExifLong l;
-       ExifSLong sl;
-       ExifRational r;
-       ExifSRational sr;
 
        if (!e)
                return;
 
-       switch (e->format) {
-       case EXIF_FORMAT_SHORT:
-               for (i = 0; i < e->components; i++) {
-                       s = exif_get_short (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->old);
-                       exif_set_short (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->new, s);
-               }
-               break;
-       case EXIF_FORMAT_LONG:
-               for (i = 0; i < e->components; i++) {
-                       l = exif_get_long (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->old);
-                       exif_set_long (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->new, l);
-               }
-               break;
-       case EXIF_FORMAT_RATIONAL:
-               for (i = 0; i < e->components; i++) {
-                       r = exif_get_rational (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->old);
-                       exif_set_rational (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->new, r);
-               }
-               break;
-       case EXIF_FORMAT_SLONG:
-               for (i = 0; i < e->components; i++) {
-                       sl = exif_get_slong (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->old);
-                       exif_set_slong (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->new, sl);
-               }
-               break;
-       case EXIF_FORMAT_SRATIONAL:
-               for (i = 0; i < e->components; i++) {
-                       sr = exif_get_srational (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->old);
-                       exif_set_srational (e->data +
-                               (i * exif_format_get_size (e->format)),
-                               d->new, sr);
-               }
-               break;
-       case EXIF_FORMAT_UNDEFINED:
-       case EXIF_FORMAT_BYTE:
-       case EXIF_FORMAT_SBYTE:
-       case EXIF_FORMAT_ASCII:
-       default:
-               /* Nothing here. */
-               break;
-       }
+       exif_array_set_byte_order (e->format, e->data, e->components, d->old, d->new);
 }
 
 static void
@@ -1030,10 +1018,15 @@ exif_data_set_byte_order (ExifData *data, ExifByteOrder order)
 void
 exif_data_log (ExifData *data, ExifLog *log)
 {
+       unsigned int i;
+
        if (!data || !data->priv) return;
        exif_log_unref (data->priv->log);
        data->priv->log = log;
        exif_log_ref (log);
+
+       for (i = 0; i < EXIF_IFD_COUNT; i++)
+               exif_content_log (data->ifd[i], log);
 }
 
 /* Used internally within libexif */