From e86d7651f3618c456234d4adc945c2ff451bceb7 Mon Sep 17 00:00:00 2001 From: Sergey S Prozhogin Date: Thu, 28 Aug 2003 19:14:00 +0000 Subject: [PATCH] Import release 0.98 --- EXIF.pm | 2 +- canon.c | 466 ++++++++++++++++++++++++++++++++++------------------- casio.c | 88 +--------- exif.c | 333 ++++++++++++++++++++++---------------- exif.h | 65 ++++++-- exifint.h | 59 +++---- exifutil.c | 157 +++++++++--------- fuji.c | 59 ++----- jpeg.c | 2 +- jpeg.h | 2 +- makers.c | 9 +- makers.h | 19 ++- minolta.c | 135 +++++++--------- nikon.c | 148 ++++++++++------- olympus.c | 60 ++----- tagdefs.c | 2 +- 16 files changed, 859 insertions(+), 747 deletions(-) diff --git a/EXIF.pm b/EXIF.pm index e676fc6..4c6c859 100644 --- a/EXIF.pm +++ b/EXIF.pm @@ -31,7 +31,7 @@ our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( ); -our $VERSION = '0.04'; +our $VERSION = '0.98'; sub AUTOLOAD { # This AUTOLOAD is used to 'autoload' constants from the constant() diff --git a/canon.c b/canon.c index ac1bebe..857808c 100644 --- a/canon.c +++ b/canon.c @@ -29,35 +29,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: canon.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: canon.c,v 1.38 2003/08/08 20:40:55 ejohnst Exp $ */ /* * Exif tag definitions for Canon maker notes. * Developed from http://www.burren.cx/david/canon.html. * EOS 1D and 1Ds contributions from Stan Jirman . + * EOS 10D contributions from Jason Montojo . * */ #include #include #include -#include -#include "exif.h" -#include "exifint.h" #include "makers.h" -/* Custom function field description lookup table. */ - -struct ccstm { - int32_t val; - const char *descr; - struct descrip *table; -}; - - /* Macro mode. */ static struct descrip canon_macro[] = { @@ -72,6 +61,7 @@ static struct descrip canon_macro[] = { static struct descrip canon_focustype[] = { { 0, "Manual" }, { 1, "Auto" }, + { 2, "Auto" }, { 3, "Close-Up (Macro Mode)" }, { 7, "Infinity Mode" }, { 8, "Locked (Pan Mode)" }, @@ -276,7 +266,7 @@ static struct exiftag canon_tags[] = { "Custom Function", NULL }, { 0x00a0, TIFF_SHORT, 0, ED_UNK, "CanonA0Tag", "Canon TagA0 Offset", NULL }, - { 0xffff, TIFF_UNKN, 0, ED_UNK, "Unknown", + { 0xffff, TIFF_UNKN, 0, ED_UNK, "CanonUnknown", "Canon Unknown", NULL }, }; @@ -334,7 +324,7 @@ static struct exiftag canon_tags01[] = { "Zoomed Resolution", NULL }, { 37, TIFF_SHORT, 0, ED_VRB, "CanonBZoomRes", "Base Zoom Resolution", NULL }, - { 0xffff, TIFF_SHORT, 0, ED_UNK, "CanonUnknown", + { 0xffff, TIFF_SHORT, 0, ED_UNK, "Canon01Unknown", "Canon Tag1 Unknown", NULL }, }; @@ -354,7 +344,7 @@ static struct exiftag canon_tags04[] = { "Flash Bias", canon_fbias }, { 19, TIFF_SHORT, 0, ED_UNK, "CanonSubjDst", "Subject Distance", NULL }, - { 0xffff, TIFF_SHORT, 0, ED_UNK, "CanonUnknown", + { 0xffff, TIFF_SHORT, 0, ED_UNK, "Canon04Unknown", "Canon Tag4 Unknown", NULL }, }; @@ -364,12 +354,22 @@ static struct exiftag canon_tags04[] = { static struct exiftag canon_tagsA0[] = { { 9, TIFF_SHORT, 0, ED_IMG, "CanonColorTemp", "Color Temperature", NULL }, - { 0xffff, TIFF_SHORT, 0, ED_UNK, "CanonUnknown", + { 10, TIFF_SHORT, 0, ED_IMG, "CanonColorMatrix", + "Color Matrix", NULL }, + { 0xffff, TIFF_SHORT, 0, ED_UNK, "CanonA0Unknown", "Canon TagA0 Unknown", NULL }, }; -/* Value descriptions for D30, D60 custom functions. */ +/* Placeholder for unknown fields. */ + +static struct exiftag canon_tagsunk[] = { + { 0xffff, TIFF_SHORT, 0, ED_UNK, "CanonUnknown", + "Canon Unknown", NULL }, +}; + + +/* Value descriptions for custom functions. */ static struct descrip ccstm_offon[] = { { 0, "Off" }, @@ -457,6 +457,12 @@ static struct descrip ccstm_yesno[] = { { -1, "Unknown" }, }; +static struct descrip ccstm_noyes[] = { + { 0, "No" }, + { 1, "Yes" }, + { -1, "Unknown" }, +}; + static struct descrip ccstm_onoff[] = { { 0, "On" }, { 1, "Off" }, @@ -564,60 +570,196 @@ static struct descrip ccstm_fscr[] = { { -1, "Unknown" }, }; -static struct descrip ccstm_finder[] = { - { 0, "No Viewfinder Display" }, - { 1, "Finder Display On" }, +static struct descrip ccstm_10dsetbut[] = { + { 0, "Not Assigned" }, + { 1, "Change Quality" }, + { 2, "Change Parameters" }, + { 3, "Menu Display" }, + { 4, "Image Replay" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_10dshutter[] = { + { 0, "AF/AE Lock" }, + { 1, "AE Lock/AF" }, + { 2, "AF/AF Lock, No AE Lock" }, + { 3, "AE/AF, No AE Lock" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_assistflash[] = { + { 0, "Emits/Fires" }, + { 1, "Does Not Emit/Fires" }, + { 2, "Only Ext. Flash Emits/Fires" }, + { 3, "Emits/Does Not Fire" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_afptreg[] = { + { 0, "Center" }, + { 1, "Bottom" }, + { 2, "Right" }, + { 3, "Extreme Right" }, + { 4, "Automatic" }, + { 5, "Extreme Left" }, + { 6, "Left" }, + { 7, "Top" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_rawjpeg[] = { + { 0, "RAW+Small/Normal" }, + { 1, "RAW+Small/Fine" }, + { 2, "RAW+Medium/Normal" }, + { 3, "RAW+Medium/Fine" }, + { 4, "RAW+Large/Normal" }, + { 5, "RAW+Large/Fine" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_10dmenubut[] = { + { 0, "Previous (Volatile)" }, + { 1, "Previous" }, + { 2, "Top" }, + { -1, "Unknown" }, +}; + +static struct descrip ccstm_assistbut[] = { + { 0, "Normal" }, + { 1, "Select Home Position" }, + { 2, "Select HP (while pressing)" }, + { 3, "Av+/- (AF point by QCD)" }, + { 4, "FE lock" }, { -1, "Unknown" }, }; /* D30/D60 custom functions. */ -static struct ccstm canon_d30custom[] = { - { 1, "Long exposure noise reduction", ccstm_offon }, - { 2, "Shutter/AE lock buttons", ccstm_shutter }, - { 3, "Mirror lockup", ccstm_disen }, - { 4, "Tv/Av and exposure level", ccstm_explvl }, - { 5, "AF-assist light", ccstm_autooff }, - { 6, "Av mode shutter speed", ccstm_shutspd }, - { 7, "AEB sequence/auto cancellation", ccstm_aebseq }, - { 8, "Shutter curtain sync", ccstm_shutsync }, - { 9, "Lens AF stop button", ccstm_lensaf }, - { 10, "Fill flash auto reduction", ccstm_endis }, - { 11, "Menu button return position", ccstm_menubut }, - { 12, "Shooting Set button function", ccstm_setbut }, - { 13, "Sensor cleaning", ccstm_disen }, - { 14, "Superimposed display", ccstm_onoff }, - { 15, "Shutter release w/o CF card", ccstm_yesno }, - { -1, "Unknown function", NULL }, +static struct exiftag canon_d30custom[] = { + { 1, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Long exposure noise reduction", ccstm_offon }, + { 2, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Shutter/AE lock buttons", ccstm_shutter }, + { 3, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Mirror lockup", ccstm_disen }, + { 4, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Tv/Av and exposure level", ccstm_explvl }, + { 5, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "AF-assist light", ccstm_autooff }, + { 6, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Av mode shutter speed", ccstm_shutspd }, + { 7, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "AEB sequence/auto cancellation", ccstm_aebseq }, + { 8, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Shutter curtain sync", ccstm_shutsync }, + { 9, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Lens AF stop button", ccstm_lensaf }, + { 10, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Fill flash auto reduction", ccstm_endis }, + { 11, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Menu button return position", ccstm_menubut }, + { 12, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Shooting Set button function", ccstm_setbut }, + { 13, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Sensor cleaning", ccstm_disen }, + { 14, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Superimposed display", ccstm_onoff }, + { 15, TIFF_SHORT, 0, ED_VRB, "D30Custom", + "Shutter release w/o CF card", ccstm_yesno }, + { 0xffff, TIFF_SHORT, 0, ED_UNK, "D30CustomUnknown", + "Canon D30/D60 Custom Unknown", NULL }, }; /* EOS-1D/1Ds custom functions. */ -static struct ccstm canon_1dcustom[] = { - { 0, "Focusing screen", ccstm_fscr }, - { 1, "Finder display during exposure", ccstm_finder }, - { 2, "Shutter release w/o CF card", ccstm_yesno }, - { 3, "ISO speed expansion", ccstm_yesno }, - { 4, "Shutter button/AEL button", ccstm_shutterael }, - { 5, "Manual Tv/Av for M", ccstm_tvavform }, - { 6, "Exposure level increments", ccstm_explvlinc }, - { 7, "USM lens electronic MF", ccstm_usmmf }, - { 8, "Top/back LCD panels", ccstm_lcdpanels }, - { 9, "AEB sequence/auto cancellation", ccstm_aebseq }, - { 10, "AF point illumination", ccstm_afill }, - { 11, "AF point selection", ccstm_afsel }, - { 12, "Mirror lockup", ccstm_disen }, - { 13, "# AF points/spot metering", ccstm_afspot }, - { 14, "Fill flash auto reduction", ccstm_endis }, - { 15, "Shutter curtain sync", ccstm_shutsync }, - { 16, "Safety shift in Av or Tv", ccstm_endis }, - { 17, "AF point activation area", ccstm_afact }, - { 18, "Switch to registered AF point", ccstm_regaf }, - { 19, "Lens AF stop button", ccstm_lensaf1 }, - { 20, "AI servo tracking sensitivity", ccstm_aisens }, - { -1, "Unknown function", NULL }, +static struct exiftag canon_1dcustom[] = { + { 0, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Focusing screen", ccstm_fscr }, + { 1, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Finder display during exposure", ccstm_offon }, + { 2, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Shutter release w/o CF card", ccstm_yesno }, + { 3, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "ISO speed expansion", ccstm_noyes }, + { 4, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Shutter button/AEL button", ccstm_shutterael }, + { 5, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Manual Tv/Av for M", ccstm_tvavform }, + { 6, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Exposure level increments", ccstm_explvlinc }, + { 7, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "USM lens electronic MF", ccstm_usmmf }, + { 8, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Top/back LCD panels", ccstm_lcdpanels }, + { 9, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "AEB sequence/auto cancellation", ccstm_aebseq }, + { 10, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "AF point illumination", ccstm_afill }, + { 11, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "AF point selection", ccstm_afsel }, + { 12, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Mirror lockup", ccstm_disen }, + { 13, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "# AF points/spot metering", ccstm_afspot }, + { 14, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Fill flash auto reduction", ccstm_endis }, + { 15, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Shutter curtain sync", ccstm_shutsync }, + { 16, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Safety shift in Av or Tv", ccstm_disen }, + { 17, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "AF point activation area", ccstm_afact }, + { 18, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Switch to registered AF point", ccstm_regaf }, + { 19, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "Lens AF stop button", ccstm_lensaf1 }, + { 20, TIFF_SHORT, 0, ED_VRB, "1DCustom", + "AI servo tracking sensitivity", ccstm_aisens }, + { 0xffff, TIFF_SHORT, 0, ED_UNK, "1DCustomUnknown", + "Canon 1D/1Ds Custom Unknown", NULL }, +}; + +/* 10D custom functions. */ + +static struct exiftag canon_10dcustom[] = { + { 1, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "SET button function when shooting", ccstm_10dsetbut }, + { 2, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Shutter release w/o CF card", ccstm_yesno }, + { 3, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Flash sync speed in Av mode", ccstm_shutspd }, + { 4, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Shutter button/AE lock button", ccstm_10dshutter }, + { 5, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "AF-assist beam/Flash firing", ccstm_assistflash }, + { 6, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Exposure level increments", ccstm_explvl }, + { 7, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "AF point registration", ccstm_afptreg }, + { 8, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "RAW+JPEG recording", ccstm_rawjpeg }, + { 9, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "AEB sequence/auto cancellation", ccstm_aebseq }, + { 10, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Superimposed display", ccstm_onoff }, + { 11, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Menu button display position", ccstm_10dmenubut }, + { 12, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Mirror lockup", ccstm_disen }, + { 13, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Assist button function", ccstm_assistbut }, + { 14, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Fill flash auto reduction", ccstm_endis }, + { 15, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Shutter curtain sync", ccstm_shutsync }, + { 16, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Safety shift in Av or Tv", ccstm_disen }, + { 17, TIFF_SHORT, 0, ED_VRB, "10DCustom", + "Lens AF stop button", ccstm_lensaf }, + { 0xffff, TIFF_SHORT, 0, ED_UNK, "10DCustomUnknown", + "Canon 10D Custom Unknown", NULL }, }; @@ -625,18 +767,16 @@ static struct ccstm canon_1dcustom[] = { * Process maker note tag 0x0001 values. */ static int -canon_prop01(struct exifprop *aprop, struct exifprop *prop, char *off, - enum order o) +canon_prop01(struct exifprop *aprop, struct exifprop *prop, + unsigned char *off, enum byteorder o) { u_int16_t v = (u_int16_t)aprop->value; - switch (aprop->subtag) { + switch (aprop->tag) { case 2: aprop->lvl = v ? ED_IMG : ED_VRB; - if (!(aprop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&aprop->str, 32); snprintf(aprop->str, 31, "%d sec", v / 10); - aprop->str[31] = '\0'; break; case 5: /* Change "Single" to "Timed" if #2 > 0. */ @@ -653,12 +793,10 @@ canon_prop01(struct exifprop *aprop, struct exifprop *prop, char *off, */ if (v == 3 && prop->count >= 37) { - if (!(aprop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&aprop->str, 32); snprintf(aprop->str, 31, "x%.1f", 2 * (float)exif2byte(off + 37 * 2, o) / (float)exif2byte(off + 36 * 2, o)); - aprop->str[31] = '\0'; } else aprop->str = finddescr(canon_dzoom, v); break; @@ -690,11 +828,11 @@ canon_prop01(struct exifprop *aprop, struct exifprop *prop, char *off, * Process maker note tag 0x0004 values. */ static int -canon_prop04(struct exifprop *aprop, struct exifprop *prop, char *off, - enum order o) +canon_prop04(struct exifprop *aprop, struct exifprop *prop, + unsigned char *off, enum byteorder o) { - switch (aprop->subtag) { + switch (aprop->tag) { case 7: aprop->override = EXIF_T_WHITEBAL; break; @@ -713,16 +851,14 @@ canon_prop04(struct exifprop *aprop, struct exifprop *prop, char *off, * Process maker note tag 0x00a0 values. */ static int -canon_propA0(struct exifprop *aprop, struct exifprop *prop, char *off, - enum order o) +canon_propA0(struct exifprop *aprop, struct exifprop *prop, + unsigned char *off, enum byteorder o) { - switch (aprop->subtag) { + switch (aprop->tag) { case 9: - if (!(aprop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&aprop->str, 32); snprintf(aprop->str, 31, "%d K", aprop->value); - aprop->str[31] = '\0'; break; default: return (FALSE); @@ -743,21 +879,26 @@ canon_subval(struct exifprop *prop, struct exiftags *t, int i, j; u_int16_t v; struct exifprop *aprop; - char *off = t->btiff + prop->value; + unsigned char *off = t->md.btiff + prop->value; - /* Check size of tag (first value). */ + /* Check size of tag (first value) if we're not debugging. */ - if (exif2byte(off, t->tifforder) != 2 * prop->count) { + if (valfun && exif2byte(off, t->md.order) != 2 * prop->count) { exifwarn("Canon maker tag appears corrupt"); return (FALSE); } + if (debug) + printf("Processing %s (0x%04X) directory, %d entries\n", + prop->name, prop->tag, prop->count); + for (i = 0; i < (int)prop->count; i++) { - v = exif2byte(off + i * 2, t->tifforder); + v = exif2byte(off + i * 2, t->md.order); aprop = childprop(prop); aprop->value = (u_int32_t)v; - aprop->subtag = i; + aprop->tag = i; + aprop->tagset = subtags; /* Lookup property name and description. */ @@ -776,13 +917,13 @@ canon_subval(struct exifprop *prop, struct exiftags *t, if (valfun && !valfun(aprop, prop, off, t)) { if (aprop->lvl != ED_UNK) continue; - - if (!(aprop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&aprop->str, 32); snprintf(aprop->str, 31, "num %02d, val 0x%04X", i, v); - aprop->str[31] = '\0'; } } + + if (debug) + printf("\n"); return (TRUE); } @@ -791,10 +932,10 @@ canon_subval(struct exifprop *prop, struct exiftags *t, * Process custom function tag values. */ static void -canon_custom(struct exifprop *prop, char *off, enum order o, - struct ccstm *table) +canon_custom(struct exifprop *prop, unsigned char *off, enum byteorder o, + struct exiftag *table) { - int i, j; + int i, j = -1; const char *cn; char *cv = NULL; u_int16_t v; @@ -813,36 +954,38 @@ canon_custom(struct exifprop *prop, char *off, enum order o, return; } + if (debug) + printf("Processing %s directory, %d entries\n", prop->name, + prop->count); + for (i = 1; i < (int)prop->count; i++) { v = exif2byte(off + i * 2, o); aprop = childprop(prop); - aprop->value = (u_int32_t)v; - aprop->subtag = i; - aprop->name = prop->name; - aprop->descr = prop->descr; - aprop->lvl = ED_VRB; - - dumpprop(aprop, NULL); + aprop->value = v & 0xff; + aprop->tag = v >> 8 & 0xff; + aprop->tagset = table; /* - * If we have a table, lookup function name and value. - * First byte is function number; second is function value. + * Lookup function name and value. First byte is function + * number; second is function value. */ - if (table) { - for (j = 0; table[j].val != -1 && - table[j].val != (v >> 8 & 0xff); j++); - if (table[j].table) - cv = finddescr(table[j].table, - (u_int16_t)(v & 0xff)); - cn = table[j].descr; - } else - cn = "Unknown"; + for (j = 0; table[j].tag != EXIF_T_UNKNOWN && + table[j].tag != (v >> 8 & 0xff); j++); + aprop->name = table[j].name; + aprop->descr = prop->descr; + aprop->lvl = table[j].lvl; + if (table[j].table) + cv = finddescr(table[j].table, + (u_int16_t)(v & 0xff)); + cn = table[j].descr; + - if (!(aprop->str = (char *)malloc(4 + strlen(cn) + - (cv ? strlen(cv) : 10)))) - exifdie((const char *)strerror(errno)); + dumpprop(aprop, NULL); + + exifstralloc(&aprop->str, 4 + strlen(cn) + + (cv ? strlen(cv) : 10)); if (cv && j != -1) { snprintf(aprop->str, 4 + strlen(cn) + strlen(cv), @@ -856,6 +999,9 @@ canon_custom(struct exifprop *prop, char *off, enum order o, aprop->lvl = ED_UNK; } } + + if (debug) + printf("\n"); } @@ -865,37 +1011,10 @@ canon_custom(struct exifprop *prop, char *off, enum order o, void canon_prop(struct exifprop *prop, struct exiftags *t) { - unsigned int i; - char *offset; - u_int16_t v, flmin = 0, flmax = 0, flunit = 0; + unsigned char *offset; + u_int16_t flmin = 0, flmax = 0, flunit = 0; struct exifprop *tmpprop; - /* - * Don't process child properties we've created while looking at - * other maker note tags. - */ - - if (prop->subtag > -2) - return; - - /* Lookup the field name (if known). */ - - for (i = 0; canon_tags[i].tag < EXIF_T_UNKNOWN && - canon_tags[i].tag != prop->tag; i++); - prop->name = canon_tags[i].name; - prop->descr = canon_tags[i].descr; - prop->lvl = canon_tags[i].lvl; - - if (debug) { - static int once = 0; - - if (!once) { - printf("Processing Canon Maker Note\n"); - once = 1; - } - dumpprop(prop, NULL); - } - switch (prop->tag) { /* Various image data. */ @@ -911,18 +1030,17 @@ canon_prop(struct exifprop *prop, struct exiftags *t) */ if (prop->count >= 25) { - offset = t->btiff + prop->value; - flmax = exif2byte(offset + 23 * 2, t->tifforder); - flmin = exif2byte(offset + 24 * 2, t->tifforder); - flunit = exif2byte(offset + 25 * 2, t->tifforder); + offset = t->md.btiff + prop->value; + flmax = exif2byte(offset + 23 * 2, t->md.order); + flmin = exif2byte(offset + 24 * 2, t->md.order); + flunit = exif2byte(offset + 25 * 2, t->md.order); } if (flunit && (flmin || flmax)) { tmpprop = childprop(prop); tmpprop->name = "CanonLensSz"; tmpprop->descr = "Lens Size"; - if (!(tmpprop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&tmpprop->str, 32); if (flmin == flmax) { snprintf(tmpprop->str, 31, "%.2f mm", @@ -947,9 +1065,9 @@ canon_prop(struct exifprop *prop, struct exiftags *t) /* Color temp is bad if white balance isn't manual. */ - if ((tmpprop = findsprop(t->props, 0x0004, 7))) + if ((tmpprop = findprop(t->props, canon_tags04, 7))) if (tmpprop->value != 9) { - if ((tmpprop = findsprop(prop, 0x00a0, 9))) + if ((tmpprop = findprop(prop, canon_tagsA0, 9))) tmpprop->lvl = ED_BAD; } break; @@ -957,30 +1075,46 @@ canon_prop(struct exifprop *prop, struct exiftags *t) /* Image number. */ case 0x0008: - if (!(prop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 32); snprintf(prop->str, 31, "%03d-%04d", prop->value / 10000, prop->value % 10000); - prop->str[31] = '\0'; break; /* Serial number. */ case 0x000c: - if (!(prop->str = (char *)malloc(11))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 11); snprintf(prop->str, 11, "%010d", prop->value); break; /* Custom functions. */ case 0x000f: - canon_custom(prop, t->btiff + prop->value, t->tifforder, - canon_d30custom); + /* + * Canon annoyingly reuses this tag value for different sets + * of custom functions (e.g., D30/60, 10D). Therefore, we + * won't try to interpret them unless we know for sure that + * the camera model is supported. + */ + + if (!t->model) { + exifwarn("Canon model unset; please report to author"); + break; + } + + if (strstr(t->model, "10D")) + canon_custom(prop, t->md.btiff + prop->value, + t->md.order, canon_10dcustom); + else if (strstr(t->model, "D30") || strstr(t->model, "D60")) + canon_custom(prop, t->md.btiff + prop->value, + t->md.order, canon_d30custom); + else + exifwarn2("Custom function unsupported for %s; please " + "report to author", t->model); break; case 0x0090: - canon_custom(prop, t->btiff + prop->value, t->tifforder, + canon_custom(prop, t->md.btiff + prop->value, t->md.order, canon_1dcustom); break; @@ -988,12 +1122,18 @@ canon_prop(struct exifprop *prop, struct exiftags *t) default: if (prop->type == TIFF_SHORT && prop->count > 1 && debug) - for (i = 0; i < prop->count; i++) { - v = exif2byte(t->btiff + prop->value + - (i * 2), t->tifforder); - printf(" Unknown (%d): %d, 0x%04X\n", - i, v, v); - } + canon_subval(prop, t, canon_tagsunk, NULL); break; } } + + +/* + * Try to read Canon maker note IFDs. + */ +struct ifd * +canon_ifd(u_int32_t offset, struct tiffmeta *md) +{ + + return(readifds(offset, canon_tags, md)); +} diff --git a/casio.c b/casio.c index f6221ba..0be574c 100644 --- a/casio.c +++ b/casio.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: casio.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: casio.c,v 1.11 2003/08/06 02:26:42 ejohnst Exp $ */ /* @@ -40,7 +40,6 @@ #include #include #include -#include #include "makers.h" @@ -189,84 +188,11 @@ static struct exiftag casio_tags1[] = { }; -/* - * Process older Casio maker note tags. - */ -static void -casio_prop0(struct exifprop *prop, struct exiftags *t) -{ - int i; - u_int16_t v = (u_int16_t)prop->value; - - /* Lookup the field name (if known). */ - - for (i = 0; casio_tags0[i].tag < EXIF_T_UNKNOWN && - casio_tags0[i].tag != prop->tag; i++); - prop->name = casio_tags0[i].name; - prop->descr = casio_tags0[i].descr; - prop->lvl = casio_tags0[i].lvl; - if (casio_tags0[i].table) - prop->str = finddescr(casio_tags0[i].table, v); -} - - -/* - * Process newer Casio maker note tags. - */ -static void -casio_prop1(struct exifprop *prop, struct exiftags *t) -{ - int i; - u_int16_t v = (u_int16_t)prop->value; - - /* Lookup the field name (if known). */ - - for (i = 0; casio_tags1[i].tag < EXIF_T_UNKNOWN && - casio_tags1[i].tag != prop->tag; i++); - prop->name = casio_tags1[i].name; - prop->descr = casio_tags1[i].descr; - prop->lvl = casio_tags1[i].lvl; - if (casio_tags1[i].table) - prop->str = finddescr(casio_tags1[i].table, v); -} - - -/* - * Process Casio maker note tags. - */ -void -casio_prop(struct exifprop *prop, struct exiftags *t) -{ - - /* - * XXX This is a rather ugly hack, but we don't really have a way - * to figure out which type of Casio maker note we're dealing with - * (easily). - */ - - if (t->mkrinfo) - casio_prop1(prop, t); - else - casio_prop0(prop, t); - - if (debug) { - static int once = 0; /* XXX Breaks on multiple files. */ - - if (!once) { - printf("Processing Casio Maker Note (%d)\n", - t->mkrinfo); - once = 1; - } - dumpprop(prop, NULL); - } -} - - /* * Try to read a Casio maker note IFD. */ struct ifd * -casio_ifd(u_int32_t offset, struct exiftags *t) +casio_ifd(u_int32_t offset, struct tiffmeta *md) { struct ifd *myifd; @@ -276,15 +202,11 @@ casio_ifd(u_int32_t offset, struct exiftags *t) * format; the other starts at offset + 6 ("QVC\0\0\0"). */ - if (!memcmp("QVC\0\0\0", t->btiff + offset, 6)) { - - /* What a hack. Indicates we need to use casio_tags1[]. */ - t->mkrinfo = 1; - - readifd(t->btiff + offset + strlen("QVC") + 3, &myifd, t); + if (!memcmp("QVC\0\0\0", md->btiff + offset, 6)) { + readifd(offset + strlen("QVC") + 3, &myifd, casio_tags1, md); exifwarn("Casio maker note version not supported"); } else - readifd(t->btiff + offset, &myifd, t); + readifd(offset, &myifd, casio_tags0, md); return (myifd); } diff --git a/exif.c b/exif.c index d23b320..0da32ca 100644 --- a/exif.c +++ b/exif.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exif.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: exif.c,v 1.60 2003/08/16 03:34:21 ejohnst Exp $ */ /* @@ -57,13 +57,13 @@ #include "makers.h" #define OLYMPUS_BUGS /* Work around Olympus stupidity. */ -#define FUJI_BUGS /* Work around Fuji stupidity. */ #define WINXP_BUGS /* Work around Windows XP stupidity. */ +#define UNCREDITED_BUGS /* Work around uncredited stupidity. */ /* Function prototypes. */ -static int parsetag(struct exifprop *prop, struct ifd *dir, +static void parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr); @@ -76,42 +76,56 @@ readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t, { int i, j; struct exifprop *prop, *tmpprop; + u_int16_t tag; prop = newprop(); + if (dir->par) + tag = dir->par->tag; + else + tag = EXIF_T_UNKNOWN; /* Field info. */ - prop->tag = exif2byte(afield->tag, t->tifforder); - prop->type = exif2byte(afield->type, t->tifforder); - prop->count = exif4byte(afield->count, t->tifforder); + prop->tag = exif2byte(afield->tag, dir->md.order); + prop->type = exif2byte(afield->type, dir->md.order); + prop->count = exif4byte(afield->count, dir->md.order); if ((prop->type == TIFF_SHORT || prop->type == TIFF_SSHORT) && prop->count <= 1) - prop->value = exif2byte(afield->value, t->tifforder); + prop->value = exif2byte(afield->value, dir->md.order); else - prop->value = exif4byte(afield->value, t->tifforder); + prop->value = exif4byte(afield->value, dir->md.order); /* IFD identifying info. */ prop->ifdseq = ifdseq; - prop->ifdtag = dir->tag; + prop->par = dir->par; + prop->tagset = dir->tagset; /* Lookup the field name. */ - for (i = 0; tags[i].tag < EXIF_T_UNKNOWN && - tags[i].tag != prop->tag; i++); - prop->name = tags[i].name; - prop->descr = tags[i].descr; - prop->lvl = tags[i].lvl; + for (i = 0; prop->tagset[i].tag < EXIF_T_UNKNOWN && + prop->tagset[i].tag != prop->tag; i++); + prop->name = prop->tagset[i].name; + prop->descr = prop->tagset[i].descr; + prop->lvl = prop->tagset[i].lvl; - /* Lookup and check the field type. */ + /* + * Lookup and check the field type. + * + * We have to be pretty severe with entries that have an invalid + * field type -- too many assumptions in the rest of the code. + */ for (j = 0; ftypes[j].type && ftypes[j].type != prop->type; j++); - if (!ftypes[j].type) - exifdie("unknown TIFF field type"); + if (!ftypes[j].type) { + exifwarn2("unknown TIFF field type; discarding", prop->name); + free(prop); + return; + } /* Skip sanity checking on maker note tags; we'll get to them later. */ - if (prop->ifdtag != EXIF_T_MAKERNOTE) { + if (tag != EXIF_T_MAKERNOTE) { /* * XXX Ignore UserComment -- a hack to get around an apparent * WinXP Picture Viewer bug (err, liberty). When you rotate @@ -120,7 +134,7 @@ readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t, * (At least we're able to ID invalid comments...) */ - if (tags[i].type && tags[i].type != prop->type + if (prop->tagset[i].type && prop->tagset[i].type != prop->type #ifdef WINXP_BUGS && prop->tag != EXIF_T_USERCOMMENT #endif @@ -129,7 +143,8 @@ readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t, /* Check the field count. */ - if (tags[i].count && tags[i].count != prop->count) + if (prop->tagset[i].count && prop->tagset[i].count != + prop->count) exifwarn2("field count mismatch", prop->name); } @@ -139,18 +154,16 @@ readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t, /* * Do as much as we can with the tag at this point and add it - * to our list if it's not an IFD pointer. + * to our list. */ - if (parsetag(prop, dir, t, domkr)) { - if ((tmpprop = t->props)) { - while (tmpprop->next) - tmpprop = tmpprop->next; - tmpprop->next = prop; - } else - t->props = prop; + parsetag(prop, dir, t, domkr); + if ((tmpprop = t->props)) { + while (tmpprop->next) + tmpprop = tmpprop->next; + tmpprop->next = prop; } else - free(prop); + t->props = prop; } @@ -162,28 +175,16 @@ readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t, * the count here. Root IFDs (0 and 1) are processed first (along with any * other "root" IFDs we find), then any nested IFDs in the order they're * encountered. - * - * XXX To work around some Fuji braindeadness, if we're dealing with the - * maker note we set our byte order to little endian. */ static void readtags(struct ifd *dir, int seq, struct exiftags *t, int domkr) { int i; -#ifdef FUJI_BUGS - enum order tmporder; - - tmporder = t->tifforder; - if (dir->tag == EXIF_T_MAKERNOTE && t->mkrval == EXIF_MKR_FUJI) - t->tifforder = LITTLE; -#endif if (debug) { - if (dir->tag != EXIF_T_UNKNOWN) { - for (i = 0; tags[i].tag < EXIF_T_UNKNOWN && - tags[i].tag != dir->tag; i++); + if (dir->par && dir->par->tag != EXIF_T_UNKNOWN) { printf("Processing %s directory, %d entries\n", - tags[i].name, dir->num); + dir->par->name, dir->num); } else printf("Processing directory %d, %d entries\n", seq, dir->num); @@ -192,10 +193,6 @@ readtags(struct ifd *dir, int seq, struct exiftags *t, int domkr) for (i = 0; i < dir->num; i++) readtag(&(dir->fields[i]), seq, dir, t, domkr); -#ifdef FUJI_BUGS - if (dir->tag == EXIF_T_MAKERNOTE && t->mkrval == EXIF_MKR_FUJI) - t->tifforder = tmporder; -#endif if (debug) printf("\n"); } @@ -205,6 +202,9 @@ readtags(struct ifd *dir, int seq, struct exiftags *t, int domkr) * Post-process property values. By now we've got all of the standard * Exif tags read in (but not maker tags), so it's safe to work out * dependencies between tags. + * + * XXX At this point, we've lost IFD-level TIFF metadata. Therefore, + * assumptions about byte order and beginning of the TIFF might be false. */ static void postprop(struct exifprop *prop, struct exiftags *t) @@ -213,16 +213,35 @@ postprop(struct exifprop *prop, struct exiftags *t) u_int16_t v; u_int32_t val; float fval; - enum order o = t->tifforder; + enum byteorder o = t->md.order; struct exifprop *h = t->props; - /* Process maker note tags specially... */ + /* + * Process tags from special IFDs. + * XXX Don't properly pass IFD byte order here. + */ - if (prop->ifdtag == EXIF_T_MAKERNOTE && makers[t->mkrval].propfun) { - makers[t->mkrval].propfun(prop, t); - return; + if (prop->par && prop->par->tagset == tags) { + switch (prop->par->tag) { + + case EXIF_T_MAKERNOTE: + if (makers[t->mkrval].propfun) { + makers[t->mkrval].propfun(prop, t); + return; + } + break; + + case EXIF_T_GPSIFD: + gpsprop(prop, t); + return; + } } + /* Process normal tags. */ + + if (prop->tagset != tags) + return; + switch (prop->tag) { case EXIF_T_XRES: @@ -230,12 +249,14 @@ postprop(struct exifprop *prop, struct exiftags *t) case EXIF_T_FPXRES: case EXIF_T_FPYRES: if (prop->tag == EXIF_T_XRES || prop->tag == EXIF_T_YRES) { - if (!(tmpprop = findprop(h, EXIF_T_RESUNITS))) break; + if (!(tmpprop = findprop(h, tags, EXIF_T_RESUNITS))) + break; } else { - if (!(tmpprop = findprop(h, EXIF_T_FPRESUNITS))) break; + if (!(tmpprop = findprop(h, tags, EXIF_T_FPRESUNITS))) + break; } - val = exif4byte(t->btiff + prop->value, o) / - exif4byte(t->btiff + prop->value + 4, o); + val = exif4byte(t->md.btiff + prop->value, o) / + exif4byte(t->md.btiff + prop->value + 4, o); snprintf(prop->str, 31, "%d dp%s", val, tmpprop->str); prop->str[31] = '\0'; break; @@ -247,8 +268,8 @@ postprop(struct exifprop *prop, struct exiftags *t) */ case EXIF_T_SHUTTER: - fval = (float)exif4sbyte(t->btiff + prop->value, o) / - (float)exif4sbyte(t->btiff + prop->value + 4, o); + fval = (float)exif4sbyte(t->md.btiff + prop->value, o) / + (float)exif4sbyte(t->md.btiff + prop->value + 4, o); if (isnan(fval)) fval = 0; /* 1 / (2^speed) */ snprintf(prop->str, 31, "1/%d", @@ -264,8 +285,8 @@ postprop(struct exifprop *prop, struct exiftags *t) break; case EXIF_T_FNUMBER: - fval = (float)exif4byte(t->btiff + prop->value, o) / - (float)exif4byte(t->btiff + prop->value + 4, o); + fval = (float)exif4byte(t->md.btiff + prop->value, o) / + (float)exif4byte(t->md.btiff + prop->value + 4, o); if (isnan(fval)) fval = 0; snprintf(prop->str, 31, "f/%.1f", fval); prop->str[31] = '\0'; @@ -273,8 +294,8 @@ postprop(struct exifprop *prop, struct exiftags *t) case EXIF_T_LAPERTURE: case EXIF_T_MAXAPERTURE: - fval = (float)exif4byte(t->btiff + prop->value, o) / - (float)exif4byte(t->btiff + prop->value + 4, o); + fval = (float)exif4byte(t->md.btiff + prop->value, o) / + (float)exif4byte(t->md.btiff + prop->value + 4, o); if (isnan(fval)) fval = 0; /* sqrt(2)^aperture */ snprintf(prop->str, 31, "f/%.1f", pow(1.4142, (double)fval)); @@ -282,7 +303,7 @@ postprop(struct exifprop *prop, struct exiftags *t) break; case EXIF_T_BRIGHTVAL: - if (exif4byte(t->btiff + prop->value, o) == 0xffffffff) { + if (exif4byte(t->md.btiff + prop->value, o) == 0xffffffff) { strcpy(prop->str, "Unknown"); break; } @@ -294,16 +315,16 @@ postprop(struct exifprop *prop, struct exiftags *t) break; case EXIF_T_DISTANCE: - if (exif4byte(t->btiff + prop->value, o) == 0xffffffff) { + if (exif4byte(t->md.btiff + prop->value, o) == 0xffffffff) { strcpy(prop->str, "Infinity"); break; } - if (exif4byte(t->btiff + prop->value + 4, o) == 0) { + if (exif4byte(t->md.btiff + prop->value + 4, o) == 0) { strcpy(prop->str, "Unknown"); break; } - fval = (float)exif4byte(t->btiff + prop->value, o) / - (float)exif4byte(t->btiff + prop->value + 4, o); + fval = (float)exif4byte(t->md.btiff + prop->value, o) / + (float)exif4byte(t->md.btiff + prop->value + 4, o); if (isnan(fval)) fval = 0; snprintf(prop->str, 31, "%.2f m", fval); prop->str[31] = '\0'; @@ -320,8 +341,8 @@ postprop(struct exifprop *prop, struct exiftags *t) break; case EXIF_T_FOCALLEN: - fval = (float)exif4byte(t->btiff + prop->value, o) / - (float)exif4byte(t->btiff + prop->value + 4, o); + fval = (float)exif4byte(t->md.btiff + prop->value, o) / + (float)exif4byte(t->md.btiff + prop->value + 4, o); if (isnan(fval)) fval = 0; snprintf(prop->str, 31, "%.2f mm", fval); prop->str[31] = '\0'; @@ -330,19 +351,27 @@ postprop(struct exifprop *prop, struct exiftags *t) /* Digital zoom: set to verbose if numerator is 0 or fraction = 1. */ case EXIF_T_DIGIZOOM: - if (!exif4byte(t->btiff + prop->value, o)) + if (!exif4byte(t->md.btiff + prop->value, o)) strcpy(prop->str, "Unused"); - else if (exif4byte(t->btiff + prop->value, o) != - exif4byte(t->btiff + prop->value + 4, o)) + else if (exif4byte(t->md.btiff + prop->value, o) != + exif4byte(t->md.btiff + prop->value + 4, o)) break; prop->lvl = ED_VRB; break; case EXIF_T_FOCALLEN35: - if (!(prop->str = (char *)malloc(16))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 16); snprintf(prop->str, 15, "%d mm", prop->value); - prop->str[15] = '\0'; + break; + + /* + * XXX This really should be in parsetag() to guarantee that it's + * done before we process the maker notes. However, I haven't seen + * model not come first, so it should be safe (and more convenient). + */ + + case EXIF_T_MODEL: + t->model = prop->str; break; } } @@ -373,7 +402,10 @@ tweaklvl(struct exifprop *prop, struct exiftags *t) if (prop->ifdseq == 1 && prop->lvl != ED_UNK) prop->lvl = ED_VRB; - if (prop->override && (tmpprop = findprop(t->props, prop->override))) + /* Maker tags can override normal Exif tags. */ + + if (prop->override && (tmpprop = findprop(t->props, tags, + prop->override))) if (tmpprop->lvl & (ED_CAM | ED_IMG | ED_PAS)) tmpprop->lvl = ED_OVR; } @@ -382,7 +414,7 @@ tweaklvl(struct exifprop *prop, struct exiftags *t) /* * Fetch the data for an Exif tag. */ -static int +static void parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) { unsigned int i, len; @@ -390,16 +422,21 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) u_int32_t un, ud, denom; int32_t sn, sd; char buf[32], *c, *d; + struct tiffmeta *md; + unsigned char *btiff = dir->md.btiff; + enum byteorder o = dir->md.order; /* Set description if we have a lookup table. */ - for (i = 0; tags[i].tag < EXIF_T_UNKNOWN && - tags[i].tag != prop->tag; i++); - if (tags[i].table) { - prop->str = finddescr(tags[i].table, v); - return (TRUE); + for (i = 0; prop->tagset[i].tag < EXIF_T_UNKNOWN && + prop->tagset[i].tag != prop->tag; i++); + if (prop->tagset[i].table) { + prop->str = finddescr(prop->tagset[i].table, v); + return; } + /* XXX Probably shouldn't process this switch for non-standard tags. */ + switch (prop->tag) { /* Process an Exif IFD. */ @@ -407,6 +444,7 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) case EXIF_T_EXIFIFD: case EXIF_T_GPSIFD: case EXIF_T_INTEROP: + md = &dir->md; while (dir->next) dir = dir->next; @@ -417,10 +455,14 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) */ #ifdef OLYMPUS_BUGS if (prop->tag == EXIF_T_EXIFIFD) - readifd(t->btiff + prop->value, &dir->next, t); + readifd(prop->value, &dir->next, tags, md); else #endif - dir->next = readifds(prop->value, t); + if (prop->tag == EXIF_T_GPSIFD) { + dir->next = readifds(prop->value, gpstags, md); + } else { + dir->next = readifds(prop->value, tags, md); + } if (!dir->next) { @@ -438,15 +480,15 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) break; } - dir->next->tag = prop->tag; - return (FALSE); /* No need to add to property list. */ + /* XXX Doesn't catch multiple IFDs. */ + dir->next->par = prop; + return; /* Record the Exif version. */ case EXIF_T_VERSION: /* These contortions are to make 0220 = 2.20. */ - if (!(prop->str = (char *)malloc(8))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 8); /* Platform byte order affects this... */ @@ -456,7 +498,7 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) else for (i = 0; i < 4; i++) buf[i] = ((const char *)&prop->value)[3 - i]; - buf[4] = prop->str[7] = '\0'; + buf[4] = '\0'; t->exifmin = (short)atoi(buf + 2); buf[2] = '\0'; t->exifmaj = (short)atoi(buf); @@ -467,8 +509,9 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) case EXIF_T_MAKERNOTE: if (!domkr) - return (TRUE); + return; + md = &dir->md; while (dir->next) dir = dir->next; @@ -481,20 +524,21 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) */ if (makers[t->mkrval].ifdfun) - dir->next = makers[t->mkrval].ifdfun(prop->value, t); + dir->next = makers[t->mkrval].ifdfun(prop->value, md); else exifwarn("maker note not supported"); if (!dir->next) break; - dir->next->tag = prop->tag; - return (FALSE); /* No need to add to property list. */ + /* XXX Doesn't catch multiple IFDs. */ + dir->next->par = prop; + return; /* Lookup functions for maker note. */ case EXIF_T_EQUIPMAKE: - strncpy(buf, t->btiff + prop->value, sizeof(buf)); + strncpy(buf, (const char *)(btiff + prop->value), sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; for (c = buf; *c; c++) *c = tolower(*c); @@ -511,9 +555,24 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) * Handle user comment. According to the spec, the first 8 bytes * of the comment indicate what charset follows. For now, we * just support ASCII. + * + * XXX A handful of the GPS tags are also stored in this format + * (GPSProcessingMethod & GPSAreaInformation). */ + case 0x001b: + case 0x001c: + /* + * XXX Note that this is kind of dangerous -- any other + * tag set won't reach the end of the switch... + */ + if (prop->tagset != gpstags) + break; + /* FALLTHROUGH */ + case EXIF_T_USERCOMMENT: + if (prop->count < 8) + break; /* Ignore the 'comments' WinXP creates when rotating. */ #ifdef WINXP_BUGS @@ -525,27 +584,24 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) /* Lookup the comment type. */ for (i = 0; ucomment[i].descr; i++) - if (!memcmp(ucomment[i].descr, - t->btiff + prop->value, 8)) + if (!memcmp(ucomment[i].descr, btiff + prop->value, 8)) break; /* Handle an ASCII comment; strip any trailing whitespace. */ if (ucomment[i].val == TIFF_ASCII && (prop->value + prop->count < - (u_int32_t)(t->etiff - t->btiff))) { - c = t->btiff + prop->value + 8; + (u_int32_t)(dir->md.etiff - btiff))) { + c = (char *)(btiff + prop->value + 8); d = strlen(c) < prop->count - 8 ? c + strlen(c) : c + prop->count - 8; while (d > c && isspace((int)*(d - 1))) --d; - if (!(prop->str = (char *)malloc(d - c + 1))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, d - c + 1); strncpy(prop->str, c, d - c); - prop->str[d - c] = '\0'; prop->lvl = prop->str[0] ? ED_IMG : ED_VRB; - return (TRUE); + return; } break; @@ -559,7 +615,7 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) #else prop->str = finddescr(filesrcs, v); #endif - return (TRUE); + return; } /* @@ -568,12 +624,12 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) */ if (prop->type == TIFF_ASCII && - (prop->value + prop->count < (u_int32_t)(t->etiff - t->btiff))) { - if (!(prop->str = (char *)malloc(prop->count + 1))) - exifdie((const char *)strerror(errno)); - strncpy(prop->str, t->btiff + prop->value, prop->count); - prop->str[prop->count] = '\0'; - return (TRUE); + (prop->value + prop->count <= + (u_int32_t)(dir->md.etiff - btiff))) { + exifstralloc(&prop->str, prop->count + 1); + strncpy(prop->str, (const char *)(btiff + prop->value), + prop->count); + return; } /* @@ -583,25 +639,22 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) if ((prop->type == TIFF_RTNL || prop->type == TIFF_SRTNL) && (prop->value + prop->count * 8 <= - (u_int32_t)(t->etiff - t->btiff))) { + (u_int32_t)(dir->md.etiff - btiff))) { - if (!(prop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 32); if (prop->type == TIFF_RTNL) { - un = exif4byte(t->btiff + prop->value, t->tifforder); - ud = exif4byte(t->btiff + prop->value + 4, - t->tifforder); + un = exif4byte(btiff + prop->value, o); + ud = exif4byte(btiff + prop->value + 4, o); denom = gcd(un, ud); fixfract(prop->str, un, ud, denom); } else { - sn = exif4sbyte(t->btiff + prop->value, t->tifforder); - sd = exif4sbyte(t->btiff + prop->value + 4, - t->tifforder); + sn = exif4sbyte(btiff + prop->value, o); + sd = exif4sbyte(btiff + prop->value + 4, o); denom = gcd(abs(sn), abs(sd)); fixfract(prop->str, sn, sd, (int32_t)denom); } - return (TRUE); + return; } /* @@ -613,32 +666,29 @@ parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr) if ((prop->type == TIFF_SHORT || prop->type == TIFF_SSHORT) && prop->count > 1 && (prop->value + prop->count * 2 <= - (u_int32_t)(t->etiff - t->btiff))) { + (u_int32_t)(dir->md.etiff - btiff))) { if (prop->count > 8) - return (TRUE); - + return; len = 8 * prop->count + 1; - if (!(prop->str = (char *)malloc(len))) - exifdie((const char *)strerror(errno)); - prop->str[0] = '\0'; + exifstralloc(&prop->str, len); for (i = 0; i < prop->count; i++) { if (prop->type == TIFF_SHORT) snprintf(prop->str + strlen(prop->str), len - strlen(prop->str) - 1, "%d, ", - exif2byte(t->btiff + prop->value + - (i * 2), t->tifforder)); + exif2byte(btiff + prop->value + + (i * 2), o)); else snprintf(prop->str + strlen(prop->str), len - strlen(prop->str) - 1, "%d, ", - exif2sbyte(t->btiff + prop->value + - (i * 2), t->tifforder)); + exif2sbyte(btiff + prop->value + + (i * 2), o)); } prop->str[strlen(prop->str) - 2] = '\0'; - return (TRUE); + return; } - return (TRUE); + return; } @@ -675,12 +725,15 @@ exifscan(unsigned char *b, int len, int domkr) /* Create and initialize our file info structure. */ t = (struct exiftags *)malloc(sizeof(struct exiftags)); - if (!t) - exifdie((const char *)strerror(errno)); + if (!t) { + exifwarn2("can't allocate file info", + (const char *)strerror(errno)); + return (NULL); + } memset(t, 0, sizeof(struct exiftags)); seq = 0; - t->etiff = b + len; /* End of TIFF. */ + t->md.etiff = b + len; /* End of TIFF. */ /* * Make sure we've got the proper Exif header. If not, we're @@ -696,21 +749,21 @@ exifscan(unsigned char *b, int len, int domkr) /* Determine endianness of the TIFF data. */ if (*((u_int16_t *)b) == 0x4d4d) - t->tifforder = BIG; + t->md.order = BIG; else if (*((u_int16_t *)b) == 0x4949) - t->tifforder = LITTLE; + t->md.order = LITTLE; else { exifwarn("invalid TIFF header"); exiffree(t); return (NULL); } - t->btiff = b; /* Beginning of TIFF. */ + t->md.btiff = b; /* Beginning of TIFF. */ b += 2; /* Verify the TIFF header. */ - if (exif2byte(b, t->tifforder) != 42) { + if (exif2byte(b, t->md.order) != 42) { exifwarn("invalid TIFF header"); exiffree(t); return (NULL); @@ -719,8 +772,8 @@ exifscan(unsigned char *b, int len, int domkr) /* Get the 0th IFD, where all of the good stuff should start. */ - ifdoff = exif4byte(b, t->tifforder); - curifd = readifds(ifdoff, t); + ifdoff = exif4byte(b, t->md.order); + curifd = readifds(ifdoff, tags, &t->md); if (!curifd) { exifwarn("invalid Exif format (couldn't read IFD0)"); exiffree(t); diff --git a/exif.h b/exif.h index 674afe5..d4e0422 100644 --- a/exif.h +++ b/exif.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Eric M. Johnston + * Copyright (c) 2001-2003, Eric M. Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exif.h,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: exif.h,v 1.33 2003/08/06 02:26:42 ejohnst Exp $ */ /* @@ -121,6 +121,7 @@ typedef __int32 int32_t; #define EXIF_T_EXPOSURE 0x829a #define EXIF_T_FNUMBER 0x829d #define EXIF_T_EXPPROG 0x8822 +#define EXIF_T_GPSIFD 0x8825 #define EXIF_T_ISOSPEED 0x8827 #define EXIF_T_VERSION 0x9000 #define EXIF_T_COMPCONFIG 0x9101 @@ -154,7 +155,28 @@ typedef __int32 int32_t; /* Byte order. */ -enum order { LITTLE, BIG }; +enum byteorder { LITTLE, BIG }; + + +/* Generic field description lookup table. */ + +struct descrip { + int32_t val; + const char *descr; +}; + + +/* Tag lookup table. */ + +struct exiftag { + u_int16_t tag; /* Tag ID. */ + u_int16_t type; /* Expected type. */ + u_int16_t count; /* Expected count. */ + unsigned short lvl; /* Output level. */ + const char *name; + const char *descr; + struct descrip *table; /* Value lookup table. */ +}; /* Final Exif property info. (Note: descr can be NULL.) */ @@ -169,28 +191,47 @@ struct exifprop { char *str; /* String representation of value (dynamic). */ unsigned short lvl; /* Verbosity level. */ int ifdseq; /* Sequence number of parent IFD. */ - u_int16_t ifdtag; /* Parent IFD tag association. */ u_int16_t override; /* Override display of another tag. */ - int16_t subtag; /* Index of a tag's sub-value (def: -2). */ + struct exiftag *tagset; /* Tags used to create property. */ + struct exifprop *par; /* Parent property association. */ struct exifprop *next; }; +/* + * TIFF/IFD metadata. + * + * Implementation note: ordinarily, this information wouldn't be stored + * at the directory (IFD) level -- it's characteristic of the TIFF itself. + * However, the format of some maker notes force this level of detail. + * For example, Fuji notes can be in a different byte order than the rest of + * the TIFF. Also, some Nikon notes actually contain a full TIFF header + * and specify their own byte order and offset base. + * + * Therefore, while this information is generally true for the TIFF, it + * may not apply to maker note properties. + */ + +struct tiffmeta { + enum byteorder order; /* Endianness of IFD. */ + unsigned char *btiff; /* Beginning of TIFF (offset base). */ + unsigned char *etiff; /* End of TIFF. */ +}; + + /* Image info and exifprop pointer returned by exifscan(). */ struct exiftags { struct exifprop *props; /* The good stuff. */ + struct tiffmeta md; /* Beginning, end, and endianness of TIFF. */ - enum order tifforder; /* Endianness of TIFF. */ - unsigned char *btiff; /* Beginning of TIFF. */ - unsigned char *etiff; /* End of TIFF. */ + const char *model; /* Camera model, to aid maker tag processing. */ + short mkrval; /* Maker index (see makers.h). */ /* Version info. */ short exifmaj; /* Exif version, major. */ short exifmin; /* Exif version, minor. */ - short mkrval; /* Maker index (XXX uhh, somewhat opaque). */ - short mkrinfo; /* Maker info (XXX uhh, a hack for Nikon). */ }; @@ -198,8 +239,10 @@ struct exiftags { extern int debug; extern const char *progname; +extern struct exiftag tags[]; -extern struct exifprop *findprop(struct exifprop *prop, u_int16_t tag); +extern struct exifprop *findprop(struct exifprop *prop, + struct exiftag *tagset, u_int16_t tag); extern void exifdie(const char *msg); extern void exifwarn(const char *msg); extern void exifwarn2(const char *msg1, const char *msg2); diff --git a/exifint.h b/exifint.h index 003eb9e..1b78c0b 100644 --- a/exifint.h +++ b/exifint.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Eric M. Johnston + * Copyright (c) 2001-2003, Eric M. Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exifint.h,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: exifint.h,v 1.26 2003/08/06 02:26:42 ejohnst Exp $ */ /* @@ -53,31 +53,10 @@ #define EXIF_T_EXIFIFD 0x8769 #define EXIF_T_GPSIFD 0x8825 -#define EXIF_T_MAKERNOTE 0x927c /* (potentially) */ +#define EXIF_T_MAKERNOTE 0x927c #define EXIF_T_INTEROP 0xa005 -/* Generic field description lookup table. */ - -struct descrip { - int32_t val; - const char *descr; -}; - - -/* Tag lookup table. */ - -struct exiftag { - u_int16_t tag; /* Tag ID. */ - u_int16_t type; /* Expected type. */ - u_int16_t count; /* Expected count. */ - unsigned short lvl; /* Output level. */ - const char *name; - const char *descr; - struct descrip *table; /* Value lookup table. */ -}; - - /* IFD field types. */ struct fieldtype { @@ -100,9 +79,11 @@ struct field { /* IFD entry. */ struct ifd { - u_int16_t tag; /* Associated tag. */ u_int16_t num; /* Number of fields. */ struct field *fields; /* Array of fields. */ + struct exifprop *par; /* Parent property association. */ + struct exiftag *tagset; /* Tag definitions. */ + struct tiffmeta md; /* Metadata. */ struct ifd *next; }; @@ -121,37 +102,39 @@ struct ifd { ((double)(n) / (double)(d)) >= 0.1) \ snprintf((str), 31, "%.1f", (double)(n) / (double)(d)); \ else snprintf((str), 31, "%d/%d", (n), (d)); \ - (str)[31] = '\0'; \ } /* The tables from tagdefs.c. */ extern struct fieldtype ftypes[]; -extern struct exiftag tags[]; - extern struct descrip ucomment[]; - extern struct descrip flashes[]; extern struct descrip filesrcs[]; /* Utility functions from exifutil.c. */ -extern u_int16_t exif2byte(unsigned char *b, enum order o); -extern int16_t exif2sbyte(unsigned char *b, enum order o); -extern u_int32_t exif4byte(unsigned char *b, enum order o); -extern int32_t exif4sbyte(unsigned char *b, enum order o); -extern struct exifprop *findsprop(struct exifprop *prop, u_int16_t tag, - int16_t subtag); +extern u_int16_t exif2byte(unsigned char *b, enum byteorder o); +extern int16_t exif2sbyte(unsigned char *b, enum byteorder o); +extern u_int32_t exif4byte(unsigned char *b, enum byteorder o); +extern void byte4exif(u_int32_t n, unsigned char *b, enum byteorder o); +extern int32_t exif4sbyte(unsigned char *b, enum byteorder o); extern char *finddescr(struct descrip *table, u_int16_t val); extern struct exifprop *newprop(void); extern struct exifprop *childprop(struct exifprop *parent); +extern void exifstralloc(char **str, int len); extern void hexprint(unsigned char *b, int len); extern void dumpprop(struct exifprop *prop, struct field *afield); -extern struct ifd *readifds(u_int32_t offset, struct exiftags *t); -extern u_int32_t readifd(unsigned char *b, struct ifd **dir, - struct exiftags *t); +extern struct ifd *readifds(u_int32_t offset, struct exiftag *tagset, + struct tiffmeta *md); +extern u_int32_t readifd(u_int32_t offset, struct ifd **dir, + struct exiftag *tagset, struct tiffmeta *md); extern u_int32_t gcd(u_int32_t a, u_int32_t b); +/* Interface to exifgps.c. */ + +extern struct exiftag gpstags[]; +extern void gpsprop(struct exifprop *prop, struct exiftags *t); + #endif diff --git a/exifutil.c b/exifutil.c index 719b8ab..a955d98 100644 --- a/exifutil.c +++ b/exifutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Eric M. Johnston + * Copyright (c) 2001-2003, Eric M. Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: exifutil.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: exifutil.c,v 1.24 2003/08/08 22:31:32 ejohnst Exp $ */ /* @@ -52,7 +52,7 @@ int debug; const char *progname; -extern char error[256]; + /* * Logging and error functions. @@ -61,22 +61,22 @@ void exifdie(const char *msg) { - fprintf(error, "%s: %s\n", progname, msg); -/* exit(1);*/ + fprintf(stderr, "%s: %s\n", progname, msg); + exit(1); } void exifwarn(const char *msg) { - fprintf(error, "%s: %s\n", progname, msg); + fprintf(stderr, "%s: %s\n", progname, msg); } void exifwarn2(const char *msg1, const char *msg2) { - fprintf(error, "%s: %s (%s)\n", progname, msg1, msg2); + fprintf(stderr, "%s: %s (%s)\n", progname, msg1, msg2); } @@ -84,7 +84,7 @@ exifwarn2(const char *msg1, const char *msg2) * Read an unsigned 2-byte int from the buffer. */ u_int16_t -exif2byte(unsigned char *b, enum order o) +exif2byte(unsigned char *b, enum byteorder o) { if (o == BIG) @@ -98,7 +98,7 @@ exif2byte(unsigned char *b, enum order o) * Read a signed 2-byte int from the buffer. */ int16_t -exif2sbyte(unsigned char *b, enum order o) +exif2sbyte(unsigned char *b, enum byteorder o) { if (o == BIG) @@ -112,7 +112,7 @@ exif2sbyte(unsigned char *b, enum order o) * Read an unsigned 4-byte int from the buffer. */ u_int32_t -exif4byte(unsigned char *b, enum order o) +exif4byte(unsigned char *b, enum byteorder o) { if (o == BIG) @@ -122,11 +122,28 @@ exif4byte(unsigned char *b, enum order o) } +/* + * Write an unsigned 4-byte int to a buffer. + */ +void +byte4exif(u_int32_t n, unsigned char *b, enum byteorder o) +{ + int i; + + if (o == BIG) + for (i = 0; i < 4; i++) + b[3 - i] = (unsigned char)((n >> (i * 8)) & 0xff); + else + for (i = 0; i < 4; i++) + b[i] = (unsigned char)((n >> (i * 8)) & 0xff); +} + + /* * Read a signed 4-byte int from the buffer. */ int32_t -exif4sbyte(unsigned char *b, enum order o) +exif4sbyte(unsigned char *b, enum byteorder o) { if (o == BIG) @@ -137,7 +154,7 @@ exif4sbyte(unsigned char *b, enum order o) /* - * Lookup description for a value. + * Lookup and allocate description for a value. */ char * finddescr(struct descrip *table, u_int16_t val) @@ -154,25 +171,13 @@ finddescr(struct descrip *table, u_int16_t val) /* - * Lookup a property entry. - */ -struct exifprop * -findprop(struct exifprop *prop, u_int16_t tag) -{ - - for (; prop && prop->tag != tag; prop = prop->next); - return (prop); -} - - -/* - * Lookup a sub-property entry given tag and subtag. + * Lookup a property entry belonging to a particular set of tags. */ struct exifprop * -findsprop(struct exifprop *prop, u_int16_t tag, int16_t subtag) +findprop(struct exifprop *prop, struct exiftag *tagset, u_int16_t tag) { - for (; prop && (prop->tag != tag || prop->subtag != subtag); + for (; prop && (prop->tagset != tagset || prop->tag != tag); prop = prop->next); return (prop); } @@ -190,14 +195,6 @@ newprop(void) if (!prop) exifdie((const char *)strerror(errno)); memset(prop, 0, sizeof(struct exifprop)); - - /* - * Default; maker modules can depend on this being -2 unless they - * they touch it. (-1 is reserved for synthesized maker values.) - */ - - prop->subtag = -2; - return (prop); } @@ -214,7 +211,7 @@ childprop(struct exifprop *parent) prop = newprop(); - /* Property inherits everything but type & subtag from its parent. */ + /* By default, the child inherits most values from its parent. */ prop->tag = parent->tag; prop->type = TIFF_UNKN; @@ -222,8 +219,7 @@ childprop(struct exifprop *parent) prop->descr = parent->descr; prop->lvl = parent->lvl; prop->ifdseq = parent->ifdseq; - prop->ifdtag = parent->ifdtag; - prop->subtag = -1; + prop->par = parent; prop->next = parent->next; /* Now insert the new property into our list. */ @@ -234,6 +230,22 @@ childprop(struct exifprop *parent) } +/* + * Allocate a buffer for a property's display string. + */ +void +exifstralloc(char **str, int len) +{ + + if (*str) { + exifwarn("tried to alloc over non-null string"); + abort(); + } + if (!(*str = (char *)calloc(1, len))) + exifdie((const char *)strerror(errno)); +} + + /* * Print hex values of a buffer. */ @@ -258,29 +270,23 @@ dumpprop(struct exifprop *prop, struct field *afield) if (!debug) return; for (i = 0; ftypes[i].type && ftypes[i].type != prop->type; i++); - - if (prop->subtag < -1) { - if (afield) { - printf(" %s (0x%04X): %s, %d; %d\n", prop->name, - prop->tag, ftypes[i].name, prop->count, - prop->value); - printf(" "); - hexprint(afield->tag, 2); - printf(" |"); - hexprint(afield->type, 2); - printf(" |"); - hexprint(afield->count, 4); - printf(" |"); - hexprint(afield->value, 4); - printf("\n"); - } else - printf(" %s (0x%04X): %s, %d; %d, 0x%04X\n", - prop->name, prop->tag, ftypes[i].name, - prop->count, prop->value, prop->value); - } else - printf(" %s (%d): %s, %d; %d, 0x%04X\n", prop->name, - prop->subtag, ftypes[i].name, prop->count, prop->value, + if (afield) { + printf(" %s (0x%04X): %s, %d; %d\n", prop->name, + prop->tag, ftypes[i].name, prop->count, prop->value); + printf(" "); + hexprint(afield->tag, 2); + printf(" |"); + hexprint(afield->type, 2); + printf(" |"); + hexprint(afield->count, 4); + printf(" |"); + hexprint(afield->value, 4); + printf("\n"); + } else + printf(" %s (0x%04X): %s, %d; %d, 0x%04X\n", + prop->name, prop->tag, ftypes[i].name, + prop->count, prop->value, prop->value); } @@ -289,9 +295,13 @@ dumpprop(struct exifprop *prop, struct field *afield) * Exif buffer, returns the IFD and an offset to the next IFD. */ u_int32_t -readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) +readifd(u_int32_t offset, struct ifd **dir, struct exiftag *tagset, + struct tiffmeta *md) { u_int32_t ifdsize; + unsigned char *b; + + b = md->btiff; /* * Verify that we have a valid offset. Some maker note IFDs prepend @@ -299,7 +309,7 @@ readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) * (Number of directory entries is in the first 2 bytes.) */ - if (b + 2 > t->etiff) { + if (b + offset + 2 > md->etiff) { *dir = NULL; return (0); } @@ -308,15 +318,18 @@ readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) if (!*dir) exifdie((const char *)strerror(errno)); + (*dir)->num = exif2byte(b + offset, md->order); + (*dir)->par = NULL; + (*dir)->tagset = tagset; + (*dir)->md = *md; (*dir)->next = NULL; - (*dir)->num = exif2byte(b, t->tifforder); - (*dir)->tag = EXIF_T_UNKNOWN; + ifdsize = (*dir)->num * sizeof(struct field); - b += 2; + b += offset + 2; /* Sanity check our sizes. */ - if (b + ifdsize > t->etiff) { + if (b + ifdsize > md->etiff) { free(*dir); *dir = NULL; return (0); @@ -329,7 +342,7 @@ readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) /* * While we're here, find the offset to the next IFD. * - * XXX Note that this offset isn't always going to be valid. It + * Note that this offset isn't always going to be valid. It * seems that some camera implementations of Exif ignore the spec * and do not include the offset for all IFDs (e.g., maker note). * Therefore, it may be necessary to call readifd() directly (in @@ -337,8 +350,8 @@ readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) * standard IFDs. */ - return ((b + ifdsize + 4 > t->etiff) ? 0 : - exif4byte(b + ifdsize, t->tifforder)); + return ((b + ifdsize + 4 > md->etiff) ? 0 : + exif4byte(b + ifdsize, md->order)); } @@ -347,19 +360,19 @@ readifd(unsigned char *b, struct ifd **dir, struct exiftags *t) * node in a chain of IFDs. Note that it can return NULL. */ struct ifd * -readifds(u_int32_t offset, struct exiftags *t) +readifds(u_int32_t offset, struct exiftag *tagset, struct tiffmeta *md) { struct ifd *firstifd, *curifd; /* Fetch our first one. */ - offset = readifd(t->btiff + offset, &firstifd, t); + offset = readifd(offset, &firstifd, tagset, md); curifd = firstifd; /* Fetch any remaining ones. */ while (offset) { - offset = readifd(t->btiff + offset, &(curifd->next), t); + offset = readifd(offset, &(curifd->next), tagset, md); curifd = curifd->next; } return (firstifd); diff --git a/fuji.c b/fuji.c index 871e13d..a5e712d 100644 --- a/fuji.c +++ b/fuji.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: fuji.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: fuji.c,v 1.14 2003/08/06 22:54:33 ejohnst Exp $ */ /* @@ -40,7 +40,6 @@ #include #include #include -#include #include "makers.h" @@ -200,38 +199,16 @@ static struct exiftag fuji_tags[] = { void fuji_prop(struct exifprop *prop, struct exiftags *t) { - int i; - u_int16_t v = (u_int16_t)prop->value; - - /* Lookup the field name (if known). */ - - for (i = 0; fuji_tags[i].tag < EXIF_T_UNKNOWN && - fuji_tags[i].tag != prop->tag; i++); - prop->name = fuji_tags[i].name; - prop->descr = fuji_tags[i].descr; - prop->lvl = fuji_tags[i].lvl; - if (fuji_tags[i].table) - prop->str = finddescr(fuji_tags[i].table, v); - - if (debug) { - static int once = 0; /* XXX Breaks on multiple files. */ - - if (!once) { - printf("Processing Fuji Maker Note\n"); - once = 1; - } - dumpprop(prop, NULL); - } switch (prop->tag) { /* Maker note version. */ case 0x0000: - if (!(prop->str = (char *)malloc(prop->count + 1))) - exifdie((const char *)strerror(errno)); - strncpy(prop->str, (const char*)(&prop->value), prop->count); - prop->str[prop->count] = '\0'; + if (prop->count != 4) + break; + exifstralloc(&prop->str, prop->count + 1); + byte4exif(prop->value, (unsigned char *)prop->str, LITTLE); break; } } @@ -241,32 +218,28 @@ fuji_prop(struct exifprop *prop, struct exiftags *t) * Try to read a Fuji maker note IFD. */ struct ifd * -fuji_ifd(u_int32_t offset, struct exiftags *t) +fuji_ifd(u_int32_t offset, struct tiffmeta *md) { struct ifd *myifd; - struct exiftags fujit; int fujilen, fujioff; + struct tiffmeta mkrmd; fujilen = strlen("FUJIFILM"); + mkrmd = *md; /* * The Fuji maker note appears to be in Intel byte order - * regardless of the rest of the file (!). - */ - - fujit = *t; - fujit.tifforder = LITTLE; - - /* - * Seems that Fuji maker notes start with an ID string, followed by - * an IFD offset relative to the MakerNote tag. + * regardless of the rest of the file (!). Also, it seems that + * Fuji maker notes start with an ID string, followed by an IFD + * offset relative to the MakerNote tag. */ - if (!strncmp(t->btiff + offset, "FUJIFILM", fujilen)) { - fujioff = exif2byte(t->btiff + offset + fujilen, LITTLE); - readifd(t->btiff + offset + fujioff, &myifd, &fujit); + if (!strncmp((const char *)(md->btiff + offset), "FUJIFILM", fujilen)) { + fujioff = exif2byte(md->btiff + offset + fujilen, LITTLE); + mkrmd.order = LITTLE; + readifd(offset + fujioff, &myifd, fuji_tags, &mkrmd); } else - readifd(t->btiff + offset, &myifd, t); + readifd(offset, &myifd, fuji_tags, &mkrmd); return (myifd); } diff --git a/jpeg.c b/jpeg.c index a0c1570..49a6797 100644 --- a/jpeg.c +++ b/jpeg.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: jpeg.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: jpeg.c,v 1.5 2002/10/15 02:57:09 ejohnst Exp $ */ /* diff --git a/jpeg.h b/jpeg.h index c7d8417..a899804 100644 --- a/jpeg.h +++ b/jpeg.h @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: jpeg.h,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: jpeg.h,v 1.4 2002/10/15 02:57:09 ejohnst Exp $ */ /* diff --git a/makers.c b/makers.c index d1b60bc..9c021c4 100644 --- a/makers.c +++ b/makers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Eric M. Johnston + * Copyright (c) 2002, 2003, Eric M. Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: makers.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: makers.c,v 1.5 2003/08/06 06:28:43 ejohnst Exp $ */ /* @@ -44,11 +44,12 @@ struct makerfun makers[] = { { 0, "unknown", NULL, NULL }, /* default value */ - { EXIF_MKR_CANON, "canon", canon_prop, readifds }, + { EXIF_MKR_CANON, "canon", canon_prop, canon_ifd }, { EXIF_MKR_OLYMPUS, "olympus", olympus_prop, olympus_ifd }, { EXIF_MKR_FUJI, "fujifilm", fuji_prop, fuji_ifd }, { EXIF_MKR_NIKON, "nikon", nikon_prop, nikon_ifd }, - { EXIF_MKR_CASIO, "casio", casio_prop, casio_ifd }, + { EXIF_MKR_CASIO, "casio", NULL, casio_ifd }, { EXIF_MKR_MINOLTA, "minolta", minolta_prop, minolta_ifd }, + { EXIF_MKR_SANYO, "sanyo", sanyo_prop, sanyo_ifd }, { EXIF_MKR_UNKNOWN, "unknown", NULL, NULL }, }; diff --git a/makers.h b/makers.h index a22e2ab..52d74b6 100644 --- a/makers.h +++ b/makers.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2002, Eric M. Johnston + * Copyright (c) 2001-2003, Eric M. Johnston * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: makers.h,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: makers.h,v 1.12 2003/08/06 06:28:43 ejohnst Exp $ */ /* @@ -66,26 +66,31 @@ extern struct makerfun makers[]; #define EXIF_MKR_NIKON 4 #define EXIF_MKR_CASIO 5 #define EXIF_MKR_MINOLTA 6 +#define EXIF_MKR_SANYO 7 #define EXIF_MKR_UNKNOWN -1 /* Maker note functions. */ extern void canon_prop(struct exifprop *prop, struct exiftags *t); +extern struct ifd *canon_ifd(u_int32_t offset, struct tiffmeta *md); extern void olympus_prop(struct exifprop *prop, struct exiftags *t); -extern struct ifd *olympus_ifd(u_int32_t offset, struct exiftags *t); +extern struct ifd *olympus_ifd(u_int32_t offset, struct tiffmeta *md); extern void fuji_prop(struct exifprop *prop, struct exiftags *t); -extern struct ifd *fuji_ifd(u_int32_t offset, struct exiftags *t); +extern struct ifd *fuji_ifd(u_int32_t offset, struct tiffmeta *md); extern void nikon_prop(struct exifprop *prop, struct exiftags *t); -extern struct ifd *nikon_ifd(u_int32_t offset, struct exiftags *t); +extern struct ifd *nikon_ifd(u_int32_t offset, struct tiffmeta *md); extern void casio_prop(struct exifprop *prop, struct exiftags *t); -extern struct ifd *casio_ifd(u_int32_t offset, struct exiftags *t); +extern struct ifd *casio_ifd(u_int32_t offset, struct tiffmeta *md); extern void minolta_prop(struct exifprop *prop, struct exiftags *t); -extern struct ifd *minolta_ifd(u_int32_t offset, struct exiftags *t); +extern struct ifd *minolta_ifd(u_int32_t offset, struct tiffmeta *md); + +extern void sanyo_prop(struct exifprop *prop, struct exiftags *t); +extern struct ifd *sanyo_ifd(u_int32_t offset, struct tiffmeta *t); #endif diff --git a/minolta.c b/minolta.c index 71e3fc7..09748c0 100644 --- a/minolta.c +++ b/minolta.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: minolta.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: minolta.c,v 1.25 2003/08/08 22:31:32 ejohnst Exp $ * */ @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "makers.h" @@ -302,7 +301,7 @@ static struct exiftag minolta_tags[] = { /* Fields under tags 0x0001 and 0x0003. */ -static struct exiftag minolta_0TLM[] = { +static struct exiftag minolta_MLT0[] = { { 1, TIFF_LONG, 1, ED_IMG, "MinoltaExpProg", "Exposure Program", minolta_prog }, { 2, TIFF_LONG, 1, ED_IMG, "MinoltaFlashMode", @@ -408,17 +407,19 @@ static struct exiftag minolta_unkn[] = { * Process maker note tag 0x0001 and 0x0003 fields. */ void -minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, +minolta_cprop(struct exifprop *prop, unsigned char *off, struct exiftags *t, struct exiftag *thetags) { unsigned int i, j, k; u_int32_t v; int32_t model; double d; - unsigned char *cp, *valbuf; + char *valbuf; + unsigned char buf[8]; struct exifprop *aprop; valbuf = NULL; + model = -1; for (i = 0; i * 4 < prop->count; i++) { @@ -428,14 +429,15 @@ minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, * skip #51. */ - if (thetags == minolta_0TLM && i >= 51 && model == 5) { + if (thetags == minolta_MLT0 && i >= 51 && model == 5) { if (i == 51) continue; k = i - 1; } else k = i; aprop = childprop(prop); - aprop->subtag = i; + aprop->tag = i; + aprop->tagset = thetags; /* Note: these are big-endian regardless. */ aprop->value = exif4byte(off + (4 * i), BIG); @@ -460,14 +462,11 @@ minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, * tags passed in. */ - if (thetags != minolta_0TLM) + if (thetags != minolta_MLT0) continue; - if (!valbuf) { - if (!(valbuf = (char *)malloc(16))) - exifdie((const char *)strerror(errno)); - valbuf[15] = '\0'; - } + if (!valbuf) + exifstralloc(&valbuf, 16); switch (k) { @@ -587,9 +586,9 @@ minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, case 21: aprop->str = valbuf; valbuf = NULL; - cp = (unsigned char *)&aprop->value; + byte4exif(aprop->value, buf, LITTLE); snprintf(aprop->str, 15, "%02d/%02d/%04d", - cp[0], cp[1], cp[3] << 8 | cp[2]); + buf[0], buf[1], buf[3] << 8 | buf[2]); break; /* Time. */ @@ -597,9 +596,9 @@ minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, case 22: aprop->str = valbuf; valbuf = NULL; - cp = (unsigned char *)&aprop->value; + byte4exif(aprop->value, buf, LITTLE); snprintf(aprop->str, 9, "%02d:%02d:%02d", - cp[2], cp[1], cp[0]); + buf[2], buf[1], buf[0]); break; /* White balance. */ @@ -653,17 +652,17 @@ minolta_cprop(struct exifprop *prop, char *off, struct exiftags *t, * Make sure meaningless values are meaningless. */ void -minolta_naval(struct exifprop *props, u_int16_t tag, int16_t subtag) +minolta_naval(struct exifprop *props, struct exiftag *tags, int16_t tag) { struct exifprop *prop; const char *na = "n/a"; - if (!(prop = findsprop(props, tag, subtag))) + if (!(prop = findprop(props, tags, tag))) return; free(prop->str); - if (!(prop->str = (char *)malloc(strlen(na) + 1))) - exifdie((const char *)strerror(errno)); + prop->str = NULL; + exifstralloc(&prop->str, strlen(na) + 1); strcpy(prop->str, na); prop->lvl = ED_BAD; } @@ -675,26 +674,9 @@ minolta_naval(struct exifprop *props, u_int16_t tag, int16_t subtag) void minolta_prop(struct exifprop *prop, struct exiftags *t) { - int i; - struct exiftag *fielddefs; + struct exiftag *fielddefs = NULL; struct exifprop *tmpprop; - /* - * Don't process properties we've created while looking at other - * maker note tags. - */ - - if (prop->subtag > -2) - return; - - /* Lookup the field name (if known). */ - - for (i = 0; minolta_tags[i].tag < EXIF_T_UNKNOWN && - minolta_tags[i].tag != prop->tag; i++); - prop->name = minolta_tags[i].name; - prop->descr = minolta_tags[i].descr; - prop->lvl = minolta_tags[i].lvl; - if (debug) { static int once = 0; /* XXX Breaks on multiple files. */ @@ -710,14 +692,14 @@ minolta_prop(struct exifprop *prop, struct exiftags *t) /* Maker note type. */ case 0x0000: - if (!(prop->str = (char *)malloc(prop->count + 1))) - exifdie((const char *)strerror(errno)); - strncpy(prop->str, (const char *)&prop->value, prop->count); - prop->str[prop->count] = '\0'; + if (prop->count < 4) + break; + exifstralloc(&prop->str, prop->count + 1); + byte4exif(prop->value, (unsigned char *)prop->str, t->md.order); - /* We recognize two types: 0TLM and mlt0. */ + /* We recognize two types: MLT0 and mlt0. */ - if (strcmp(prop->str, "0TLM") && strcmp(prop->str, "mlt0")) + if (strcmp(prop->str, "MLT0") && strcmp(prop->str, "mlt0")) exifwarn2("Minolta maker note version not supported", prop->str); break; @@ -732,8 +714,8 @@ minolta_prop(struct exifprop *prop, struct exiftags *t) exifwarn("Minolta maker note not fully supported"); fielddefs = minolta_unkn; } else - fielddefs = minolta_0TLM; - minolta_cprop(prop, t->btiff + prop->value, t, fielddefs); + fielddefs = minolta_MLT0; + minolta_cprop(prop, t->md.btiff + prop->value, t, fielddefs); break; case 0x0003: @@ -741,62 +723,62 @@ minolta_prop(struct exifprop *prop, struct exiftags *t) exifwarn("Minolta maker note not fully supported"); fielddefs = minolta_unkn; } else - fielddefs = minolta_0TLM; - minolta_cprop(prop, t->btiff + prop->value, t, fielddefs); + fielddefs = minolta_MLT0; + minolta_cprop(prop, t->md.btiff + prop->value, t, fielddefs); break; } /* Override meaningless values. */ - if (prop->tag == 0x0001 || prop->tag == 0x0003) { + if (fielddefs) { /* Drive mode (bracketing step & mode). */ - if ((tmpprop = findsprop(t->props, prop->tag, 6))) + if ((tmpprop = findprop(t->props, fielddefs, 6))) if (tmpprop->value != 4) { - minolta_naval(t->props, prop->tag, 14); - minolta_naval(t->props, prop->tag, 50); + minolta_naval(t->props, fielddefs, 14); + minolta_naval(t->props, fielddefs, 50); } /* Focus mode (wide focus area, AF zone, point X & Y). */ - if ((tmpprop = findsprop(t->props, prop->tag, 48))) + if ((tmpprop = findprop(t->props, fielddefs, 48))) if (tmpprop->value == 1) { - minolta_naval(t->props, prop->tag, 45); - minolta_naval(t->props, prop->tag, 46); - minolta_naval(t->props, prop->tag, 47); - minolta_naval(t->props, prop->tag, 49); + minolta_naval(t->props, fielddefs, 45); + minolta_naval(t->props, fielddefs, 46); + minolta_naval(t->props, fielddefs, 47); + minolta_naval(t->props, fielddefs, 49); } /* Flash fired (flash comp, mode, & internal flash). */ - if ((tmpprop = findsprop(t->props, prop->tag, 20))) + if ((tmpprop = findprop(t->props, fielddefs, 20))) if (tmpprop->value != 1) { - minolta_naval(t->props, prop->tag, 2); - minolta_naval(t->props, prop->tag, 35); - minolta_naval(t->props, prop->tag, 43); + minolta_naval(t->props, fielddefs, 2); + minolta_naval(t->props, fielddefs, 35); + minolta_naval(t->props, fielddefs, 43); } /* Exposure mode (meter mode, exposure comp). */ - if ((tmpprop = findprop(t->props, EXIF_T_EXPMODE))) + if ((tmpprop = findprop(t->props, tags, EXIF_T_EXPMODE))) if (tmpprop->value == 1) { - minolta_naval(t->props, prop->tag, 7); - minolta_naval(t->props, prop->tag, 13); + minolta_naval(t->props, fielddefs, 7); + minolta_naval(t->props, fielddefs, 13); } /* Exposure prog (scene capture type). */ - if ((tmpprop = findsprop(t->props, prop->tag, 1))) + if ((tmpprop = findprop(t->props, fielddefs, 1))) if (tmpprop->value != 0) - minolta_naval(t->props, prop->tag, 34); + minolta_naval(t->props, fielddefs, 34); /* Interval mode (interval pics, time). */ - if ((tmpprop = findsprop(t->props, prop->tag, 38))) + if ((tmpprop = findprop(t->props, fielddefs, 38))) if (tmpprop->value != 1) { - minolta_naval(t->props, prop->tag, 16); - minolta_naval(t->props, prop->tag, 17); + minolta_naval(t->props, fielddefs, 16); + minolta_naval(t->props, fielddefs, 17); } } } @@ -806,25 +788,26 @@ minolta_prop(struct exifprop *prop, struct exiftags *t) * Try to read a Minolta maker note IFD, which differs by model. */ struct ifd * -minolta_ifd(u_int32_t offset, struct exiftags *t) +minolta_ifd(u_int32_t offset, struct tiffmeta *md) { /* DiMAGE E201. */ - if (!strcmp(t->btiff + offset, "+M")) { + if (!strcmp((const char *)(md->btiff + offset), "+M")) { exifwarn("Minolta maker note version not supported"); return (NULL); } /* - * Assume that if IFD num > 255, this isn't a real IFD. - * Takes care of the unfortunate DiMAGE 2300. + * Assume that if IFD num > 255 or < 2, this isn't a real IFD. + * Takes care of the unfortunate DiMAGE 2300 & EX. */ - if (exif2byte(t->btiff + offset, t->tifforder) > 0xff) { + if (exif2byte(md->btiff + offset, md->order) > 0xff || + exif2byte(md->btiff + offset, md->order) < 0x02) { exifwarn("Minolta maker note version not supported"); return (NULL); } - return (readifds(offset, t)); + return (readifds(offset, minolta_tags, md)); } diff --git a/nikon.c b/nikon.c index 4f9d53a..379ca9b 100644 --- a/nikon.c +++ b/nikon.c @@ -29,18 +29,19 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: nikon.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: nikon.c,v 1.17 2003/08/16 03:02:16 ejohnst Exp $ */ /* * Exif tag definitions for Nikon maker notes. * + * Some information for Nikon D1X support obtained from JoJoThumb, version + * 2.7.2 (http://www.jojosoftware.de/jojothumb/). */ #include #include #include -#include #include "makers.h" @@ -167,30 +168,51 @@ static struct exiftag nikon_tags1[] = { }; +static struct exiftag nikon_tags2[] = { + { 0x0001, TIFF_UNDEF, 4, ED_VRB, "NikonVersion", + "Nikon Note Version", NULL }, + { 0x0002, TIFF_SHORT, 2, ED_UNK, "NikonISOSetting", + "ISO Setting", NULL }, + { 0x0003, TIFF_ASCII, 0, ED_IMG, "NikonColor", + "Color Mode", NULL }, + { 0x0004, TIFF_ASCII, 0, ED_IMG, "NikonQuality", + "Image Quality", NULL }, + { 0x0005, TIFF_ASCII, 0, ED_IMG, "NikonWhiteBal", + "White Balance", NULL }, + { 0x0006, TIFF_ASCII, 0, ED_IMG, "NikonImgSharp", + "Image Sharpening", NULL }, + { 0x0007, TIFF_ASCII, 0, ED_IMG, "NikonFocus", + "Focus Mode", NULL }, + { 0x0008, TIFF_ASCII, 0, ED_IMG, "NikonFlash", + "Flash Setting", NULL }, + { 0x000b, TIFF_UNKN, 0, ED_UNK, "NikonWhiteBalBias", + "White Balance Bias", NULL }, + { 0x0081, TIFF_ASCII, 0, ED_IMG, "NikonImgAdjust", + "Image Adjustment", NULL }, + { 0x0088, TIFF_UNDEF, 0, ED_UNK, "NikonAutoFocus", + "Auto Focus Position", NULL }, + { 0x0092, TIFF_UNDEF, 0, ED_UNK, "NikonHueAdjust", + "Hue Adjustment", NULL }, + { 0xffff, TIFF_UNKN, 0, ED_UNK, "NikonUnknown", + "Nikon Unknown", NULL }, +}; + + /* * Process normal Nikon maker note tags. */ static void nikon_prop0(struct exifprop *prop, struct exiftags *t) { - int i; u_int32_t a, b; - /* Lookup the field name (if known). */ - - for (i = 0; nikon_tags0[i].tag < EXIF_T_UNKNOWN && - nikon_tags0[i].tag != prop->tag; i++); - prop->name = nikon_tags0[i].name; - prop->descr = nikon_tags0[i].descr; - prop->lvl = nikon_tags0[i].lvl; - switch (prop->tag) { /* Manual focus distance. */ case 0x0085: - a = exif4byte(t->btiff + prop->value, t->tifforder); - b = exif4byte(t->btiff + prop->value + 4, t->tifforder); + a = exif4byte(t->md.btiff + prop->value, t->md.order); + b = exif4byte(t->md.btiff + prop->value + 4, t->md.order); if (a == b) { snprintf(prop->str, 31, "N/A"); @@ -202,8 +224,8 @@ nikon_prop0(struct exifprop *prop, struct exiftags *t) /* Digital zoom. */ case 0x0086: - a = exif4byte(t->btiff + prop->value, t->tifforder); - b = exif4byte(t->btiff + prop->value + 4, t->tifforder); + a = exif4byte(t->md.btiff + prop->value, t->md.order); + b = exif4byte(t->md.btiff + prop->value + 4, t->md.order); if (a == b) { snprintf(prop->str, 31, "None"); @@ -221,27 +243,15 @@ nikon_prop0(struct exifprop *prop, struct exiftags *t) static void nikon_prop1(struct exifprop *prop, struct exiftags *t) { - int i; u_int32_t a, b; - u_int16_t v = (u_int16_t)prop->value; - - /* Lookup the field name (if known). */ - - for (i = 0; nikon_tags1[i].tag < EXIF_T_UNKNOWN && - nikon_tags1[i].tag != prop->tag; i++); - prop->name = nikon_tags1[i].name; - prop->descr = nikon_tags1[i].descr; - prop->lvl = nikon_tags1[i].lvl; - if (nikon_tags1[i].table) - prop->str = finddescr(nikon_tags1[i].table, v); switch (prop->tag) { /* Digital zoom. */ case 0x000a: - a = exif4byte(t->btiff + prop->value, t->tifforder); - b = exif4byte(t->btiff + prop->value + 4, t->tifforder); + a = exif4byte(t->md.btiff + prop->value, t->md.order); + b = exif4byte(t->md.btiff + prop->value + 4, t->md.order); if (!a) { snprintf(prop->str, 31, "None"); @@ -260,27 +270,10 @@ void nikon_prop(struct exifprop *prop, struct exiftags *t) { - /* - * XXX This is a rather ugly hack, but we don't really have a way - * to figure out which type of Nikon maker note we're dealing with - * (easily). - */ - - if (t->mkrinfo) + if (prop->tagset == nikon_tags1) nikon_prop1(prop, t); else nikon_prop0(prop, t); - - if (debug) { - static int once = 0; /* XXX Breaks on multiple files. */ - - if (!once) { - printf("Processing Nikon Maker Note (%d)\n", - t->mkrinfo); - once = 1; - } - dumpprop(prop, NULL); - } } @@ -288,25 +281,62 @@ nikon_prop(struct exifprop *prop, struct exiftags *t) * Try to read a Nikon maker note IFD. */ struct ifd * -nikon_ifd(u_int32_t offset, struct exiftags *t) +nikon_ifd(u_int32_t offset, struct tiffmeta *md) { struct ifd *myifd; + unsigned char *b; + struct tiffmeta mkrmd; + + b = md->btiff + offset; + mkrmd = *md; /* * Seems that some Nikon maker notes start with an ID string. - * Therefore, * try reading the IFD starting at offset + 8 - * ("Nikon" + 3). */ - if (!strcmp(t->btiff + offset, "Nikon")) { - - /* What a hack. Indicates we need to use nikon_tags1[]. */ - t->mkrinfo = 1; - - readifd(t->btiff + offset + strlen("Nikon") + 3, &myifd, t); - - } else - readifd(t->btiff + offset, &myifd, t); + if (!strcmp((const char *)b, "Nikon")) { + b += 6; + + switch (exif2byte(b, md->order)) { + case 0x0001: + readifd(offset + 8, &myifd, nikon_tags1, &mkrmd); + return (myifd); + + case 0x0200: + b += 4; + + /* + * So, this is interesting: they've put a full-fledged + * TIFF header here. + */ + + /* Determine endianness of the TIFF data. */ + + if (*((u_int16_t *)b) == 0x4d4d) + mkrmd.order = BIG; + else if (*((u_int16_t *)b) == 0x4949) + mkrmd.order = LITTLE; + else { + exifwarn("invalid Nikon TIFF header"); + return (NULL); + } + mkrmd.btiff = b; /* Beginning of maker. */ + b += 2; + + /* Verify the TIFF header. */ + + if (exif2byte(b, mkrmd.order) != 42) { + exifwarn("invalid Nikon TIFF header"); + return (NULL); + } + b += 2; + + readifd(exif4byte(b, mkrmd.order), &myifd, + nikon_tags2, &mkrmd); + return (myifd); + } + } + readifd(offset, &myifd, nikon_tags0, &mkrmd); return (myifd); } diff --git a/olympus.c b/olympus.c index 7291e1e..5b76369 100644 --- a/olympus.c +++ b/olympus.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: olympus.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: olympus.c,v 1.16 2003/08/06 02:26:42 ejohnst Exp $ */ /* @@ -42,9 +42,7 @@ #include #include #include -#include -#include "exif.h" #include "makers.h" @@ -95,46 +93,16 @@ static struct exiftag olympus_tags[] = { void olympus_prop(struct exifprop *prop, struct exiftags *t) { - int i; u_int32_t a, b; - u_int16_t v = (u_int16_t)prop->value; - char *offset; + unsigned char *offset; struct exifprop *aprop; - /* - * Don't process properties we've created while looking at other - * maker note tags. - */ - - if (prop->subtag > -2) - return; - - /* Lookup the field name (if known). */ - - for (i = 0; olympus_tags[i].tag < EXIF_T_UNKNOWN && - olympus_tags[i].tag != prop->tag; i++); - prop->name = olympus_tags[i].name; - prop->descr = olympus_tags[i].descr; - prop->lvl = olympus_tags[i].lvl; - if (olympus_tags[i].table) - prop->str = finddescr(olympus_tags[i].table, v); - - if (debug) { - static int once = 0; /* XXX Breaks on multiple files. */ - - if (!once) { - printf("Processing Olympus Maker Note\n"); - once = 1; - } - dumpprop(prop, NULL); - } - switch (prop->tag) { /* Various image data. */ case 0x0200: - offset = t->btiff + prop->value; + offset = t->md.btiff + prop->value; /* * XXX Would be helpful to test this with a panoramic. @@ -146,7 +114,7 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) /* Picture taking mode. */ aprop = childprop(prop); - aprop->value = exif4byte(offset, t->tifforder); + aprop->value = exif4byte(offset, t->md.order); aprop->name = "OlympusPicMode"; aprop->descr = "Picture Mode"; aprop->lvl = ED_UNK; @@ -154,7 +122,7 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) /* Sequence number. */ aprop = childprop(prop); - aprop->value = exif4byte(offset + 4, t->tifforder); + aprop->value = exif4byte(offset + 4, t->md.order); aprop->name = "OlympusSeqNum"; aprop->descr = "Sequence Number"; aprop->lvl = ED_UNK; @@ -162,7 +130,7 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) /* Panorama direction. */ aprop = childprop(prop); - aprop->value = exif4byte(offset + 8, t->tifforder); + aprop->value = exif4byte(offset + 8, t->md.order); aprop->name = "OlympusPanDir"; aprop->descr = "Panoramic Direction"; aprop->lvl = ED_UNK; @@ -172,8 +140,8 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) /* Digital zoom. */ case 0x0204: - a = exif4byte(t->btiff + prop->value, t->tifforder); - b = exif4byte(t->btiff + prop->value + 4, t->tifforder); + a = exif4byte(t->md.btiff + prop->value, t->md.order); + b = exif4byte(t->md.btiff + prop->value + 4, t->md.order); if (a == b) snprintf(prop->str, 31, "None"); @@ -184,11 +152,9 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) /* Image number. */ case 0x0008: - if (!(prop->str = (char *)malloc(32))) - exifdie((const char *)strerror(errno)); + exifstralloc(&prop->str, 32); snprintf(prop->str, 31, "%03d-%04d", prop->value / 10000, prop->value % 10000); - prop->str[31] = '\0'; break; } } @@ -198,7 +164,7 @@ olympus_prop(struct exifprop *prop, struct exiftags *t) * Try to read an Olympus maker note IFD. */ struct ifd * -olympus_ifd(u_int32_t offset, struct exiftags *t) +olympus_ifd(u_int32_t offset, struct tiffmeta *md) { struct ifd *myifd; @@ -207,10 +173,10 @@ olympus_ifd(u_int32_t offset, struct exiftags *t) * try reading the IFD starting at offset + 8 ("OLYMP" + 3). */ - if (!strcmp(t->btiff + offset, "OLYMP")) - readifd(t->btiff + offset + strlen("OLYMP") + 3, &myifd, t); + if (!strcmp((const char *)(md->btiff + offset), "OLYMP")) + readifd(offset + strlen("OLYMP") + 3, &myifd, olympus_tags, md); else - readifd(t->btiff + offset, &myifd, t); + readifd(offset, &myifd, olympus_tags, md); return (myifd); } diff --git a/tagdefs.c b/tagdefs.c index dc727c4..72b0a5b 100644 --- a/tagdefs.c +++ b/tagdefs.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: tagdefs.c,v 1.1.1.1 2003/08/07 16:46:05 ccpro Exp $ + * $Id: tagdefs.c,v 1.20 2003/01/20 21:37:41 ejohnst Exp $ */ /*