diff options
Diffstat (limited to 'src/libexif')
48 files changed, 9877 insertions, 0 deletions
diff --git a/src/libexif/_stdint.h b/src/libexif/_stdint.h new file mode 100644 index 0000000..401189b --- /dev/null +++ b/src/libexif/_stdint.h @@ -0,0 +1,19 @@ + +#ifndef __STDINT_H +#define __STDINT_H + +#ifndef __int8_t_defined +#define __int8_t_defined +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +#endif + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +#ifndef __uint32_t_defined +#define __uint32_t_defined +typedef unsigned int uint32_t; +#endif + +#endif diff --git a/src/libexif/canon/exif-mnote-data-canon.c b/src/libexif/canon/exif-mnote-data-canon.c new file mode 100644 index 0000000..b1c5dab --- /dev/null +++ b/src/libexif/canon/exif-mnote-data-canon.c @@ -0,0 +1,281 @@ +/* exif-mnote-data-canon.c + * + * Copyright © 2002, 2003 Lutz Müller <lutz@users.sourceforge.net> + * Copyright © 2003 Matthieu Castet <mat-c@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "exif-mnote-data-canon.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-data.h> + +#define DEBUG + +static void +exif_mnote_data_canon_clear (ExifMnoteDataCanon *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_canon_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_canon_clear ((ExifMnoteDataCanon *) n); +} + +static char * +exif_mnote_data_canon_get_value (ExifMnoteData *note, unsigned int n, char *val, unsigned int maxlen) +{ + ExifMnoteDataCanon *cnote = (ExifMnoteDataCanon *) note; + + if (!note) return NULL; + if (cnote->count <= n) return NULL; + return mnote_canon_entry_get_value (&cnote->entries[n], val, maxlen); +} + +static void +exif_mnote_data_canon_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +static void +exif_mnote_data_canon_set_offset (ExifMnoteData *n, unsigned int o) +{ + if (n) ((ExifMnoteDataCanon *) n)->offset = o; +} + +static void +exif_mnote_data_canon_save (ExifMnoteData *ne, + unsigned char **buf, unsigned int *buf_size) +{ + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; + unsigned int i, o, s, doff; + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for all entries and the number + * of entries. + */ + *buf_size = 2 + n->count * 12 + 4; + *buf = exif_mem_alloc (ne->mem, sizeof (char) * *buf_size); + if (!*buf) return; + + /* Save the number of entries */ + exif_set_short (*buf, n->order, (ExifShort) n->count); + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + o = 2 + i * 12; + exif_set_short (*buf + o + 0, n->order, (ExifShort) n->entries[i].tag); + exif_set_short (*buf + o + 2, n->order, (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, + n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 4) { + *buf_size += s; + + /* Ensure even offsets. Set padding bytes to 0. */ + if (s & 1) *buf_size += 1; + *buf = exif_mem_realloc (ne->mem, *buf, + sizeof (char) * *buf_size); + if (!*buf) return; + doff = *buf_size - s; + if (s & 1) { doff--; *(*buf + *buf_size - 1) = '\0'; } + exif_set_long (*buf + o, n->order, n->offset + doff); + } else + doff = o; + + /* + * Write the data. Fill unneeded bytes with 0. Do not + * crash if data is NULL. + */ + if (!n->entries[i].data) memset (*buf + doff, 0, s); + else memcpy (*buf + doff, n->entries[i].data, s); + if (s < 4) memset (*buf + doff + s, 0, (4 - s)); + } +} + +/* XXX + * FIXME: exif_mnote_data_canon_load() may fail and there is no + * semantics to express that. + * See bug #1054323 for details, especially the comment by liblit + * after it has supposedly been fixed: + * + * https://sourceforge.net/tracker/?func=detail&aid=1054323&group_id=12272&atid=112272 + * Unfortunately, the "return" statements aren't commented at + * all, so it isn't trivial to find out what is a normal + * return, and what is a reaction to an error condition. + */ + +static void +exif_mnote_data_canon_load (ExifMnoteData *ne, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataCanon *n = (ExifMnoteDataCanon *) ne; + ExifShort c; + unsigned int i, o, s; + + if (!n || !buf || !buf_size || (buf_size < 6 + n->offset + 2)) return; + + /* Read the number of entries and remove old ones. */ + c = exif_get_short (buf + 6 + n->offset, n->order); + exif_mnote_data_canon_clear (n); + + /* Parse the entries */ + for (i = 0; i < c; i++) { + o = 6 + 2 + n->offset + 12 * i; + if (o + 8 > buf_size) return; + + n->count = i + 1; + n->entries = exif_mem_realloc (ne->mem, n->entries, + sizeof (MnoteCanonEntry) * (i+1)); + memset (&n->entries[i], 0, sizeof (MnoteCanonEntry)); + n->entries[i].tag = exif_get_short (buf + o, n->order); + n->entries[i].format = exif_get_short (buf + o + 2, n->order); + n->entries[i].components = exif_get_long (buf + o + 4, n->order); + n->entries[i].order = n->order; + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (!s) return; + o += 8; + if (s > 4) o = exif_get_long (buf + o, n->order) + 6; + if (o + s > buf_size) return; + + /* Sanity check */ + n->entries[i].data = exif_mem_alloc (ne->mem, sizeof (char) * s); + if (!n->entries[i].data) return; + n->entries[i].size = s; + memcpy (n->entries[i].data, buf + o, s); + } +} + +static unsigned int +exif_mnote_data_canon_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataCanon *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_canon_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataCanon *note = (ExifMnoteDataCanon *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_canon_get_name (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *cnote = (ExifMnoteDataCanon *) note; + + if (!note) return NULL; + if (i >= cnote->count) return NULL; + return mnote_canon_tag_get_name (cnote->entries[i].tag); +} + +static const char * +exif_mnote_data_canon_get_title (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *cnote = (ExifMnoteDataCanon *) note; + + if (!note) return NULL; + if (i >= cnote->count) return NULL; + return mnote_canon_tag_get_title (cnote->entries[i].tag); +} + +static const char * +exif_mnote_data_canon_get_description (ExifMnoteData *note, unsigned int i) +{ + ExifMnoteDataCanon *cnote = (ExifMnoteDataCanon *) note; + if (!note) return NULL; + if (i >= cnote->count) return NULL; + return mnote_canon_tag_get_description (cnote->entries[i].tag); +} + +ExifMnoteData * +exif_mnote_data_canon_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataCanon)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_canon_free; + d->methods.set_byte_order = exif_mnote_data_canon_set_byte_order; + d->methods.set_offset = exif_mnote_data_canon_set_offset; + d->methods.load = exif_mnote_data_canon_load; + d->methods.save = exif_mnote_data_canon_save; + d->methods.count = exif_mnote_data_canon_count; + d->methods.get_id = exif_mnote_data_canon_get_id; + d->methods.get_name = exif_mnote_data_canon_get_name; + d->methods.get_title = exif_mnote_data_canon_get_title; + d->methods.get_description = exif_mnote_data_canon_get_description; + d->methods.get_value = exif_mnote_data_canon_get_value; + + return d; +} diff --git a/src/libexif/canon/exif-mnote-data-canon.h b/src/libexif/canon/exif-mnote-data-canon.h new file mode 100644 index 0000000..a476ca0 --- /dev/null +++ b/src/libexif/canon/exif-mnote-data-canon.h @@ -0,0 +1,45 @@ +/* exif-mnote-data-canon.h + * + * Copyright © 2002, 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_MNOTE_DATA_CANON_H__ +#define __EXIF_MNOTE_DATA_CANON_H__ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/exif-mem.h> + +typedef struct _ExifMnoteDataCanon ExifMnoteDataCanon; + +#include <libexif/canon/mnote-canon-entry.h> + +struct _ExifMnoteDataCanon { + ExifMnoteData parent; + + MnoteCanonEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; +}; + +ExifMnoteData *exif_mnote_data_canon_new (ExifMem *mem); + +#endif /* __EXIF_MNOTE_DATA_CANON_H__ */ diff --git a/src/libexif/canon/mnote-canon-entry.c b/src/libexif/canon/mnote-canon-entry.c new file mode 100644 index 0000000..5fa4991 --- /dev/null +++ b/src/libexif/canon/mnote-canon-entry.c @@ -0,0 +1,590 @@ +/* mnote-canon-entry.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * Copyright © 2003 Matthieu Castet <mat-c@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "mnote-canon-entry.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/i18n.h> + +/* #define DEBUG */ + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} +#define CC2(number,t1,t2,v,maxlen) \ +{ \ + if ((number != t1) && (number != t2)) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i or %i)."), (int) number, \ + (int) t1, (int) t2); \ + break; \ + } \ +} + +char * +mnote_canon_entry_get_value (const MnoteCanonEntry *entry, char *val, unsigned int maxlen) +{ + char buf[128]; + ExifLong vl; + ExifShort vs, n; + int i; + unsigned char *data = entry->data; + + if (!entry) return NULL; + + memset (val, 0, maxlen); + maxlen--; + + switch (entry->tag) { + case MNOTE_CANON_TAG_SETTINGS_1: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order) / 2; + data += 2; + CC (entry->components, n, val, maxlen); + for (i = 1; i < n; i++) { + vs = exif_get_short (data, entry->order); + data += 2; + switch (i) { + case 1: + strncpy (val, _("Macro mode : "), maxlen); + switch (vs) { + case 1: + strncat (val, _("Macro"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("Normal"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 2: + if (vs) { + snprintf (buf, sizeof (buf), + _(" / Self Timer : %i (ms)"), vs*100); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 4: + strncat (val, _(" / Flash mode : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Flash not fired"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("auto"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("on"), maxlen - strlen(val)); + break; + case 3: + strncat (val, _("red eyes reduction"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("slow synchro"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("auto + red eyes reduction"), maxlen - strlen(val)); + break; + case 6: + strncat (val, _("on + red eyes reduction"), maxlen - strlen(val)); + break; + case 16: + strncat (val, _("external"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 5: + strncat (val, _(" / Continuous drive mode : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("single or timer"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("continuous"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 7: + strncat (val, _(" / Focus mode : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("One-Shot"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("AI Servo"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("AI Focus"), maxlen - strlen(val)); + break; + case 3: + strncat (val, _("MF"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("Single"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("Continuous"), maxlen - strlen(val)); + break; + case 6: + strncat (val, _("MF"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 10: + strncat (val, _(" / Image size : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Large"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("Medium"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("Small"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 11: + strncat (val, _(" / Easy shooting mode : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Full Auto"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("Manual"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("Landscape"), maxlen - strlen(val)); + break; + case 3: + strncat (val, _("Fast Shutter"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("Slow Shutter"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("Night"), maxlen - strlen(val)); + break; + case 6: + strncat (val, _("Black & White"), maxlen - strlen(val)); + break; + case 7: + strncat (val, _("Sepia"), maxlen - strlen(val)); + break; + case 8: + strncat (val, _("Portrait"), maxlen - strlen(val)); + break; + case 9: + strncat (val, _("Sports"), maxlen - strlen(val)); + break; + case 10: + strncat (val, _("Macro / Close-Up"), maxlen - strlen(val)); + break; + case 11: + strncat (val, _("Pan Focus"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 13: + strncat (val, _(" / Contrast : "), maxlen - strlen(val)); + switch (vs) { + case 0xffff: + strncat (val, _("Low"), maxlen - strlen(val)); + break; + case 0x0000: + strncat (val, _("Normal"), maxlen - strlen(val)); + break; + case 0x0001: + strncat (val, _("High"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 14: + strncat (val, _(" / Saturation : "), maxlen - strlen(val)); + switch (vs) { + case 0xffff: + strncat (val, _("Low"), maxlen - strlen(val)); + break; + case 0x0000: + strncat (val, _("Normal"), maxlen - strlen(val)); + break; + case 0x0001: + strncat (val, _("High"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 15: + strncat (val, _(" / Sharpness : "), maxlen - strlen(val)); + switch (vs) { + case 0xffff: + strncat (val, _("Low"), maxlen - strlen(val)); + break; + case 0x0000: + strncat (val, _("Normal"), maxlen - strlen(val)); + break; + case 0x0001: + strncat (val, _("High"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 16: + if (vs) { + strncat (val, _(" / ISO : "), maxlen - strlen(val)); + switch (vs) { + case 15: + strncat (val, _("auto"), maxlen - strlen(val)); + break; + case 16: + strncat (val, _("50"), maxlen - strlen(val)); + break; + case 17: + strncat (val, _("100"), maxlen - strlen(val)); + break; + case 18: + strncat (val, _("200"), maxlen - strlen(val)); + break; + case 19: + strncat (val, _("400"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + } + case 17: + strncat (val, _(" / Metering mode : "), maxlen - strlen(val)); + switch (vs) { + case 3: + strncat (val, _("Evaluative"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("Partial"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("Center-weighted"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 19: + strncat (val, _(" / AF point selected : "), maxlen - strlen(val)); + switch (vs) { + case 0x3000: + strncat (val, _("none (MF)"), maxlen - strlen(val)); + break; + case 0x3001: + strncat (val, _("auto-selected"), maxlen - strlen(val)); + break; + case 0x3002: + strncat (val, _("right"), maxlen - strlen(val)); + break; + case 0x3003: + strncat (val, _("center"), maxlen - strlen(val)); + break; + case 0x3004: + strncat (val, _("left"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("0x%x???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 20: + strncat (val, _(" / Exposure mode : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Easy shooting"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("Program"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("Tv-priority"), maxlen - strlen(val)); + break; + case 3: + strncat (val, _("Av-priority"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("Manual"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("A-DEP"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 23: + snprintf (buf, sizeof (buf), _(" / long focal length of lens (in focal units) : %u"), vs); + strncat (val, buf, maxlen - strlen(val)); + break; + case 24: + snprintf (buf, sizeof (buf), _(" / short focal length of lens (in focal units) : %u"), vs); + strncat (val, buf, maxlen - strlen(val)); + break; + case 25: + snprintf (buf, sizeof (buf), _(" / focal units per mm : %u"), vs); + strncat (val, buf, maxlen - strlen(val)); + break; + case 29: + strncat (val, _(" / Flash details : "), maxlen - strlen(val)); + if ((vs>>14)&1) + strncat (val, _("External E-TTL"), maxlen - strlen(val)); + if ((vs>>13)&1) + strncat (val, _("Internal flash"), maxlen - strlen(val)); + if ((vs>>11)&1) + strncat (val, _("FP sync used"), maxlen - strlen(val)); + if ((vs>>4)&1) + strncat (val, _("FP sync enabled"), maxlen - strlen(val)); +#ifdef DEBUG + printf ("Value29=0x%08x\n", vs); +#endif + break; + case 32: + strncat (val, _(" / Focus mode2 : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Single"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("Continuous"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; +#ifdef DEBUG + default: + printf ("Value%d=%d\n", i, vs); +#endif + } + } + + break; + + case MNOTE_CANON_TAG_SETTINGS_2: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order)/2; + data += 2; + CC (entry->components, n, val, maxlen); +#ifdef DEBUG + printf ("Setting2 size %d %d\n",n,entry->size); +#endif + for (i=1;i<n;i++) + { + vs = exif_get_short (data, entry->order); + data+=2; + switch(i) { + case 7: + strncpy (val, _("White balance : "), maxlen - strlen(val)); + switch (vs) { + case 0: + strncat (val, _("Auto"), maxlen - strlen(val)); + break; + case 1: + strncat (val, _("Sunny"), maxlen - strlen(val)); + break; + case 2: + strncat (val, _("Cloudy"), maxlen - strlen(val)); + break; + case 3: + strncat (val, _("Tungsten"), maxlen - strlen(val)); + break; + case 4: + strncat (val, _("Flourescent"), maxlen - strlen(val)); + break; + case 5: + strncat (val, _("Flash"), maxlen - strlen(val)); + break; + case 6: + strncat (val, _("Custom"), maxlen - strlen(val)); + break; + default: + snprintf (buf, sizeof (buf), _("%i???"), vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + case 9: + snprintf (buf, sizeof (buf), _(" / Sequence number : %u"), vs); + strncat (val, buf, maxlen - strlen(val)); + break; + case 14: + if (vs>>12) + { + strncat (val, _(" / AF point used : "), maxlen - strlen(val)); + if (vs&1) + strncat (val, _("Right"), maxlen - strlen(val)); + if ((vs>>1)&1) + strncat (val, _("Center"), maxlen - strlen(val)); + if ((vs>>2)&1) + strncat (val, _("Left"), maxlen - strlen(val)); + snprintf (buf, sizeof (buf), _(" (%u available focus point)"), vs>>12); + strncat (val, buf, maxlen - strlen(val)); + } +#ifdef DEBUG + printf ("0x%08x\n", vs); +#endif + break; + case 15: + snprintf (buf, sizeof (buf), _(" / Flash bias : %.2f EV"), vs/32.0); + strncat (val, buf, maxlen - strlen(val)); + + break; + case 19: + snprintf (buf, sizeof (buf), _(" / Subject Distance (mm) : %u"), vs); + strncat (val, buf, maxlen - strlen(val)); + break; +#ifdef DEBUG + default: + printf ("Value%d=%d\n", i, vs); +#endif + } + } + + break; + + case MNOTE_CANON_TAG_IMAGE_TYPE: + case MNOTE_CANON_TAG_OWNER: + CF (entry->format, EXIF_FORMAT_ASCII, val, maxlen); + CC (entry->components, 32, val, maxlen); + strncpy (val, data, MIN (entry->size, maxlen)); + break; + + case MNOTE_CANON_TAG_FIRMWARE: + CF (entry->format, EXIF_FORMAT_ASCII, val, maxlen); + CC2 (entry->components, 24, 32, val, maxlen); + strncpy (val, data, MIN (entry->size, maxlen)); + break; + + case MNOTE_CANON_TAG_IMAGE_NUMBER: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (data, entry->order); + snprintf (val, maxlen, "%03lu-%04lu", + (unsigned long) vl/10000, + (unsigned long) vl%10000); + break; + + case MNOTE_CANON_TAG_SERIAL_NUMBER: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (data, entry->order); + snprintf (val, maxlen, "%04X-%05d", (int)vl>>16,(int)vl&0xffff); + break; + + case MNOTE_CANON_TAG_CUSTOM_FUNCS: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + n = exif_get_short (data, entry->order)/2; + data+=2; + CC (entry->components, n, val, maxlen); +#ifdef DEBUG + printf ("Custom Function size %d %d\n",n,entry->size); +#endif + for (i=1;i<n;i++) + { + vs = exif_get_short (data, entry->order); + data += 2; + snprintf (buf, sizeof(buf), _("C.F%d : %u"), i, vs); + strncat (val, buf, maxlen - strlen(val)); + } + break; + + default: +#ifdef DEBUG + if (entry->format == EXIF_FORMAT_SHORT) + for(i=0;i<entry->components;i++) { + vs = exif_get_short (data, entry->order); + data+=2; + printf ("Value%d=%d\n", i, vs); + } + else if (entry->format == EXIF_FORMAT_LONG) + for(i=0;i<entry->components;i++) { + vl = exif_get_long (data, entry->order); + data+=4; + printf ("Value%d=%d\n", i, vs); + } + else if (entry->format == EXIF_FORMAT_ASCII) + strncpy (val, data, MIN (entry->size, maxlen)); +#endif + break; + } + + return val; +} diff --git a/src/libexif/canon/mnote-canon-entry.h b/src/libexif/canon/mnote-canon-entry.h new file mode 100644 index 0000000..62345d8 --- /dev/null +++ b/src/libexif/canon/mnote-canon-entry.h @@ -0,0 +1,43 @@ +/* mnote-canon-entry.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_CANON_ENTRY_H__ +#define __MNOTE_CANON_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/canon/mnote-canon-tag.h> + +typedef struct _MnoteCanonEntry MnoteCanonEntry; + +struct _MnoteCanonEntry { + MnoteCanonTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_canon_entry_get_value (const MnoteCanonEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_CANON_ENTRY_H__ */ diff --git a/src/libexif/canon/mnote-canon-tag.c b/src/libexif/canon/mnote-canon-tag.c new file mode 100644 index 0000000..890a5fc --- /dev/null +++ b/src/libexif/canon/mnote-canon-tag.c @@ -0,0 +1,75 @@ +/* mnote-canon-tag.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "mnote-canon-tag.h" + +#include <stdlib.h> + +#include <libexif/i18n.h> + +static struct { + MnoteCanonTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { + {MNOTE_CANON_TAG_SETTINGS_1, "Settings1", N_("Settings (first part)"), ""}, + {MNOTE_CANON_TAG_SETTINGS_2, "Settings2", N_("Settings (second part)"), ""}, + {MNOTE_CANON_TAG_IMAGE_TYPE, "ImageType", N_("Image type"), ""}, + {MNOTE_CANON_TAG_FIRMWARE, "FirmwareVersion", N_("Firmware version"), ""}, + {MNOTE_CANON_TAG_IMAGE_NUMBER, "ImageNumber", N_("Image number"), ""}, + {MNOTE_CANON_TAG_OWNER, "OwnerName", N_("Owner name"), ""}, + {MNOTE_CANON_TAG_SERIAL_NUMBER, "SerialNumber", N_("Serial number"), ""}, + {MNOTE_CANON_TAG_CUSTOM_FUNCS, "CustomFunctions", N_("Custom functions"), ""}, + {0, NULL, NULL, NULL} +}; + +const char * +mnote_canon_tag_get_name (MnoteCanonTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].name)); + return NULL; +} + +const char * +mnote_canon_tag_get_title (MnoteCanonTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_canon_tag_get_description (MnoteCanonTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].description)); + return NULL; +} diff --git a/src/libexif/canon/mnote-canon-tag.h b/src/libexif/canon/mnote-canon-tag.h new file mode 100644 index 0000000..ce1a72e --- /dev/null +++ b/src/libexif/canon/mnote-canon-tag.h @@ -0,0 +1,52 @@ +/* mnote-canon-tag.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_CANON_TAG_H__ +#define __MNOTE_CANON_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum _MnoteCanonTag { + MNOTE_CANON_TAG_UNKNOWN_0 = 0x0, + MNOTE_CANON_TAG_SETTINGS_1 = 0x1, + MNOTE_CANON_TAG_UNKNOWN_3 = 0x3, + MNOTE_CANON_TAG_SETTINGS_2 = 0x4, + MNOTE_CANON_TAG_IMAGE_TYPE = 0x6, + MNOTE_CANON_TAG_FIRMWARE = 0x7, + MNOTE_CANON_TAG_IMAGE_NUMBER = 0x8, + MNOTE_CANON_TAG_OWNER = 0x9, + MNOTE_CANON_TAG_UNKNOWN_10 = 0xa, + MNOTE_CANON_TAG_SERIAL_NUMBER = 0xc, + MNOTE_CANON_TAG_UNKNOWN_13 = 0xd, + MNOTE_CANON_TAG_CUSTOM_FUNCS = 0xf +}; +typedef enum _MnoteCanonTag MnoteCanonTag; + +const char *mnote_canon_tag_get_name (MnoteCanonTag tag); +const char *mnote_canon_tag_get_title (MnoteCanonTag tag); +const char *mnote_canon_tag_get_description (MnoteCanonTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_CANON_TAG_H__ */ diff --git a/src/libexif/config.h b/src/libexif/config.h new file mode 100644 index 0000000..54325e3 --- /dev/null +++ b/src/libexif/config.h @@ -0,0 +1,12 @@ + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +/* #undef ENABLE_NLS */ + +/* The gettext domain we're using */ +#define GETTEXT_PACKAGE "libexif-9" + +#ifdef WIN32 +#define snprintf _snprintf +#endif + diff --git a/src/libexif/exif-byte-order.c b/src/libexif/exif-byte-order.c new file mode 100644 index 0000000..1a4279f --- /dev/null +++ b/src/libexif/exif-byte-order.c @@ -0,0 +1,39 @@ +/* exif-byte-order.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/i18n.h> + +#include <stdlib.h> + +const char * +exif_byte_order_get_name (ExifByteOrder order) +{ + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return (_("Motorola")); + case EXIF_BYTE_ORDER_INTEL: + return (_("Intel")); + default: + return NULL; + } +} diff --git a/src/libexif/exif-byte-order.h b/src/libexif/exif-byte-order.h new file mode 100644 index 0000000..bd51d3c --- /dev/null +++ b/src/libexif/exif-byte-order.h @@ -0,0 +1,39 @@ +/* exif-byte-order.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_BYTE_ORDER_H__ +#define __EXIF_BYTE_ORDER_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + EXIF_BYTE_ORDER_MOTOROLA, + EXIF_BYTE_ORDER_INTEL +} ExifByteOrder; + +const char *exif_byte_order_get_name (ExifByteOrder order); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_BYTE_ORDER_H__ */ diff --git a/src/libexif/exif-content.c b/src/libexif/exif-content.c new file mode 100644 index 0000000..39d73ad --- /dev/null +++ b/src/libexif/exif-content.c @@ -0,0 +1,209 @@ +/* exif-content.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-content.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + +struct _ExifContentPrivate +{ + unsigned int ref_count; + + ExifMem *mem; + ExifLog *log; +}; + +ExifContent * +exif_content_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifContent *content = exif_content_new_mem (mem); + + exif_mem_unref (mem); + + return content; +} + +ExifContent * +exif_content_new_mem (ExifMem *mem) +{ + ExifContent *content; + + if (!mem) return NULL; + + content = exif_mem_alloc (mem, (ExifLong) sizeof (ExifContent)); + if (!content) + return NULL; + content->priv = exif_mem_alloc (mem, + (ExifLong) sizeof (ExifContentPrivate)); + if (!content->priv) { + exif_mem_free (mem, content); + return NULL; + } + + content->priv->ref_count = 1; + + content->priv->mem = mem; + exif_mem_ref (mem); + + return content; +} + +void +exif_content_ref (ExifContent *content) +{ + content->priv->ref_count++; +} + +void +exif_content_unref (ExifContent *content) +{ + content->priv->ref_count--; + if (!content->priv->ref_count) + exif_content_free (content); +} + +void +exif_content_free (ExifContent *content) +{ + ExifMem *mem = (content && content->priv) ? content->priv->mem : NULL; + unsigned int i; + + if (!content) return; + + for (i = 0; i < content->count; i++) + exif_entry_unref (content->entries[i]); + exif_mem_free (mem, content->entries); + + if (content->priv) { + exif_log_unref (content->priv->log); + } + + exif_mem_free (mem, content->priv); + exif_mem_free (mem, content); + exif_mem_unref (mem); +} + +void +exif_content_dump (ExifContent *content, unsigned int indent) +{ + char buf[1024]; + unsigned int i; + + for (i = 0; i < 2 * indent; i++) + buf[i] = ' '; + buf[i] = '\0'; + + if (!content) + return; + + printf ("%sDumping exif content (%i entries)...\n", buf, + content->count); + for (i = 0; i < content->count; i++) + exif_entry_dump (content->entries[i], indent + 1); +} + +void +exif_content_add_entry (ExifContent *c, ExifEntry *entry) +{ + if (!c || !c->priv || !entry || entry->parent) return; + + /* One tag can only be added once to an IFD. */ + if (exif_content_get_entry (c, entry->tag)) { + exif_log (c->priv->log, EXIF_LOG_CODE_DEBUG, "ExifContent", + "An attempt has been made to add " + "the tag '%s' twice to an IFD. This is against " + "specification.", exif_tag_get_name (entry->tag)); + return; + } + + entry->parent = c; + c->entries = exif_mem_realloc (c->priv->mem, + c->entries, sizeof (ExifEntry) * (c->count + 1)); + if (!c->entries) return; + c->entries[c->count] = entry; + exif_entry_ref (entry); + c->count++; +} + +void +exif_content_remove_entry (ExifContent *c, ExifEntry *e) +{ + unsigned int i; + + if (!c || !c->priv || !e || (e->parent != c)) return; + + /* Search the entry */ + for (i = 0; i < c->count; i++) if (c->entries[i] == e) break; + if (i == c->count) return; + + /* Remove the entry */ + memmove (&c->entries[i], &c->entries[i + 1], + sizeof (ExifEntry) * (c->count - i - 1)); + c->count--; + e->parent = NULL; + exif_entry_unref (e); + c->entries = exif_mem_realloc (c->priv->mem, c->entries, + sizeof(ExifEntry) * c->count); +} + +ExifEntry * +exif_content_get_entry (ExifContent *content, ExifTag tag) +{ + unsigned int i; + + if (!content) + return (NULL); + + for (i = 0; i < content->count; i++) + if (content->entries[i]->tag == tag) + return (content->entries[i]); + return (NULL); +} + +void +exif_content_foreach_entry (ExifContent *content, + ExifContentForeachEntryFunc func, void *data) +{ + unsigned int i; + + if (!content || !func) + return; + + for (i = 0; i < content->count; i++) + func (content->entries[i], data); +} + +void +exif_content_log (ExifContent *content, ExifLog *log) +{ + if (!content || !content->priv || !log || content->priv->log == log) + return; + + if (content->priv->log) exif_log_unref (content->priv->log); + content->priv->log = log; + exif_log_ref (log); +} diff --git a/src/libexif/exif-content.h b/src/libexif/exif-content.h new file mode 100644 index 0000000..115f8ed --- /dev/null +++ b/src/libexif/exif-content.h @@ -0,0 +1,76 @@ +/* exif-content.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_CONTENT_H__ +#define __EXIF_CONTENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _ExifContent ExifContent; +typedef struct _ExifContentPrivate ExifContentPrivate; + +#include <libexif/exif-tag.h> +#include <libexif/exif-entry.h> +#include <libexif/exif-data.h> +#include <libexif/exif-log.h> +#include <libexif/exif-mem.h> + +struct _ExifContent +{ + ExifEntry **entries; + unsigned int count; + + /* Data containing this content */ + ExifData *parent; + + ExifContentPrivate *priv; +}; + +/* Lifecycle */ +ExifContent *exif_content_new (void); +ExifContent *exif_content_new_mem (ExifMem *); +void exif_content_ref (ExifContent *content); +void exif_content_unref (ExifContent *content); +void exif_content_free (ExifContent *content); + +void exif_content_add_entry (ExifContent *content, ExifEntry *e); +void exif_content_remove_entry (ExifContent *content, ExifEntry *e); +ExifEntry *exif_content_get_entry (ExifContent *content, ExifTag tag); + +typedef void (* ExifContentForeachEntryFunc) (ExifEntry *, void *user_data); +void exif_content_foreach_entry (ExifContent *content, + ExifContentForeachEntryFunc func, + void *user_data); + +/* For your convenience */ +#define exif_content_get_value(c,t,v,m) \ + (exif_content_get_entry (c,t) ? \ + exif_entry_get_value (exif_content_get_entry (c,t),v,m) : NULL) + +void exif_content_dump (ExifContent *content, unsigned int indent); +void exif_content_log (ExifContent *content, ExifLog *log); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_CONTENT_H__ */ diff --git a/src/libexif/exif-data.c b/src/libexif/exif-data.c new file mode 100644 index 0000000..92e5857 --- /dev/null +++ b/src/libexif/exif-data.c @@ -0,0 +1,1039 @@ +/* exif-data.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-data.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-loader.h> +#include <libexif/exif-log.h> +#include <libexif/i18n.h> + +#include <libexif/olympus/exif-mnote-data-olympus.h> +#include <libexif/canon/exif-mnote-data-canon.h> +#include <libexif/pentax/exif-mnote-data-pentax.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#if defined(__WATCOMC__) || defined(_MSC_VER) +# 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 +{ + ExifByteOrder order; + + ExifMnoteData *md; + + ExifLog *log; + ExifMem *mem; + + unsigned int ref_count; + + /* Temporarily used while loading data */ + unsigned int offset_mnote; +}; + +static void * +exif_data_alloc (ExifData *data, unsigned int i) +{ + void *d; + + if (!data || !i) return NULL; + + d = exif_mem_alloc (data->priv->mem, i); + if (d) return d; + + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", i); + return NULL; +} + +ExifMnoteData * +exif_data_get_mnote_data (ExifData *d) +{ + return (d && d->priv) ? d->priv->md : NULL; +} + +ExifData * +exif_data_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifData *d = exif_data_new_mem (mem); + + exif_mem_unref (mem); + + return d; +} + +ExifData * +exif_data_new_mem (ExifMem *mem) +{ + ExifData *data; + unsigned int i; + + if (!mem) return NULL; + + data = exif_mem_alloc (mem, sizeof (ExifData)); + if (!data) return (NULL); + data->priv = exif_mem_alloc (mem, sizeof (ExifDataPrivate)); + if (!data->priv) { exif_mem_free (mem, data); return (NULL); } + data->priv->ref_count = 1; + + data->priv->mem = mem; + exif_mem_ref (mem); + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + data->ifd[i] = exif_content_new_mem (data->priv->mem); + if (!data->ifd[i]) { + exif_data_free (data); + return (NULL); + } + data->ifd[i]->parent = data; + } + + return (data); +} + +ExifData * +exif_data_new_from_data (const unsigned char *data, unsigned int size) +{ + ExifData *edata; + + edata = exif_data_new (); + exif_data_load_data (edata, data, size); + return (edata); +} + +static void +exif_data_load_data_entry (ExifData *data, ExifEntry *entry, + const unsigned char *d, + unsigned int size, unsigned int offset) +{ + unsigned int s, doff; + + entry->tag = exif_get_short (d + offset + 0, data->priv->order); + entry->format = exif_get_short (d + offset + 2, data->priv->order); + entry->components = exif_get_long (d + offset + 4, data->priv->order); + + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Loading entry 0x%x ('%s')...", entry->tag, + exif_tag_get_name (entry->tag)); + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (entry->format) * entry->components; + if (!s) + return; + if (s > 4) + doff = exif_get_long (d + offset + 8, data->priv->order); + else + doff = offset + 8; + + /* Sanity check */ + if (size < doff + s) + return; + + entry->data = exif_data_alloc (data, s); + if (entry->data) { + entry->size = s; + memcpy (entry->data, d + doff, s); + } + + /* If this is the MakerNote, remember the offset */ + if (entry->tag == EXIF_TAG_MAKER_NOTE) { + if (entry->size > 6) exif_log (data->priv->log, + EXIF_LOG_CODE_DEBUG, "ExifData", + "MakerNote found (%02x %02x %02x %02x " + "%02x %02x %02x...).", + entry->data[0], entry->data[1], entry->data[2], + entry->data[3], entry->data[4], entry->data[5], + entry->data[6]); + data->priv->offset_mnote = doff; + } + + exif_entry_fix (entry); +} + +static void +exif_data_save_data_entry (ExifData *data, ExifEntry *e, + unsigned char **d, unsigned int *ds, + unsigned int offset) +{ + unsigned int doff, s; + + if (!data || !data->priv) return; + + /* + * Each entry is 12 bytes long. The memory for the entry has + * already been allocated. + */ + exif_set_short (*d + 6 + offset + 0, + data->priv->order, (ExifShort) e->tag); + exif_set_short (*d + 6 + offset + 2, + data->priv->order, (ExifShort) e->format); + +#ifndef EXIF_DONT_CHANGE_MAKER_NOTE + /* If this is the maker note tag, update it. */ + if ((e->tag == EXIF_TAG_MAKER_NOTE) && data->priv->md) { + exif_mem_free (data->priv->mem, e->data); + e->data = NULL; + e->size = 0; + exif_mnote_data_set_offset (data->priv->md, *ds - 6); + exif_mnote_data_save (data->priv->md, &e->data, &e->size); + e->components = e->size; + } +#endif + + exif_set_long (*d + 6 + offset + 4, + data->priv->order, e->components); + + /* + * Size? If bigger than 4 bytes, the actual data is not in + * the entry but somewhere else. + */ + s = exif_format_get_size (e->format) * e->components; + 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); + if (s & 1) *(*d + *ds - 1) = '\0'; + + } else + doff = offset + 8; + + /* Write the data. Fill unneeded bytes with 0. */ + memcpy (*d + 6 + doff, e->data, s); + if (s < 4) memset (*d + 6 + doff + s, 0, (4 - s)); +} + +static void +exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d, + unsigned int ds, ExifLong offset, ExifLong size) +{ + if (ds < offset + size) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Bogus thumbnail offset and size: %i < %i + %i.", + (int) ds, (int) offset, (int) size); + return; + } + if (data->data) exif_mem_free (data->priv->mem, data->data); + data->size = size; + data->data = exif_data_alloc (data, data->size); + if (!data->data) return; + memcpy (data->data, d + offset, data->size); +} + +#undef CHECK_REC +#define CHECK_REC(i) \ +if (data->ifd[(i)] == ifd) { \ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, \ + "ExifData", "Recursive entry in IFD " \ + "'%s' detected. Skipping...", \ + exif_ifd_get_name (i)); \ + break; \ +} \ +if (data->ifd[(i)]->count) { \ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, \ + "ExifData", "Attemt to load IFD " \ + "'%s' multiple times detected. " \ + "Skipping...", \ + exif_ifd_get_name (i)); \ + break; \ +} + +static void +exif_data_load_data_content (ExifData *data, ExifContent *ifd, + const unsigned char *d, + unsigned int ds, unsigned int offset) +{ + ExifLong o, thumbnail_offset = 0, thumbnail_length = 0; + ExifShort n; + ExifEntry *entry; + unsigned int i; + ExifTag tag; + + if (!data || !data->priv) return; + + /* Read the number of entries */ + if (offset >= ds - 1) return; + n = exif_get_short (d + offset, data->priv->order); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Loading %i entries...", n); + offset += 2; + + /* Check if we have enough data. */ + if (offset + 12 * n > ds) n = (ds - offset) / 12; + + for (i = 0; i < n; i++) { + + tag = exif_get_short (d + offset + 12 * i, data->priv->order); + switch (tag) { + case EXIF_TAG_EXIF_IFD_POINTER: + case EXIF_TAG_GPS_INFO_IFD_POINTER: + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + o = exif_get_long (d + offset + 12 * i + 8, + data->priv->order); + switch (tag) { + case EXIF_TAG_EXIF_IFD_POINTER: + CHECK_REC (EXIF_IFD_EXIF); + exif_data_load_data_content (data, + data->ifd[EXIF_IFD_EXIF], d, ds, o); + break; + case EXIF_TAG_GPS_INFO_IFD_POINTER: + CHECK_REC (EXIF_IFD_GPS); + exif_data_load_data_content (data, + data->ifd[EXIF_IFD_GPS], d, ds, o); + break; + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + CHECK_REC (EXIF_IFD_INTEROPERABILITY); + exif_data_load_data_content (data, + data->ifd[EXIF_IFD_INTEROPERABILITY], d, ds, o); + break; + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + thumbnail_offset = o; + if (thumbnail_offset && thumbnail_length) + exif_data_load_data_thumbnail (data, d, + ds, thumbnail_offset, + thumbnail_length); + break; + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + thumbnail_length = o; + if (thumbnail_offset && thumbnail_length) + exif_data_load_data_thumbnail (data, d, + ds, thumbnail_offset, + thumbnail_length); + break; + default: + return; + } + break; + default: + + /* + * 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)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Unknown tag %x (entry %i)", tag, i); + return; + } + entry = exif_entry_new_mem (data->priv->mem); + 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, + unsigned int offset) +{ + unsigned int j, n_ptr = 0, n_thumb = 0; + ExifIfd i; + + if (!data || !data->priv || !ifd || !d || !ds) return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) + if (ifd == data->ifd[i]) + break; + if (i == EXIF_IFD_COUNT) + return; + + /* + * Check if we need some extra entries for pointers or the thumbnail. + */ + switch (i) { + case EXIF_IFD_0: + + /* + * The pointer to IFD_EXIF is in IFD_0. The pointer to + * IFD_INTEROPERABILITY is in IFD_EXIF. + */ + if (data->ifd[EXIF_IFD_EXIF]->count || + data->ifd[EXIF_IFD_INTEROPERABILITY]->count) + n_ptr++; + + /* The pointer to IFD_GPS is in IFD_0. */ + if (data->ifd[EXIF_IFD_GPS]->count) + n_ptr++; + + break; + case EXIF_IFD_1: + if (data->size) + n_thumb = 2; + break; + case EXIF_IFD_EXIF: + if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) + n_ptr++; + default: + break; + } + + /* + * Allocate enough memory for all entries + * and the number of entries. + */ + *ds += (2 + (ifd->count + n_ptr + n_thumb) * 12 + 4); + *d = exif_mem_realloc (data->priv->mem, *d, *ds); + if (!*d) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", *ds); + return; + } + + /* Save the number of entries */ + exif_set_short (*d + 6 + offset, data->priv->order, + (ExifShort) (ifd->count + n_ptr + n_thumb)); + offset += 2; + + /* Save each entry */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "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); + + offset += 12 * ifd->count; + + /* Now save special entries. */ + switch (i) { + case EXIF_IFD_0: + + /* + * The pointer to IFD_EXIF is in IFD_0. + * However, the pointer to IFD_INTEROPERABILITY is in IFD_EXIF, + * therefore, if IFD_INTEROPERABILITY is not empty, we need + * IFD_EXIF even if latter is empty. + */ + if (data->ifd[EXIF_IFD_EXIF]->count || + data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_EXIF_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_EXIF], d, ds, *ds - 6); + offset += 12; + } + + /* The pointer to IFD_GPS is in IFD_0, too. */ + if (data->ifd[EXIF_IFD_GPS]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_GPS_INFO_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_GPS], d, ds, *ds - 6); + offset += 12; + } + + break; + case EXIF_IFD_EXIF: + + /* + * The pointer to IFD_INTEROPERABILITY is in IFD_EXIF. + * See note above. + */ + if (data->ifd[EXIF_IFD_INTEROPERABILITY]->count) { + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_INTEROPERABILITY_IFD_POINTER); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + exif_data_save_data_content (data, + data->ifd[EXIF_IFD_INTEROPERABILITY], d, ds, + *ds - 6); + offset += 12; + } + + break; + case EXIF_IFD_1: + + /* + * Information about the thumbnail (if any) is saved in + * IFD_1. + */ + if (data->size) { + + /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT */ + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + *ds - 6); + *ds += data->size; + *d = exif_mem_realloc (data->priv->mem, *d, *ds); + if (!*d) { + EXIF_LOG_NO_MEMORY (data->priv->log, "ExifData", + *ds); + return; + } + memcpy (*d + *ds - data->size, data->data, data->size); + offset += 12; + + /* EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH */ + exif_set_short (*d + 6 + offset + 0, data->priv->order, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); + exif_set_short (*d + 6 + offset + 2, data->priv->order, + EXIF_FORMAT_LONG); + exif_set_long (*d + 6 + offset + 4, data->priv->order, + 1); + exif_set_long (*d + 6 + offset + 8, data->priv->order, + data->size); + offset += 12; + } + + break; + default: + 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)) { + + /* + * We are saving IFD 0. Tell where IFD 1 starts and save + * IFD 1. + */ + exif_set_long (*d + 6 + offset, data->priv->order, *ds - 6); + exif_data_save_data_content (data, data->ifd[EXIF_IFD_1], d, ds, + *ds - 6); + } else + exif_set_long (*d + 6 + offset, data->priv->order, 0); +} + +typedef enum { + EXIF_DATA_TYPE_MAKER_NOTE_NONE = 0, + EXIF_DATA_TYPE_MAKER_NOTE_CANON = 1, + EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS = 2, + EXIF_DATA_TYPE_MAKER_NOTE_PENTAX = 3 +} ExifDataTypeMakerNote; + +static ExifDataTypeMakerNote +exif_data_get_type_maker_note (ExifData *d) +{ + ExifEntry *e, *em; + char value[1024]; + + if (!d) return EXIF_DATA_TYPE_MAKER_NOTE_NONE; + + e = exif_data_get_entry (d, EXIF_TAG_MAKER_NOTE); + if (!e) return EXIF_DATA_TYPE_MAKER_NOTE_NONE; + + /* Olympus & Nikon */ + if ((e->size >= 5) && (!memcmp (e->data, "OLYMP", 5) || + !memcmp (e->data, "Nikon", 5))) + return EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS; + + em = exif_data_get_entry (d, EXIF_TAG_MAKE); + if (!em) return EXIF_DATA_TYPE_MAKER_NOTE_NONE; + + /* Canon */ + if (!strcmp (exif_entry_get_value (em, value, sizeof (value)), "Canon")) + return EXIF_DATA_TYPE_MAKER_NOTE_CANON; + + /* Pentax & some variant of Nikon */ + if ((e->size >= 2) && (e->data[0] == 0x00) && (e->data[1] == 0x1b)) { + if (!strncasecmp ( + exif_entry_get_value (em, value, sizeof(value)), + "Nikon", 5)) + return EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS; + else + return EXIF_DATA_TYPE_MAKER_NOTE_PENTAX; + } + + 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) +{ + unsigned int l; + ExifLong offset; + ExifShort n; + const unsigned char *d = d_orig; + unsigned int ds = ds_orig, len; + + if (!data || !data->priv || !d || !ds) return; + + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Parsing %i byte(s) EXIF data...\n", ds); + + /* + * It can be that the data starts with the EXIF header. If it does + * not, search the EXIF marker. + */ + if (ds < 6) { + LOG_TOO_SMALL; + return; + } + if (!memcmp (d, ExifHeader, 6)) { + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Found EXIF header."); + } else { + while (1) { + while ((d[0] == 0xff) && ds) { + d++; + ds--; + } + + /* JPEG_MARKER_SOI */ + if (d[0] == JPEG_MARKER_SOI) { + d++; + ds--; + continue; + } + + /* JPEG_MARKER_APP0 */ + if (d[0] == JPEG_MARKER_APP0) { + d++; + ds--; + l = (d[0] << 8) | d[1]; + if (l > ds) + return; + d += l; + ds -= l; + continue; + } + + /* JPEG_MARKER_APP1 */ + if (d[0] == JPEG_MARKER_APP1) + break; + + /* Unknown marker or data. Give up. */ + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", _("EXIF marker not found.")); + return; + } + d++; + ds--; + if (ds < 2) { + LOG_TOO_SMALL; + return; + } + len = (d[0] << 8) | d[1]; + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "We have to deal with %i byte(s) of EXIF data.", + len); + d += 2; + ds -= 2; + } + + /* + * Verify the exif header + * (offset 2, length 6). + */ + if (ds < 6) { + LOG_TOO_SMALL; + return; + } + if (memcmp (d, ExifHeader, 6)) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", _("EXIF header not found.")); + return; + } + + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Found EXIF header."); + + /* Byte order (offset 6, length 2) */ + 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 { + 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) + return; + + /* IFD 0 offset */ + offset = exif_get_long (d + 10, data->priv->order); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "IFD 0 at %i.", (int) offset); + + /* 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", + "IFD 1 at %i.", (int) offset); + + /* Sanity check. */ + if (offset > ds - 6) { + exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, + "ExifData", "Bogus offset."); + return; + } + + exif_data_load_data_content (data, data->ifd[EXIF_IFD_1], d + 6, + ds - 6, offset); + } + + /* + * If we got an EXIF_TAG_MAKER_NOTE, try to interpret it. Some + * cameras use pointers in the maker note tag that point to the + * space between IFDs. Here is the only place where we have access + * to that data. + */ + switch (exif_data_get_type_maker_note (data)) { + case EXIF_DATA_TYPE_MAKER_NOTE_OLYMPUS: + data->priv->md = exif_mnote_data_olympus_new (data->priv->mem); + break; + case EXIF_DATA_TYPE_MAKER_NOTE_PENTAX: + data->priv->md = exif_mnote_data_pentax_new (data->priv->mem); + break; + case EXIF_DATA_TYPE_MAKER_NOTE_CANON: + data->priv->md = exif_mnote_data_canon_new (data->priv->mem); + break; + default: + break; + } + + /* + * If we are able to interpret the maker note, do so. + */ + if (data->priv->md) { + exif_mnote_data_log (data->priv->md, data->priv->log); + exif_mnote_data_set_byte_order (data->priv->md, + data->priv->order); + exif_mnote_data_set_offset (data->priv->md, + data->priv->offset_mnote); + exif_mnote_data_load (data->priv->md, d, ds); + } +} + +void +exif_data_save_data (ExifData *data, unsigned char **d, unsigned int *ds) +{ + if (!data || !d || !ds) + return; + + /* Header */ + *ds = 14; + *d = exif_data_alloc (data, *ds); + if (!*d) return; + memcpy (*d, ExifHeader, 6); + + /* Order (offset 6) */ + if (data->priv->order == EXIF_BYTE_ORDER_INTEL) { + memcpy (*d + 6, "II", 2); + } else { + memcpy (*d + 6, "MM", 2); + } + + /* Fixed value (2 bytes, offset 8) */ + exif_set_short (*d + 8, data->priv->order, 0x002a); + + /* + * IFD 0 offset (4 bytes, offset 10). + * We will start 8 bytes after the + * EXIF header (2 bytes for order, another 2 for the test, and + * 4 bytes for the IFD 0 offset make 8 bytes together). + */ + exif_set_long (*d + 10, data->priv->order, 8); + + /* Now save IFD 0. IFD 1 will be saved automatically. */ + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Saving IFDs..."); + exif_data_save_data_content (data, data->ifd[EXIF_IFD_0], d, ds, + *ds - 6); + exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData", + "Saved %i byte(s) EXIF data.", *ds); +} + +ExifData * +exif_data_new_from_file (const char *path) +{ + ExifData *edata; + ExifLoader *loader; + + loader = exif_loader_new (); + exif_loader_write_file (loader, path); + edata = exif_loader_get_data (loader); + exif_loader_unref (loader); + + return (edata); +} + +void +exif_data_ref (ExifData *data) +{ + if (!data) + return; + + data->priv->ref_count++; +} + +void +exif_data_unref (ExifData *data) +{ + if (!data) return; + + data->priv->ref_count--; + if (!data->priv->ref_count) exif_data_free (data); +} + +void +exif_data_free (ExifData *data) +{ + unsigned int i; + ExifMem *mem = (data && data->priv) ? data->priv->mem : NULL; + + if (!data) return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + if (data->ifd[i]) { + exif_content_unref (data->ifd[i]); + data->ifd[i] = NULL; + } + } + + if (data->data) { + exif_mem_free (mem, data->data); + data->data = NULL; + } + + if (data->priv) { + if (data->priv->log) { + exif_log_unref (data->priv->log); + data->priv->log = NULL; + } + if (data->priv->md) { + exif_mnote_data_unref (data->priv->md); + data->priv->md = NULL; + } + exif_mem_free (mem, data->priv); + exif_mem_free (mem, data); + } + + exif_mem_unref (mem); +} + +void +exif_data_dump (ExifData *data) +{ + unsigned int i; + + if (!data) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) { + if (data->ifd[i] && data->ifd[i]->count) { + printf ("Dumping IFD '%s'...\n", + exif_ifd_get_name (i)); + exif_content_dump (data->ifd[i], 0); + } + } + + if (data->data) { + printf ("%i byte(s) thumbnail data available.", data->size); + if (data->size >= 4) { + printf ("0x%02x 0x%02x ... 0x%02x 0x%02x\n", + data->data[0], data->data[1], + data->data[data->size - 2], + data->data[data->size - 1]); + } + } +} + +ExifByteOrder +exif_data_get_byte_order (ExifData *data) +{ + if (!data) + return (0); + + return (data->priv->order); +} + +void +exif_data_foreach_content (ExifData *data, ExifDataForeachContentFunc func, + void *user_data) +{ + unsigned int i; + + if (!data || !func) + return; + + for (i = 0; i < EXIF_IFD_COUNT; i++) + func (data->ifd[i], user_data); +} + +typedef struct _ByteOrderChangeData ByteOrderChangeData; +struct _ByteOrderChangeData { + ExifByteOrder old, new; +}; + +static void +entry_set_byte_order (ExifEntry *e, void *data) +{ + ByteOrderChangeData *d = data; + + if (!e) + return; + + exif_array_set_byte_order (e->format, e->data, e->components, d->old, d->new); +} + +static void +content_set_byte_order (ExifContent *content, void *data) +{ + exif_content_foreach_entry (content, entry_set_byte_order, data); +} + +void +exif_data_set_byte_order (ExifData *data, ExifByteOrder order) +{ + ByteOrderChangeData d; + + if (!data || (order == data->priv->order)) + return; + + d.old = data->priv->order; + d.new = order; + exif_data_foreach_content (data, content_set_byte_order, &d); + data->priv->order = order; + if (data->priv->md) + exif_mnote_data_set_byte_order (data->priv->md, 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 */ +ExifLog *exif_data_get_log (ExifData *); +ExifLog * +exif_data_get_log (ExifData *data) +{ + if (!data || !data->priv) return NULL; + return data->priv->log; +} diff --git a/src/libexif/exif-data.h b/src/libexif/exif-data.h new file mode 100644 index 0000000..9ecad1d --- /dev/null +++ b/src/libexif/exif-data.h @@ -0,0 +1,104 @@ +/*! \file exif-data.h + * \brief FIXME foo bar blah + * + * \author Lutz Müller <lutz@users.sourceforge.net> + * \date 2001-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_DATA_H__ +#define __EXIF_DATA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-log.h> +#include <libexif/exif-tag.h> + +typedef struct _ExifData ExifData; +typedef struct _ExifDataPrivate ExifDataPrivate; + +#include <libexif/exif-content.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mem.h> + +struct _ExifData +{ + ExifContent *ifd[EXIF_IFD_COUNT]; + + unsigned char *data; + unsigned int size; + + ExifDataPrivate *priv; +}; + +ExifData *exif_data_new (void); +ExifData *exif_data_new_mem (ExifMem *); + +/*! \brief load exif data from file + * \param[in] path filename including path + * + * Foo bar blah bleh baz. + */ +ExifData *exif_data_new_from_file (const char *path); +ExifData *exif_data_new_from_data (const unsigned char *data, + unsigned int size); + +void exif_data_load_data (ExifData *data, const unsigned char *d, + unsigned int size); +void exif_data_save_data (ExifData *data, unsigned char **d, + unsigned int *size); + +void exif_data_ref (ExifData *data); +void exif_data_unref (ExifData *data); +void exif_data_free (ExifData *data); + +ExifByteOrder exif_data_get_byte_order (ExifData *data); +void exif_data_set_byte_order (ExifData *data, ExifByteOrder order); + +ExifMnoteData *exif_data_get_mnote_data (ExifData *); + +typedef void (* ExifDataForeachContentFunc) (ExifContent *, void *user_data); +void exif_data_foreach_content (ExifData *data, + ExifDataForeachContentFunc func, + void *user_data); + +/* For debugging purposes and error reporting */ +void exif_data_dump (ExifData *data); +void exif_data_log (ExifData *data, ExifLog *log); + +/* For your convenience */ +#define exif_data_get_entry(d,t) \ + (exif_content_get_entry(d->ifd[EXIF_IFD_0],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_0],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_1],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_1],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_EXIF],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_EXIF],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_GPS],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_GPS],t) : \ + exif_content_get_entry(d->ifd[EXIF_IFD_INTEROPERABILITY],t) ? \ + exif_content_get_entry(d->ifd[EXIF_IFD_INTEROPERABILITY],t) : NULL) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_DATA_H__ */ diff --git a/src/libexif/exif-entry.c b/src/libexif/exif-entry.c new file mode 100644 index 0000000..09d37e2 --- /dev/null +++ b/src/libexif/exif-entry.c @@ -0,0 +1,1383 @@ +/* exif-entry.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-entry.h> +#include <libexif/exif-ifd.h> +#include <libexif/exif-utils.h> +#include <libexif/i18n.h> + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <math.h> + +struct _ExifEntryPrivate +{ + unsigned int ref_count; + + ExifMem *mem; +}; + +/* This function is hidden in exif-data.c */ +ExifLog *exif_data_get_log (ExifData *); + +static void +exif_entry_log (ExifEntry *e, ExifLogCode code, const char *format, ...) +{ + va_list args; + ExifLog *l = NULL; + + if (e && e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + va_start (args, format); + exif_logv (l, code, "ExifEntry", format, args); + va_end (args); +} + +static void * +exif_entry_alloc (ExifEntry *e, unsigned int i) +{ + void *d; + ExifLog *l = NULL; + + if (!e || !e->priv || !i) return NULL; + + d = exif_mem_alloc (e->priv->mem, i); + if (d) return d; + + if (e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + EXIF_LOG_NO_MEMORY (l, "ExifEntry", i); + return NULL; +} + +static void * +exif_entry_realloc (ExifEntry *e, void *d_orig, unsigned int i) +{ + void *d; + ExifLog *l = NULL; + + if (!e || !e->priv) return NULL; + + if (!i) { exif_mem_free (e->priv->mem, d_orig); return NULL; } + + d = exif_mem_realloc (e->priv->mem, d_orig, i); + if (d) return d; + + if (e->parent && e->parent->parent) + l = exif_data_get_log (e->parent->parent); + EXIF_LOG_NO_MEMORY (l, "ExifEntry", i); + return NULL; +} + +ExifEntry * +exif_entry_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifEntry *e = exif_entry_new_mem (mem); + + exif_mem_unref (mem); + + return e; +} + +ExifEntry * +exif_entry_new_mem (ExifMem *mem) +{ + ExifEntry *e = NULL; + + e = exif_mem_alloc (mem, sizeof (ExifEntry)); + if (!e) return NULL; + e->priv = exif_mem_alloc (mem, sizeof (ExifEntryPrivate)); + if (!e->priv) { exif_mem_free (mem, e); return NULL; } + e->priv->ref_count = 1; + + e->priv->mem = mem; + exif_mem_ref (mem); + + return e; +} + +void +exif_entry_ref (ExifEntry *e) +{ + if (!e) return; + + e->priv->ref_count++; +} + +void +exif_entry_unref (ExifEntry *e) +{ + if (!e) return; + + e->priv->ref_count--; + if (!e->priv->ref_count) + exif_entry_free (e); +} + +void +exif_entry_free (ExifEntry *e) +{ + if (!e) return; + + if (e->priv) { + ExifMem *mem = e->priv->mem; + if (e->data) + exif_mem_free (mem, e->data); + exif_mem_free (mem, e->priv); + exif_mem_free (mem, e); + exif_mem_unref (mem); + } +} + +void +exif_entry_fix (ExifEntry *e) +{ + unsigned int i; + ExifByteOrder o; + ExifRational r; + ExifSRational sr; + + if (!e || !e->priv) return; + + switch (e->tag) { + + /* These tags all need to be of format SHORT. */ + case EXIF_TAG_YCBCR_SUB_SAMPLING: + case EXIF_TAG_SUBJECT_AREA: + case EXIF_TAG_COLOR_SPACE: + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_YCBCR_POSITIONING: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SATURATION: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SHARPNESS: + switch (e->format) { + case EXIF_FORMAT_LONG: + if (!e->parent || !e->parent->parent) break; + o = exif_data_get_byte_order (e->parent->parent); + for (i = 0; i < e->components; i++) + exif_set_short ( + e->data + i * + exif_format_get_size ( + EXIF_FORMAT_SHORT), o, + (ExifShort) exif_get_long ( + e->data + i * + exif_format_get_size ( + EXIF_FORMAT_LONG), o)); + e->format = EXIF_FORMAT_SHORT; + e->size = e->components * + exif_format_get_size (e->format); + e->data = exif_entry_realloc (e, e->data, e->size); + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag '%s' was of format '%s' (which is " + "against specification) and has been " + "changed to format '%s'.", + exif_tag_get_name (e->tag), + exif_format_get_name (EXIF_FORMAT_LONG), + exif_format_get_name (EXIF_FORMAT_SHORT)); + break; + case EXIF_FORMAT_SHORT: + default: + break; + } + break; + + /* All these tags need to be of format 'Rational'. */ + case EXIF_TAG_FNUMBER: + case EXIF_TAG_APERTURE_VALUE: + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FOCAL_LENGTH: + switch (e->format) { + case EXIF_FORMAT_SRATIONAL: + if (!e->parent || !e->parent->parent) break; + o = exif_data_get_byte_order (e->parent->parent); + for (i = 0; i < e->components; i++) { + sr = exif_get_srational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_SRATIONAL), o); + r.numerator = (ExifLong) sr.numerator; + r.denominator = (ExifLong) sr.denominator; + exif_set_rational (e->data + i * + exif_format_get_size ( + EXIF_FORMAT_RATIONAL), o, r); + } + e->format = EXIF_FORMAT_RATIONAL; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag '%s' was of format '%s' (which is " + "against specification) and has been " + "changed to format '%s'.", + exif_tag_get_name (e->tag), + exif_format_get_name (EXIF_FORMAT_SRATIONAL), + exif_format_get_name (EXIF_FORMAT_RATIONAL)); + break; + default: + break; + } + break; + + case EXIF_TAG_USER_COMMENT: + + /* Format needs to be UNDEFINED. */ + if (e->format != EXIF_FORMAT_UNDEFINED) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag 'UserComment' had invalid format '%s'. " + "Format has been set to 'undefined'.", + exif_format_get_name (e->format)); + e->format = EXIF_FORMAT_UNDEFINED; + } + /* Some packages like Canon ZoomBrowser EX 4.5 store + only one zero byte followed by 7 bytes of rubbish */ + if ((e->size >= 8) && (e->data[0] == 0)) { + memcpy(e->data, "\0\0\0\0\0\0\0\0", 8); + } + + /* Some cameras fill the tag with '\0' or ' '. */ + for (i = 0; i < e->size && + (!e->data[i] || (e->data[i] == ' ')); i++); + if (i && (i == e->size)) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag 'UserComment' contained unnecessary " + "data which has been removed."); + exif_mem_free (e->priv->mem, e->data); + e->data = NULL; + e->size = 0; + e->components = 0; + } + + /* There need to be at least 8 bytes. */ + if (e->size < 8) { + e->data = exif_entry_realloc (e, e->data, 8 + e->size); + if (!e->data) { + e->size = 0; + e->components = 0; + return; + } + + /* Assume ASCII */ + memmove (e->data + 8, e->data, e->size); + memcpy (e->data, "ASCII\0\0\0", 8); + e->size += 8; + e->components += 8; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag 'UserComment' has been expanded to at " + "least 8 bytes in order to follow the " + "specification."); + break; + } + + /* + * If the first 8 bytes are empty and real data starts + * afterwards, let's assume ASCII and claim the 8 first + * bytes for the format specifyer. + */ + if (i >= 8) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag 'UserComment' did not start with " + "format identifyer. This has been fixed."); + memcpy (e->data, "ASCII\0\0\0", 8); + } + + /* First 8 bytes need to follow the specification. */ + if (memcmp (e->data, "ASCII\0\0\0" , 8) && + memcmp (e->data, "UNICODE\0" , 8) && + memcmp (e->data, "JIS\0\0\0\0\0" , 8) && + memcmp (e->data, "\0\0\0\0\0\0\0\0", 8)) { + e->data = exif_entry_realloc (e, e->data, 8 + e->size); + if (!e->data) { + e->size = 0; + e->components = 0; + break; + } + + /* Assume ASCII */ + memmove (e->data + 8, e->data, e->size); + memcpy (e->data, "ASCII\0\0\0", 8); + e->size += 8; + e->components += 8; + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag 'UserComment' did not start with " + "format identifyer. This has been fixed."); + break; + } + + break; + default: + break; + } +} + +void +exif_entry_dump (ExifEntry *e, unsigned int indent) +{ + char buf[1024]; + char value[1024]; + unsigned int i; + + for (i = 0; i < 2 * indent; i++) + buf[i] = ' '; + buf[i] = '\0'; + + if (!e) + return; + + printf ("%sTag: 0x%x ('%s')\n", buf, e->tag, + exif_tag_get_name (e->tag)); + printf ("%s Format: %i ('%s')\n", buf, e->format, + exif_format_get_name (e->format)); + printf ("%s Components: %i\n", buf, (int) e->components); + printf ("%s Size: %i\n", buf, e->size); + printf ("%s Value: %s\n", buf, exif_entry_get_value (e, value, sizeof(value))); +} + +#define CF(entry,target,v,maxlen) \ +{ \ + if (entry->format != target) { \ + exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA, \ + _("The tag '%s' contains data of an invalid " \ + "format ('%s', expected '%s')."), \ + exif_tag_get_name (entry->tag), \ + exif_format_get_name (entry->format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(entry,target,v,maxlen) \ +{ \ + if (entry->components != target) { \ + exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA, \ + _("The tag '%s' contains an invalid number of " \ + "components (%i, expected %i)."), \ + exif_tag_get_name (entry->tag), \ + (int) entry->components, (int) target); \ + break; \ + } \ +} + +static struct { + ExifTag tag; + const char *strings[10]; +} list[] = { + { EXIF_TAG_PLANAR_CONFIGURATION, + { N_("chunky format"), N_("planar format"), NULL}}, + { EXIF_TAG_SENSING_METHOD, + { "", N_("Not defined"), N_("One-chip color area sensor"), + N_("Two-chip color area sensor"), N_("Three-chip color area sensor"), + N_("Color sequential area sensor"), "", N_("Trilinear sensor"), + N_("Color sequential linear sensor"), NULL}}, + { EXIF_TAG_ORIENTATION, + { "", N_("top - left"), N_("top - right"), N_("bottom - right"), + N_("bottom - left"), N_("left - top"), N_("right - top"), + N_("right - bottom"), N_("left - bottom"), NULL}}, + { EXIF_TAG_YCBCR_POSITIONING, + { "", N_("centered"), N_("co-sited"), NULL}}, + { EXIF_TAG_PHOTOMETRIC_INTERPRETATION, {"", N_("RGB"), N_("YCbCr"), NULL}}, + { EXIF_TAG_CUSTOM_RENDERED, + { N_("Normal process"), N_("Custom process"), NULL}}, + { EXIF_TAG_EXPOSURE_MODE, + { N_("Auto exposure"), N_("Manual exposure"), N_("Auto bracket"), NULL}}, + { EXIF_TAG_WHITE_BALANCE, + { N_("Auto white balance"), N_("Manual white balance"), NULL}}, + { EXIF_TAG_SCENE_CAPTURE_TYPE, + { N_("Standard"), N_("Landscape"), N_("Portrait"), + N_("Night scene"), NULL}}, + { EXIF_TAG_GAIN_CONTROL, + { N_("Normal"), N_("Low gain up"), N_("High gain up"), + N_("Low gain down"), N_("High gain down"), NULL}}, + { EXIF_TAG_SATURATION, + { N_("Normal"), N_("Low saturation"), N_("High saturation"), NULL}}, + { EXIF_TAG_CONTRAST , {N_("Normal"), N_("Soft"), N_("Hard"), NULL}}, + { EXIF_TAG_SHARPNESS, {N_("Normal"), N_("Soft"), N_("Hard"), NULL}}, + { 0, {NULL}} +}; + +static struct { + ExifTag tag; + struct { + int index; + const char *values[4]; + } elem[25]; +} list2[] = { + { EXIF_TAG_METERING_MODE, + { { 0, {N_("Unknown"), NULL}}, + { 1, {N_("Average"), N_("avg"), NULL}}, + { 2, {N_("Center-Weighted Average"), N_("Center-Weight"), NULL}}, + { 3, {N_("Spot"), NULL}}, + { 4, {N_("Multi Spot"), NULL}}, + { 5, {N_("Pattern"), NULL}}, + { 6, {N_("Partial"), NULL}}, + {255, {N_("Other"), NULL}}, + { 0, {NULL}}}}, + { EXIF_TAG_COMPRESSION, + { {1, {N_("Uncompressed"), NULL}}, + {5, {N_("LZW compression"), NULL}}, + {6, {N_("JPEG compression"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_LIGHT_SOURCE, + { { 0, {N_("Unknown"), NULL}}, + { 1, {N_("Daylight"), NULL}}, + { 2, {N_("Fluorescent"), NULL}}, + { 3, {N_("Tungsten incandescent light"), N_("Tungsten"), NULL}}, + { 4, {N_("Flash"), NULL}}, + { 9, {N_("Fine weather"), NULL}}, + { 10, {N_("Cloudy weather"), N_("cloudy"), NULL}}, + { 11, {N_("Shade"), NULL}}, + { 12, {N_("Daylight fluorescent"), NULL}}, + { 13, {N_("Day white fluorescent"), NULL}}, + { 14, {N_("Cool white fluorescent"), NULL}}, + { 15, {N_("White fluorescent"), NULL}}, + { 17, {N_("Standard light A"), NULL}}, + { 18, {N_("Standard light B"), NULL}}, + { 19, {N_("Standard light C"), NULL}}, + { 20, {N_("D55"), NULL}}, + { 21, {N_("D65"), NULL}}, + { 22, {N_("D75"), NULL}}, + { 24, {N_("ISO studio tungsten"),NULL}}, + {255, {N_("Other"), NULL}}, + { 0, {NULL}}}}, + { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, + { {2, {N_("Inch"), N_("in"), NULL}}, + {3, {N_("Centimeter"), N_("cm"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_RESOLUTION_UNIT, + { {2, {N_("Inch"), N_("in"), NULL}}, + {3, {N_("Centimeter"), N_("cm"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_EXPOSURE_PROGRAM, + { {0, {N_("Not defined"), NULL}}, + {1, {N_("Manual"), NULL}}, + {2, {N_("Normal program"), N_("Normal"), NULL}}, + {3, {N_("Aperture priority"), N_("Aperture"), NULL}}, + {4, {N_("Shutter priority"),N_("Shutter"), NULL}}, + {5, {N_("Creative program (biased toward depth of field)"), + N_("Creative"), NULL}}, + {6, {N_("Creative program (biased toward fast shutter speed"), + N_("Action"), NULL}}, + {7, {N_("Portrait mode (for closeup photos with the background out " + "of focus)"), N_("Portrait"), NULL}}, + {8, {N_("Landscape mode (for landscape photos with the background " + "in focus)"), N_("Landscape"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_FLASH, + { {0x0000, {N_("Flash did not fire."), N_("no flash"), NULL}}, + {0x0001, {N_("Flash fired."), N_("flash"), N_("Yes"), NULL}}, + {0x0005, {N_("Strobe return light not detected."), N_("W/o strobe"), + NULL}}, + {0x0007, {N_("Strobe return light detected."), N_("W. strobe"), NULL}}, + {0x0009, {N_("Flash fired, compulsatory flash mode"), NULL}}, + {0x000d, {N_("Flash fired, compulsatory flash mode, return light " + "not detected."), NULL}}, + {0x000f, {N_("Flash fired, compulsatory flash mode, return light " + "detected."), NULL}}, + {0x0010, {N_("Flash did not fire, compulsatory flash mode."), NULL}}, + {0x0018, {N_("Flash did not fire, auto mode."), NULL}}, + {0x0019, {N_("Flash fired, auto mode."), NULL}}, + {0x001d, {N_("Flash fired, auto mode, return light not detected."), + NULL}}, + {0x001f, {N_("Flash fired, auto mode, return light detected."), NULL}}, + {0x0020, {N_("No flash function."),NULL}}, + {0x0041, {N_("Flash fired, red-eye reduction mode."), NULL}}, + {0x0045, {N_("Flash fired, red-eye reduction mode, return light " + "not detected."), NULL}}, + {0x0047, {N_("Flash fired, red-eye reduction mode, return light " + "detected."), NULL}}, + {0x0049, {N_("Flash fired, compulsory flash mode, red-eye reduction " + "mode."), NULL}}, + {0x004d, {N_("Flash fired, compulsory flash mode, red-eye reduction " + "mode, return light not detected"), NULL}}, + {0x004f, {N_("Flash fired, compulsory flash mode, red-eye reduction, " + "return light detected"), NULL}}, + {0x0058, {N_("Flash did not fire, auto mode, red-eye reduction mode"), NULL}}, + {0x0059, {N_("Flash fired, auto mode, red-eye reduction mode"), NULL}}, + {0x005d, {N_("Flash fired, auto mode, return light not detected, " + "red-eye reduction mode."), NULL}}, + {0x005f, {N_("Flash fired, auto mode, return light detected, " + "red-eye reduction mode."), NULL}}, + {0x0000, {NULL}}}}, + {EXIF_TAG_SUBJECT_DISTANCE_RANGE, + { {0, {N_("Unknown"), N_("?"), NULL}}, + {1, {N_("Macro"), NULL}}, + {2, {N_("Close view"), N_("close"), NULL}}, + {3, {N_("Distant view"), N_("distant"), NULL}}, + {0, {NULL}}}}, + { EXIF_TAG_COLOR_SPACE, + { {1, {N_("sRGB"), NULL}}, + {0xffff, {N_("Uncalibrated"), NULL}}}}, + {0, } +}; + +const char * +exif_entry_get_value (ExifEntry *e, char *val, unsigned int maxlen) +{ + unsigned int i, j, k, l, ts; + const unsigned char *t; + ExifByte v_byte; + ExifShort v_short, v_short2, v_short3, v_short4; + ExifLong v_long; + ExifSLong v_slong; + ExifRational v_rat; + ExifSRational v_srat; + char b[64]; + const char *c; + ExifByteOrder o; + double d; + ExifEntry *entry; + static struct { + char *label; + char major, minor; + } versions[] = { + {"0110", 1, 1}, + {"0120", 1, 2}, + {"0200", 2, 0}, + {"0210", 2, 1}, + {"0220", 2, 2}, + {"0221", 2, 21}, + {NULL , 0, 0} + }; + + /* FIXME: This belongs to somewhere else. */ + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + /* We need the byte order */ + if (!e || !e->parent || !e->parent->parent) + return val; + o = exif_data_get_byte_order (e->parent->parent); + + memset (val, 0, maxlen); + memset (b, 0, sizeof (b)); + maxlen--; + + /* Sanity check */ + if (e->size != e->components * exif_format_get_size (e->format)) { + snprintf (val, maxlen, _("Invalid size of entry (%i, " + "expected %li x %i)."), e->size, e->components, + exif_format_get_size (e->format)); + return val; + } + + switch (e->tag) { + case EXIF_TAG_USER_COMMENT: + + /* + * The specification says UNDEFINED, but some + * manufacturers don't care and use ASCII. If this is the + * case here, only refuse to read it if there is no chance + * of finding readable data. + */ + if ((e->format != EXIF_FORMAT_ASCII) || + (e->size <= 8) || + ( memcmp (e->data, "ASCII\0\0\0" , 8) && + memcmp (e->data, "UNICODE\0" , 8) && + memcmp (e->data, "JIS\0\0\0\0\0", 8) && + memcmp (e->data, "\0\0\0\0\0\0\0\0", 8))) + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + + /* + * Note that, according to the specification (V2.1, p 40), + * the user comment field does not have to be + * NULL terminated. + */ + if ((e->size >= 8) && !memcmp (e->data, "ASCII\0\0\0", 8)) { + strncpy (val, (char *) e->data + 8, MIN (e->size - 8, maxlen)); + break; + } + if ((e->size >= 8) && !memcmp (e->data, "UNICODE\0", 8)) { + strncpy (val, _("Unsupported UNICODE string"), maxlen); + break; + } + if ((e->size >= 8) && !memcmp (e->data, "JIS\0\0\0\0\0", 8)) { + strncpy (val, _("Unsupported JIS string"), maxlen); + break; + } + + /* Check if there is really some information in the tag. */ + for (i = 0; (i < e->size) && + (!e->data[i] || (e->data[i] == ' ')); i++); + if (i == e->size) break; + + /* + * If we reach this point, the tag does not + * comply with the standard and seems to contain data. + * Print as much as possible. + */ + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Tag UserComment does not comply " + "with standard but contains data."); + for (; (i < e->size) && (strlen (val) < maxlen - 1); i++) { + exif_entry_log (e, EXIF_LOG_CODE_DEBUG, + "Byte at position %i: 0x%02x", i, e->data[i]); + val[strlen (val)] = + isprint (e->data[i]) ? e->data[i] : '.'; + } + break; + + case EXIF_TAG_EXIF_VERSION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + strncpy (val, _("Unknown Exif Version"), maxlen); + for (i = 0; versions[i].label; i++) { + if (!memcmp (e->data, versions[i].label, 4)) { + snprintf (val, maxlen, + _("Exif Version %d.%d"), + versions[i].major, + versions[i].minor); + break; + } + } + break; + case EXIF_TAG_FLASH_PIX_VERSION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + if (!memcmp (e->data, "0100", 4)) + strncpy (val, _("FlashPix Version 1.0"), maxlen); + else if (!memcmp (e->data, "0101", 4)) + strncpy (val, _("FlashPix Version 1.01"), maxlen); + else + strncpy (val, _("Unknown FlashPix Version"), maxlen); + break; + case EXIF_TAG_COPYRIGHT: + CF (e, EXIF_FORMAT_ASCII, val, maxlen); + + /* + * First part: Photographer. + * Some cameras store a string like " " here. Ignore it. + */ + if (e->size && e->data && + (strspn (e->data, " ") != strlen ((char *) e->data))) + strncpy (val, (char *) e->data, MIN (maxlen, e->size)); + else + strncpy (val, _("[None]"), maxlen); + strncat (val, " ", maxlen - strlen (val)); + strncat (val, _("(Photographer)"), maxlen - strlen (val)); + + /* Second part: Editor. */ + t = e->data + strlen ((char *) e->data) + 1; + ts = e->data + e->size - t; + strncat (val, " - ", maxlen - strlen (val)); + if (e->size && e->data && (ts > 0) && + (strspn (t, " ") != ts)) + strncat (val, t, MIN (maxlen - strlen (val), ts)); + else + strncat (val, _("[None]"), maxlen - strlen (val)); + strncat (val, " ", maxlen - strlen (val)); + strncat (val, _("(Editor)"), maxlen - strlen (val)); + + break; + case EXIF_TAG_FNUMBER: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) return val; + snprintf (val, maxlen, "f/%.01f", (float) v_rat.numerator / + (float) v_rat.denominator); + break; + case EXIF_TAG_APERTURE_VALUE: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) return val; + snprintf (val, maxlen, "f/%.01f", + pow (2 , ((float) v_rat.numerator / + (float) v_rat.denominator) / 2.)); + break; + case EXIF_TAG_FOCAL_LENGTH: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) return val; + + /* + * For calculation of the 35mm equivalent, + * Minolta cameras need a multiplier that depends on the + * camera model. + */ + d = 0.; + entry = exif_content_get_entry ( + e->parent->parent->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); + if (entry && entry->data && + !strncmp (entry->data, "Minolta", 7)) { + entry = exif_content_get_entry ( + e->parent->parent->ifd[EXIF_IFD_0], + EXIF_TAG_MODEL); + if (entry && entry->data) { + if (!strncmp (entry->data, "DiMAGE 7", 8)) + d = 3.9; + else if (!strncmp (entry->data, "DiMAGE 5", 8)) + d = 4.9; + } + } + if (d) + snprintf (b, sizeof (b), _(" (35 equivalent: %d mm)"), + (int) (d * (double) v_rat.numerator / + (double) v_rat.denominator)); + + snprintf (val, maxlen, "%.1f mm", + (float) v_rat.numerator / (float) v_rat.denominator); + if (maxlen > strlen (val) + strlen (b)) + strncat (val, b, maxlen - strlen (val) - 1); + break; + case EXIF_TAG_SUBJECT_DISTANCE: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) return val; + snprintf (val, maxlen, "%.1f m", (float) v_rat.numerator / + (float) v_rat.denominator); + break; + case EXIF_TAG_EXPOSURE_TIME: + CF (e, EXIF_FORMAT_RATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_rat = exif_get_rational (e->data, o); + if (!v_rat.denominator) return val; + d = (double) v_rat.numerator / (double) v_rat.denominator; + if (d < 1) + snprintf (val, maxlen, _("1/%d"), + (int) (1. / d)); + else + snprintf (val, maxlen, _("%d"), (int) d); + if (maxlen > strlen (val) + strlen (_(" sec."))) + strncat (val, _(" sec."), maxlen - strlen (val) - 1); + break; + case EXIF_TAG_SHUTTER_SPEED_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + if (!v_srat.denominator) return val; + snprintf (val, maxlen, "%.0f/%.0f", (float) v_srat.numerator, + (float) v_srat.denominator); + if (maxlen > strlen (val) + strlen (_(" sec."))) + strncat (val, _(" sec."), maxlen - strlen (val) - 1); + snprintf (b, sizeof (b), " (APEX: %i)", + (int) pow (sqrt(2), (float) v_srat.numerator / + (float) v_srat.denominator)); + if (maxlen > strlen (val) + strlen (b)) + strncat (val, b, maxlen - strlen (val) - 1); + break; + case EXIF_TAG_BRIGHTNESS_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + snprintf (val, maxlen, "%i/%i", (int) v_srat.numerator, + (int) v_srat.denominator); + /* FIXME: How do I calculate the APEX value? */ + break; + case EXIF_TAG_FILE_SOURCE: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 1, val, maxlen); + switch (e->data[0]) { + case 0x03: strncpy (val, _("DSC"), maxlen); break; + default: snprintf (val, maxlen, "0x%02x", e->data[0]); break; + } + break; + case EXIF_TAG_COMPONENTS_CONFIGURATION: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (e, 4, val, maxlen); + for (i = 0; i < 4; i++) { + switch (e->data[i]) { + case 0: c = _("-"); break; + case 1: c = _("Y"); break; + case 2: c = _("Cb"); break; + case 3: c = _("Cr"); break; + case 4: c = _("R"); break; + case 5: c = _("G"); break; + case 6: c = _("B"); break; + default: c = _("reserved"); break; + } + strncat (val, c, maxlen - strlen (val)); + if (i < 3) strncat (val, " ", maxlen - strlen (val)); + } + break; + case EXIF_TAG_EXPOSURE_BIAS_VALUE: + CF (e, EXIF_FORMAT_SRATIONAL, val, maxlen); + CC (e, 1, val, maxlen); + v_srat = exif_get_srational (e->data, o); + if (!v_srat.denominator) return val; + snprintf (val, maxlen, "%s%.01f", + v_srat.denominator * v_srat.numerator > 0 ? "+" : "", + (double) v_srat.numerator / + (double) v_srat.denominator); + break; + case EXIF_TAG_YCBCR_SUB_SAMPLING: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 2, val, maxlen); + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short ( + e->data + exif_format_get_size (e->format), + o); + if ((v_short == 2) && (v_short2 == 1)) + strncpy (val, _("YCbCr4:2:2"), maxlen); + else if ((v_short == 2) && (v_short2 == 2)) + strncpy (val, _("YCbCr4:2:0"), maxlen); + else + snprintf (val, maxlen, "%i, %i", v_short, v_short2); + break; + case EXIF_TAG_MAKER_NOTE: + CF (e, EXIF_FORMAT_UNDEFINED, val, maxlen); + snprintf (val, maxlen, _("%i bytes unknown data"), + (int) e->components); + break; + case EXIF_TAG_SUBJECT_AREA: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + switch (e->components) { + case 2: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + snprintf (val, maxlen, "(x,y) = (%i,%i)", + v_short, v_short2); + break; + case 3: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + v_short3 = exif_get_short (e->data + 4, o); + snprintf (val, maxlen, _("Within distance %i of " + "(x,y) = (%i,%i)"), v_short3, v_short, + v_short2); + break; + case 4: + v_short = exif_get_short (e->data, o); + v_short2 = exif_get_short (e->data + 2, o); + v_short3 = exif_get_short (e->data + 4, o); + v_short4 = exif_get_short (e->data + 6, o); + snprintf (val, maxlen, _("Within rectangle " + "(width %i, height %i) around " + "(x,y) = (%i,%i)"), v_short3, v_short4, + v_short, v_short2); + break; + default: + snprintf (val, maxlen, _("Unexpected number " + "of components (%li, expected 2, 3, or 4)."), + e->components); + } + break; + + case EXIF_TAG_METERING_MODE: + case EXIF_TAG_COMPRESSION: + case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT: + case EXIF_TAG_RESOLUTION_UNIT: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_FLASH: + case EXIF_TAG_SUBJECT_DISTANCE_RANGE: + case EXIF_TAG_COLOR_SPACE: + CF (e,EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 1, val, maxlen); + v_short = exif_get_short (e->data, o); + + /* Search the tag */ + for (i = 0; list2[i].tag && (list2[i].tag != e->tag); i++); + if (!list2[i].tag) { + strncpy (val, "Internal error.", maxlen - 1); + break; + } + + /* Find the value */ + for (j = 0; list2[i].elem[j].values && + (list2[i].elem[j].index < v_short); j++); + if (list2[i].elem[j].index != v_short) { + snprintf (val, maxlen, "Internal error (unknown " + "value %i).", v_short); + break; + } + + /* Find a short enough value */ + memset (val, 0, maxlen); + for (k = 0; list2[i].elem[j].values && + list2[i].elem[j].values[k]; k++) { + l = strlen (_(list2[i].elem[j].values[k])); + if ((maxlen > l) && (strlen (val) < l)) + strncpy (val, _(list2[i].elem[j].values[k]), maxlen - 1); + } + if (!strlen (val)) snprintf (val, maxlen, "%i", v_short); + + break; + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_YCBCR_POSITIONING: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SATURATION: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SHARPNESS: + CF (e, EXIF_FORMAT_SHORT, val, maxlen); + CC (e, 1, val, maxlen); + v_short = exif_get_short (e->data, o); + + /* Search the tag */ + for (i = 0; list[i].tag && (list[i].tag != e->tag); i++); + if (!list[i].tag) { + strncpy (val, "Internal error.", maxlen - 1); + break; + } + + /* Find the value */ + for (j = 0; list[i].strings[j] && (j < v_short); j++); + if (!list[i].strings[j]) + snprintf (val, maxlen, "%i", v_short); + else + strncpy (val, _(list[i].strings[j]), maxlen - 1); + break; + default: + if (!e->components) break; + switch (e->format) { + case EXIF_FORMAT_UNDEFINED: + break; + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_SBYTE: + v_byte = e->data[0]; + snprintf (val, maxlen, "0x%02x", v_byte); + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_byte = e->data[i]; + snprintf (b, sizeof (b), ", 0x%02x", v_byte); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_FORMAT_SHORT: + case EXIF_FORMAT_SSHORT: + v_short = exif_get_short (e->data, o); + snprintf (val, maxlen, "%i", v_short); + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_short = exif_get_short (e->data + + exif_format_get_size (e->format) * + i, o); + snprintf (b, sizeof (b), ", %i", v_short); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_FORMAT_LONG: + v_long = exif_get_long (e->data, o); + snprintf (val, maxlen, "%li", (long int) v_long); + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_long = exif_get_long (e->data + + exif_format_get_size (e->format) * + i, o); + snprintf (b, sizeof (b), ", %li", + (long int) v_long); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_FORMAT_SLONG: + v_slong = exif_get_slong (e->data, o); + snprintf (val, maxlen, "%li", (long int) v_slong); + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_long = exif_get_slong (e->data + + exif_format_get_size (e->format) * + i, o); + snprintf (b, sizeof (b), ", %li", + (long int) v_long); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_FORMAT_ASCII: + strncpy (val, (char *) e->data, MIN (maxlen, e->size)); + break; + case EXIF_FORMAT_RATIONAL: + v_rat = exif_get_rational (e->data, o); + if (v_rat.denominator) { + snprintf (val, maxlen, "%2.2f", (double)v_rat.numerator / v_rat.denominator); + } else { + snprintf (val, maxlen, "%i/%i", v_rat.numerator, v_rat.denominator); + } + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_rat = exif_get_rational ( + e->data + 8 * i, o); + snprintf (b, sizeof (b), ", %2.2f", + (double)v_rat.numerator / v_rat.denominator); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed)maxlen <= 0) break; + } + break; + case EXIF_FORMAT_SRATIONAL: + v_srat = exif_get_srational (e->data, o); + if (v_srat.denominator) { + snprintf (val, maxlen, "%2.2f", (double)v_srat.numerator / v_srat.denominator); + } else { + snprintf (val, maxlen, "%i/%i", v_srat.numerator, v_srat.denominator); + } + maxlen -= strlen (val); + for (i = 1; i < e->components; i++) { + v_srat = exif_get_srational ( + e->data + 8 * i, o); + snprintf (b, sizeof (b), ", %2.2f", + (double)v_srat.numerator / v_srat.denominator); + strncat (val, b, maxlen); + maxlen -= strlen (b); + if ((signed) maxlen <= 0) break; + } + break; + case EXIF_FORMAT_DOUBLE: + case EXIF_FORMAT_FLOAT: + default: + /* What to do here? */ + break; + } + } + + return val; +} + +void +exif_entry_initialize (ExifEntry *e, ExifTag tag) +{ + time_t t; + struct tm *tm; + ExifRational r; + ExifByteOrder o; + + /* We need the byte order */ + if (!e || !e->parent || e->data || !e->parent->parent) + return; + o = exif_data_get_byte_order (e->parent->parent); + + e->tag = tag; + switch (tag) { + + /* LONG, 1 component, no default */ + case EXIF_TAG_PIXEL_X_DIMENSION: + case EXIF_TAG_PIXEL_Y_DIMENSION: + case EXIF_TAG_EXIF_IFD_POINTER: + case EXIF_TAG_GPS_INFO_IFD_POINTER: + case EXIF_TAG_INTEROPERABILITY_IFD_POINTER: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: + case EXIF_TAG_JPEG_INTERCHANGE_FORMAT: + e->components = 1; + e->format = EXIF_FORMAT_LONG; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + /* SHORT, 1 component, no default */ + case EXIF_TAG_SUBJECT_LOCATION: + case EXIF_TAG_SENSING_METHOD: + case EXIF_TAG_PHOTOMETRIC_INTERPRETATION: + case EXIF_TAG_COMPRESSION: + case EXIF_TAG_EXPOSURE_MODE: + case EXIF_TAG_WHITE_BALANCE: + case EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM: + case EXIF_TAG_GAIN_CONTROL: + case EXIF_TAG_SUBJECT_DISTANCE_RANGE: + case EXIF_TAG_FLASH: + case EXIF_TAG_COLOR_SPACE: + + /* SHORT, 1 component, default 0 */ + case EXIF_TAG_IMAGE_WIDTH: + case EXIF_TAG_IMAGE_LENGTH: + case EXIF_TAG_EXPOSURE_PROGRAM: + case EXIF_TAG_LIGHT_SOURCE: + case EXIF_TAG_METERING_MODE: + case EXIF_TAG_CUSTOM_RENDERED: + case EXIF_TAG_SCENE_CAPTURE_TYPE: + case EXIF_TAG_CONTRAST: + case EXIF_TAG_SATURATION: + case EXIF_TAG_SHARPNESS: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + exif_set_short (e->data, o, 0); + break; + + /* SHORT, 1 component, default 1 */ + case EXIF_TAG_ORIENTATION: + case EXIF_TAG_PLANAR_CONFIGURATION: + case EXIF_TAG_YCBCR_POSITIONING: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + exif_set_short (e->data, o, 1); + break; + + /* SHORT, 1 component, default 2 */ + case EXIF_TAG_RESOLUTION_UNIT: + case EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + exif_set_short (e->data, o, 2); + break; + + /* SHORT, 1 component, default 3 */ + case EXIF_TAG_SAMPLES_PER_PIXEL: + e->components = 1; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + exif_set_short (e->data, o, 3); + break; + + case EXIF_TAG_BITS_PER_SAMPLE: + e->components = 3; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 8); + exif_set_short ( + e->data + exif_format_get_size (e->format), + o, 8); + exif_set_short ( + e->data + 2 * exif_format_get_size (e->format), + o, 8); + break; + case EXIF_TAG_YCBCR_SUB_SAMPLING: + e->components = 2; + e->format = EXIF_FORMAT_SHORT; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + exif_set_short (e->data, o, 2); + exif_set_short ( + e->data + exif_format_get_size (e->format), + o, 1); + break; + + /* SHORT, any component, no default */ + case EXIF_TAG_SUBJECT_AREA: + case EXIF_TAG_ISO_SPEED_RATINGS: + e->components = 0; + e->format = EXIF_FORMAT_SHORT; + e->size = 0; + e->data = 0; + break; + + /* SRATIONAL, 1 component, no default */ + case EXIF_TAG_EXPOSURE_BIAS_VALUE: + case EXIF_TAG_BRIGHTNESS_VALUE: + case EXIF_TAG_SHUTTER_SPEED_VALUE: + e->components = 1; + e->format = EXIF_FORMAT_SRATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + /* RATIONAL, 1 component, no default */ + case EXIF_TAG_EXPOSURE_TIME: + case EXIF_TAG_FOCAL_PLANE_X_RESOLUTION: + case EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION: + case EXIF_TAG_EXPOSURE_INDEX: + case EXIF_TAG_FLASH_ENERGY: + case EXIF_TAG_FNUMBER: + case EXIF_TAG_FOCAL_LENGTH: + case EXIF_TAG_SUBJECT_DISTANCE: + case EXIF_TAG_MAX_APERTURE_VALUE: + case EXIF_TAG_APERTURE_VALUE: + case EXIF_TAG_COMPRESSED_BITS_PER_PIXEL: + case EXIF_TAG_PRIMARY_CHROMATICITIES: + case EXIF_TAG_DIGITAL_ZOOM_RATIO: + e->components = 1; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + /* RATIONAL, 1 component, default 72/1 */ + case EXIF_TAG_X_RESOLUTION: + case EXIF_TAG_Y_RESOLUTION: + e->components = 1; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + r.numerator = 72; + r.denominator = 1; + exif_set_rational (e->data, o, r); + break; + + /* RATIONAL, 2 components, no default */ + case EXIF_TAG_WHITE_POINT: + e->components = 2; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + /* RATIONAL, 6 components */ + case EXIF_TAG_REFERENCE_BLACK_WHITE: + e->components = 6; + e->format = EXIF_FORMAT_RATIONAL; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + r.denominator = 1; + r.numerator = 0; + exif_set_rational (e->data, o, r); + r.numerator = 255; + exif_set_rational ( + e->data + exif_format_get_size (e->format), o, r); + r.numerator = 0; + exif_set_rational ( + e->data + 2 * exif_format_get_size (e->format), o, r); + r.numerator = 255; + exif_set_rational ( + e->data + 3 * exif_format_get_size (e->format), o, r); + r.numerator = 0; + exif_set_rational ( + e->data + 4 * exif_format_get_size (e->format), o, r); + r.numerator = 255; + exif_set_rational ( + e->data + 5 * exif_format_get_size (e->format), o, r); + break; + + /* ASCII, 20 components, default current time */ + case EXIF_TAG_DATE_TIME: + case EXIF_TAG_DATE_TIME_ORIGINAL: + case EXIF_TAG_DATE_TIME_DIGITIZED: + t = time (NULL); + tm = localtime (&t); + e->components = 20; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + snprintf ((char *) e->data, e->size, + "%04i:%02i:%02i %02i:%02i:%02i", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + break; + + /* EXIF_FORMAT_ASCII, 13 components */ + case EXIF_TAG_RELATED_SOUND_FILE: + e->components = 13; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + case EXIF_TAG_IMAGE_UNIQUE_ID: + e->components = 33; + e->format = EXIF_FORMAT_ASCII; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + break; + + /* ASCII, any components, no default */ + case EXIF_TAG_SPECTRAL_SENSITIVITY: + case EXIF_TAG_SUB_SEC_TIME: + case EXIF_TAG_SUB_SEC_TIME_ORIGINAL: + case EXIF_TAG_SUB_SEC_TIME_DIGITIZED: + case EXIF_TAG_IMAGE_DESCRIPTION: + case EXIF_TAG_MAKE: + case EXIF_TAG_MODEL: + case EXIF_TAG_SOFTWARE: + case EXIF_TAG_ARTIST: + case EXIF_TAG_COPYRIGHT: + e->components = 0; + e->format = EXIF_FORMAT_ASCII; + e->size = 0; + e->data = NULL; + break; + + /* UNDEFINED, no components, no default */ + case EXIF_TAG_OECF: + case EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE: + case EXIF_TAG_NEW_CFA_PATTERN: + case EXIF_TAG_DEVICE_SETTING_DESCRIPTION: + case EXIF_TAG_MAKER_NOTE: + case EXIF_TAG_USER_COMMENT: + e->components = 0; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = 0; + e->data = NULL; + break; + + /* UNDEFINED, 1 component, default 1 */ + case EXIF_TAG_SCENE_TYPE: + e->components = 1; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + e->data[0] = 0x01; + break; + + /* UNDEFINED, 1 component, default 3 */ + case EXIF_TAG_FILE_SOURCE: + e->components = 1; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + e->data[0] = 0x03; + break; + + /* UNDEFINED, 4 components, default 0 1 0 0 */ + case EXIF_TAG_FLASH_PIX_VERSION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + memcpy (e->data, "0100", 4); + break; + + /* UNDEFINED, 4 components, default 0 2 1 0 */ + case EXIF_TAG_EXIF_VERSION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = exif_entry_alloc (e, e->size); + if (!e->data) break; + memcpy (e->data, "0210", 4); + break; + + /* UNDEFINED, 4 components, no default */ + case EXIF_TAG_COMPONENTS_CONFIGURATION: + e->components = 4; + e->format = EXIF_FORMAT_UNDEFINED; + e->size = exif_format_get_size (e->format) * e->components; + e->data = malloc (e->size); + break; + + default: + break; + } +} diff --git a/src/libexif/exif-entry.h b/src/libexif/exif-entry.h new file mode 100644 index 0000000..072ee29 --- /dev/null +++ b/src/libexif/exif-entry.h @@ -0,0 +1,69 @@ +/* exif-entry.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_ENTRY_H__ +#define __EXIF_ENTRY_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _ExifEntry ExifEntry; +typedef struct _ExifEntryPrivate ExifEntryPrivate; + +#include <libexif/exif-content.h> +#include <libexif/exif-format.h> +#include <libexif/exif-mem.h> + +struct _ExifEntry { + ExifTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + /* Content containing this entry */ + ExifContent *parent; + + ExifEntryPrivate *priv; +}; + +/* Lifecycle */ +ExifEntry *exif_entry_new (void); +ExifEntry *exif_entry_new_mem (ExifMem *); +void exif_entry_ref (ExifEntry *entry); +void exif_entry_unref (ExifEntry *entry); +void exif_entry_free (ExifEntry *entry); + +void exif_entry_initialize (ExifEntry *entry, ExifTag tag); +void exif_entry_fix (ExifEntry *entry); + +/* For your convenience */ +const char *exif_entry_get_value (ExifEntry *entry, char *val, + unsigned int maxlen); + +void exif_entry_dump (ExifEntry *entry, unsigned int indent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_ENTRY_H__ */ diff --git a/src/libexif/exif-format.c b/src/libexif/exif-format.c new file mode 100644 index 0000000..e0c3650 --- /dev/null +++ b/src/libexif/exif-format.c @@ -0,0 +1,72 @@ +/* exif-format.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-format.h> +#include <libexif/i18n.h> + +#include <stdlib.h> + +static struct { + ExifFormat format; + const char *name; + unsigned char size; +} ExifFormatTable[] = { + {EXIF_FORMAT_BYTE, N_("Byte"), 1}, + {EXIF_FORMAT_ASCII, N_("Ascii"), 1}, + {EXIF_FORMAT_SHORT, N_("Short"), 2}, + {EXIF_FORMAT_LONG, N_("Long"), 4}, + {EXIF_FORMAT_RATIONAL, N_("Rational"), 8}, + {EXIF_FORMAT_SBYTE, N_("SByte"), 1}, + {EXIF_FORMAT_SSHORT, N_("SShort"), 2}, + {EXIF_FORMAT_SLONG, N_("SLong"), 4}, + {EXIF_FORMAT_SRATIONAL, N_("SRational"), 8}, + {EXIF_FORMAT_FLOAT, N_("Float"), 4}, + {EXIF_FORMAT_DOUBLE, N_("Double"), 8}, + {EXIF_FORMAT_UNDEFINED, N_("Undefined"), 1}, + {0, NULL, 0} +}; + +const char * +exif_format_get_name (ExifFormat format) +{ + unsigned int i; + + /* FIXME: This belongs to somewhere else. */ + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + for (i = 0; ExifFormatTable[i].name; i++) + if (ExifFormatTable[i].format == format) + return _(ExifFormatTable[i].name); + return NULL; +} + +unsigned char +exif_format_get_size (ExifFormat format) +{ + unsigned int i; + + for (i = 0; ExifFormatTable[i].size; i++) + if (ExifFormatTable[i].format == format) + return ExifFormatTable[i].size; + return 0; +} diff --git a/src/libexif/exif-format.h b/src/libexif/exif-format.h new file mode 100644 index 0000000..0eae425 --- /dev/null +++ b/src/libexif/exif-format.h @@ -0,0 +1,50 @@ +/* exif-format.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_FORMAT_H__ +#define __EXIF_FORMAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + EXIF_FORMAT_BYTE = 1, + EXIF_FORMAT_ASCII = 2, + EXIF_FORMAT_SHORT = 3, + EXIF_FORMAT_LONG = 4, + EXIF_FORMAT_RATIONAL = 5, + EXIF_FORMAT_SBYTE = 6, + EXIF_FORMAT_UNDEFINED = 7, + EXIF_FORMAT_SSHORT = 8, + EXIF_FORMAT_SLONG = 9, + EXIF_FORMAT_SRATIONAL = 10, + EXIF_FORMAT_FLOAT = 11, + EXIF_FORMAT_DOUBLE = 12 +} ExifFormat; + +const char *exif_format_get_name (ExifFormat format); +unsigned char exif_format_get_size (ExifFormat format); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_FORMAT_H__ */ diff --git a/src/libexif/exif-ifd.c b/src/libexif/exif-ifd.c new file mode 100644 index 0000000..96de261 --- /dev/null +++ b/src/libexif/exif-ifd.c @@ -0,0 +1,49 @@ +/* exif-ifd.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-ifd.h> + +#include <stdlib.h> + +static struct { + ExifIfd ifd; + const char *name; +} ExifIfdTable[] = { + {EXIF_IFD_0, "0"}, + {EXIF_IFD_1, "1"}, + {EXIF_IFD_EXIF, "EXIF"}, + {EXIF_IFD_GPS, "GPS"}, + {EXIF_IFD_INTEROPERABILITY, "Interoperability"}, + {0, NULL} +}; + +const char * +exif_ifd_get_name (ExifIfd ifd) +{ + unsigned int i; + + for (i = 0; ExifIfdTable[i].name; i++) + if (ExifIfdTable[i].ifd == ifd) + break; + + return (ExifIfdTable[i].name); +} diff --git a/src/libexif/exif-ifd.h b/src/libexif/exif-ifd.h new file mode 100644 index 0000000..01f0019 --- /dev/null +++ b/src/libexif/exif-ifd.h @@ -0,0 +1,35 @@ +/* exif-ifd.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_IFD_H__ +#define __EXIF_IFD_H__ + +typedef enum { + EXIF_IFD_0 = 0, + EXIF_IFD_1, + EXIF_IFD_EXIF, + EXIF_IFD_GPS, + EXIF_IFD_INTEROPERABILITY, + EXIF_IFD_COUNT +} ExifIfd; + +const char *exif_ifd_get_name (ExifIfd ifd); + +#endif /* __EXIF_IFD_H__ */ diff --git a/src/libexif/exif-loader.c b/src/libexif/exif-loader.c new file mode 100644 index 0000000..d6eba7d --- /dev/null +++ b/src/libexif/exif-loader.c @@ -0,0 +1,349 @@ +#include <config.h> + +#include <libexif/exif-loader.h> +#include <libexif/i18n.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#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 +#undef JPEG_MARKER_APP13 +#define JPEG_MARKER_APP13 0xed +#undef JPEG_MARKER_COM +#define JPEG_MARKER_COM 0xfe + +typedef enum { + EL_READ = 0, + EL_READ_SIZE_BYTE_24, + EL_READ_SIZE_BYTE_16, + EL_READ_SIZE_BYTE_08, + EL_READ_SIZE_BYTE_00, + EL_SKIP_BYTES, + EL_EXIF_FOUND, +} ExifLoaderState; + +typedef enum { + EL_DATA_FORMAT_UNKNOWN, + EL_DATA_FORMAT_EXIF, + EL_DATA_FORMAT_JPEG, + EL_DATA_FORMAT_FUJI_RAW +} ExifLoaderDataFormat; + +struct _ExifLoader { + ExifLoaderState state; + ExifLoaderDataFormat data_format; + + /* Small buffer used for detection of format */ + unsigned char b[12]; + unsigned char b_len; + + unsigned int size; + unsigned char *buf; + unsigned int bytes_read; + + unsigned int ref_count; + + ExifLog *log; + ExifMem *mem; +}; + +static const unsigned char ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + +static void * +exif_loader_alloc (ExifLoader *l, unsigned int i) +{ + void *d; + + if (!l || !i) return NULL; + + d = exif_mem_alloc (l->mem, i); + if (d) return d; + + EXIF_LOG_NO_MEMORY (l->log, "ExifLog", i); + return NULL; +} + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +void +exif_loader_write_file (ExifLoader *l, const char *path) +{ + FILE *f; + int size; + unsigned char data[1024]; + + if (!l) return; + + f = fopen (path, "rb"); + if (!f) { + exif_log (l->log, EXIF_LOG_CODE_NONE, "ExifLoader", + _("The file '%s' could not be opened."), path); + return; + } + while (1) { + size = fread (data, 1, sizeof (data), f); + if (size <= 0) break; + if (!exif_loader_write (l, data, size)) break; + } + fclose (f); +} + +static unsigned int +exif_loader_copy (ExifLoader *eld, unsigned char *buf, unsigned int len) +{ + if (!eld || (len && !buf) || (eld->bytes_read >= eld->size)) return 0; + + /* If needed, allocate the buffer. */ + if (!eld->buf) eld->buf = exif_loader_alloc (eld, eld->size); + if (!eld->buf) return 0; + + /* Copy memory */ + len = MIN (len, eld->size - eld->bytes_read); + memcpy (eld->buf + eld->bytes_read, buf, len); + eld->bytes_read += len; + + return (eld->bytes_read >= eld->size) ? 0 : 1; +} + +unsigned char +exif_loader_write (ExifLoader *eld, unsigned char *buf, unsigned int len) +{ + unsigned int i; + + if (!eld || (len && !buf)) return 0; + + switch (eld->state) { + case EL_EXIF_FOUND: + return exif_loader_copy (eld, buf, len); + case EL_SKIP_BYTES: + if (eld->size > len) { eld->size -= len; return 1; } + len -= eld->size; + buf += eld->size; + eld->size = 0; + eld->b_len = 0; + switch (eld->data_format) { + case EL_DATA_FORMAT_FUJI_RAW: + eld->state = EL_READ_SIZE_BYTE_24; + break; + default: + eld->state = EL_READ; + break; + } + break; + default: + break; + } + + exif_log (eld->log, EXIF_LOG_CODE_DEBUG, "ExifLoader", + "Scanning %i byte(s) of data...", len); + + /* + * First fill the small buffer. Only continue if the buffer + * is filled. Note that EXIF data contains at least 12 bytes. + */ + i = MIN (len, sizeof (eld->b) - eld->b_len); + if (i) { + memcpy (&eld->b[eld->b_len], buf, i); + eld->b_len += i; + if (eld->b_len < sizeof (eld->b)) return 1; + buf += i; + len -= i; + } + + switch (eld->data_format) { + case EL_DATA_FORMAT_UNKNOWN: + + /* Check the small buffer against known formats. */ + if (!memcmp (eld->b, "FUJIFILM", 8)) { + + /* Skip to byte 84. There is another offset there. */ + eld->data_format = EL_DATA_FORMAT_FUJI_RAW; + eld->size = 84; + eld->state = EL_SKIP_BYTES; + eld->size = 84; + + } else if (!memcmp (eld->b + 2, ExifHeader, sizeof (ExifHeader))) { + + /* Read the size (2 bytes). */ + eld->data_format = EL_DATA_FORMAT_EXIF; + eld->state = EL_READ_SIZE_BYTE_08; + } + default: + break; + } + + for (i = 0; i < sizeof (eld->b); i++) + switch (eld->state) { + case EL_EXIF_FOUND: + if (!exif_loader_copy (eld, eld->b + i, + sizeof (eld->b) - i)) return 0; + return exif_loader_copy (eld, buf, len); + case EL_SKIP_BYTES: + eld->size--; + if (!eld->size) eld->state = EL_READ; + break; + + case EL_READ_SIZE_BYTE_24: + eld->size |= eld->b[i] << 24; + eld->state = EL_READ_SIZE_BYTE_16; + break; + case EL_READ_SIZE_BYTE_16: + eld->size |= eld->b[i] << 16; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case EL_READ_SIZE_BYTE_08: + eld->size |= eld->b[i] << 8; + eld->state = EL_READ_SIZE_BYTE_00; + break; + case EL_READ_SIZE_BYTE_00: + eld->size |= eld->b[i] << 0; + switch (eld->data_format) { + case EL_DATA_FORMAT_JPEG: + eld->state = EL_SKIP_BYTES; + eld->size -= 2; + break; + case EL_DATA_FORMAT_FUJI_RAW: + eld->data_format = EL_DATA_FORMAT_EXIF; + eld->state = EL_SKIP_BYTES; + eld->size -= 86; + break; + case EL_DATA_FORMAT_EXIF: + eld->state = EL_EXIF_FOUND; + break; + default: + break; + } + break; + + default: + switch (eld->b[i]) { + case JPEG_MARKER_APP1: + eld->data_format = EL_DATA_FORMAT_EXIF; + eld->size = 0; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case JPEG_MARKER_APP0: + case JPEG_MARKER_APP13: + case JPEG_MARKER_COM: + eld->data_format = EL_DATA_FORMAT_JPEG; + eld->size = 0; + eld->state = EL_READ_SIZE_BYTE_08; + break; + case 0xff: + case JPEG_MARKER_SOI: + break; + default: + exif_log (eld->log, + EXIF_LOG_CODE_CORRUPT_DATA, + "ExifLoader", _("The data supplied " + "does not seem to contain " + "EXIF data.")); + exif_loader_reset (eld); + return 0; + } + } + + /* + * If we reach this point, the buffer has not been big enough + * to read all data we need. Fill it with new data. + */ + eld->b_len = 0; + return exif_loader_write (eld, buf, len); +} + +ExifLoader * +exif_loader_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifLoader *l = exif_loader_new_mem (mem); + + exif_mem_unref (mem); + + return l; +} + +ExifLoader * +exif_loader_new_mem (ExifMem *mem) +{ + ExifLoader *loader; + + if (!mem) return NULL; + + loader = exif_mem_alloc (mem, sizeof (ExifLoader)); + if (!loader) return NULL; + loader->ref_count = 1; + + loader->mem = mem; + exif_mem_ref (mem); + + return loader; +} + +void +exif_loader_ref (ExifLoader *loader) +{ + if (loader) loader->ref_count++; +} + +static void +exif_loader_free (ExifLoader *loader) +{ + ExifMem *mem; + + if (!loader) return; + + mem = loader->mem; + exif_loader_reset (loader); + exif_mem_free (mem, loader); + exif_mem_unref (mem); +} + +void +exif_loader_unref (ExifLoader *loader) +{ + if (!loader) return; + if (!--loader->ref_count) + exif_loader_free (loader); +} + +void +exif_loader_reset (ExifLoader *loader) +{ + if (!loader) return; + exif_mem_free (loader->mem, loader->buf); loader->buf = NULL; + loader->size = 0; + loader->bytes_read = 0; + loader->state = 0; + loader->b_len = 0; + loader->data_format = EL_DATA_FORMAT_UNKNOWN; +} + +ExifData * +exif_loader_get_data (ExifLoader *loader) +{ + ExifData *ed; + + if (!loader) return NULL; + + ed = exif_data_new_mem (loader->mem); + exif_data_log (ed, loader->log); + exif_data_load_data (ed, loader->buf, loader->bytes_read); + + return ed; +} + +void +exif_loader_log (ExifLoader *loader, ExifLog *log) +{ + if (!loader) return; + exif_log_unref (loader->log); + loader->log = log; + exif_log_ref (log); +} diff --git a/src/libexif/exif-loader.h b/src/libexif/exif-loader.h new file mode 100644 index 0000000..cf900c8 --- /dev/null +++ b/src/libexif/exif-loader.h @@ -0,0 +1,57 @@ +/* exif-loader.h + * + * Copyright © 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_LOADER_H__ +#define __EXIF_LOADER_H__ + +#include <libexif/exif-data.h> +#include <libexif/exif-loader.h> +#include <libexif/exif-log.h> +#include <libexif/exif-mem.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct _ExifLoader ExifLoader; + +ExifLoader *exif_loader_new (void); +ExifLoader *exif_loader_new_mem (ExifMem *); +void exif_loader_ref (ExifLoader *); +void exif_loader_unref (ExifLoader *); + +void exif_loader_write_file (ExifLoader *, const char *fname); + +/* + * Returns 1 while EXIF data is read (or while there is still + * hope that there will be EXIF data later on), 0 otherwise. + */ +unsigned char exif_loader_write (ExifLoader *, unsigned char *, unsigned int); + +void exif_loader_reset (ExifLoader *); +ExifData *exif_loader_get_data (ExifLoader *); + +void exif_loader_log (ExifLoader *, ExifLog *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_LOADER_H__ */ diff --git a/src/libexif/exif-log.c b/src/libexif/exif-log.c new file mode 100644 index 0000000..5dde1ce --- /dev/null +++ b/src/libexif/exif-log.c @@ -0,0 +1,148 @@ +/* exif-log.c + * + * Copyright © 2004 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-log.h> +#include <libexif/i18n.h> + +#include <stdlib.h> +#include <string.h> + +struct _ExifLog { + unsigned int ref_count; + + ExifLogFunc func; + void *data; + + ExifMem *mem; +}; + +static struct { + ExifLogCode code; + const char *title; + const char *message; +} codes[] = { + { EXIF_LOG_CODE_DEBUG, N_("Debugging information"), + N_("Debugging information is available.") }, + { EXIF_LOG_CODE_NO_MEMORY, N_("Not enough memory"), + N_("The system cannot provide enough memory.") }, + { EXIF_LOG_CODE_CORRUPT_DATA, N_("Corrupt data"), + N_("The data provided does not follow the specification.") }, + { 0, NULL, NULL } +}; + +const char * +exif_log_code_get_title (ExifLogCode code) +{ + unsigned int i; + + for (i = 0; codes[i].title; i++) if (codes[i].code == code) break; + return _(codes[i].title); +} + +const char * +exif_log_code_get_message (ExifLogCode code) +{ + unsigned int i; + + for (i = 0; codes[i].message; i++) if (codes[i].code == code) break; + return _(codes[i].message); +} + +ExifLog * +exif_log_new_mem (ExifMem *mem) +{ + ExifLog *log; + + log = exif_mem_alloc (mem, sizeof (ExifLog)); + if (!log) return NULL; + log->ref_count = 1; + + log->mem = mem; + exif_mem_ref (mem); + + return log; +} + +ExifLog * +exif_log_new (void) +{ + ExifMem *mem = exif_mem_new_default (); + ExifLog *log = exif_log_new_mem (mem); + + exif_mem_unref (mem); + + return log; +} + +void +exif_log_ref (ExifLog *log) +{ + if (!log) return; + log->ref_count++; +} + +void +exif_log_unref (ExifLog *log) +{ + if (!log) return; + if (log->ref_count > 0) log->ref_count--; + if (!log->ref_count) exif_log_free (log); +} + +void +exif_log_free (ExifLog *log) +{ + ExifMem *mem = log ? log->mem : NULL; + + if (!log) return; + + exif_mem_free (mem, log); + exif_mem_unref (mem); +} + +void +exif_log_set_func (ExifLog *log, ExifLogFunc func, void *data) +{ + if (!log) return; + log->func = func; + log->data = data; +} + +void +exif_log (ExifLog *log, ExifLogCode code, const char *domain, + const char *format, ...) +{ + va_list args; + + va_start (args, format); + exif_logv (log, code, domain, format, args); + va_end (args); +} + +void +exif_logv (ExifLog *log, ExifLogCode code, const char *domain, + const char *format, va_list args) +{ + if (!log) return; + if (!log->func) return; + log->func (log, code, domain, format, args, log->data); +} diff --git a/src/libexif/exif-log.h b/src/libexif/exif-log.h new file mode 100644 index 0000000..01eed3f --- /dev/null +++ b/src/libexif/exif-log.h @@ -0,0 +1,75 @@ +/*! \file exif-log.h + * \brief log message infrastructure + * + * Copyright © 2004 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_LOG_H__ +#define __EXIF_LOG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-mem.h> +#include <stdarg.h> + +typedef struct _ExifLog ExifLog; + +ExifLog *exif_log_new (void); +ExifLog *exif_log_new_mem (ExifMem *); +void exif_log_ref (ExifLog *log); +void exif_log_unref (ExifLog *log); +void exif_log_free (ExifLog *log); + +typedef enum { + EXIF_LOG_CODE_NONE, + EXIF_LOG_CODE_DEBUG, + EXIF_LOG_CODE_NO_MEMORY, + EXIF_LOG_CODE_CORRUPT_DATA +} ExifLogCode; +const char *exif_log_code_get_title (ExifLogCode); /* Title for dialog */ +const char *exif_log_code_get_message (ExifLogCode); /* Message for dialog */ + +/** Log callback function prototype. + */ +typedef void (* ExifLogFunc) (ExifLog *log, ExifLogCode, const char *domain, + const char *format, va_list args, void *data); + +/** Register log callback function. + */ +void exif_log_set_func (ExifLog *log, ExifLogFunc func, void *data); + +void exif_log (ExifLog *log, ExifLogCode, const char *domain, + const char *format, ...) +#ifdef __GNUC__ + __attribute__((__format__(printf,4,5))) +#endif +; + +void exif_logv (ExifLog *log, ExifLogCode, const char *domain, + const char *format, va_list args); + +/* For your convenience */ +#define EXIF_LOG_NO_MEMORY(l,d,s) exif_log (l, EXIF_LOG_CODE_NO_MEMORY, d, "Could not allocate %i byte(s).", s) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_LOG_H__ */ diff --git a/src/libexif/exif-mem.c b/src/libexif/exif-mem.c new file mode 100644 index 0000000..12027d1 --- /dev/null +++ b/src/libexif/exif-mem.c @@ -0,0 +1,95 @@ +#include <libexif/exif-mem.h> + +#include <stdlib.h> + +struct _ExifMem { + unsigned int ref_count; + ExifMemAllocFunc alloc_func; + ExifMemReallocFunc realloc_func; + ExifMemFreeFunc free_func; +}; + +static void * +exif_mem_alloc_func (ExifLong ds) +{ + return calloc ((size_t) ds, 1); +} + +static void * +exif_mem_realloc_func (void *d, ExifLong ds) +{ + return realloc (d, (size_t) ds); +} + +static void +exif_mem_free_func (void *d) +{ + free (d); +} + +ExifMem * +exif_mem_new (ExifMemAllocFunc alloc_func, ExifMemReallocFunc realloc_func, + ExifMemFreeFunc free_func) +{ + ExifMem *mem; + + if (!alloc_func || !realloc_func) return NULL; + mem = alloc_func ? alloc_func (sizeof (ExifMem)) : + realloc_func (NULL, sizeof (ExifMem)); + if (!mem) return NULL; + mem->ref_count = 1; + + mem->alloc_func = alloc_func; + mem->realloc_func = realloc_func; + mem->free_func = free_func; + + return mem; +} + +void +exif_mem_ref (ExifMem *mem) +{ + if (!mem) return; + mem->ref_count++; +} + +void +exif_mem_unref (ExifMem *mem) +{ + if (!mem) return; + if (!--mem->ref_count) + exif_mem_free (mem, mem); +} + +void +exif_mem_free (ExifMem *mem, void *d) +{ + if (!mem) return; + if (mem->free_func) { + mem->free_func (d); + return; + } +} + +void * +exif_mem_alloc (ExifMem *mem, ExifLong ds) +{ + if (!mem) return NULL; + if (mem->alloc_func || mem->realloc_func) + return mem->alloc_func ? mem->alloc_func (ds) : + mem->realloc_func (NULL, ds); + return NULL; +} + +void * +exif_mem_realloc (ExifMem *mem, void *d, ExifLong ds) +{ + return (mem && mem->realloc_func) ? mem->realloc_func (d, ds) : NULL; +} + +ExifMem * +exif_mem_new_default (void) +{ + return exif_mem_new (exif_mem_alloc_func, exif_mem_realloc_func, + exif_mem_free_func); +} diff --git a/src/libexif/exif-mem.h b/src/libexif/exif-mem.h new file mode 100644 index 0000000..aa774c6 --- /dev/null +++ b/src/libexif/exif-mem.h @@ -0,0 +1,54 @@ +/* exif-mem.h + * + * Copyright © 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_MEM_H__ +#define __EXIF_MEM_H__ + +#include <libexif/exif-utils.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Should work like calloc: Needs to return initialized memory. */ +typedef void * (* ExifMemAllocFunc) (ExifLong); + +typedef void * (* ExifMemReallocFunc) (void *, ExifLong); +typedef void (* ExifMemFreeFunc) (void *); + +typedef struct _ExifMem ExifMem; + +ExifMem *exif_mem_new (ExifMemAllocFunc, ExifMemReallocFunc, + ExifMemFreeFunc); +void exif_mem_ref (ExifMem *); +void exif_mem_unref (ExifMem *); + +void *exif_mem_alloc (ExifMem *, ExifLong); +void *exif_mem_realloc (ExifMem *, void *, ExifLong); +void exif_mem_free (ExifMem *, void *); + +/* For your convenience */ +ExifMem *exif_mem_new_default (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MEM_H__ */ diff --git a/src/libexif/exif-mnote-data-priv.h b/src/libexif/exif-mnote-data-priv.h new file mode 100644 index 0000000..3a13883 --- /dev/null +++ b/src/libexif/exif-mnote-data-priv.h @@ -0,0 +1,76 @@ +/* exif-mnote-data-priv.h + * + * Copyright © 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_MNOTE_DATA_PRIV_H__ +#define __EXIF_MNOTE_DATA_PRIV_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-byte-order.h> +#include <libexif/exif-log.h> + +typedef struct _ExifMnoteDataMethods ExifMnoteDataMethods; +struct _ExifMnoteDataMethods { + + /* Live cycle */ + void (* free) (ExifMnoteData *); + + /* Modification */ + void (* save) (ExifMnoteData *, unsigned char **, unsigned int *); + void (* load) (ExifMnoteData *, const unsigned char *, unsigned int); + void (* set_offset) (ExifMnoteData *, unsigned int); + void (* set_byte_order) (ExifMnoteData *, ExifByteOrder); + + /* Query */ + unsigned int (* count) (ExifMnoteData *); + unsigned int (* get_id) (ExifMnoteData *, unsigned int); + const char * (* get_name) (ExifMnoteData *, unsigned int); + const char * (* get_title) (ExifMnoteData *, unsigned int); + const char * (* get_description) (ExifMnoteData *, unsigned int); + char * (* get_value) (ExifMnoteData *, unsigned int, char *val, unsigned int maxlen); +}; + +typedef struct _ExifMnoteDataPriv ExifMnoteDataPriv; + +struct _ExifMnoteData +{ + ExifMnoteDataPriv *priv; + + ExifMnoteDataMethods methods; + + /* Logging */ + ExifLog *log; + + /* Memory management */ + ExifMem *mem; +}; + +void exif_mnote_data_construct (ExifMnoteData *, ExifMem *mem); +void exif_mnote_data_set_byte_order (ExifMnoteData *, ExifByteOrder); +void exif_mnote_data_set_offset (ExifMnoteData *, unsigned int); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MNOTE_PRIV_H__ */ diff --git a/src/libexif/exif-mnote-data.c b/src/libexif/exif-mnote-data.c new file mode 100644 index 0000000..f55cdd4 --- /dev/null +++ b/src/libexif/exif-mnote-data.c @@ -0,0 +1,158 @@ +/* exif-mnote-data.c + * + * Copyright (C) 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> + +#include <stdlib.h> +#include <string.h> + +struct _ExifMnoteDataPriv +{ + unsigned int ref_count; +}; + +void +exif_mnote_data_construct (ExifMnoteData *d, ExifMem *mem) +{ + if (!d || !mem) return; + if (d->priv) return; + d->priv = exif_mem_alloc (mem, sizeof (ExifMnoteDataPriv)); + if (!d->priv) return; + + d->priv->ref_count = 1; + + d->mem = mem; + exif_mem_ref (mem); +} + +void +exif_mnote_data_ref (ExifMnoteData *d) +{ + if (d && d->priv) d->priv->ref_count++; +} + +static void +exif_mnote_data_free (ExifMnoteData *d) +{ + ExifMem *mem = d ? d->mem : NULL; + + if (!d) return; + if (d->priv) { + if (d->methods.free) d->methods.free (d); + exif_mem_free (mem, d->priv); + d->priv = NULL; + } + exif_log_unref (d->log); + exif_mem_free (mem, d); + exif_mem_unref (mem); +} + +void +exif_mnote_data_unref (ExifMnoteData *d) +{ + if (!d || !d->priv) return; + if (d->priv->ref_count > 0) d->priv->ref_count--; + if (!d->priv->ref_count) + exif_mnote_data_free (d); +} + +void +exif_mnote_data_load (ExifMnoteData *d, const unsigned char *buf, + unsigned int buf_size) +{ + if (!d || !d->methods.load) return; + d->methods.load (d, buf, buf_size); +} + +void +exif_mnote_data_save (ExifMnoteData *d, unsigned char **buf, + unsigned int *buf_size) +{ + if (!d || !d->methods.save) return; + d->methods.save (d, buf, buf_size); +} + +void +exif_mnote_data_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + if (!d || !d->methods.set_byte_order) return; + d->methods.set_byte_order (d, o); +} + +void +exif_mnote_data_set_offset (ExifMnoteData *d, unsigned int o) +{ + if (!d || !d->methods.set_offset) return; + d->methods.set_offset (d, o); +} + +unsigned int +exif_mnote_data_count (ExifMnoteData *d) +{ + if (!d || !d->methods.count) return 0; + return d->methods.count (d); +} + +unsigned int +exif_mnote_data_get_id (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_id) return 0; + return d->methods.get_id (d, n); +} + +const char * +exif_mnote_data_get_name (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_name) return NULL; + return d->methods.get_name (d, n); +} + +const char * +exif_mnote_data_get_title (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_title) return NULL; + return d->methods.get_title (d, n); +} + +const char * +exif_mnote_data_get_description (ExifMnoteData *d, unsigned int n) +{ + if (!d || !d->methods.get_description) return NULL; + return d->methods.get_description (d, n); +} + +char * +exif_mnote_data_get_value (ExifMnoteData *d, unsigned int n, char *val, unsigned int maxlen) +{ + if (!d || !d->methods.get_value) return NULL; + return d->methods.get_value (d, n, val, maxlen); +} + +void +exif_mnote_data_log (ExifMnoteData *d, ExifLog *log) +{ + if (!d) return; + exif_log_unref (d->log); + d->log = log; + exif_log_ref (log); +} diff --git a/src/libexif/exif-mnote-data.h b/src/libexif/exif-mnote-data.h new file mode 100644 index 0000000..015f2ae --- /dev/null +++ b/src/libexif/exif-mnote-data.h @@ -0,0 +1,54 @@ +/* exif-mnote-data.h + * + * Copyright © 2003 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_MNOTE_DATA_H__ +#define __EXIF_MNOTE_DATA_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-log.h> + +typedef struct _ExifMnoteData ExifMnoteData; + +void exif_mnote_data_ref (ExifMnoteData *); +void exif_mnote_data_unref (ExifMnoteData *); + +void exif_mnote_data_load (ExifMnoteData *, const unsigned char *, + unsigned int); +void exif_mnote_data_save (ExifMnoteData *, unsigned char **, unsigned int *); + +unsigned int exif_mnote_data_count (ExifMnoteData *); +unsigned int exif_mnote_data_get_id (ExifMnoteData *, unsigned int); +const char *exif_mnote_data_get_name (ExifMnoteData *, unsigned int); +const char *exif_mnote_data_get_title (ExifMnoteData *, unsigned int); +const char *exif_mnote_data_get_description (ExifMnoteData *, unsigned int); + +/* Returns NULL or val */ +char *exif_mnote_data_get_value (ExifMnoteData *, unsigned int, char *val, unsigned int maxlen); + +void exif_mnote_data_log (ExifMnoteData *, ExifLog *); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_MNOTE_DATA_H__ */ diff --git a/src/libexif/exif-tag.c b/src/libexif/exif-tag.c new file mode 100644 index 0000000..7781611 --- /dev/null +++ b/src/libexif/exif-tag.c @@ -0,0 +1,686 @@ +/* exif-tag.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-tag.h> +#include <libexif/i18n.h> + +#include <stdlib.h> +#include <string.h> + +typedef enum { + ESL_MANDATORY = 1, /* Mandatory */ + ESL_CMANDATORY = 2, /* Conditionally mandatory */ + ESL_OPTIONAL = 3, /* Optional */ + ESL_NOT_RECORDED = 4 /* Not recorded */ +} ExifSL; /* Exif Support Level */ + +static struct { + ExifTag tag; + const char *name; + const char *title; + const char *description; + ExifSL esl_0[4], esl_1[4], esl_exif[4], esl_gps[4]; +} ExifTagTable[] = { + {EXIF_TAG_NEW_SUBFILE_TYPE, "NewSubfileType", + "New Subfile Type", N_("A general indication of the kind of data " + "contained in this subfile.")}, + {EXIF_TAG_INTEROPERABILITY_INDEX, "InteroperabilityIndex", + "InteroperabilityIndex", + N_("Indicates the identification of the Interoperability rule. " + "Use \"R98\" for stating ExifR98 Rules. Four bytes used " + "including the termination code (NULL). see the separate " + "volume of Recommended Exif Interoperability Rules (ExifR98) " + "for other tags used for ExifR98.")}, + {EXIF_TAG_INTEROPERABILITY_VERSION, "InteroperabilityVersion", + "InteroperabilityVersion", ""}, + {EXIF_TAG_IMAGE_WIDTH, "ImageWidth", N_("Image Width"), + N_("The number of columns of image data, equal to the number of " + "pixels per row. In JPEG compressed data a JPEG marker is " + "used instead of this tag."), + {ESL_MANDATORY, ESL_MANDATORY, ESL_MANDATORY, ESL_NOT_RECORDED}}, + {EXIF_TAG_IMAGE_LENGTH, "ImageLength", N_("Image Length"), + N_("The number of rows of image data. In JPEG compressed data a " + "JPEG marker is used instead of this tag."), + {ESL_MANDATORY, ESL_MANDATORY, ESL_MANDATORY, ESL_NOT_RECORDED}}, + {EXIF_TAG_BITS_PER_SAMPLE, "BitsPerSample", N_("Bits per Sample"), + N_("The number of bits per image component. In this standard each " + "component of the image is 8 bits, so the value for this " + "tag is 9. See also <SamplesPerPixel>. In JPEG compressed data " + "a JPEG marker is used instead of this tag."), + {ESL_MANDATORY, ESL_MANDATORY, ESL_MANDATORY, ESL_NOT_RECORDED}}, + {EXIF_TAG_COMPRESSION, "Compression", N_("Compression"), + N_("The compression scheme used for the image data. When a " + "primary image is JPEG compressed, this designation is " + "not necessary and is omitted. When thumbnails use JPEG " + "compression, this tag value is set to 6."), + {ESL_MANDATORY, ESL_MANDATORY, ESL_MANDATORY, ESL_NOT_RECORDED}}, + {EXIF_TAG_PHOTOMETRIC_INTERPRETATION, "PhotometricInterpretation", + N_("Photometric Interpretation"), + N_("The pixel composition. In JPEG compressed data a JPEG " + "marker is used instead of this tag."), + {ESL_MANDATORY, ESL_MANDATORY, ESL_MANDATORY, ESL_NOT_RECORDED}}, + {EXIF_TAG_FILL_ORDER, "FillOrder", N_("Fill Order"), ""}, + {EXIF_TAG_DOCUMENT_NAME, "DocumentName", N_("Document Name"), ""}, + {EXIF_TAG_IMAGE_DESCRIPTION, "ImageDescription", + N_("Image Description"), + N_("A character string giving the title of the image. It may be " + "a comment such as \"1988 company picnic\" or " + "the like. Two-bytes character codes cannot be used. " + "When a 2-bytes code is necessary, the Exif Private tag " + "<UserComment> is to be used."), + {ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY}}, + {EXIF_TAG_MAKE, "Make", N_("Manufacturer"), + N_("The manufacturer of the recording " + "equipment. This is the manufacturer of the DSC, scanner, " + "video digitizer or other equipment that generated the " + "image. When the field is left blank, it is treated as " + "unknown."), + {ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY}}, + {EXIF_TAG_MODEL, "Model", N_("Model"), + N_("The model name or model number of the equipment. This is the " + "model name or number of the DSC, scanner, video digitizer " + "or other equipment that generated the image. When the field " + "is left blank, it is treated as unknown."), + {ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY}}, + {EXIF_TAG_STRIP_OFFSETS, "StripOffsets", N_("Strip Offsets"), + N_("For each strip, the byte offset of that strip. It is " + "recommended that this be selected so the number of strip " + "bytes does not exceed 64 Kbytes. With JPEG compressed " + "data this designation is not needed and is omitted. See also " + "<RowsPerStrip> and <StripByteCounts>."), + {ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY}}, + {EXIF_TAG_ORIENTATION, "Orientation", N_("Orientation"), + N_("The image orientation viewed in terms of rows and columns."), + {ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY, ESL_CMANDATORY}}, + {EXIF_TAG_SAMPLES_PER_PIXEL, "SamplesPerPixel", + N_("Samples per Pixel"), + N_("The number of components per pixel. Since this standard applies " + "to RGB and YCbCr images, the value set for this tag is 3. " + "In JPEG compressed data a JPEG marker is used instead of this " + "tag.")}, + {EXIF_TAG_ROWS_PER_STRIP, "RowsPerStrip", N_("Rows per Strip"), + N_("The number of rows per strip. This is the number of rows " + "in the image of one strip when an image is divided into " + "strips. With JPEG compressed data this designation is not " + "needed and is omitted. See also <RowsPerStrip> and " + "<StripByteCounts>.")}, + {EXIF_TAG_STRIP_BYTE_COUNTS, "StripByteCounts", N_("Strip Byte Count"), + N_("The total number of bytes in each strip. With JPEG compressed " + "data this designation is not needed and is omitted.")}, + {EXIF_TAG_X_RESOLUTION, "XResolution", N_("x-Resolution"), + N_("The number of pixels per <ResolutionUnit> in the <ImageWidth> " + "direction. When the image resolution is unknown, 72 [dpi] " + "is designated.")}, + {EXIF_TAG_Y_RESOLUTION, "YResolution", N_("y-Resolution"), + N_("The number of pixels per <ResolutionUnit> in the <ImageLength> " + "direction. The same value as <XResolution> is designated.")}, + {EXIF_TAG_PLANAR_CONFIGURATION, "PlanarConfiguration", + N_("Planar Configuration"), + N_("Indicates whether pixel components are recorded in a chunky " + "or planar format. In JPEG compressed files a JPEG marker " + "is used instead of this tag. If this field does not exist, " + "the TIFF default of 1 (chunky) is assumed.")}, + {EXIF_TAG_RESOLUTION_UNIT, "ResolutionUnit", N_("Resolution Unit"), + N_("The unit for measuring <XResolution> and <YResolution>. The same " + "unit is used for both <XResolution> and <YResolution>. If " + "the image resolution is unknown, 2 (inches) is designated.")}, + {EXIF_TAG_TRANSFER_FUNCTION, "TransferFunction", + N_("Transfer Function"), + N_("A transfer function for the image, described in tabular style. " + "Normally this tag is not necessary, since color space is " + "specified in the color space information tag (<ColorSpace>).")}, + {EXIF_TAG_SOFTWARE, "Software", N_("Software"), + N_("This tag records the name and version of the software or " + "firmware of the camera or image input device used to " + "generate the image. The detailed format is not specified, but " + "it is recommended that the example shown below be " + "followed. When the field is left blank, it is treated as " + "unknown.")}, + {EXIF_TAG_DATE_TIME, "DateTime", N_("Date and Time"), + N_("The date and time of image creation. In this standard " + "(EXIF-2.1) it is the date and time the file was changed.")}, + {EXIF_TAG_ARTIST, "Artist", N_("Artist"), + N_("This tag records the name of the camera owner, photographer or " + "image creator. The detailed format is not specified, but it is " + "recommended that the information be written as in the example " + "below for ease of Interoperability. When the field is " + "left blank, it is treated as unknown.")}, + {EXIF_TAG_WHITE_POINT, "WhitePoint", N_("White Point"), + N_("The chromaticity of the white point of the image. Normally " + "this tag is not necessary, since color space is specified " + "in the colorspace information tag (<ColorSpace>).")}, + {EXIF_TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", + N_("Primary Chromaticities"), + N_("The chromaticity of the three primary colors of the image. " + "Normally this tag is not necessary, since colorspace is " + "specified in the colorspace information tag (<ColorSpace>).")}, + {EXIF_TAG_TRANSFER_RANGE, "TransferRange", N_("Transfer Range"), ""}, + {EXIF_TAG_SUB_IFDS, "SubIFDs", "SubIFD Offsets", N_("Defined by Adobe Corporation " + "to enable TIFF Trees within a TIFF file.")}, + {EXIF_TAG_JPEG_PROC, "JPEGProc", "JPEGProc", ""}, + {EXIF_TAG_JPEG_INTERCHANGE_FORMAT, "JPEGInterchangeFormat", + N_("JPEG Interchange Format"), + N_("The offset to the start byte (SOI) of JPEG compressed " + "thumbnail data. This is not used for primary image " + "JPEG data.")}, + {EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, + "JPEGInterchangeFormatLength", N_("JPEG Interchange Format Length"), + N_("The number of bytes of JPEG compressed thumbnail data. This " + "is not used for primary image JPEG data. JPEG thumbnails " + "are not divided but are recorded as a continuous JPEG " + "bitstream from SOI to EOI. Appn and COM markers should " + "not be recorded. Compressed thumbnails must be recorded in no " + "more than 64 Kbytes, including all other data to be " + "recorded in APP1.")}, + {EXIF_TAG_YCBCR_COEFFICIENTS, "YCbCrCoefficients", + N_("YCbCr Coefficients"), + N_("The matrix coefficients for transformation from RGB to YCbCr " + "image data. No default is given in TIFF; but here the " + "value given in Appendix E, \"Color Space Guidelines\", is used " + "as the default. The color space is declared in a " + "color space information tag, with the default being the value " + "that gives the optimal image characteristics " + "Interoperability this condition.")}, + {EXIF_TAG_YCBCR_SUB_SAMPLING, "YCbCrSubSampling", + N_("YCbCr Sub-Sampling"), + N_("The sampling ratio of chrominance components in relation to the " + "luminance component. In JPEG compressed data a JPEG marker " + "is used instead of this tag.")}, + {EXIF_TAG_YCBCR_POSITIONING, "YCbCrPositioning", + N_("YCbCr Positioning"), + N_("The position of chrominance components in relation to the " + "luminance component. This field is designated only for " + "JPEG compressed data or uncompressed YCbCr data. The TIFF " + "default is 1 (centered); but when Y:Cb:Cr = 4:2:2 it is " + "recommended in this standard that 2 (co-sited) be used to " + "record data, in order to improve the image quality when viewed " + "on TV systems. When this field does not exist, the reader shall " + "assume the TIFF default. In the case of Y:Cb:Cr = 4:2:0, the " + "TIFF default (centered) is recommended. If the reader " + "does not have the capability of supporting both kinds of " + "<YCbCrPositioning>, it shall follow the TIFF default regardless " + "of the value in this field. It is preferable that readers " + "be able to support both centered and co-sited positioning.")}, + {EXIF_TAG_REFERENCE_BLACK_WHITE, "ReferenceBlackWhite", + N_("Reference Black/White"), + N_("The reference black point value and reference white point " + "value. No defaults are given in TIFF, but the values " + "below are given as defaults here. The color space is declared " + "in a color space information tag, with the default " + "being the value that gives the optimal image characteristics " + "Interoperability these conditions.")}, + {EXIF_TAG_XML_PACKET, "XMLPacket", N_("XML Packet"), N_("XMP Metadata")}, + {EXIF_TAG_RELATED_IMAGE_FILE_FORMAT, "RelatedImageFileFormat", + "RelatedImageFileFormat", ""}, + {EXIF_TAG_RELATED_IMAGE_WIDTH, "RelatedImageWidth", + "RelatedImageWidth", ""}, + {EXIF_TAG_RELATED_IMAGE_LENGTH, "RelatedImageLength", + "RelatedImageLength", ""}, + {EXIF_TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", + "CFARepeatPatternDim", ""}, + {EXIF_TAG_CFA_PATTERN, "CFAPattern", + N_("CFA Pattern"), + N_("Indicates the color filter array (CFA) geometric pattern of the " + "image sensor when a one-chip color area sensor is used. " + "It does not apply to all sensing methods.")}, + {EXIF_TAG_BATTERY_LEVEL, "BatteryLevel", N_("Battery Level"), ""}, + {EXIF_TAG_COPYRIGHT, "Copyright", N_("Copyright"), + N_("Copyright information. In this standard the tag is used to " + "indicate both the photographer and editor copyrights. It is " + "the copyright notice of the person or organization claiming " + "rights to the image. The Interoperability copyright " + "statement including date and rights should be written in this " + "field; e.g., \"Copyright, John Smith, 19xx. All rights " + "reserved.\". In this standard the field records both the " + "photographer and editor copyrights, with each recorded in a " + "separate part of the statement. When there is a clear " + "distinction between the photographer and editor copyrights, " + "these are to be written in the order of photographer followed " + "by editor copyright, separated by NULL (in this case, " + "since the statement also ends with a NULL, there are two NULL " + "codes) (see example 1). When only the photographer is given, " + "it is terminated by one NULL code (see example 2). When only " + "the editor copyright is given, " + "the photographer copyright part consists of one space followed " + "by a terminating NULL code, then the editor copyright is given " + "(see example 3). When the field is left blank, it is treated " + "as unknown.")}, + {EXIF_TAG_EXPOSURE_TIME, "ExposureTime", N_("Exposure Time"), + N_("Exposure time, given in seconds (sec).")}, + {EXIF_TAG_FNUMBER, "FNumber", N_("FNumber"), + N_("The F number.")}, + {EXIF_TAG_IPTC_NAA, "IPTC/NAA", "IPTC/NAA", ""}, + {EXIF_TAG_IMAGE_RESOURCES, "ImageResources", N_("Image Resources Block"), ""}, + {EXIF_TAG_EXIF_IFD_POINTER, "ExifIFDPointer", "ExifIFDPointer", + N_("A pointer to the Exif IFD. Interoperability, Exif IFD has the " + "same structure as that of the IFD specified in TIFF. " + "ordinarily, however, it does not contain image data as in " + "the case of TIFF.")}, + {EXIF_TAG_INTER_COLOR_PROFILE, "InterColorProfile", + "InterColorProfile", ""}, + {EXIF_TAG_EXPOSURE_PROGRAM, "ExposureProgram", "ExposureProgram", + N_("The class of the program used by the camera to set exposure " + "when the picture is taken.")}, + {EXIF_TAG_SPECTRAL_SENSITIVITY, "SpectralSensitivity", + N_("Spectral Sensitivity"), + N_("Indicates the spectral sensitivity of each channel of the " + "camera used. The tag value is an ASCII string compatible " + "with the standard developed by the ASTM Technical committee.")}, + {EXIF_TAG_GPS_INFO_IFD_POINTER, "GPSInfoIFDPointer", + "GPSInfoIFDPointer", + N_("A pointer to the GPS Info IFD. The " + "Interoperability structure of the GPS Info IFD, like that of " + "Exif IFD, has no image data.")}, +#if 0 + {EXIF_TAG_GPS_VERSION_ID, "GPSVersionID", "", + N_("Indicates the version of <GPSInfoIFD>. The version is given " + "as 2.0.0.0. This tag is mandatory when <GPSInfo> tag is " + "present. (Note: The <GPSVersionID tag is given in bytes, " + "unlike the <ExifVersion> tag. When the version is " + "2.0.0.0, the tag value is 02000000.H).")}, + {EXIF_TAG_GPS_LATITUDE_REF, "GPSLatitudeRef", "" + N_("Indicates whether the latitude is north or south latitude. The " + "ASCII value 'N' indicates north latitude, and 'S' is south " + "latitude.")}, + {EXIF_TAG_GPS_LATITUDE, "GPSLatitude", "" + N_("Indicates the latitude. The latitude is expressed as three " + "RATIONAL values giving the degrees, minutes, and seconds, " + "respectively. When degrees, minutes and seconds are expressed, " + "the format is dd/1,mm/1,ss/1. When degrees and minutes are used " + "and, for example, fractions of minutes are given up to two " + "two decimal places, the format is dd/1,mmmm/100,0/1.")}, + {EXIF_TAG_GPS_LONGITUDE_REF, "GPSLongitudeRef", "" + N_("Indicates whether the longitude is east or west longitude. " + "ASCII 'E' indicates east longitude, and 'W' is west " + "longitude.")}, + {EXIF_TAG_GPS_LONGITUDE, "GPSLongitude", "" + N_("Indicates the longitude. The longitude is expressed as three " + "RATIONAL values giving the degrees, minutes, and seconds, " + "respectively. When degrees, minutes and seconds are expressed, " + "the format is ddd/1,mm/1,ss/1. When degrees and minutes are " + "used and, for example, fractions of minutes are given up to " + "two decimal places, the format is ddd/1,mmmm/100,0/1.")}, +#endif + {EXIF_TAG_ISO_SPEED_RATINGS, "ISOSpeedRatings", + N_("ISO Speed Ratings"), + N_("Indicates the ISO Speed and ISO Latitude of the camera or " + "input device as specified in ISO 12232.")}, + {EXIF_TAG_OECF, "OECF", "OECF", + N_("Indicates the Opto-Electoric Conversion Function (OECF) " + "specified in ISO 14524. <OECF> is the relationship between " + "the camera optical input and the image values.")}, + {EXIF_TAG_EXIF_VERSION, "ExifVersion", N_("Exif Version"), + N_("The version of this standard supported. Nonexistence of this " + "field is taken to mean nonconformance to the standard.")}, + {EXIF_TAG_DATE_TIME_ORIGINAL, "DateTimeOriginal", + N_("Date and Time (original)"), + N_("The date and time when the original image data was generated. " + "For a digital still camera " + "the date and time the picture was taken are recorded.")}, + {EXIF_TAG_DATE_TIME_DIGITIZED, "DateTimeDigitized", + N_("Date and Time (digitized)"), + N_("The date and time when the image was stored as digital data. ")}, + {EXIF_TAG_COMPONENTS_CONFIGURATION, "ComponentsConfiguration", + "ComponentsConfiguration", + N_("Information specific to compressed data. The channels of " + "each component are arranged in order from the 1st " + "component to the 4th. For uncompressed data the data " + "arrangement is given in the <PhotometricInterpretation> tag. " + "However, since <PhotometricInterpretation> can only " + "express the order of Y, Cb and Cr, this tag is provided " + "for cases when compressed data uses components other than " + "Y, Cb, and Cr and to enable support of other sequences.")}, + {EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, "CompressedBitsPerPixel", + N_("Compressed Bits per Pixel"), + N_("Information specific to compressed data. The compression mode " + "used for a compressed image is indicated in unit bits " + "per pixel.")}, + {EXIF_TAG_SHUTTER_SPEED_VALUE, "ShutterSpeedValue", N_("Shutter speed"), + N_("Shutter speed. The unit is the APEX (Additive System of " + "Photographic Exposure) setting (see Appendix C).")}, + {EXIF_TAG_APERTURE_VALUE, "ApertureValue", N_("Aperture"), + N_("The lens aperture. The unit is the APEX value.")}, + {EXIF_TAG_BRIGHTNESS_VALUE, "BrightnessValue", N_("Brightness"), + N_("The value of brightness. The unit is the APEX value. " + "Ordinarily it is given in the range of -99.99 to 99.99.")}, + {EXIF_TAG_EXPOSURE_BIAS_VALUE, "ExposureBiasValue", + N_("Exposure Bias"), + N_("The exposure bias. The units is the APEX value. Ordinarily " + "it is given in the range of -99.99 to 99.99.")}, + {EXIF_TAG_MAX_APERTURE_VALUE, "MaxApertureValue", "MaxApertureValue", + N_("The smallest F number of the lens. The unit is the APEX value. " + "Ordinarily it is given in the range of 00.00 to 99.99, " + "but it is not limited to this range.")}, + {EXIF_TAG_SUBJECT_DISTANCE, "SubjectDistance", + N_("Subject Distance"), + N_("The distance to the subject, given in meters.")}, + {EXIF_TAG_METERING_MODE, "MeteringMode", N_("Metering Mode"), + N_("The metering mode.")}, + {EXIF_TAG_LIGHT_SOURCE, "LightSource", N_("Light Source"), + N_("The kind of light source.")}, + {EXIF_TAG_FLASH, "Flash", N_("Flash"), + N_("This tag is recorded when an image is taken using a strobe " + "light (flash).")}, + {EXIF_TAG_FOCAL_LENGTH, "FocalLength", N_("Focal Length"), + N_("The actual focal length of the lens, in mm. Conversion is not " + "made to the focal length of a 35 mm film camera.")}, + {EXIF_TAG_MAKER_NOTE, "MakerNote", N_("Maker Note"), + N_("A tag for manufacturers of Exif writers to record any desired " + "information. The contents are up to the manufacturer.")}, + {EXIF_TAG_USER_COMMENT, "UserComment", N_("User Comment"), + N_("A tag for Exif users to write keywords or comments on the image " + "besides those in <ImageDescription>, and without the " + "character code limitations of the <ImageDescription> tag. The " + "character code used in the <UserComment> tag is identified " + "based on an ID code in a fixed 8-byte area at the start of " + "the tag data area. The unused portion of the area is padded " + "with NULL (\"00.h\"). ID codes are assigned by means of " + "registration. The designation method and references for each " + "character code are given in Table 6. The value of CountN " + "is determinated based on the 8 bytes in the character code " + "area and the number of bytes in the user comment part. Since " + "the TYPE is not ASCII, NULL termination is not necessary " + "(see Fig. 9). " + "The ID code for the <UserComment> area may be a Defined code " + "such as JIS or ASCII, or may be Undefined. The Undefined name " + "is UndefinedText, and the ID code is filled with 8 bytes of all " + "\"NULL\" (\"00.H\"). An Exif reader that reads the " + "<UserComment> tag must have a function for determining the " + "ID code. This function is not required in Exif readers that " + "do not use the <UserComment> tag (see Table 7). " + "When a <UserComment> area is set aside, it is recommended that " + "the ID code be ASCII and that the following user comment " + "part be filled with blank characters [20.H].")}, + {EXIF_TAG_SUB_SEC_TIME, "SubsecTime", "SubsecTime", + N_("A tag used to record fractions of seconds for the " + "<DateTime> tag.")}, + {EXIF_TAG_SUB_SEC_TIME_ORIGINAL, "SubSecTimeOriginal", + "SubSecTimeOriginal", + N_("A tag used to record fractions of seconds for the " + "<DateTimeOriginal> tag.")}, + {EXIF_TAG_SUB_SEC_TIME_DIGITIZED, "SubSecTimeDigitized", + "SubSecTimeDigitized", + N_("A tag used to record fractions of seconds for the " + "<DateTimeDigitized> tag.")}, + {EXIF_TAG_FLASH_PIX_VERSION, "FlashPixVersion", "FlashPixVersion", + N_("The FlashPix format version supported by a FPXR file.")}, + {EXIF_TAG_COLOR_SPACE, "ColorSpace", N_("Color Space"), + N_("The color space information tag is always " + "recorded as the color space specifier. Normally sRGB (=1) " + "is used to define the color space based on the PC monitor " + "conditions and environment. If a color space other than " + "sRGB is used, Uncalibrated (=FFFF.H) is set. Image data " + "recorded as Uncalibrated can be treated as sRGB when it is " + "converted to FlashPix. On sRGB see Appendix E.")}, + {EXIF_TAG_PIXEL_X_DIMENSION, "PixelXDimension", "PixelXDimension", + N_("Information specific to compressed data. When a " + "compressed file is recorded, the valid width of the " + "meaningful image must be recorded in this tag, whether or " + "not there is padding data or a restart marker. This tag " + "should not exist in an uncompressed file. For details see " + "section 2.8.1 and Appendix F.")}, + {EXIF_TAG_PIXEL_Y_DIMENSION, "PixelYDimension", "PixelYDimension", + N_("Information specific to compressed data. When a compressed " + "file is recorded, the valid height of the meaningful image " + "must be recorded in this tag, whether or not there is padding " + "data or a restart marker. This tag should not exist in an " + "uncompressed file. For details see section 2.8.1 and Appendix " + "F. Since data padding is unnecessary in the vertical direction, " + "the number of lines recorded in this valid image height tag " + "will in fact be the same as that recorded in the SOF.")}, + {EXIF_TAG_RELATED_SOUND_FILE, "RelatedSoundFile", + "RelatedSoundFile", + N_("This tag is used to record the name of an audio file related " + "to the image data. The only relational information " + "recorded here is the Exif audio file name and extension (an " + "ASCII string consisting of 8 characters + '.' + 3 " + "characters). The path is not recorded. Stipulations on audio " + "are given in section 3.6.3. File naming conventions are " + "given in section 3.7.1. " + "When using this tag, audio files must be recorded in " + "conformance to the Exif audio format. Writers are also allowed " + "to store the data such as Audio within APP2 as FlashPix " + "extension stream data. " + "Audio files must be recorded in conformance to the Exif audio " + "format. The mapping of Exif image files and audio files is done " + "in any of the three ways shown in Table 8. If multiple files " + "are mapped to one file as in [2] or [3] of this table, the above " + "format is used to record just one audio file name. If " + "there are multiple audio files, the first recorded file is " + "given. In the case of [3] in Table 8, for example, for the " + "Exif image file \"DSC00001.JPG\" only \"SND00001.WAV\" is " + "given as the related Exif audio file. When there are three " + "Exif audio files \"SND00001.WAV\", \"SND00002.WAV\" and " + "\"SND00003.WAV\", the Exif image file name for each of them, " + "\"DSC00001.JPG\", is indicated. By combining multiple " + "relational information, a variety of playback possibilities " + "can be supported. The method of using relational information " + "is left to the implementation on the playback side. Since this " + "information is an ASCII character string, it is terminated by " + "NULL. When this tag is used to map audio files, the relation " + "of the audio file to image data must also be indicated on the " + "audio file end.")}, + {EXIF_TAG_INTEROPERABILITY_IFD_POINTER, "InteroperabilityIFDPointer", + "InteroperabilityIFDPointer", + N_("Interoperability IFD is composed of tags which stores the " + "information to ensure the Interoperability and pointed " + "by the following tag located in Exif IFD. " + "The Interoperability structure of Interoperability IFD is " + "the same as TIFF defined IFD structure " + "but does not contain the " + "image data characteristically compared with normal TIFF " + "IFD.")}, + {EXIF_TAG_FLASH_ENERGY, "FlashEnergy", N_("Flash Energy"), + N_("Indicates the strobe energy at the time the image is " + "captured, as measured in Beam Candle Power Seconds (BCPS).")}, + {EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, "SpatialFrequencyResponse", + N_("Spatial Frequency Response"), + N_("This tag records the camera or input device spatial frequency " + "table and SFR values in the direction of image width, " + "image height, and diagonal direction, as specified in ISO " + "12233.")}, + {EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, "FocalPlaneXResolution", + N_("Focal Plane x-Resolution"), + N_("Indicates the number of pixels in the image width (X) direction " + "per <FocalPlaneResolutionUnit> on the camera focal plane.")}, + {EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, "FocalPlaneYResolution", + N_("Focal Plane y-Resolution"), + N_("Indicates the number of pixels in the image height (V) direction " + "per <FocalPlaneResolutionUnit> on the camera focal plane.")}, + {EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, "FocalPlaneResolutionUnit", + N_("Focal Plane Resolution Unit"), + N_("Indicates the unit for measuring <FocalPlaneXResolution> and " + "<FocalPlaneYResolution>. This value is the same as the " + "<ResolutionUnit>.")}, + {EXIF_TAG_SUBJECT_LOCATION, "SubjectLocation", + N_("Subject Location"), + N_("Indicates the location of the main subject in the scene. The " + "value of this tag represents the pixel at the center of the " + "main subject relative to the left edge, prior to rotation " + "processing as per the <Rotation> tag. The first value " + "indicates the X column number and second indicates " + "the Y row number.")}, + {EXIF_TAG_EXPOSURE_INDEX, "ExposureIndex", N_("Exposure index"), + N_("Indicates the exposure index selected on the camera or " + "input device at the time the image is captured.")}, + {EXIF_TAG_SENSING_METHOD, "SensingMethod", N_("Sensing Method"), + N_("Indicates the image sensor type on the camera or input " + "device.")}, + {EXIF_TAG_FILE_SOURCE, "FileSource", N_("File Source"), + N_("Indicates the image source. If a DSC recorded the image, " + "this tag value of this tag always be set to 3, indicating " + "that the image was recorded on a DSC.")}, + {EXIF_TAG_SCENE_TYPE, "SceneType", N_("Scene Type"), + N_("Indicates the type of scene. If a DSC recorded the image, " + "this tag value must always be set to 1, indicating that the " + "image was directly photographed.")}, + {EXIF_TAG_NEW_CFA_PATTERN, "CFAPattern", + N_("CFA Pattern"), + N_("Indicates the color filter array (CFA) geometric pattern of the " + "image sensor when a one-chip color area sensor is used. " + "It does not apply to all sensing methods.")}, + {EXIF_TAG_SUBJECT_AREA, "SubjectArea", N_("Subject Area"), + N_("This tag indicates the location and area of the main subject " + "in the overall scene.")}, + {EXIF_TAG_TIFF_EP_STANDARD_ID, "TIFF/EPStandardID", N_("TIFF/EP Standard ID"), ""}, + {EXIF_TAG_CUSTOM_RENDERED, "CustomRendered", N_("Custom Rendered"), + N_("This tag indicates the use of special processing on image " + "data, such as rendering geared to output. When special " + "processing is performed, the reader is expected to disable " + "or minimize any further processing.")}, + {EXIF_TAG_EXPOSURE_MODE, "ExposureMode", N_("Exposure Mode"), + N_("This tag indicates the exposure mode set when the image was " + "shot. In auto-bracketing mode, the camera shoots a series of " + "frames of the same scene at different exposure settings.")}, + {EXIF_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), + N_("This tag indicates the white balance mode set when the image " + "was shot.")}, + {EXIF_TAG_DIGITAL_ZOOM_RATIO, "DigitalZoomRatio", + N_("Digital Zoom Ratio"), + N_("This tag indicates the digital zoom ratio when the image was " + "shot. If the numerator of the recorded value is 0, this " + "indicates that digital zoom was not used.")}, + {EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, "FocalLengthIn35mmFilm", + N_("Focal Length In 35mm Film"), + N_("This tag indicates the equivalent focal length assuming a " + "35mm film camera, in mm. A value of 0 means the focal " + "length is unknown. Note that this tag differs from the " + "FocalLength tag.")}, + {EXIF_TAG_SCENE_CAPTURE_TYPE, "SceneCaptureType", + N_("Scene Capture Type"), + N_("This tag indicates the type of scene that was shot. It can " + "also be used to record the mode in which the image was " + "shot. Note that this differs from the scene type " + "(SceneType) tag.")}, + {EXIF_TAG_GAIN_CONTROL, "GainControl", N_("Gain Control"), + N_("This tag indicates the degree of overall image gain " + "adjustment.")}, + {EXIF_TAG_CONTRAST, "Contrast", N_("Contrast"), + N_("This tag indicates the direction of contrast processing " + "applied by the camera when the image was shot.")}, + {EXIF_TAG_SATURATION, "Saturation", N_("Saturation"), + N_("This tag indicates the direction of saturation processing " + "applied by the camera when the image was shot.")}, + {EXIF_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), + N_("This tag indicates the direction of sharpness processing " + "applied by the camera when the image was shot.")}, + {EXIF_TAG_DEVICE_SETTING_DESCRIPTION, "DeviceSettingDescription", + N_("Device Setting Description"), + N_("This tag indicates information on the picture-taking " + "conditions of a particular camera model. The tag is used " + "only to indicate the picture-taking conditions in the " + "reader.")}, + {EXIF_TAG_SUBJECT_DISTANCE_RANGE, "SubjectDistanceRange", + N_("Subject Distance Range"), + N_("This tag indicates the distance to the subject.")}, + {EXIF_TAG_IMAGE_UNIQUE_ID, "ImageUniqueID", N_("Image Unique ID"), + N_("This tag indicates an identifier assigned uniquely to " + "each image. It is recorded as an ASCII string equivalent " + "to hexadecimal notation and 128-bit fixed length.")}, + {0, NULL, NULL, NULL} +}; + +/* For now, do not use these functions. */ +ExifTag exif_tag_table_get_tag (unsigned int n); +const char *exif_tag_table_get_name (unsigned int n); +unsigned int exif_tag_table_count (void); + +ExifTag +exif_tag_table_get_tag (unsigned int n) +{ + return (n < exif_tag_table_count ()) ? ExifTagTable[n].tag : 0; +} + +const char * +exif_tag_table_get_name (unsigned int n) +{ + return (n < exif_tag_table_count ()) ? ExifTagTable[n].name : NULL; +} + +unsigned int +exif_tag_table_count (void) +{ + return sizeof (ExifTagTable) / sizeof (ExifTagTable[0]); +} + +const char * +exif_tag_get_name (ExifTag tag) +{ + unsigned int i; + + for (i = 0; ExifTagTable[i].name; i++) + if (ExifTagTable[i].tag == tag) + break; + + return ExifTagTable[i].name; +} + +const char * +exif_tag_get_title (ExifTag tag) +{ + unsigned int i; + + /* FIXME: This belongs to somewhere else. */ + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + for (i = 0; ExifTagTable[i].title; i++) + if (ExifTagTable[i].tag == tag) break; + return _(ExifTagTable[i].title); +} + +const char * +exif_tag_get_description (ExifTag tag) +{ + unsigned int i; + + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + + for (i = 0; ExifTagTable[i].description; i++) + if (ExifTagTable[i].tag == tag) break; + return _(ExifTagTable[i].description); +} + +ExifTag +exif_tag_from_name (const char *name) +{ + unsigned int i; + + if (!name) return 0; + + for (i = 0; ExifTagTable[i].name; i++) + if (!strcmp (ExifTagTable[i].name, name)) break; + return ExifTagTable[i].tag; +} + +const char * +exif_tag_get_name_index (unsigned int i, ExifTag *tag) +{ + if (!ExifTagTable[i].name) + return NULL; + + *tag = ExifTagTable[i].tag; + + return (ExifTagTable[i].name); +} + diff --git a/src/libexif/exif-tag.h b/src/libexif/exif-tag.h new file mode 100644 index 0000000..f928374 --- /dev/null +++ b/src/libexif/exif-tag.h @@ -0,0 +1,148 @@ +/* exif-tag.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_TAG_H__ +#define __EXIF_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum { + EXIF_TAG_INTEROPERABILITY_INDEX = 0x0001, + EXIF_TAG_INTEROPERABILITY_VERSION = 0x0002, + EXIF_TAG_NEW_SUBFILE_TYPE = 0x00fe, + EXIF_TAG_IMAGE_WIDTH = 0x0100, + EXIF_TAG_IMAGE_LENGTH = 0x0101, + EXIF_TAG_BITS_PER_SAMPLE = 0x0102, + EXIF_TAG_COMPRESSION = 0x0103, + EXIF_TAG_PHOTOMETRIC_INTERPRETATION = 0x0106, + EXIF_TAG_FILL_ORDER = 0x010a, + EXIF_TAG_DOCUMENT_NAME = 0x010d, + EXIF_TAG_IMAGE_DESCRIPTION = 0x010e, + EXIF_TAG_MAKE = 0x010f, + EXIF_TAG_MODEL = 0x0110, + EXIF_TAG_STRIP_OFFSETS = 0x0111, + EXIF_TAG_ORIENTATION = 0x0112, + EXIF_TAG_SAMPLES_PER_PIXEL = 0x0115, + EXIF_TAG_ROWS_PER_STRIP = 0x0116, + EXIF_TAG_STRIP_BYTE_COUNTS = 0x0117, + EXIF_TAG_X_RESOLUTION = 0x011a, + EXIF_TAG_Y_RESOLUTION = 0x011b, + EXIF_TAG_PLANAR_CONFIGURATION = 0x011c, + EXIF_TAG_RESOLUTION_UNIT = 0x0128, + EXIF_TAG_TRANSFER_FUNCTION = 0x012d, + EXIF_TAG_SOFTWARE = 0x0131, + EXIF_TAG_DATE_TIME = 0x0132, + EXIF_TAG_ARTIST = 0x013b, + EXIF_TAG_WHITE_POINT = 0x013e, + EXIF_TAG_PRIMARY_CHROMATICITIES = 0x013f, + EXIF_TAG_TRANSFER_RANGE = 0x0156, + EXIF_TAG_SUB_IFDS = 0x014a, + EXIF_TAG_JPEG_PROC = 0x0200, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT = 0x0201, + EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = 0x0202, + EXIF_TAG_YCBCR_COEFFICIENTS = 0x0211, + EXIF_TAG_YCBCR_SUB_SAMPLING = 0x0212, + EXIF_TAG_YCBCR_POSITIONING = 0x0213, + EXIF_TAG_REFERENCE_BLACK_WHITE = 0x0214, + EXIF_TAG_XML_PACKET = 0x02bc, + EXIF_TAG_RELATED_IMAGE_FILE_FORMAT = 0x1000, + EXIF_TAG_RELATED_IMAGE_WIDTH = 0x1001, + EXIF_TAG_RELATED_IMAGE_LENGTH = 0x1002, + EXIF_TAG_CFA_REPEAT_PATTERN_DIM = 0x828d, + EXIF_TAG_CFA_PATTERN = 0x828e, + EXIF_TAG_BATTERY_LEVEL = 0x828f, + EXIF_TAG_COPYRIGHT = 0x8298, + EXIF_TAG_EXPOSURE_TIME = 0x829a, + EXIF_TAG_FNUMBER = 0x829d, + EXIF_TAG_IPTC_NAA = 0x83bb, + EXIF_TAG_IMAGE_RESOURCES = 0x8649, + EXIF_TAG_EXIF_IFD_POINTER = 0x8769, + EXIF_TAG_INTER_COLOR_PROFILE = 0x8773, + EXIF_TAG_EXPOSURE_PROGRAM = 0x8822, + EXIF_TAG_SPECTRAL_SENSITIVITY = 0x8824, + EXIF_TAG_GPS_INFO_IFD_POINTER = 0x8825, + EXIF_TAG_ISO_SPEED_RATINGS = 0x8827, + EXIF_TAG_OECF = 0x8828, + EXIF_TAG_EXIF_VERSION = 0x9000, + EXIF_TAG_DATE_TIME_ORIGINAL = 0x9003, + EXIF_TAG_DATE_TIME_DIGITIZED = 0x9004, + EXIF_TAG_COMPONENTS_CONFIGURATION = 0x9101, + EXIF_TAG_COMPRESSED_BITS_PER_PIXEL = 0x9102, + EXIF_TAG_SHUTTER_SPEED_VALUE = 0x9201, + EXIF_TAG_APERTURE_VALUE = 0x9202, + EXIF_TAG_BRIGHTNESS_VALUE = 0x9203, + EXIF_TAG_EXPOSURE_BIAS_VALUE = 0x9204, + EXIF_TAG_MAX_APERTURE_VALUE = 0x9205, + EXIF_TAG_SUBJECT_DISTANCE = 0x9206, + EXIF_TAG_METERING_MODE = 0x9207, + EXIF_TAG_LIGHT_SOURCE = 0x9208, + EXIF_TAG_FLASH = 0x9209, + EXIF_TAG_FOCAL_LENGTH = 0x920a, + EXIF_TAG_SUBJECT_AREA = 0x9214, + EXIF_TAG_TIFF_EP_STANDARD_ID = 0x9216, + EXIF_TAG_MAKER_NOTE = 0x927c, + EXIF_TAG_USER_COMMENT = 0x9286, + EXIF_TAG_SUB_SEC_TIME = 0x9290, + EXIF_TAG_SUB_SEC_TIME_ORIGINAL = 0x9291, + EXIF_TAG_SUB_SEC_TIME_DIGITIZED = 0x9292, + EXIF_TAG_FLASH_PIX_VERSION = 0xa000, + EXIF_TAG_COLOR_SPACE = 0xa001, + EXIF_TAG_PIXEL_X_DIMENSION = 0xa002, + EXIF_TAG_PIXEL_Y_DIMENSION = 0xa003, + EXIF_TAG_RELATED_SOUND_FILE = 0xa004, + EXIF_TAG_INTEROPERABILITY_IFD_POINTER = 0xa005, + EXIF_TAG_FLASH_ENERGY = 0xa20b, + EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE = 0xa20c, + EXIF_TAG_FOCAL_PLANE_X_RESOLUTION = 0xa20e, + EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION = 0xa20f, + EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT = 0xa210, + EXIF_TAG_SUBJECT_LOCATION = 0xa214, + EXIF_TAG_EXPOSURE_INDEX = 0xa215, + EXIF_TAG_SENSING_METHOD = 0xa217, + EXIF_TAG_FILE_SOURCE = 0xa300, + EXIF_TAG_SCENE_TYPE = 0xa301, + EXIF_TAG_NEW_CFA_PATTERN = 0xa302, + EXIF_TAG_CUSTOM_RENDERED = 0xa401, + EXIF_TAG_EXPOSURE_MODE = 0xa402, + EXIF_TAG_WHITE_BALANCE = 0xa403, + EXIF_TAG_DIGITAL_ZOOM_RATIO = 0xa404, + EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM = 0xa405, + EXIF_TAG_SCENE_CAPTURE_TYPE = 0xa406, + EXIF_TAG_GAIN_CONTROL = 0xa407, + EXIF_TAG_CONTRAST = 0xa408, + EXIF_TAG_SATURATION = 0xa409, + EXIF_TAG_SHARPNESS = 0xa40a, + EXIF_TAG_DEVICE_SETTING_DESCRIPTION = 0xa40b, + EXIF_TAG_SUBJECT_DISTANCE_RANGE = 0xa40c, + EXIF_TAG_IMAGE_UNIQUE_ID = 0xa420 +} ExifTag; + +ExifTag exif_tag_from_name (const char *); +const char *exif_tag_get_name (ExifTag tag); +const char *exif_tag_get_title (ExifTag tag); +const char *exif_tag_get_description (ExifTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_TAG_H__ */ diff --git a/src/libexif/exif-utils.c b/src/libexif/exif-utils.c new file mode 100644 index 0000000..9386012 --- /dev/null +++ b/src/libexif/exif-utils.c @@ -0,0 +1,214 @@ +/* exif-utils.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> + +#include <libexif/exif-utils.h> + +void +exif_array_set_byte_order (ExifFormat f, unsigned char *b, unsigned int n, + ExifByteOrder o_orig, ExifByteOrder o_new) +{ + unsigned int j; + unsigned int fs = exif_format_get_size (f); + ExifShort s; + ExifSShort ss; + ExifLong l; + ExifSLong sl; + ExifRational r; + ExifSRational sr; + + if (!b || !n || !fs) return; + + switch (f) { + case EXIF_FORMAT_SHORT: + for (j = 0; j < n; j++) { + s = exif_get_short (b + j * fs, o_orig); + exif_set_short (b + j * fs, o_new, s); + } + break; + case EXIF_FORMAT_SSHORT: + for (j = 0; j < n; j++) { + ss = exif_get_sshort (b + j * fs, o_orig); + exif_set_sshort (b + j * fs, o_new, ss); + } + break; + case EXIF_FORMAT_LONG: + for (j = 0; j < n; j++) { + l = exif_get_long (b + j * fs, o_orig); + exif_set_long (b + j * fs, o_new, l); + } + break; + case EXIF_FORMAT_RATIONAL: + for (j = 0; j < n; j++) { + r = exif_get_rational (b + j * fs, o_orig); + exif_set_rational (b + j * fs, o_new, r); + } + break; + case EXIF_FORMAT_SLONG: + for (j = 0; j < n; j++) { + sl = exif_get_slong (b + j * fs, o_orig); + exif_set_slong (b + j * fs, o_new, sl); + } + break; + case EXIF_FORMAT_SRATIONAL: + for (j = 0; j < n; j++) { + sr = exif_get_srational (b + j * fs, o_orig); + exif_set_srational (b + j * fs, o_new, sr); + } + break; + case EXIF_FORMAT_UNDEFINED: + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_ASCII: + default: + /* Nothing here. */ + break; + } +} + +ExifSShort +exif_get_sshort (const unsigned char *buf, ExifByteOrder order) +{ + if (!buf) return 0; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return ((buf[0] << 8) | buf[1]); + case EXIF_BYTE_ORDER_INTEL: + return ((buf[1] << 8) | buf[0]); + } + + /* Won't be reached */ + return (0); +} + +ExifShort +exif_get_short (const unsigned char *buf, ExifByteOrder order) +{ + return (exif_get_sshort (buf, order) & 0xffff); +} + +void +exif_set_sshort (unsigned char *b, ExifByteOrder order, ExifSShort value) +{ + if (!b) return; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + b[0] = (unsigned char) (value >> 8); + b[1] = (unsigned char) value; + break; + case EXIF_BYTE_ORDER_INTEL: + b[0] = (unsigned char) value; + b[1] = (unsigned char) (value >> 8); + break; + } +} + +void +exif_set_short (unsigned char *b, ExifByteOrder order, ExifShort value) +{ + exif_set_sshort (b, order, value); +} + +ExifSLong +exif_get_slong (const unsigned char *b, ExifByteOrder order) +{ + if (!b) return 0; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]); + case EXIF_BYTE_ORDER_INTEL: + return ((b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0]); + } + + /* Won't be reached */ + return (0); +} + +void +exif_set_slong (unsigned char *b, ExifByteOrder order, ExifSLong value) +{ + if (!b) return; + switch (order) { + case EXIF_BYTE_ORDER_MOTOROLA: + b[0] = (unsigned char) (value >> 24); + b[1] = (unsigned char) (value >> 16); + b[2] = (unsigned char) (value >> 8); + b[3] = (unsigned char) value; + break; + case EXIF_BYTE_ORDER_INTEL: + b[3] = (unsigned char) (value >> 24); + b[2] = (unsigned char) (value >> 16); + b[1] = (unsigned char) (value >> 8); + b[0] = (unsigned char) value; + break; + } +} + +ExifLong +exif_get_long (const unsigned char *buf, ExifByteOrder order) +{ + return (exif_get_slong (buf, order) & 0xffffffff); +} + +void +exif_set_long (unsigned char *b, ExifByteOrder order, ExifLong value) +{ + exif_set_slong (b, order, value); +} + +ExifSRational +exif_get_srational (const unsigned char *buf, ExifByteOrder order) +{ + ExifSRational r; + + r.numerator = buf ? exif_get_slong (buf, order) : 0; + r.denominator = buf ? exif_get_slong (buf + 4, order) : 0; + + return (r); +} + +ExifRational +exif_get_rational (const unsigned char *buf, ExifByteOrder order) +{ + ExifRational r; + + r.numerator = buf ? exif_get_long (buf, order) : 0; + r.denominator = buf ? exif_get_long (buf + 4, order) : 0; + + return (r); +} + +void +exif_set_rational (unsigned char *buf, ExifByteOrder order, + ExifRational value) +{ + if (!buf) return; + exif_set_long (buf, order, value.numerator); + exif_set_long (buf + 4, order, value.denominator); +} + +void +exif_set_srational (unsigned char *buf, ExifByteOrder order, + ExifSRational value) +{ + if (!buf) return; + exif_set_slong (buf, order, value.numerator); + exif_set_slong (buf + 4, order, value.denominator); +} diff --git a/src/libexif/exif-utils.h b/src/libexif/exif-utils.h new file mode 100644 index 0000000..a75db0b --- /dev/null +++ b/src/libexif/exif-utils.h @@ -0,0 +1,81 @@ +/* exif-utils.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_UTILS_H__ +#define __EXIF_UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-format.h> +#include <libexif/_stdint.h> + + +/* If these definitions don't work for you, please let us fix the + * macro generating _stdint.h */ + +typedef char ExifByte; /* 1 byte */ +typedef char * ExifAscii; +typedef uint16_t ExifShort; /* 2 bytes */ +typedef int16_t ExifSShort; /* 2 bytes */ +typedef uint32_t ExifLong; /* 4 bytes */ +typedef struct {ExifLong numerator; ExifLong denominator;} ExifRational; +typedef char ExifUndefined; /* 1 byte */ +typedef int32_t ExifSLong; /* 4 bytes */ +typedef struct {ExifSLong numerator; ExifSLong denominator;} ExifSRational; + + +ExifShort exif_get_short (const unsigned char *b, ExifByteOrder order); +ExifSShort exif_get_sshort (const unsigned char *b, ExifByteOrder order); +ExifLong exif_get_long (const unsigned char *b, ExifByteOrder order); +ExifSLong exif_get_slong (const unsigned char *b, ExifByteOrder order); +ExifRational exif_get_rational (const unsigned char *b, ExifByteOrder order); +ExifSRational exif_get_srational (const unsigned char *b, ExifByteOrder order); + +void exif_set_short (unsigned char *b, ExifByteOrder order, + ExifShort value); +void exif_set_sshort (unsigned char *b, ExifByteOrder order, + ExifSShort value); +void exif_set_long (unsigned char *b, ExifByteOrder order, + ExifLong value); +void exif_set_slong (unsigned char *b, ExifByteOrder order, + ExifSLong value); +void exif_set_rational (unsigned char *b, ExifByteOrder order, + ExifRational value); +void exif_set_srational (unsigned char *b, ExifByteOrder order, + ExifSRational value); + +/* Please do not use this function outside of the library. */ +void exif_array_set_byte_order (ExifFormat, unsigned char *, unsigned int, + ExifByteOrder o_orig, ExifByteOrder o_new); + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* For compatibility with older versions */ +#define EXIF_TAG_SUBSEC_TIME EXIF_TAG_SUB_SEC_TIME + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EXIF_UTILS_H__ */ diff --git a/src/libexif/exif.c b/src/libexif/exif.c new file mode 100644 index 0000000..3be72a3 --- /dev/null +++ b/src/libexif/exif.c @@ -0,0 +1,1274 @@ +/* + +Copyright © 2000 Matthias Wandel, The PHP Group, Curtis Galloway + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#include <sys/time.h> +#include <malloc.h> +#include <stdio.h> +#include <string.h> + +#include <math.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <fcntl.h> + +#include "exif.h" + +typedef unsigned char uchar; + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +/* + This structure stores global state for an EXIF image file. +*/ +typedef struct { + exif_data_t *d; + int MotorolaOrder; + const char *filename; + + char *Thumbnail; + int ThumbnailSize; +} ImageInfoType; + +void *(*exif_malloc_fn)(int); +void *(*exif_realloc_fn)(void *, int); +void (*exif_free_fn)(void *); + +static char * +exif_strndup(char *str, int len) +{ + char *rval = (*exif_malloc_fn)(len+1); + strncpy(rval, str, len); + rval[len] = '\0'; + return rval; +} + +struct exif_data * +exif_alloc(void) +{ + exif_data_t *d; + + d = (*exif_malloc_fn)(sizeof(exif_data_t)); + bzero(d, sizeof(*d)); + return d; +} + +static void +exif_error(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + + +/* This structure is used to store a section of a Jpeg file. */ +typedef struct { + uchar *Data; + int Type; + unsigned Size; +} Section_t; + +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + + +/* + JPEG markers consist of one or more 0xFF bytes, followed by a marker + code byte (which is not an FF). Here are the marker codes of interest + in this program. (See jdmarker.c for a more complete list.) +*/ + +#define M_SOF0 0xC0 /* Start Of Frame N */ +#define M_SOF1 0xC1 /* N indicates which compression process */ +#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ +#define M_SOF3 0xC3 +#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ +#define M_SOF6 0xC6 +#define M_SOF7 0xC7 +#define M_SOF9 0xC9 +#define M_SOF10 0xCA +#define M_SOF11 0xCB +#define M_SOF13 0xCD +#define M_SOF14 0xCE +#define M_SOF15 0xCF +#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ +#define M_EOI 0xD9 /* End Of Image (end of datastream) */ +#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ +#define M_EXIF 0xE1 +#define M_COM 0xFE /* COMment */ + + +#define PSEUDO_IMAGE_MARKER 0x123; /* Extra value. */ + +#define EXIF_ALLOC_SIZE 16 + +/* + * The name gets copied, so you can pass a static string; + * the data is not copied, so if it is a string, + * you must allocate it yourself. + */ +static int +exif_append_data(exif_data_t **d_p, + char *name, + char rec_type, + int exif_format, + exif_rec_data_t *data) +{ + exif_data_t *d = *d_p; + + if (rec_type == '\0') + return EXIT_FAILURE; + + if (d->n_alloc <= d->n_recs) { + d->n_alloc += EXIF_ALLOC_SIZE; + d = (*exif_realloc_fn)(d, sizeof(exif_data_t) + + sizeof(exif_record_t) * d->n_alloc); + *d_p = d; + } + d->recs[d->n_recs].rec_type = rec_type; + bcopy(data, &d->recs[d->n_recs].rec_data, sizeof(exif_rec_data_t)); + d->recs[d->n_recs].rec_name = (char*)strdup(name); + d->n_recs++; + return EXIT_SUCCESS; +} + +/* + Get 16 bits motorola order (always) for jpeg header stuff. +*/ +static int +Get16m(void *Short) +{ + return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; +} + + +/* + Process a COM marker. + We want to print out the marker contents as legible text; + we must guard against random junk and varying newline representations. +*/ +static void +process_COM (ImageInfoType *ImageInfo, uchar *Data, int length) +{ + int ch; + char *Comment; + int nch; + int a; + exif_rec_data_t rd; + + nch = 0; + Comment = (*exif_malloc_fn)(length+1); + + for (a=2;a<length;a++) { + ch = Data[a]; + + if (ch == '\r' && Data[a+1] == '\n') continue; /* Remove cr followed by lf. */ + + if (isprint(ch) || ch == '\n' || ch == '\t') { + Comment[nch++] = (char)ch; + } else { + Comment[nch++] = '?'; + } + } + + Comment[nch] = '\0'; /* Null terminate */ + + rd.s = Comment; + exif_append_data(&ImageInfo->d, "Comment", 's', EXIF_FMT_COMPUTED, &rd); +} + +/* Process a SOFn marker. This is useful for the image dimensions. */ +static void +process_SOFn (ImageInfoType *ImageInfo, uchar *Data, int marker) +{ + int data_precision, num_components; + const char *process; + exif_rec_data_t rd; + + data_precision = Data[2]; + rd.l = Get16m(Data+3); + exif_append_data(&ImageInfo->d, + "Height", + 'l', + EXIF_FMT_COMPUTED, + &rd); + rd.l = Get16m(Data+5); + exif_append_data(&ImageInfo->d, + "Width", + 'l', + EXIF_FMT_COMPUTED, + &rd); + num_components = Data[7]; + + if (num_components == 3) { + rd.l = 1; + } else { + rd.l = 0; + } + exif_append_data(&ImageInfo->d, "IsColor", 'l', EXIF_FMT_COMPUTED, &rd); + + switch (marker) { + case M_SOF0: process = "Baseline"; break; + case M_SOF1: process = "Extended sequential"; break; + case M_SOF2: process = "Progressive"; break; + case M_SOF3: process = "Lossless"; break; + case M_SOF5: process = "Differential sequential"; break; + case M_SOF6: process = "Differential progressive"; break; + case M_SOF7: process = "Differential lossless"; break; + case M_SOF9: process = "Extended sequential, arithmetic coding"; break; + case M_SOF10: process = "Progressive, arithmetic coding"; break; + case M_SOF11: process = "Lossless, arithmetic coding"; break; + case M_SOF13: process = "Differential sequential, arithmetic coding"; break; + case M_SOF14: process = "Differential progressive, arithmetic coding"; break; + case M_SOF15: process = "Differential lossless, arithmetic coding"; break; + default: process = "Unknown"; break; + } +} + +/* + Describes format descriptor +*/ +static int ExifBytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8}; +#define NUM_FORMATS EXIF_FMT_DOUBLE + +/* + Describes tag values +*/ + +#define TAG_EXIF_OFFSET 0x8769 +#define TAG_INTEROP_OFFSET 0xa005 + +#define TAG_COMPRESSION 0x0103 + +#define TAG_MAKE 0x010F +#define TAG_MODEL 0x0110 +#define TAG_ORIENTATION 0x0112 + +#define TAG_SOFTWARE 0x0131 + +/* Olympus specific tags */ +#define TAG_SPECIALMODE 0x0200 +#define TAG_JPEGQUAL 0x0201 +#define TAG_MACRO 0x0202 +#define TAG_DIGIZOOM 0x0204 +#define TAG_SOFTWARERELEASE 0x0207 +#define TAG_PICTINFO 0x0208 +#define TAG_CAMERAID 0x0209 +/* end Olympus specific tags */ + +#define TAG_COPYRIGHT 0x8298 + +#define TAG_EXPOSURETIME 0x829A +#define TAG_FNUMBER 0x829D + +#define TAG_GPSINFO 0x8825 +#define TAG_ISOSPEED 0x8827 +#define TAG_EXIFVERSION 0x9000 + +#define TAG_SHUTTERSPEED 0x9201 +#define TAG_APERTURE 0x9202 +#define TAG_MAXAPERTURE 0x9205 +#define TAG_FOCALLENGTH 0x920A + +#define TAG_DATETIME_ORIGINAL 0x9003 +#define TAG_USERCOMMENT 0x9286 + +#define TAG_SUBJECT_DISTANCE 0x9206 +#define TAG_LIGHT_SOURCE 0x9208 +#define TAG_FLASH 0x9209 + +#define TAG_FOCALPLANEXRES 0xa20E +#define TAG_FOCALPLANEUNITS 0xa210 +#define TAG_IMAGEWIDTH 0xA002 + +struct ExifTag { + unsigned short Tag; + char *Desc; + void (*Func)(); +}; + + + +/* Convert a 16 bit unsigned value from file's native byte order */ +static int +Get16u(void *Short, int MotorolaOrder) +{ + if (MotorolaOrder) { + return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1]; + } else { + return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0]; + } +} + +/* Convert a 32 bit signed value from file's native byte order */ +static int +Get32s(void *Long, int MotorolaOrder) +{ + if (MotorolaOrder) { + return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16) + | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 ); + } else { + return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16) + | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 ); + } +} + +/* Convert a 32 bit unsigned value from file's native byte order */ +static unsigned +Get32u(void *Long, int MotorolaOrder) +{ + return (unsigned)Get32s(Long, MotorolaOrder) & 0xffffffff; +} + + +/* Evaluate number, be it int, rational, or float from directory. */ +static double +ConvertAnyFormat(void *ValuePtr, int Format, int MotorolaOrder) +{ + double Value; + Value = 0; + + switch(Format) { + case EXIF_FMT_SBYTE: Value = *(signed char *)ValuePtr; break; + case EXIF_FMT_BYTE: Value = *(uchar *)ValuePtr; break; + + case EXIF_FMT_USHORT: Value = Get16u(ValuePtr,MotorolaOrder); break; + case EXIF_FMT_ULONG: Value = Get32u(ValuePtr,MotorolaOrder); break; + + case EXIF_FMT_URATIONAL: + case EXIF_FMT_SRATIONAL: + { + int Num,Den; + Num = Get32s(ValuePtr,MotorolaOrder); + Den = Get32s(4+(char *)ValuePtr,MotorolaOrder); + if (Den == 0) { + Value = 0; + } else { + Value = (double)Num/Den; + } + break; + } + + case EXIF_FMT_SSHORT: Value = (signed short)Get16u(ValuePtr,MotorolaOrder); break; + case EXIF_FMT_SLONG: Value = Get32s(ValuePtr,MotorolaOrder); break; + + /* Not sure if this is correct (never seen float used in Exif format) */ + case EXIF_FMT_SINGLE: Value = (double)*(float *)ValuePtr; break; + case EXIF_FMT_DOUBLE: Value = *(double *)ValuePtr; break; + } + return Value; +} + +/* Evaluate number, be it int, rational, or float from directory. */ +static char +ConvertAnyFormat2(void *ValuePtr, int ByteCount, int Format, int MotorolaOrder, exif_rec_data_t *data_p) +{ + char *str, *p; + char r_type; + unsigned char c; + static char hexdigits[] = "0123456789ABCDEF"; + + switch(Format) { + case EXIF_FMT_STRING: + data_p->s = exif_strndup(ValuePtr, ByteCount); + r_type = 's'; + break; + + case EXIF_FMT_SBYTE: + data_p->l = (long)*(signed char *)ValuePtr; + r_type = 'l'; + break; + + case EXIF_FMT_BYTE: + data_p->l = (long)*(uchar *)ValuePtr; + r_type = 'l'; + break; + + case EXIF_FMT_USHORT: + data_p->l = (long)Get16u(ValuePtr,MotorolaOrder); + r_type = 'l'; + break; + case EXIF_FMT_ULONG: + data_p->l = (long)Get32u(ValuePtr,MotorolaOrder); + r_type = 'l'; + break; + + case EXIF_FMT_URATIONAL: + case EXIF_FMT_SRATIONAL: + { + int Num,Den; + data_p->r.num = Get32s(ValuePtr,MotorolaOrder); + data_p->r.denom = Get32s(4+(char *)ValuePtr,MotorolaOrder); + r_type = 'r'; + break; + } + + case EXIF_FMT_SSHORT: + data_p->l = (signed short)Get16u(ValuePtr,MotorolaOrder); + r_type = 'l'; + break; + case EXIF_FMT_SLONG: + data_p->l = (long)Get32s(ValuePtr,MotorolaOrder); + r_type = 'l'; + break; + + /* Not sure if this is correct (never seen float used in Exif format) */ + case EXIF_FMT_SINGLE: + data_p->f = *(float *)ValuePtr; + r_type = 'f'; + break; + + case EXIF_FMT_DOUBLE: + data_p->g = *(double *)ValuePtr; + r_type = 'f'; + break; + + default: + /* unknown type */ + p = str = (*exif_malloc_fn)(ByteCount*2 + 1); + while (ByteCount--) { + c = *(unsigned char *)ValuePtr++; + *p++ = hexdigits[c / 16]; + *p++ = hexdigits[c % 16]; + } + *p++ = '\0'; + data_p->s = str; + r_type = 's'; + break; + } + return r_type; +} + + +static void +ProcessFocalPlaneUnits(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p) +{ + exif_rec_data_t rd; + float FocalPlaneUnits; + + switch((int)ConvertAnyFormat(ValuePtr, Format, ImageInfo->MotorolaOrder)) { + case 1: + FocalPlaneUnits = 25.4; + break; /* inch */ + case 2: + /* According to the information I was using, 2 means meters. + But looking at the Canon PowerShot's files, inches is the only + sensible value. */ + FocalPlaneUnits = 25.4; + break; + + case 3: + FocalPlaneUnits = 10; + break; /* centimeter */ + case 4: + FocalPlaneUnits = 1; + break; /* milimeter */ + case 5: + FocalPlaneUnits = .001; + break; /* micrometer */ + } + + rd.f = FocalPlaneUnits; + exif_append_data(&ImageInfo->d, + "FocalPlaneUnits", + 'f', + Format, + &rd); +} + +static void +ProcessVersion(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p) +{ + exif_rec_data_t rd; + rd.s = exif_strndup(ValuePtr, ByteCount); + exif_append_data(&ImageInfo->d, + tag_p->Desc, + 's', + Format, + &rd); +} + +static void +ProcessUserComment(ImageInfoType *ImageInfo, + void *_ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p) +{ + char *ValuePtr = (char *)_ValuePtr; + exif_rec_data_t rd; + int a; + + /* Olympus has this padded with trailing spaces. Remove these first. */ + for (a=ByteCount;;) { + a--; + if ((ValuePtr)[a] == ' ') { + (ValuePtr)[a] = '\0'; + } else { + break; + } + if (a == 0) break; + } + + /* Copy the comment */ + if (memcmp(ValuePtr, "ASCII",5) == 0) { + for (a=5;a<10;a++) { + int c; + c = (ValuePtr)[a]; + if (c != '\0' && c != ' ') { + rd.s = exif_strndup(a+ValuePtr, ByteCount - a); + exif_append_data(&ImageInfo->d, + "UserComment", + 's', + Format, + &rd); + break; + } + } + + } else { + rd.s = exif_strndup(ValuePtr, ByteCount); + exif_append_data(&ImageInfo->d, + "UserComment", + 's', + Format, + &rd); + } +} + +static void +ProcessShutterSpeed(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p) +{ + exif_rec_data_t rd; + char rec_type; + + rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format, + ImageInfo->MotorolaOrder, + &rd); + exif_append_data(&ImageInfo->d, + tag_p->Desc, + rec_type, + Format, + &rd); + + /* Convert shutter speed value to shutter speed; + * shutter speed is 1/(2**ShutterSpeedValue) + */ + rd.r.denom = (int)pow(2.0, ((double)rd.r.num)/((double)rd.r.denom)); + rd.r.num = 1; + exif_append_data(&ImageInfo->d, + "ShutterSpeed", + 'r', + EXIF_FMT_COMPUTED, + &rd); + +} + +static void +ProcessAperture(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p) +{ + exif_rec_data_t rd; + char rec_type; + double fstop; + char label[32]; + + rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format, + ImageInfo->MotorolaOrder, + &rd); + exif_append_data(&ImageInfo->d, + tag_p->Desc, + rec_type, + Format, + &rd); + + if (exif_find_record(ImageInfo->d, "FNumber") == NULL) { + /* Convert aperture to F-stop. */ + fstop = pow(sqrt(2), ((double)rd.r.num)/((double)rd.r.denom)); + sprintf(label, "f%.1g", fstop); + rd.s = (char*)strdup(label); + exif_append_data(&ImageInfo->d, + "FNumber", + 's', + EXIF_FMT_COMPUTED, + &rd); + } +} + +static void +ProcessCanonMakerNote(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p, + char *OffsetBase) +{ + + /* This is for the Canon MakerNote. */ + /* XXX - go by value of Maker tag. */ + exif_rec_data_t rd; + char rec_type; + unsigned long n_dir, tag, format, components, offset; + char label[32]; + void *OffsetPtr; + + n_dir = Get16u(ValuePtr, ImageInfo->MotorolaOrder); + ValuePtr += 2; + while (n_dir--) { + tag = Get16u(ValuePtr, ImageInfo->MotorolaOrder); + ValuePtr += 2; + format = Get16u(ValuePtr, ImageInfo->MotorolaOrder); + ValuePtr += 2; + components = Get32u(ValuePtr, ImageInfo->MotorolaOrder); + ValuePtr += 4; + offset = Get32u(ValuePtr, ImageInfo->MotorolaOrder); + ByteCount = components * ExifBytesPerFormat[format]; + if (ByteCount > 4) { + OffsetPtr = OffsetBase + offset; + } else { + OffsetPtr = ValuePtr; + } + ValuePtr += 4; + rec_type = ConvertAnyFormat2(OffsetPtr, ByteCount, format, + ImageInfo->MotorolaOrder, + &rd); + sprintf(label, "MakerNote%04x", tag); + exif_append_data(&ImageInfo->d, + label, + rec_type, + format, + &rd); + + } +} + + +struct MakerNote { + char *Make; + void (*Func)(); +}; + +static struct MakerNote +MakerProcessors[] = { + {"Canon", ProcessCanonMakerNote}, + {NULL, NULL} +}; + +static void +ProcessMakerNote(ImageInfoType *ImageInfo, + void *ValuePtr, + int ByteCount, + int Format, + struct ExifTag *tag_p, + char *OffsetBase) +{ + struct MakerNote *mn_p; + exif_record_t *rec_p; + + rec_p = exif_find_record(ImageInfo->d, "Make"); + if (rec_p == NULL) { + return; + } + + for(mn_p = &MakerProcessors[0]; mn_p->Make != NULL; mn_p++) { + if (strcmp(mn_p->Make, rec_p->rec_data.s) == 0) { + (*mn_p->Func)(ImageInfo, ValuePtr, ByteCount, Format, tag_p, OffsetBase); + break; + } + } +} + +static struct ExifTag +TagTable[] = { + { 0x0001, "InteroperabilityIndex"}, + { 0x0002, "InteroperabilityVersion", ProcessVersion}, + { 0x0100, "ImageWidth"}, + { 0x0101, "ImageLength"}, + { 0x0102, "BitsPerSample"}, + { 0x0103, "Compression"}, + { 0x0106, "PhotometricInterpretation"}, + { 0x010A, "FillOrder"}, + { 0x010D, "DocumentName"}, + { 0x010E, "ImageDescription"}, + { 0x010F, "Make"}, + { 0x0110, "Model"}, + { 0x0111, "StripOffsets"}, + { 0x0112, "Orientation"}, + { 0x0115, "SamplesPerPixel"}, + { 0x0116, "RowsPerStrip"}, + { 0x0117, "StripByteCounts"}, + { 0x011A, "XResolution"}, + { 0x011B, "YResolution"}, + { 0x011C, "PlanarConfiguration"}, + { 0x0128, "ResolutionUnit"}, + { 0x012D, "TransferFunction"}, + { 0x0131, "Software"}, + { 0x0132, "DateTime"}, + { 0x013B, "Artist"}, + { 0x013E, "WhitePoint"}, + { 0x013F, "PrimaryChromaticities"}, + { 0x0156, "TransferRange"}, + { 0x0200, "JPEGProc"}, + { 0x0201, "JPEGInterchangeFormat"}, + { 0x0202, "JPEGInterchangeFormatLength"}, + { 0x0211, "YCbCrCoefficients"}, + { 0x0212, "YCbCrSubSampling"}, + { 0x0213, "YCbCrPositioning"}, + { 0x0214, "ReferenceBlackWhite"}, + { 0x1000, "RelatedImageFileFormat"}, + { 0x1001, "RelatedImageWidth"}, + { 0x1002, "RelatedImageLength"}, + { 0x828D, "CFARepeatPatternDim"}, + { 0x828E, "CFAPattern"}, + { 0x828F, "BatteryLevel"}, + { 0x8298, "Copyright"}, + { 0x829A, "ExposureTime"}, + { 0x829D, "FNumber"}, + { 0x83BB, "IPTC/NAA"}, + { 0x8769, "ExifOffset"}, + { 0x8773, "InterColorProfile"}, + { 0x8822, "ExposureProgram"}, + { 0x8824, "SpectralSensitivity"}, + { 0x8825, "GPSInfo"}, + { 0x8827, "ISOSpeedRatings"}, + { 0x8828, "OECF"}, + { 0x9000, "ExifVersion", ProcessVersion}, + { 0x9003, "DateTimeOriginal"}, + { 0x9004, "DateTimeDigitized"}, + { 0x9101, "ComponentsConfiguration"}, + { 0x9102, "CompressedBitsPerPixel"}, + { 0x9201, "ShutterSpeedValue", ProcessShutterSpeed}, + { 0x9202, "ApertureValue", ProcessAperture}, + { 0x9203, "BrightnessValue"}, + { 0x9204, "ExposureBiasValue"}, + { 0x9205, "MaxApertureValue", ProcessAperture}, + { 0x9206, "SubjectDistance"}, + { 0x9207, "MeteringMode"}, + { 0x9208, "LightSource"}, + { 0x9209, "Flash"}, + { 0x920A, "FocalLength"}, + { 0x927C, "MakerNote", ProcessMakerNote}, + { 0x9286, "UserComment", ProcessUserComment}, + { 0x9290, "SubSecTime"}, + { 0x9291, "SubSecTimeOriginal"}, + { 0x9292, "SubSecTimeDigitized"}, + { 0xA000, "FlashPixVersion", ProcessVersion}, + { 0xA001, "ColorSpace"}, + { 0xA002, "ExifImageWidth"}, + { 0xA003, "ExifImageLength"}, + { 0xA005, "InteroperabilityOffset"}, + { 0xA20B, "FlashEnergy"}, /* 0x920B in TIFF/EP */ + { 0xA20C, "SpatialFrequencyResponse"}, /* 0x920C - - */ + { 0xA20E, "FocalPlaneXResolution"}, /* 0x920E - - */ + { 0xA20F, "FocalPlaneYResolution"}, /* 0x920F - - */ + { 0xA210, "FocalPlaneResolutionUnit", ProcessFocalPlaneUnits}, + /* 0x9210 - - */ + { 0xA214, "SubjectLocation"}, /* 0x9214 - - */ + { 0xA215, "ExposureIndex"}, /* 0x9215 - - */ + { 0xA217, "SensingMethod"}, /* 0x9217 - - */ + { 0xA300, "FileSource"}, + { 0xA301, "SceneType"}, + { 0, NULL} +} ; + + + +/* Process one of the nested EXIF directories. */ +static int +ProcessExifDir(ImageInfoType *ImageInfo, char *DirStart, char *OffsetBase, unsigned ExifLength, char *LastExifRefd) +{ + int de; + int a; + int NumDirEntries; + exif_rec_data_t rd; + char rec_type; + char label[32]; + + NumDirEntries = Get16u(DirStart, ImageInfo->MotorolaOrder); + + if ((DirStart+2+NumDirEntries*12) > (OffsetBase+ExifLength)) { + exif_error("Illegally sized directory"); + return FALSE; + } + + + for (de=0;de<NumDirEntries;de++) { + int Tag, Format, Components; + char *ValuePtr; + int ByteCount; + char *DirEntry; + struct ExifTag *tag_p; + + DirEntry = DirStart+2+12*de; + + Tag = Get16u(DirEntry, ImageInfo->MotorolaOrder); + Format = Get16u(DirEntry+2, ImageInfo->MotorolaOrder); + Components = Get32u(DirEntry+4, ImageInfo->MotorolaOrder); + + if ((Format-1) >= NUM_FORMATS) { + /* (-1) catches illegal zero case as unsigned underflows to positive large. */ + exif_error("Illegal format code in EXIF dir"); + return FALSE; + } + + ByteCount = Components * ExifBytesPerFormat[Format]; + + if (ByteCount > 4) { + unsigned OffsetVal; + OffsetVal = Get32u(DirEntry+8, ImageInfo->MotorolaOrder); + /* If its bigger than 4 bytes, the dir entry contains an offset. */ + if (OffsetVal+ByteCount > ExifLength) { + /* Bogus pointer offset and / or bytecount value */ + /* printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength); */ + + exif_error("Illegal pointer offset value in EXIF"); + return FALSE; + } + ValuePtr = OffsetBase+OffsetVal; + } else { + /* 4 bytes or less and value is in the dir entry itself */ + ValuePtr = DirEntry+8; + } + + if (LastExifRefd < ValuePtr+ByteCount) { + /* + Keep track of last byte in the exif header that was actually referenced. + That way, we know where the discardable thumbnail data begins. + */ + LastExifRefd = ValuePtr+ByteCount; + } + + if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET) { + char *SubdirStart; + SubdirStart = OffsetBase + Get32u(ValuePtr, ImageInfo->MotorolaOrder); + if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength) { + exif_error("Illegal subdirectory link"); + return FALSE; + } + ProcessExifDir(ImageInfo, SubdirStart, OffsetBase, ExifLength, LastExifRefd); + continue; + } + + /* Search through tag table */ + for (tag_p = &TagTable[0]; tag_p->Desc != NULL; tag_p++) { + if (tag_p->Tag == Tag) { + if (tag_p->Func != NULL) { + (*tag_p->Func)(ImageInfo, ValuePtr, ByteCount, Format, tag_p, OffsetBase); + } else { + rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format, + ImageInfo->MotorolaOrder, + &rd); + exif_append_data(&ImageInfo->d, + tag_p->Desc, + rec_type, + Format, + &rd); + } + break; + } + } + if (tag_p->Desc == NULL) { + rec_type = ConvertAnyFormat2(ValuePtr, ByteCount, Format, + ImageInfo->MotorolaOrder, + &rd); + sprintf(label, "0x%04x", Tag); + exif_append_data(&ImageInfo->d, + label, + rec_type, + Format, + &rd); + } + } + return TRUE; +} + +/* + Process an EXIF marker + Describes all the drivel that most digital cameras include... +*/ +static int +process_EXIF (ImageInfoType *ImageInfo, char *CharBuf, unsigned int length, char *LastExifRefd) +{ + int cc; + exif_rec_data_t rd; + LastExifRefd = CharBuf; + + { /* Check the EXIF header component */ + static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; + if (memcmp(CharBuf+2, ExifHeader,6)) { + exif_error("Incorrect Exif header"); + return FALSE; + } + } + + if (memcmp(CharBuf+8,"II",2) == 0) { + ImageInfo->MotorolaOrder = 0; + } else { + if (memcmp(CharBuf+8,"MM",2) == 0) { + ImageInfo->MotorolaOrder = 1; + } else { + exif_error("Invalid Exif alignment marker."); + return FALSE; + } + } + + /* Check the next two values for correctness. */ + if (Get16u(CharBuf+10,ImageInfo->MotorolaOrder) != 0x2a + || Get32u(CharBuf+12,ImageInfo->MotorolaOrder) != 0x08) { + exif_error("Invalid Exif start (1, NULL)"); + return FALSE; + } + + /* First directory starts 16 bytes in. Offsets start at 8 bytes in. */ + cc = ProcessExifDir(ImageInfo, CharBuf+16, CharBuf+8, length-6, LastExifRefd); + if (cc != TRUE) { + return cc; + } + return TRUE; +} + +/* Parse the marker stream until SOS or EOI is seen; */ +static int +scan_JPEG_header (ImageInfoType *ImageInfo, FILE *infile, Section_t *Sections, int *SectionsRead, int ReadAll, char *LastExifRefd) +{ + int a; + int HaveCom = FALSE; + + a = fgetc(infile); + if (a != 0xff || fgetc(infile) != M_SOI) { + return FALSE; + } + + for(*SectionsRead=0;*SectionsRead < 19;) { + int itemlen; + int marker = 0; + int ll,lh, got; + uchar *Data; + + for (a=0;a<7;a++) { + marker = fgetc(infile); + if (marker != 0xff) break; + } + if (marker == 0xff) { + /* 0xff is legal padding, but if we get that many, something's wrong. */ + exif_error("too many padding bytes!"); + return FALSE; + } + + Sections[*SectionsRead].Type = marker; + + /* Read the length of the section. */ + lh = fgetc(infile); + ll = fgetc(infile); + + itemlen = (lh << 8) | ll; + + if (itemlen < 2) { + exif_error("invalid marker"); + return FALSE; + } + + Sections[*SectionsRead].Size = itemlen; + + Data = (uchar *)(*exif_malloc_fn)(itemlen+1); /* Add 1 to allow sticking a 0 at the end. */ + Sections[*SectionsRead].Data = Data; + + /* Store first two pre-read bytes. */ + Data[0] = (uchar)lh; + Data[1] = (uchar)ll; + + got = fread(Data+2, 1, itemlen-2, infile); /* Read the whole section. */ + if (got != itemlen-2) { + exif_error("reading from file"); + return FALSE; + } + *SectionsRead += 1; + + switch(marker) { + case M_SOS: /* stop before hitting compressed data */ + /* If reading entire image is requested, read the rest of the data. */ + if (ReadAll) { + int cp, ep, size; + /* Determine how much file is left. */ + cp = ftell(infile); + fseek(infile, 0, SEEK_END); + ep = ftell(infile); + fseek(infile, cp, SEEK_SET); + + size = ep-cp; + Data = (uchar *)(*exif_malloc_fn)(size); + if (Data == NULL) { + exif_error("could not allocate data for entire image"); + return FALSE; + } + + got = fread(Data, 1, size, infile); + if (got != size) { + exif_error("could not read the rest of the image"); + return FALSE; + } + + Sections[*SectionsRead].Data = Data; + Sections[*SectionsRead].Size = size; + Sections[*SectionsRead].Type = PSEUDO_IMAGE_MARKER; + (*SectionsRead)++; + /* + *HaveAll = 1; + */ + } + return TRUE; + + case M_EOI: /* in case it's a tables-only JPEG stream */ + exif_error("No image in jpeg!"); + return FALSE; + + case M_COM: /* Comment section */ + if (HaveCom) { + (*SectionsRead) -= 1; + (*exif_free_fn)(Sections[*SectionsRead].Data); + } else { + process_COM(ImageInfo, Data, itemlen); + HaveCom = TRUE; + } + break; + + case M_EXIF: + if (*SectionsRead <= 2) { + /* Seen files from some 'U-lead' software with Vivitar scanner + that uses marker 31 later in the file (no clue what for!) */ + process_EXIF(ImageInfo, (char *)Data, itemlen, LastExifRefd); + } + break; + + case M_SOF0: + case M_SOF1: + case M_SOF2: + case M_SOF3: + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + process_SOFn(ImageInfo, Data, marker); + break; + default: + /* skip any other marker silently. */ + break; + } + } + return TRUE; +} + +/* + Discard read data. +*/ +static void +DiscardData(Section_t *Sections, int *SectionsRead) +{ + int a; + for (a=0;a<*SectionsRead-1;a++) { + (*exif_free_fn)(Sections[a].Data); + } + *SectionsRead = 0; +} + +/* + Read image data. +*/ +static int +ReadJpegFile(ImageInfoType *ImageInfo, Section_t *Sections, + int *SectionsRead, int fd, + int ReadAll, char *LastExifRefd) +{ + FILE *infile; + int ret; + char *tmp; + char **p_argv; + int p_argc; + + infile = fdopen(fd, "rb"); /* Unix ignores 'b', windows needs it. */ + + if (infile == NULL) { + exif_error("Unable to open '%s'", ImageInfo->filename); + return FALSE; + } + + /* Start with an empty image information structure. */ + memset(ImageInfo, 0, sizeof(*ImageInfo)); + memset(Sections, 0, sizeof(*Sections)); + + ImageInfo->d = exif_alloc(); + + /* Scan the JPEG headers. */ + ret = scan_JPEG_header(ImageInfo, infile, Sections, SectionsRead, ReadAll, LastExifRefd); + if (!ret) { + exif_error("Invalid Jpeg file: '%s'",ImageInfo->filename); + return FALSE; + } + + fclose(infile); + + return ret; +} + +static int +read_jpeg_exif(ImageInfoType *ImageInfo, int fd, int ReadAll) +{ + Section_t Sections[20]; + int SectionsRead; + char *LastExifRefd=NULL; + int ret; + int thumbsize=0; + + ret = ReadJpegFile(ImageInfo, Sections, &SectionsRead, fd, ReadAll, LastExifRefd); +#if 0 + /* + * Thought this might pick out the embedded thumbnail, but it doesn't work. -RL + */ + for (i=0;i<SectionsRead-1;i++) { + if (Sections[i].Type == M_EXIF) { + thumbsize = Sections[i].Size; + if(thumbsize>0) { + ImageInfo->Thumbnail = (*exif_malloc_fn)(thumbsize+5); + ImageInfo->ThumbnailSize = thumbsize; + ImageInfo->Thumbnail[0] = 0xff; + ImageInfo->Thumbnail[1] = 0xd8; + ImageInfo->Thumbnail[2] = 0xff; + memcpy(ImageInfo->Thumbnail+4, Sections[i].Data, thumbsize+4); + } + } + } +#endif + if (ret != FALSE) { + DiscardData(Sections, &SectionsRead); + } + return(ret); +} + +exif_data_t * +exif_parse_fd(int fd) +{ + ImageInfoType ImageInfo; + + ImageInfo.filename = "<file stream>"; + if (read_jpeg_exif(&ImageInfo, fd, 1) != TRUE) { + return NULL; + } + return ImageInfo.d; +} + +exif_data_t * +exif_parse_file(const char *filename) +{ + ImageInfoType ImageInfo; + int fd; + + ImageInfo.filename = filename; + fd = open(filename, O_RDONLY); + if (fd < 0) { + return NULL; + } + + if (read_jpeg_exif(&ImageInfo, fd, 1) != TRUE) { + return NULL; + } + return ImageInfo.d; +} + +void +exif_free_data(struct exif_data *d) +{ + int i; + for (i=0; i<d->n_recs; i++) { + (*exif_free_fn)(d->recs[i].rec_name); + if (d->recs[i].rec_type == 's') { + (*exif_free_fn)(d->recs[i].rec_data.s); + } + } + (*exif_free_fn)(d); +} + +void +exif_init(void *(*malloc_fn)(int), + void (*free_fn)(void *), + void *(*realloc_fn)(void *, int)) +{ + if (malloc_fn == NULL) { + malloc_fn = (void *(*)(int))malloc; + } + exif_malloc_fn = malloc_fn; + if (free_fn == NULL) { + free_fn = (void (*)(void *))free; + } + exif_free_fn = free_fn; + if (realloc_fn == NULL) { + realloc_fn = (void *(*)(void *, int))realloc; + } + exif_realloc_fn = realloc_fn; +} + +extern exif_record_t * +exif_find_record(exif_data_t *d, const char *rec_name) +{ + int i; + for (i=0; i<d->n_recs; i++) { + if (strcmp(d->recs[i].rec_name, rec_name) == 0) { + return &d->recs[i]; + } + } + return NULL; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + + diff --git a/src/libexif/exif.h b/src/libexif/exif.h new file mode 100644 index 0000000..32f0a6d --- /dev/null +++ b/src/libexif/exif.h @@ -0,0 +1,86 @@ +/* + +Copyright © 2000 Curtis Galloway + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +typedef struct exif_rational { + int num; + unsigned denom; +} exif_rational_t; + +typedef union { + long l; + float f; + double g; + char * s; + exif_rational_t r; +} exif_rec_data_t; + +typedef struct exif_record { + char * rec_name; + char rec_type; + int exif_format; + exif_rec_data_t rec_data; +} exif_record_t; + +typedef struct exif_data { + int n_recs; + int n_alloc; + exif_record_t recs[0]; +} exif_data_t; + + +/* EXIF data formats */ + +#define EXIF_FMT_COMPUTED -1 /* Not in raw data */ +#define EXIF_FMT_BYTE 1 +#define EXIF_FMT_STRING 2 +#define EXIF_FMT_USHORT 3 +#define EXIF_FMT_ULONG 4 +#define EXIF_FMT_URATIONAL 5 +#define EXIF_FMT_SBYTE 6 +#define EXIF_FMT_UNDEFINED 7 +#define EXIF_FMT_SSHORT 8 +#define EXIF_FMT_SLONG 9 +#define EXIF_FMT_SRATIONAL 10 +#define EXIF_FMT_SINGLE 11 +#define EXIF_FMT_DOUBLE 12 + +extern void +exif_init(void *(*malloc_fn)(int), + void (*free_fn)(void *), + void *(*realloc_fn)(void *, int)); + +extern exif_data_t * +exif_parse_fd(int fd); + +extern exif_data_t * +exif_parse_file(const char *filename); + +extern void +exif_free_data(exif_data_t *d); + +extern exif_record_t * +exif_find_record(exif_data_t *d, const char *rec_name); + + diff --git a/src/libexif/i18n.h b/src/libexif/i18n.h new file mode 100644 index 0000000..6d08e3c --- /dev/null +++ b/src/libexif/i18n.h @@ -0,0 +1,51 @@ +/* i18n.h + * + * Copyright © 2001 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __I18N_H__ +#define __I18N_H__ + +#include "config.h" + +#ifdef ENABLE_NLS +# include <libintl.h> +# undef _ +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +#ifdef __WATCOMC__ +# define bind_textdomain_codeset(Domain,Codeset) +# define bindtextdomain(Domain,Directory) +#else +# define bind_textdomain_codeset(Domain,Codeset) (Codeset) +# define bindtextdomain(Domain,Directory) (Domain) +#endif +# define _(String) (String) +# define N_(String) (String) +#endif + +#endif /* __I18N_H__ */ diff --git a/src/libexif/olympus/exif-mnote-data-olympus.c b/src/libexif/olympus/exif-mnote-data-olympus.c new file mode 100644 index 0000000..02794c5 --- /dev/null +++ b/src/libexif/olympus/exif-mnote-data-olympus.c @@ -0,0 +1,403 @@ +/* exif-mnote-data-olympus.c + * + * Copyright © 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "exif-mnote-data-olympus.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <libexif/exif-utils.h> +#include <libexif/exif-data.h> + +#define DEBUG + +static void +exif_mnote_data_olympus_clear (ExifMnoteDataOlympus *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_olympus_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_olympus_clear ((ExifMnoteDataOlympus *) n); +} + +static char * +exif_mnote_data_olympus_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!d || !val) return NULL; + if (i > n->count -1) return NULL; + exif_log (d->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Querying value for tag '%s'...", + mnote_olympus_tag_get_name (n->entries[i].tag)); + return mnote_olympus_entry_get_value (&n->entries[i], val, maxlen); +} + +static void +exif_mnote_data_olympus_save (ExifMnoteData *ne, + unsigned char **buf, unsigned int *buf_size) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) ne; + unsigned int i, o, s, doff, base = 0, o2 = 6; + int datao = 0; + + if (!n || !buf || !buf_size) return; + + /* + * Allocate enough memory for all entries and the number of entries. + */ + *buf_size = 6 + 2 + 2 + n->count * 12; + switch (n->version) { + case 0: /* Olympus */ + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) return; + + /* Write the header and the number of entries. */ + strcpy (*buf, "OLYMP"); + o2 += 2; + datao = n->offset; + break; + case 1: /* Nikon v1 */ + base = MNOTE_NIKON1_TAG_BASE; + *buf_size -= 8; + /* Fall through */ + case 2: /* Nikon v2 */ + *buf_size += 8; + *buf = exif_mem_alloc (ne->mem, *buf_size); + if (!*buf) return; + + /* Write the header and the number of entries. */ + strcpy (*buf, "Nikon"); + (*buf)[6] = n->version; + o2 += 2; *buf_size += 2; + if (n->version == 2) { + exif_set_short (*buf + 10, n->order, (ExifShort) ( + (n->order == EXIF_BYTE_ORDER_INTEL) ? + ('I' << 8) | 'I' : + ('M' << 8) | 'M')); + exif_set_short (*buf + 12, n->order, (ExifShort) 0x2A); + exif_set_long (*buf + 14, n->order, (ExifShort) 8); + o2 += 2 + 8; + } + datao = -10; + break; + } + + exif_set_short (*buf + o2, n->order, (ExifShort) n->count); + o2 += 2; + + /* Save each entry */ + for (i = 0; i < n->count; i++) { + o = o2 + i * 12; + exif_set_short (*buf + o + 0, n->order, + (ExifShort) (n->entries[i].tag - base)); + exif_set_short (*buf + o + 2, n->order, + (ExifShort) n->entries[i].format); + exif_set_long (*buf + o + 4, n->order, + n->entries[i].components); + o += 8; + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (s > 4) { + doff = *buf_size; + *buf_size += s; + *buf = exif_mem_realloc (ne->mem, *buf, + sizeof (char) * *buf_size); + if (!*buf) return; + exif_set_long (*buf + o, n->order, datao + doff); + } else + doff = o; + + /* Write the data. */ + if (n->entries[i].data) { + memcpy (*buf + doff, n->entries[i].data, s); + } else { + /* Most certainly damaged input file */ + memset (*buf + doff, 0, s); + } + } +} + +static void +exif_mnote_data_olympus_load (ExifMnoteData *en, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) en; + ExifShort c; + unsigned int i, s, o, o2 = 0, datao = 6, base = 0; + + if (!n || !buf) return; + + /* Start of interesting data */ + o2 = 6 + n->offset; + + /* + * Olympus headers start with "OLYMP" and need to have at least + * a size of 22 bytes (6 for 'OLYMP', 2 other bytes, 2 for the + * number of entries, and 12 for one entry. + * + * Nikon headers start with "Nikon" (6 bytes including '\0'), + * version number (1 or 2). + * + * Version 1 continues with 0, 1, 0, number_of_tags, + * or just with number_of_tags (models D1H, D1X...). + * + * Version 2 continues with an unknown byte (0 or 10), + * two unknown bytes (0), "MM" or "II", another byte 0 and + * lastly 0x2A. + */ + if (buf_size - n->offset < 22) return; + if (!memcmp (buf + o2, "OLYMP", 5)) { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Olympus maker note..."); + + /* The number of entries is at position 8. */ + n->version = 0; + o2 += 8; + + } else if (!memcmp (buf + o2, "Nikon", 6)) { + o2 += 6; + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteDataOlympus", + "Parsing Nikon maker note (0x%02x, %02x, %02x, " + "%02x, %02x, %02x, %02x, %02x)...", + buf[o2 + 0], buf[o2 + 1], buf[o2 + 2], buf[o2 + 3], + buf[o2 + 4], buf[o2 + 5], buf[o2 + 6], buf[o2 + 7]); + + /* The first byte is the version. */ + if (o2 >= buf_size) return; + n->version = buf[o2]; + o2 += 1; + + /* Skip an unknown byte (00 or 0A). */ + o2 += 1; + + switch (n->version) { + case 1: + + base = MNOTE_NIKON1_TAG_BASE; + break; + + case 2: + + /* Skip 2 unknown bytes (00 00). */ + o2 += 2; + + /* + * Byte order. From here the data offset + * gets calculated. + */ + datao = o2; + if (o2 >= buf_size) return; + if (!strncmp (&buf[o2], "II", 2)) + n->order = EXIF_BYTE_ORDER_INTEL; + else if (!strncmp (&buf[o2], "MM", 2)) + n->order = EXIF_BYTE_ORDER_MOTOROLA; + else { + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteDatalympus", "Unknown " + "byte order '%c%c'", buf[o2], + buf[o2 + 1]); + return; + } + o2 += 2; + + /* Skip 2 unknown bytes (00 2A). */ + o2 += 2; + + /* Go to where the number of entries is. */ + if (o2 >= buf_size) return; + o2 = datao + exif_get_long (buf + o2, n->order); + break; + + default: + exif_log (en->log, EXIF_LOG_CODE_DEBUG, + "ExifMnoteDataOlympus", "Unknown version " + "number %i.", n->version); + return; + } + } else if (!memcmp (buf + o2, "\0\x1b", 2)) { + n->version = 2; + } else { + return; + } + + /* Number of entries */ + if (o2 >= buf_size) return; + c = exif_get_short (buf + o2, n->order); + o2 += 2; + + /* Read the number of entries and remove old ones. */ + exif_mnote_data_olympus_clear (n); + + n->entries = exif_mem_alloc (en->mem, sizeof (MnoteOlympusEntry) * c); + if (!n->entries) return; + + /* Parse the entries */ + for (i = 0; i < c; i++) { + o = o2 + 12 * i; + if (o + 12 > buf_size) return; + + n->count = i + 1; + n->entries[i].tag = exif_get_short (buf + o, n->order) + base; + n->entries[i].format = exif_get_short (buf + o + 2, n->order); + n->entries[i].components = exif_get_long (buf + o + 4, n->order); + n->entries[i].order = n->order; + + exif_log (en->log, EXIF_LOG_CODE_DEBUG, "ExifMnoteOlympus", + "Loading entry 0x%x ('%s')...", n->entries[i].tag, + mnote_olympus_tag_get_name (n->entries[i].tag)); + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (!s) continue; + o += 8; + if (s > 4) o = exif_get_long (buf + o, n->order) + datao; + if (o + s > buf_size) continue; + + /* Sanity check */ + n->entries[i].data = exif_mem_alloc (en->mem, s); + if (!n->entries[i].data) continue; + n->entries[i].size = s; + memcpy (n->entries[i].data, buf + o, s); + } +} + +static unsigned int +exif_mnote_data_olympus_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataOlympus *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_olympus_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataOlympus *note = (ExifMnoteDataOlympus *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_olympus_get_name (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_name (n->entries[i].tag); +} + +static const char * +exif_mnote_data_olympus_get_title (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_title (n->entries[i].tag); +} + +static const char * +exif_mnote_data_olympus_get_description (ExifMnoteData *d, unsigned int i) +{ + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + + if (!n) return NULL; + if (i >= n->count) return NULL; + return mnote_olympus_tag_get_title (n->entries[i].tag); +} + +static void +exif_mnote_data_olympus_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataOlympus *n = (ExifMnoteDataOlympus *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +static void +exif_mnote_data_olympus_set_offset (ExifMnoteData *n, unsigned int o) +{ + if (n) ((ExifMnoteDataOlympus *) n)->offset = o; +} + +ExifMnoteData * +exif_mnote_data_olympus_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataOlympus)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_olympus_free; + d->methods.set_byte_order = exif_mnote_data_olympus_set_byte_order; + d->methods.set_offset = exif_mnote_data_olympus_set_offset; + d->methods.load = exif_mnote_data_olympus_load; + d->methods.save = exif_mnote_data_olympus_save; + d->methods.count = exif_mnote_data_olympus_count; + d->methods.get_id = exif_mnote_data_olympus_get_id; + d->methods.get_name = exif_mnote_data_olympus_get_name; + d->methods.get_title = exif_mnote_data_olympus_get_title; + d->methods.get_description = exif_mnote_data_olympus_get_description; + d->methods.get_value = exif_mnote_data_olympus_get_value; + + return d; +} diff --git a/src/libexif/olympus/exif-mnote-data-olympus.h b/src/libexif/olympus/exif-mnote-data-olympus.h new file mode 100644 index 0000000..b9b4209 --- /dev/null +++ b/src/libexif/olympus/exif-mnote-data-olympus.h @@ -0,0 +1,45 @@ +/* mnote-olympus-data.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_OLYMPUS_CONTENT_H__ +#define __MNOTE_OLYMPUS_CONTENT_H__ + +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/olympus/mnote-olympus-entry.h> +#include <libexif/exif-byte-order.h> +#include <libexif/exif-mem.h> + +typedef struct _ExifMnoteDataOlympus ExifMnoteDataOlympus; + +struct _ExifMnoteDataOlympus { + ExifMnoteData parent; + + MnoteOlympusEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; + /* 0: Olympus; 1: Nikon v1; 2: Nikon v2 */ + int version; +}; + +ExifMnoteData *exif_mnote_data_olympus_new (ExifMem *); + +#endif /* __MNOTE_OLYMPUS_CONTENT_H__ */ diff --git a/src/libexif/olympus/mnote-olympus-entry.c b/src/libexif/olympus/mnote-olympus-entry.c new file mode 100644 index 0000000..1eff6fe --- /dev/null +++ b/src/libexif/olympus/mnote-olympus-entry.c @@ -0,0 +1,540 @@ +/* mnote-olympus-entry.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "mnote-olympus-entry.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-entry.h> +#include <libexif/i18n.h> + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} + +#define CC2(number,t1,t2,v,maxlen) \ +{ \ + if ((number != t1) && (number != t2)) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i or %i)."), (int) number, \ + (int) t1, (int) t2); \ + break; \ + } \ +} + +static struct { + ExifTag tag; + ExifFormat fmt; + struct { + int index; + const char *string; + } elem[10]; +} items[] = { + { MNOTE_NIKON_TAG_LENSTYPE, EXIF_FORMAT_BYTE, + { {0, N_("AF non D Lens")}, + {1, N_("Manual")}, + {2, N_("AF-D or AF-S Lens")}, + {6, N_("AF-D G Lens")}, + {10, N_("AF-D VR Lens")}, + {0, NULL}}}, + { MNOTE_NIKON_TAG_FLASHUSED, EXIF_FORMAT_BYTE, + { {0, N_("Flash did not fire")}, + {4, N_("Flash unit unknown")}, + {7, N_("Flash is external")}, + {9, N_("Flash is on Camera")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_QUALITY, EXIF_FORMAT_SHORT, + { {1, N_("VGA Basic")}, + {2, N_("VGA Normal")}, + {3, N_("VGA Fine")}, + {4, N_("SXGA Basic")}, + {5, N_("SXGA Normal")}, + {6, N_("SXGA Fine")}, + {10, N_("2 MPixel Basic")}, + {11, N_("2 MPixel Normal")}, + {12, N_("2 MPixel Fine")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_COLORMODE, EXIF_FORMAT_SHORT, + { {1, N_("Color")}, + {2, N_("Monochrome")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_IMAGEADJUSTMENT, EXIF_FORMAT_SHORT, + { {0, N_("Normal")}, + {1, N_("Bright+")}, + {2, N_("Bright-")}, + {3, N_("Contrast+")}, + {4, N_("Contrast-")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_CCDSENSITIVITY, EXIF_FORMAT_SHORT, + { {0, N_("ISO80")}, + {2, N_("ISO160")}, + {4, N_("ISO320")}, + {5, N_("ISO100")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_WHITEBALANCE, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("Preset")}, + {2, N_("Daylight")}, + {3, N_("Incandescense")}, + {4, N_("Fluorescence")}, + {5, N_("Cloudy")}, + {6, N_("SpeedLight")}, + {0, NULL}}}, + { MNOTE_NIKON1_TAG_CONVERTER, EXIF_FORMAT_SHORT, + { {0, N_("No Fisheye")}, + {1, N_("Fisheye On")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_QUALITY, EXIF_FORMAT_SHORT, + { {1, N_("SQ")}, + {2, N_("HQ")}, + {3, N_("SHQ")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_MACRO, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_DIGIZOOM, EXIF_FORMAT_SHORT, + { {0, N_("1x")}, + {2, N_("2x")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_FLASHMODE, EXIF_FORMAT_SHORT, + { {0, N_("Auto")}, + {1, N_("Red-eye reduction")}, + {2, N_("Fill")}, + {3, N_("Off")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_SHARPNESS, EXIF_FORMAT_SHORT, + { {0, N_("Normal")}, + {1, N_("Hard")}, + {2, N_("Soft")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_CONTRAST, EXIF_FORMAT_SHORT, + { {0, N_("Hard")}, + {1, N_("Normal")}, + {2, N_("Soft")}, + {0, NULL}}}, + { MNOTE_OLYMPUS_TAG_MANFOCUS, EXIF_FORMAT_SHORT, + { {0, N_("No")}, + {1, N_("Yes")}, + {0, NULL}}}, + { 0, } +}; + +char * +mnote_olympus_entry_get_value (MnoteOlympusEntry *entry, char *v, unsigned int maxlen) +{ + char buf[30]; + ExifLong vl; + ExifShort vs = 0; + ExifRational vr; + int i, j; + double r, b; + + if (!entry) + return (NULL); + + memset (v, 0, maxlen); + maxlen--; + + if ((!entry->data) && (entry->components > 0)) return (v); + + switch (entry->tag) { + + /* Nikon */ + case MNOTE_NIKON_TAG_FIRMWARE: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + if ((vl & 0xF0F0F0F0) == 0x30303030) { + memcpy (v, entry->data, MIN (maxlen, 4)); + } else { + snprintf (v, maxlen, "%04lx", (long unsigned int) vl); + } + break; + case MNOTE_NIKON_TAG_ISO: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + //vs = exif_get_short (entry->data, entry->order); + vs = exif_get_short (entry->data + 2, entry->order); + snprintf (v, maxlen, "ISO %hd", vs); + break; + case MNOTE_NIKON_TAG_ISO2: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + //vs = exif_get_short (entry->data, entry->order); + vs = exif_get_short (entry->data + 2, entry->order); + snprintf (v, maxlen, "ISO2 %hd", vs); + break; + case MNOTE_NIKON_TAG_QUALITY: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + //CC (entry->components, 8, v, maxlen); + //vl = exif_get_long (entry->data , entry->order); + //printf("-> 0x%04x\n",entry->data); + //printf("-> 0x%s<\n",entry->data - 0); + memcpy(v, entry->data ,entry->components); + //snprintf (v, maxlen, "%s<", ( entry->data - 9 ); + break; + case MNOTE_NIKON_TAG_COLORMODE: + case MNOTE_NIKON_TAG_COLORMODE1: + case MNOTE_NIKON_TAG_WHITEBALANCE: + case MNOTE_NIKON_TAG_SHARPENING: + case MNOTE_NIKON_TAG_FOCUSMODE: + case MNOTE_NIKON_TAG_FLASHSETTING: + case MNOTE_NIKON_TAG_ISOSELECTION: + case MNOTE_NIKON_TAG_FLASHMODE: + case MNOTE_NIKON_TAG_IMAGEADJUSTMENT: + case MNOTE_NIKON_TAG_ADAPTER: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + memcpy(v, entry->data, MIN (maxlen, entry->components)); + break; + case MNOTE_NIKON_TAG_TOTALPICTURES: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 1, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (v, maxlen, "%lu", (long unsigned int) vl ); + break; + case MNOTE_NIKON_TAG_WHITEBALANCEFINE: + CF (entry->format, EXIF_FORMAT_SSHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + snprintf (v, maxlen, "%hd", vs); + break; + case MNOTE_NIKON_TAG_WHITEBALANCERB: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 4, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + r = (double)vr.numerator / vr.denominator; + vr = exif_get_rational (entry->data+8, entry->order); + b = (double)vr.numerator / vr.denominator; + //printf("numerator %li, denominator %li\n", vr.numerator, vr.denominator); + snprintf (v, maxlen, "Red Correction %f, Blue Correction %f", r,b); + break; + case MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (vr.numerator) { + r = (double)vr.numerator / vr.denominator; + snprintf (v, maxlen, "%2.2f meters", r); + } else { + strncpy (v, _("No manual focus selection"), maxlen); + } + break; + case MNOTE_NIKON_TAG_DIGITALZOOM: + case MNOTE_NIKON1_TAG_DIGITALZOOM: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + r = (double)vr.numerator / vr.denominator; + snprintf (v, maxlen, "%2.2f", r); + break; + case MNOTE_NIKON_TAG_AFFOCUSPOSITION: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 4, v, maxlen); + switch ( *( entry->data+1) ) { + case 0: strncpy (v, "AF Position: Center", maxlen); break; + case 1: strncpy (v, "AF Position: Top", maxlen); break; + case 2: strncpy (v, "AF Position: Bottom", maxlen); break; + case 3: strncpy (v, "AF Position: Left", maxlen); break; + case 4: strncpy (v, "AF Position: Right", maxlen); break; + default: strncpy (v, "Unknown AF Position", maxlen); + } + break; + case MNOTE_OLYMPUS_TAG_DIGIZOOM: + if (entry->format == EXIF_FORMAT_RATIONAL) { + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + r = (double)vr.numerator / vr.denominator; + if (!vr.numerator) { + strncpy (v, _("None"), maxlen); + } else { + snprintf (v, maxlen, "%2.2f", r); + } + break; + } + /* fall through to handle SHORT version of this tag */ + case MNOTE_NIKON_TAG_LENSTYPE: + case MNOTE_NIKON_TAG_FLASHUSED: + case MNOTE_NIKON1_TAG_QUALITY: + case MNOTE_NIKON1_TAG_COLORMODE: + case MNOTE_NIKON1_TAG_IMAGEADJUSTMENT: + case MNOTE_NIKON1_TAG_CCDSENSITIVITY: + case MNOTE_NIKON1_TAG_WHITEBALANCE: + case MNOTE_NIKON1_TAG_CONVERTER: + case MNOTE_OLYMPUS_TAG_QUALITY: + case MNOTE_OLYMPUS_TAG_MACRO: + case MNOTE_OLYMPUS_TAG_FLASHMODE: + case MNOTE_OLYMPUS_TAG_SHARPNESS: + case MNOTE_OLYMPUS_TAG_CONTRAST: + case MNOTE_OLYMPUS_TAG_MANFOCUS: + /* search the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++); + if (!items[i].tag) { + strncpy (v, "Internal error", maxlen); + break; + } + CF (entry->format, items[i].fmt, v, maxlen); + CC (entry->components, 1, v, maxlen); + switch (entry->format) { + case EXIF_FORMAT_BYTE: + case EXIF_FORMAT_UNDEFINED: + vs = entry->data[0]; + break; + case EXIF_FORMAT_SHORT: + vs = exif_get_short(entry->data, entry->order); + break; + default: + vs = 0; + break; + } + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (v, maxlen, "Unknown value %hi", vs); + break; + } + strncpy (v, items[i].elem[j].string, maxlen); + break; + + case MNOTE_NIKON_TAG_LENS: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 4, v, maxlen); + { + double c,d; + unsigned long a,b; + vr = exif_get_rational (entry->data, entry->order); + a = vr.numerator / vr.denominator; + vr = exif_get_rational (entry->data+8, entry->order); + b = vr.numerator / vr.denominator; + vr = exif_get_rational (entry->data+16, entry->order); + c = (double)vr.numerator / vr.denominator; + vr = exif_get_rational (entry->data+24, entry->order); + d = (double)vr.numerator / vr.denominator; + //printf("numerator %li, denominator %li\n", vr.numerator, vr.denominator); + snprintf (v, maxlen, "%ld-%ldmm 1:%3.1f - %3.1f",a,b,c,d); + } + break; + case MNOTE_NIKON1_TAG_FOCUS: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (!vr.denominator) { + strncpy (v, _("Infinite"), maxlen); + } else { + r = (double)vr.numerator / vr.denominator; + snprintf (v, maxlen, "%2.2f", r); + } + break; + + /* Olympus */ + case MNOTE_OLYMPUS_TAG_MODE: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 3, v, maxlen); + vl = exif_get_long (entry->data, entry->order); + switch (vl) { + case 0: + strncpy (v, _("normal"), maxlen); + break; + case 1: + strncpy (v, _("unknown"), maxlen); + break; + case 2: + strncpy (v, _("fast"), maxlen); + break; + case 3: + strncpy (v, _("panorama"), maxlen); + break; + default: + snprintf (v, maxlen, _("%li"), (long int) vl); + } + vl = exif_get_long (entry->data + 4, entry->order); + snprintf (buf, sizeof (buf), "/%li/", (long int) vl); + strncat (v, buf, maxlen - strlen (v)); + vl = exif_get_long (entry->data + 4, entry->order); + switch (vl) { + case 1: + strncat (v, _("left to right"), maxlen - strlen (v)); + break; + case 2: + strncat (v, _("right to left"), maxlen - strlen (v)); + break; + case 3: + strncat (v, _("bottom to top"), maxlen - strlen (v)); + break; + case 4: + strncat (v, _("top to bottom"), maxlen - strlen (v)); + break; + default: + snprintf (buf, sizeof (buf), _("%li"), + (long int) vl); + strncat (v, buf, maxlen - strlen (v)); + } + break; + case MNOTE_OLYMPUS_TAG_UNKNOWN_1: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + strncpy (v, _("Unknown tag."), maxlen); + break; + case MNOTE_OLYMPUS_TAG_UNKNOWN_2: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + break; + case MNOTE_OLYMPUS_TAG_UNKNOWN_3: + CF (entry->format, EXIF_FORMAT_SSHORT, v, maxlen); + CC (entry->components, 1, v, maxlen); + break; + case MNOTE_OLYMPUS_TAG_VERSION: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + CC2 (entry->components, 5, 8, v, maxlen); + strncpy (v, entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_INFO: + CF (entry->format, EXIF_FORMAT_ASCII, v, maxlen); + CC2 (entry->components, 52, 53, v, maxlen); + strncpy (v, entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_ID: + CF (entry->format, EXIF_FORMAT_UNDEFINED, v, maxlen); + CC (entry->components, 32, v, maxlen); + strncpy (v, entry->data, MIN (maxlen, entry->size)); + break; + case MNOTE_OLYMPUS_TAG_UNKNOWN_4: + CF (entry->format, EXIF_FORMAT_LONG, v, maxlen); + CC (entry->components, 30, v, maxlen); + break; + case MNOTE_OLYMPUS_TAG_FOCUSDIST: + CF (entry->format, EXIF_FORMAT_RATIONAL, v, maxlen); + CC (entry->components, 1, v, maxlen); + vr = exif_get_rational (entry->data, entry->order); + if (vr.numerator == 0) { + strncpy (v, _("Unknown"), maxlen); + } + else { + unsigned long tmp = vr.numerator / vr.denominator; + /* printf("numerator %li, denominator %li\n", vr.numerator, vr.denominator); */ + snprintf (v, maxlen, "%li mm", tmp); + } + break; + case MNOTE_OLYMPUS_TAG_WBALANCE: + CF (entry->format, EXIF_FORMAT_SHORT, v, maxlen); + CC (entry->components, 2, v, maxlen); + vs = exif_get_short (entry->data, entry->order); + switch (vs) { + case 1: + strncpy (v, _("Automatic"), maxlen); + break; + case 2: + { + ExifShort v2 = exif_get_short (entry->data + 2, entry->order); + unsigned long colorTemp = 0; + switch (v2) { + case 2: + colorTemp = 3000; + break; + case 3: + colorTemp = 3700; + break; + case 4: + colorTemp = 4000; + break; + case 5: + colorTemp = 4500; + break; + case 6: + colorTemp = 5500; + break; + case 7: + colorTemp = 6500; + break; + case 9: + colorTemp = 7500; + break; + } + if (colorTemp) { + snprintf (v, maxlen, "Manual: %liK", colorTemp); + } + else { + strncpy (v, _("Manual: Unknown"), maxlen); + } + + } + break; + case 3: + strncpy (v, _("One-touch"), maxlen); + break; + default: + strncpy (v, _("Unknown"), maxlen); + break; + } + break; + default: + switch (entry->format) { + case EXIF_FORMAT_ASCII: + strncpy (v, entry->data, + MIN (maxlen, entry->components)); + break; + case EXIF_FORMAT_SHORT: + vs = exif_get_short (entry->data, entry->order); + snprintf (v, maxlen, "%hi", vs); + break; + case EXIF_FORMAT_LONG: + vl = exif_get_long (entry->data, entry->order); + snprintf (v, maxlen, "%li", (long int) vl); + break; + case EXIF_FORMAT_UNDEFINED: + default: + snprintf (v, maxlen, _("%li bytes unknown data: "), + (long int) entry->size); + for (i = 0; i < (int)entry->size; i++) { + sprintf (buf, "%02x", entry->data[i]); + strncat (v, buf, maxlen - strlen (v)); + } + break; + } + break; + } + + return (v); +} diff --git a/src/libexif/olympus/mnote-olympus-entry.h b/src/libexif/olympus/mnote-olympus-entry.h new file mode 100644 index 0000000..a725228 --- /dev/null +++ b/src/libexif/olympus/mnote-olympus-entry.h @@ -0,0 +1,43 @@ +/* mnote-olympus-entry.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_OLYMPUS_ENTRY_H__ +#define __MNOTE_OLYMPUS_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/olympus/mnote-olympus-tag.h> + +typedef struct _MnoteOlympusEntry MnoteOlympusEntry; + +struct _MnoteOlympusEntry { + MnoteOlympusTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_olympus_entry_get_value (MnoteOlympusEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_OLYMPUS_ENTRY_H__ */ diff --git a/src/libexif/olympus/mnote-olympus-tag.c b/src/libexif/olympus/mnote-olympus-tag.c new file mode 100644 index 0000000..b7beacd --- /dev/null +++ b/src/libexif/olympus/mnote-olympus-tag.c @@ -0,0 +1,155 @@ +/* mnote-olympus-tag.c: + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "mnote-olympus-tag.h" + +#include <libexif/i18n.h> +#include <libexif/exif-utils.h> + +#include <stdlib.h> + +static struct { + MnoteOlympusTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { + + /* Nikon v2 */ + {MNOTE_NIKON_TAG_FIRMWARE, "Firmware", N_("Firmware Version"), NULL}, + {MNOTE_NIKON_TAG_ISO, "ISO", N_("ISO Setting"), NULL}, + {MNOTE_NIKON_TAG_COLORMODE1, "COLORMODE1", N_("Colormode (?)"), NULL}, + {MNOTE_NIKON_TAG_QUALITY, "QUALITY", N_("Quality"), NULL}, + {MNOTE_NIKON_TAG_WHITEBALANCE, "WHITEBALANCE", N_("Whitebalance"), NULL}, + {MNOTE_NIKON_TAG_SHARPENING, "SHARPENING", N_("Image Sharpening"), NULL}, + {MNOTE_NIKON_TAG_FOCUSMODE, "FOCUSMODE", N_("Focus Mode"), NULL}, + {MNOTE_NIKON_TAG_FLASHSETTING, "FLASHSETTING", N_("Flash Setting"), NULL}, + {MNOTE_NIKON_TAG_FLASHMODE, "FLASHMODE", N_("Flash Mode"), NULL}, + {MNOTE_NIKON_TAG_WHITEBALANCEFINE,"WHITEBALANCEFINE",N_("Whitebalance fine ajustment"), NULL}, + {MNOTE_NIKON_TAG_WHITEBALANCERB, "WHITEBALANCERB", N_("Whitebalance RB"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X000D, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_ISOSELECTION, "ISOSELECTION", N_("Isoselection"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0011, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_EXPOSUREDIFF, "EXPOSUREDIFF", N_("Exposurediff ?"), NULL}, + {MNOTE_NIKON_TAG_FLASHCOMPENSATION, "FLASHCOMPENSATION", N_("Flashcompensation ?"), NULL}, + {MNOTE_NIKON_TAG_ISO2, "ISO", N_("ISO Setting"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0016, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0017, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0018, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0019, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_IMAGEADJUSTMENT, "ImageAdjustment", N_("Image Adjustment"), NULL}, + {MNOTE_NIKON_TAG_TONECOMPENSATION, "TONECOMPENSATION", N_("Tonecompensation"), NULL}, + {MNOTE_NIKON_TAG_ADAPTER, "Adapter", N_("Adapter"), NULL}, + {MNOTE_NIKON_TAG_LENSTYPE, "LENSTYPE", N_("Lenstype"), NULL}, + {MNOTE_NIKON_TAG_LENS, "LENS", N_("Lens"), NULL}, + {MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE, "MANUALFOCUSDISTANCE", N_("Manual Focus Distance"), NULL}, + {MNOTE_NIKON_TAG_DIGITALZOOM, "DigitalZoom", N_("Digital Zoom"), NULL}, + {MNOTE_NIKON_TAG_FLASHUSED, "FLASHUSED", N_("Flash used"), NULL}, + {MNOTE_NIKON_TAG_AFFOCUSPOSITION, "AFFOCUSPOSITION", N_("AF Focus position"), NULL}, + {MNOTE_NIKON_TAG_BRACKETING, "BRACKETING", N_("Bracketing"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X008A, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X008B, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_CURVE, "CURVE,", N_("Contrast curve"), NULL}, + {MNOTE_NIKON_TAG_COLORMODE, "COLORMODE,", N_("Colormode"), NULL}, + {MNOTE_NIKON_TAG_LIGHTYPE, "LIGHTYPE,", N_("Lightype"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0091, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_HUE, "Hue,", N_("Hue Adjustment"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0094, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_NOISEREDUCTION, "NOISEREDUCTION,", N_("Noisereduction"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0097, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0098, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X009A, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X009B, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A0, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A2, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A3, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_TOTALPICTURES, "TOTALPICTURES,", N_("Total number of pictures taken"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00A8, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_OPTIMIZATION, "OPTIMIZATION,", N_("Optimize Image"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00AA, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X00AB, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_CAPTUREEDITORDATA, "CAPTUREEDITORDATA", N_("Capture Editor Data"), NULL}, + {MNOTE_NIKON_TAG_CAPTUREEDITORVER, "CAPTUREEDITORVER", N_("Capture Editor Version"), NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0E0E, NULL, NULL, NULL}, + {MNOTE_NIKON_TAG_UNKNOWN_0X0E10, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_UNKNOWN_0X0002, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_QUALITY, "QUALITY", N_("Quality"), NULL}, + {MNOTE_NIKON1_TAG_COLORMODE, "COLORMODE,", N_("Colormode"), NULL}, + {MNOTE_NIKON1_TAG_IMAGEADJUSTMENT, "ImageAdjustment", N_("Image Adjustment"), NULL}, + {MNOTE_NIKON1_TAG_CCDSENSITIVITY, "CCDSensitivity", N_("CCD Sensitivity"), NULL}, + {MNOTE_NIKON1_TAG_WHITEBALANCE, "WhiteBalance", N_("Whitebalance"), NULL}, + {MNOTE_NIKON1_TAG_FOCUS, "Focus", N_("Focus"), NULL}, + {MNOTE_NIKON1_TAG_UNKNOWN_0X0009, NULL, NULL, NULL}, + {MNOTE_NIKON1_TAG_DIGITALZOOM, "DigitalZoom", N_("Digital Zoom"), NULL}, + {MNOTE_NIKON1_TAG_CONVERTER, "Converter", N_("Converter"), NULL}, + + /* Olympus */ + {MNOTE_OLYMPUS_TAG_MODE, "Mode", N_("Speed/Sequence/Panorama direction"), NULL}, + {MNOTE_OLYMPUS_TAG_QUALITY, "Quality", N_("Quality"), NULL}, + {MNOTE_OLYMPUS_TAG_MACRO, "Macro", N_("Macro"), NULL}, + {MNOTE_OLYMPUS_TAG_UNKNOWN_1, NULL, NULL, NULL}, + {MNOTE_OLYMPUS_TAG_DIGIZOOM, "DigiZoom", N_("Digital Zoom"), NULL}, + {MNOTE_OLYMPUS_TAG_UNKNOWN_2, NULL, NULL, NULL}, + {MNOTE_OLYMPUS_TAG_UNKNOWN_3, NULL, NULL, NULL}, + {MNOTE_OLYMPUS_TAG_VERSION, "FirmwareVersion", N_("Firmware version"), NULL}, + {MNOTE_OLYMPUS_TAG_INFO, "Info", N_("Info"), NULL}, + {MNOTE_OLYMPUS_TAG_ID, "CameraID", N_("Camera ID"), NULL}, + {MNOTE_OLYMPUS_TAG_UNKNOWN_4, NULL, NULL, NULL}, + {MNOTE_OLYMPUS_TAG_FLASHMODE, "FlashMode", N_("Flash Mode"), NULL}, + {MNOTE_OLYMPUS_TAG_FOCUSDIST, "ManualFocusDistance", N_("Manual Focus Distance"), NULL}, + {MNOTE_OLYMPUS_TAG_SHARPNESS, "Sharpness", N_("Sharpness Setting"), NULL}, + {MNOTE_OLYMPUS_TAG_WBALANCE, "WhiteBalance", N_("White Balance Setting"), NULL}, + {MNOTE_OLYMPUS_TAG_CONTRAST, "Contrast", N_("Contrast Setting"), NULL}, + {MNOTE_OLYMPUS_TAG_MANFOCUS, "ManualFocus", N_("Manual Focus"), NULL}, + {0, NULL, NULL, NULL} +}; + +const char * +mnote_olympus_tag_get_name (MnoteOlympusTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (table[i].name); + return NULL; +} + +const char * +mnote_olympus_tag_get_title (MnoteOlympusTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_olympus_tag_get_description (MnoteOlympusTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].description)); + return NULL; +} diff --git a/src/libexif/olympus/mnote-olympus-tag.h b/src/libexif/olympus/mnote-olympus-tag.h new file mode 100644 index 0000000..22278ac --- /dev/null +++ b/src/libexif/olympus/mnote-olympus-tag.h @@ -0,0 +1,130 @@ +/* mnote-olympus-tag.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_OLYMPUS_TAG_H__ +#define __MNOTE_OLYMPUS_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum _MnoteOlympusTag { + + /* Nikon v.2 */ + MNOTE_NIKON_TAG_FIRMWARE = 0x0001, + MNOTE_NIKON_TAG_ISO = 0x0002, + MNOTE_NIKON_TAG_COLORMODE1 = 0x0003, + MNOTE_NIKON_TAG_QUALITY = 0x0004, + MNOTE_NIKON_TAG_WHITEBALANCE = 0x0005, + MNOTE_NIKON_TAG_SHARPENING = 0x0006, + MNOTE_NIKON_TAG_FOCUSMODE = 0x0007, + MNOTE_NIKON_TAG_FLASHSETTING = 0x0008, + MNOTE_NIKON_TAG_FLASHMODE = 0x0009, + MNOTE_NIKON_TAG_WHITEBALANCEFINE = 0x000b, + MNOTE_NIKON_TAG_WHITEBALANCERB = 0x000c, + MNOTE_NIKON_TAG_UNKNOWN_0X000D = 0x000d, + MNOTE_NIKON_TAG_EXPOSUREDIFF = 0x000e, + MNOTE_NIKON_TAG_ISOSELECTION = 0x000f, + MNOTE_NIKON_TAG_UNKNOWN_0X0011 = 0x0011, + MNOTE_NIKON_TAG_FLASHCOMPENSATION = 0x0012, + MNOTE_NIKON_TAG_ISO2 = 0x0013, + MNOTE_NIKON_TAG_UNKNOWN_0X0016 = 0x0016, + MNOTE_NIKON_TAG_UNKNOWN_0X0017 = 0x0017, + MNOTE_NIKON_TAG_UNKNOWN_0X0018 = 0x0018, + MNOTE_NIKON_TAG_UNKNOWN_0X0019 = 0x0019, + MNOTE_NIKON_TAG_IMAGEADJUSTMENT = 0x0080, + MNOTE_NIKON_TAG_TONECOMPENSATION = 0x0081, + MNOTE_NIKON_TAG_ADAPTER = 0x0082, + MNOTE_NIKON_TAG_LENSTYPE = 0x0083, + MNOTE_NIKON_TAG_LENS = 0x0084, + MNOTE_NIKON_TAG_MANUALFOCUSDISTANCE = 0x0085, + MNOTE_NIKON_TAG_DIGITALZOOM = 0x0086, + MNOTE_NIKON_TAG_FLASHUSED = 0x0087, + MNOTE_NIKON_TAG_AFFOCUSPOSITION = 0x0088, + MNOTE_NIKON_TAG_BRACKETING = 0x0089, + MNOTE_NIKON_TAG_UNKNOWN_0X008A = 0x008a, + MNOTE_NIKON_TAG_UNKNOWN_0X008B = 0x008b, + MNOTE_NIKON_TAG_CURVE = 0x008c, + MNOTE_NIKON_TAG_COLORMODE = 0x008d, + MNOTE_NIKON_TAG_LIGHTYPE = 0x0090, + MNOTE_NIKON_TAG_UNKNOWN_0X0091 = 0x0091, + MNOTE_NIKON_TAG_HUE = 0x0092, + MNOTE_NIKON_TAG_UNKNOWN_0X0094 = 0x0094, + MNOTE_NIKON_TAG_NOISEREDUCTION = 0x0095, + MNOTE_NIKON_TAG_UNKNOWN_0X0097 = 0x0097, + MNOTE_NIKON_TAG_UNKNOWN_0X0098 = 0x0098, + MNOTE_NIKON_TAG_UNKNOWN_0X009A = 0x009a, + MNOTE_NIKON_TAG_UNKNOWN_0X009B = 0x009b, + MNOTE_NIKON_TAG_UNKNOWN_0X00A0 = 0x00a0, + MNOTE_NIKON_TAG_UNKNOWN_0X00A2 = 0x00a2, + MNOTE_NIKON_TAG_UNKNOWN_0X00A3 = 0x00a3, + MNOTE_NIKON_TAG_TOTALPICTURES = 0x00a7, + MNOTE_NIKON_TAG_UNKNOWN_0X00A8 = 0x00a8, + MNOTE_NIKON_TAG_OPTIMIZATION = 0x00a9, + MNOTE_NIKON_TAG_UNKNOWN_0X00AA = 0x00aa, + MNOTE_NIKON_TAG_UNKNOWN_0X00AB = 0x00ab, + MNOTE_NIKON_TAG_CAPTUREEDITORDATA = 0x0e01, + MNOTE_NIKON_TAG_CAPTUREEDITORVER = 0x0e09, + MNOTE_NIKON_TAG_UNKNOWN_0X0E0E = 0x0e0e, + MNOTE_NIKON_TAG_UNKNOWN_0X0E10 = 0x0e10, + + /* Nikon v1: real values + our proprietary base to distinguish from v2 */ + MNOTE_NIKON1_TAG_BASE = 0x8000, + MNOTE_NIKON1_TAG_UNKNOWN_0X0002 = 0x0002 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_QUALITY = 0x0003 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_COLORMODE = 0x0004 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_IMAGEADJUSTMENT = 0x0005 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_CCDSENSITIVITY = 0x0006 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_WHITEBALANCE = 0x0007 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_FOCUS = 0x0008 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_UNKNOWN_0X0009 = 0x0009 + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_DIGITALZOOM = 0x000a + MNOTE_NIKON1_TAG_BASE, + MNOTE_NIKON1_TAG_CONVERTER = 0x000b + MNOTE_NIKON1_TAG_BASE, + + /* Olympus */ + MNOTE_OLYMPUS_TAG_MODE = 0x0200, + MNOTE_OLYMPUS_TAG_QUALITY = 0x0201, + MNOTE_OLYMPUS_TAG_MACRO = 0x0202, + MNOTE_OLYMPUS_TAG_UNKNOWN_1 = 0x0203, + MNOTE_OLYMPUS_TAG_DIGIZOOM = 0x0204, + MNOTE_OLYMPUS_TAG_UNKNOWN_2 = 0x0205, + MNOTE_OLYMPUS_TAG_UNKNOWN_3 = 0x0206, + MNOTE_OLYMPUS_TAG_VERSION = 0x0207, + MNOTE_OLYMPUS_TAG_INFO = 0x0208, + MNOTE_OLYMPUS_TAG_ID = 0x0209, + MNOTE_OLYMPUS_TAG_UNKNOWN_4 = 0x0f04, + MNOTE_OLYMPUS_TAG_FLASHMODE = 0x1004, + MNOTE_OLYMPUS_TAG_MANFOCUS = 0x100b, + MNOTE_OLYMPUS_TAG_FOCUSDIST = 0x100c, + MNOTE_OLYMPUS_TAG_SHARPNESS = 0x100f, + MNOTE_OLYMPUS_TAG_WBALANCE = 0x1015, + MNOTE_OLYMPUS_TAG_CONTRAST = 0x1029 +}; +typedef enum _MnoteOlympusTag MnoteOlympusTag; + +const char *mnote_olympus_tag_get_name (MnoteOlympusTag tag); +const char *mnote_olympus_tag_get_title (MnoteOlympusTag tag); +const char *mnote_olympus_tag_get_description (MnoteOlympusTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_OLYMPUS_TAG_H__ */ diff --git a/src/libexif/pentax/exif-mnote-data-pentax.c b/src/libexif/pentax/exif-mnote-data-pentax.c new file mode 100644 index 0000000..cc2cc12 --- /dev/null +++ b/src/libexif/pentax/exif-mnote-data-pentax.c @@ -0,0 +1,209 @@ +/* exif-mnote-data-pentax.c + * + * Copyright © 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "exif-mnote-data-pentax.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-utils.h> + +/* #define DEBUG */ + +static void +exif_mnote_data_pentax_clear (ExifMnoteDataPentax *n) +{ + ExifMnoteData *d = (ExifMnoteData *) n; + unsigned int i; + + if (!n) return; + + if (n->entries) { + for (i = 0; i < n->count; i++) + if (n->entries[i].data) { + exif_mem_free (d->mem, n->entries[i].data); + n->entries[i].data = NULL; + } + exif_mem_free (d->mem, n->entries); + n->entries = NULL; + n->count = 0; + } +} + +static void +exif_mnote_data_pentax_free (ExifMnoteData *n) +{ + if (!n) return; + + exif_mnote_data_pentax_clear ((ExifMnoteDataPentax *) n); +} + +static char * +exif_mnote_data_pentax_get_value (ExifMnoteData *d, unsigned int i, char *val, unsigned int maxlen) +{ + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d; + + if (!n) return NULL; + if (n->count <= i) return NULL; + return mnote_pentax_entry_get_value (&n->entries[i], val, maxlen); +} + +static void +exif_mnote_data_pentax_load (ExifMnoteData *en, + const unsigned char *buf, unsigned int buf_size) +{ + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) en; + unsigned int i, o, s; + ExifShort c; + + /* Number of entries */ + if (buf_size < 2) return; + c = exif_get_short (buf + 6 + n->offset, n->order); + n->entries = exif_mem_alloc (en->mem, sizeof (MnotePentaxEntry) * c); + if (!n->entries) return; + + for (i = 0; i < c; i++) { + o = 6 + 2 + n->offset + 12 * i; + if (o + 8 > buf_size) return; + + n->count = i + 1; + n->entries[i].tag = exif_get_short (buf + o + 0, n->order); + n->entries[i].format = exif_get_short (buf + o + 2, n->order); + n->entries[i].components = exif_get_long (buf + o + 4, n->order); + n->entries[i].order = n->order; + + /* + * Size? If bigger than 4 bytes, the actual data is not + * in the entry but somewhere else (offset). + */ + s = exif_format_get_size (n->entries[i].format) * + n->entries[i].components; + if (!s) return; + o += 8; + if (s > 4) o = exif_get_long (buf + o, n->order) + 6; + if (o + s > buf_size) return; + + /* Sanity check */ + n->entries[i].data = exif_mem_alloc (en->mem, sizeof (char) * s); + if (!n->entries[i].data) return; + n->entries[i].size = s; + memcpy (n->entries[i].data, buf + o, s); + } +} + +static unsigned int +exif_mnote_data_pentax_count (ExifMnoteData *n) +{ + return n ? ((ExifMnoteDataPentax *) n)->count : 0; +} + +static unsigned int +exif_mnote_data_pentax_get_id (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return 0; + if (note->count <= n) return 0; + return note->entries[n].tag; +} + +static const char * +exif_mnote_data_pentax_get_name (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_name (note->entries[n].tag); +} + +static const char * +exif_mnote_data_pentax_get_title (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_title (note->entries[n].tag); +} + +static const char * +exif_mnote_data_pentax_get_description (ExifMnoteData *d, unsigned int n) +{ + ExifMnoteDataPentax *note = (ExifMnoteDataPentax *) d; + + if (!note) return NULL; + if (note->count <= n) return NULL; + return mnote_pentax_tag_get_description (note->entries[n].tag); +} + +static void +exif_mnote_data_pentax_set_offset (ExifMnoteData *d, unsigned int o) +{ + if (d) ((ExifMnoteDataPentax *) d)->offset = o; +} + +static void +exif_mnote_data_pentax_set_byte_order (ExifMnoteData *d, ExifByteOrder o) +{ + ExifByteOrder o_orig; + ExifMnoteDataPentax *n = (ExifMnoteDataPentax *) d; + unsigned int i; + + if (!n) return; + + o_orig = n->order; + n->order = o; + for (i = 0; i < n->count; i++) { + n->entries[i].order = o; + exif_array_set_byte_order (n->entries[i].format, n->entries[i].data, + n->entries[i].components, o_orig, o); + } +} + +ExifMnoteData * +exif_mnote_data_pentax_new (ExifMem *mem) +{ + ExifMnoteData *d; + + if (!mem) return NULL; + + d = exif_mem_alloc (mem, sizeof (ExifMnoteDataPentax)); + if (!d) return NULL; + + exif_mnote_data_construct (d, mem); + + /* Set up function pointers */ + d->methods.free = exif_mnote_data_pentax_free; + d->methods.set_byte_order = exif_mnote_data_pentax_set_byte_order; + d->methods.set_offset = exif_mnote_data_pentax_set_offset; + d->methods.load = exif_mnote_data_pentax_load; + d->methods.count = exif_mnote_data_pentax_count; + d->methods.get_id = exif_mnote_data_pentax_get_id; + d->methods.get_name = exif_mnote_data_pentax_get_name; + d->methods.get_title = exif_mnote_data_pentax_get_title; + d->methods.get_description = exif_mnote_data_pentax_get_description; + d->methods.get_value = exif_mnote_data_pentax_get_value; + + return d; +} diff --git a/src/libexif/pentax/exif-mnote-data-pentax.h b/src/libexif/pentax/exif-mnote-data-pentax.h new file mode 100644 index 0000000..c04bc41 --- /dev/null +++ b/src/libexif/pentax/exif-mnote-data-pentax.h @@ -0,0 +1,44 @@ +/* exif-mnote-data-pentax.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EXIF_MNOTE_DATA_PENTAX_H__ +#define __EXIF_MNOTE_DATA_PENTAX_H__ + +#include <libexif/exif-byte-order.h> +#include <libexif/exif-mnote-data.h> +#include <libexif/exif-mnote-data-priv.h> +#include <libexif/pentax/mnote-pentax-entry.h> +#include <libexif/exif-mem.h> + +typedef struct _ExifMnoteDataPentax ExifMnoteDataPentax; + +struct _ExifMnoteDataPentax { + ExifMnoteData parent; + + MnotePentaxEntry *entries; + unsigned int count; + + ExifByteOrder order; + unsigned int offset; +}; + +ExifMnoteData *exif_mnote_data_pentax_new (ExifMem *); + +#endif /* __EXIF_MNOTE_DATA_PENTAX_H__ */ diff --git a/src/libexif/pentax/mnote-pentax-entry.c b/src/libexif/pentax/mnote-pentax-entry.c new file mode 100644 index 0000000..3469f22 --- /dev/null +++ b/src/libexif/pentax/mnote-pentax-entry.c @@ -0,0 +1,210 @@ +/* mnote-pentax-entry.c + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "mnote-pentax-entry.h" + +#include <libexif/i18n.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <libexif/exif-format.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-entry.h> + + +#define CF(format,target,v,maxlen) \ +{ \ + if (format != target) { \ + snprintf (v, maxlen, \ + _("Invalid format '%s', " \ + "expected '%s'."), \ + exif_format_get_name (format), \ + exif_format_get_name (target)); \ + break; \ + } \ +} + +#define CC(number,target,v,maxlen) \ +{ \ + if (number != target) { \ + snprintf (v, maxlen, \ + _("Invalid number of components (%i, " \ + "expected %i)."), (int) number, (int) target); \ + break; \ + } \ +} + +static struct { + ExifTag tag; + struct { + int index; + const char *string; + } elem[7]; +} items[] = { + { MNOTE_PENTAX_TAG_MODE, + { {0, N_("Auto")}, + {1, N_("Night-scene")}, + {2, N_("Manual")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_QUALITY, + { {0, N_("Good")}, + {1, N_("Better")}, + {2, N_("Best")},{0,NULL}}}, + { MNOTE_PENTAX_TAG_FOCUS, + { {2, N_("Custom")}, + {3, N_("Auto")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_FLASH, + { {1, N_("Auto")}, + {2, N_("Flash on")}, + {4, N_("Flash off")}, + {6, N_("Red-eye Reduction")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_WHITE_BALANCE, + { {0, N_("Auto")}, + {1, N_("Daylight")}, + {2, N_("Shade")}, + {3, N_("Tungsten")}, + {4, N_("Fluorescent")}, + {5, N_("Manual")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_SHARPNESS, + { {0, N_("Normal")}, + {1, N_("Soft")}, + {2, N_("Hard")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_CONTRAST, + { {0, N_("Normal")}, + {1, N_("Low")}, + {2, N_("High")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_SATURATION, + { {0, N_("Normal")}, + {1, N_("Low")}, + {2, N_("High")}, + {0, NULL}}}, + { MNOTE_PENTAX_TAG_ISO_SPEED, + { {10, N_("100")}, + {16, N_("200")}, + {100, N_("100")}, + {200, N_("200")}, + { 0, NULL}}}, + { MNOTE_PENTAX_TAG_COLOR, + { {1, N_("Full")}, + {2, N_("Black & White")}, + {3, N_("Sepia")}, + {0, NULL}}}, +}; + +char * +mnote_pentax_entry_get_value (MnotePentaxEntry *entry, + char *val, unsigned int maxlen) +{ + ExifLong vl; + ExifShort vs; + int i = 0, j = 0; + + if (!entry) return (NULL); + + memset (val, 0, maxlen); + maxlen--; + + switch (entry->tag) { + case MNOTE_PENTAX_TAG_MODE: + case MNOTE_PENTAX_TAG_QUALITY: + case MNOTE_PENTAX_TAG_FOCUS: + case MNOTE_PENTAX_TAG_FLASH: + case MNOTE_PENTAX_TAG_WHITE_BALANCE: + case MNOTE_PENTAX_TAG_SHARPNESS: + case MNOTE_PENTAX_TAG_CONTRAST: + case MNOTE_PENTAX_TAG_SATURATION: + case MNOTE_PENTAX_TAG_ISO_SPEED: + case MNOTE_PENTAX_TAG_COLOR: + CF (entry->format, EXIF_FORMAT_SHORT, val, maxlen); + CC (entry->components, 1, val, maxlen); + vs = exif_get_short (entry->data, entry->order); + + /* search the tag */ + for (i = 0; (items[i].tag && items[i].tag != entry->tag); i++); + if (!items[i].tag) { + strncpy (val, "Internal error", maxlen); + break; + } + + /* find the value */ + for (j = 0; items[i].elem[j].string && + (items[i].elem[j].index < vs); j++); + if (items[i].elem[j].index != vs) { + snprintf (val, maxlen, + "Internal error (unknown value %i)", vs); + break; + } + snprintf (val, maxlen, "%s", items[i].elem[j].string); + break; + + case MNOTE_PENTAX_TAG_ZOOM: + CF (entry->format, EXIF_FORMAT_LONG, val, maxlen); + CC (entry->components, 1, val, maxlen); + vl = exif_get_long (entry->data, entry->order); + snprintf (val, maxlen, "%li", (long int) vl); + break; + case MNOTE_PENTAX_TAG_PRINTIM: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 124, val, maxlen); + snprintf (val, maxlen, "%li bytes unknown data", + entry->components); + break; + case MNOTE_PENTAX_TAG_TZ_CITY: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 4, val, maxlen); + snprintf (val, entry->components, "%s", entry->data); + break; + case MNOTE_PENTAX_TAG_TZ_DST: + CF (entry->format, EXIF_FORMAT_UNDEFINED, val, maxlen); + CC (entry->components, 4, val, maxlen); + snprintf (val, entry->components, "%s", entry->data); + break; + default: + switch (entry->format) { + case EXIF_FORMAT_ASCII: + strncpy (val, entry->data, MIN(maxlen, entry->components)); + break; + case EXIF_FORMAT_SHORT: + vs = exif_get_short (entry->data, entry->order); + snprintf (val, maxlen, "%i", vs); + break; + case EXIF_FORMAT_LONG: + vl = exif_get_long (entry->data, entry->order); + snprintf (val, maxlen, "%li", (long int) vl); + break; + case EXIF_FORMAT_UNDEFINED: + default: + snprintf (val, maxlen, "%li bytes unknown data", + entry->components); + break; + } + break; + } + + return (val); +} diff --git a/src/libexif/pentax/mnote-pentax-entry.h b/src/libexif/pentax/mnote-pentax-entry.h new file mode 100644 index 0000000..628d5dd --- /dev/null +++ b/src/libexif/pentax/mnote-pentax-entry.h @@ -0,0 +1,43 @@ +/* mnote-pentax-entry.h + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_PENTAX_ENTRY_H__ +#define __MNOTE_PENTAX_ENTRY_H__ + +#include <libexif/exif-format.h> +#include <libexif/exif-byte-order.h> +#include <libexif/pentax/mnote-pentax-tag.h> + +typedef struct _MnotePentaxEntry MnotePentaxEntry; + +struct _MnotePentaxEntry { + MnotePentaxTag tag; + ExifFormat format; + unsigned long components; + + unsigned char *data; + unsigned int size; + + ExifByteOrder order; +}; + +char *mnote_pentax_entry_get_value (MnotePentaxEntry *entry, char *val, unsigned int maxlen); + +#endif /* __MNOTE_PENTAX_ENTRY_H__ */ diff --git a/src/libexif/pentax/mnote-pentax-tag.c b/src/libexif/pentax/mnote-pentax-tag.c new file mode 100644 index 0000000..76823a4 --- /dev/null +++ b/src/libexif/pentax/mnote-pentax-tag.c @@ -0,0 +1,94 @@ +/* mnote-pentax-tag.c: + * + * Copyright © 2002 Lutz Müller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "mnote-pentax-tag.h" + +#include <stdlib.h> + +#include <libexif/i18n.h> + +static struct { + MnotePentaxTag tag; + const char *name; + const char *title; + const char *description; +} table[] = { + {MNOTE_PENTAX_TAG_MODE, "Mode", N_("Capture Mode"), NULL}, + {MNOTE_PENTAX_TAG_QUALITY, "Quality", N_("Quality Level"), NULL}, + {MNOTE_PENTAX_TAG_FOCUS, "Focus", N_("Focus Mode"), NULL}, + {MNOTE_PENTAX_TAG_FLASH, "Flash", N_("Flash Mode"), NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_05, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_06, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_WHITE_BALANCE, "WhiteBalance", N_("White Balance"), NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_08, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_09, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_ZOOM, "Zoom", N_("Zoom"), NULL}, + {MNOTE_PENTAX_TAG_SHARPNESS, "Sharpness", N_("Sharpness"), NULL}, + {MNOTE_PENTAX_TAG_CONTRAST, "Contrast", N_("Contrast"), NULL}, + {MNOTE_PENTAX_TAG_SATURATION, "Saturation", N_("Saturation"), NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_14, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_15, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_16, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_17, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_18, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_19, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_ISO_SPEED, "ISOSpeed", N_("ISOSpeed"), NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_21, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_COLOR, "Color", N_("Color"), NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_24, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_UNKNOWN_25, NULL, NULL, NULL}, + {MNOTE_PENTAX_TAG_PRINTIM, "PrintIM", N_("PrintIM Settings"), NULL}, + {MNOTE_PENTAX_TAG_TZ_CITY, "TimeZone", N_("TimeZone"), NULL}, + {MNOTE_PENTAX_TAG_TZ_DST, "DaylightSavings", N_("DaylightSavings"), NULL}, + {0, NULL, NULL, NULL} +}; + +const char * +mnote_pentax_tag_get_name (MnotePentaxTag t) +{ + unsigned int i; + + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (table[i].name); + return NULL; +} + +const char * +mnote_pentax_tag_get_title (MnotePentaxTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].title)); + return NULL; +} + +const char * +mnote_pentax_tag_get_description (MnotePentaxTag t) +{ + unsigned int i; + + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + for (i = 0; i < sizeof (table) / sizeof (table[0]); i++) + if (table[i].tag == t) return (_(table[i].description)); + return NULL; +} diff --git a/src/libexif/pentax/mnote-pentax-tag.h b/src/libexif/pentax/mnote-pentax-tag.h new file mode 100644 index 0000000..a261102 --- /dev/null +++ b/src/libexif/pentax/mnote-pentax-tag.h @@ -0,0 +1,74 @@ +/* mnote-pentax-tag.h + * + * Copyright © 2002, 2003 Lutz Mueller <lutz@users.sourceforge.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __MNOTE_PENTAX_TAG_H__ +#define __MNOTE_PENTAX_TAG_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * Missing features which are probably in the unknowns somewhere ... + * 1/ AF Area (Wide, Spot, Free) + * 2/ AE Metering (Multi segment, Centre-weighted, Spot) + * 3/ + */ + +enum _MnotePentaxTag { + MNOTE_PENTAX_TAG_MODE = 0x0001, + MNOTE_PENTAX_TAG_QUALITY = 0x0002, + MNOTE_PENTAX_TAG_FOCUS = 0x0003, + MNOTE_PENTAX_TAG_FLASH = 0x0004, + MNOTE_PENTAX_TAG_UNKNOWN_05 = 0x0005, + MNOTE_PENTAX_TAG_UNKNOWN_06 = 0x0006, + MNOTE_PENTAX_TAG_WHITE_BALANCE = 0x0007, + MNOTE_PENTAX_TAG_UNKNOWN_08 = 0x0008, + MNOTE_PENTAX_TAG_UNKNOWN_09 = 0x0009, + MNOTE_PENTAX_TAG_ZOOM = 0x000a, + MNOTE_PENTAX_TAG_SHARPNESS = 0x000b, + MNOTE_PENTAX_TAG_CONTRAST = 0x000c, + MNOTE_PENTAX_TAG_SATURATION = 0x000d, + MNOTE_PENTAX_TAG_UNKNOWN_14 = 0x000e, + MNOTE_PENTAX_TAG_UNKNOWN_15 = 0x000f, + MNOTE_PENTAX_TAG_UNKNOWN_16 = 0x0010, + MNOTE_PENTAX_TAG_UNKNOWN_17 = 0x0011, + MNOTE_PENTAX_TAG_UNKNOWN_18 = 0x0012, + MNOTE_PENTAX_TAG_UNKNOWN_19 = 0x0013, + MNOTE_PENTAX_TAG_ISO_SPEED = 0x0014, + MNOTE_PENTAX_TAG_UNKNOWN_21 = 0x0015, + MNOTE_PENTAX_TAG_COLOR = 0x0017, + MNOTE_PENTAX_TAG_UNKNOWN_24 = 0x0018, + MNOTE_PENTAX_TAG_UNKNOWN_25 = 0x0019, + MNOTE_PENTAX_TAG_PRINTIM = 0x0e00, + MNOTE_PENTAX_TAG_TZ_CITY = 0x1000, + MNOTE_PENTAX_TAG_TZ_DST = 0x1001 +}; +typedef enum _MnotePentaxTag MnotePentaxTag; + +const char *mnote_pentax_tag_get_name (MnotePentaxTag tag); +const char *mnote_pentax_tag_get_title (MnotePentaxTag tag); +const char *mnote_pentax_tag_get_description (MnotePentaxTag tag); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MNOTE_PENTAX_TAG_H__ */ |