#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
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;
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)) {
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,
"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. */
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)) {
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 */
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)
* 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)) {
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];
* (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;
}
"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)
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",
/* 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;
}
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
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 */