/*
* Copyright (c) 2001-2005, Eric M. Johnston <emj@postal.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Eric M. Johnston.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: exif.c,v 1.74 2005/01/04 23:28:25 ejohnst Exp $
*/
/*
* Exchangeable image file format (Exif) parser.
*
* Developed using the TIFF 6.0 specification:
* (http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf)
* and the EXIF 2.21 standard: (http://tsc.jeita.or.jp/avs/data/cp3451_1.pdf).
*
* Portions of this code were developed while referencing the public domain
* 'Jhead' program (version 1.2) by Matthias Wandel <mwandel@rim.net>.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <float.h>
#include <ctype.h>
#include "exif.h"
#include "exifint.h"
#include "makers.h"
#define OLYMPUS_BUGS /* Work around Olympus stupidity. */
#define WINXP_BUGS /* Work around Windows XP stupidity. */
#define SIGMA_BUGS /* Work around Sigma stupidity. */
#define UNCREDITED_BUGS /* Work around uncredited stupidity. */
/* Function prototypes. */
static void parsetag(struct exifprop *prop, struct ifd *dir,
struct exiftags *t, int domkr);
/*
* Create an Exif property from the raw IFD field data.
*/
static void
readtag(struct field *afield, int ifdseq, struct ifd *dir, struct exiftags *t,
int domkr)
{
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, dir->md.order);
prop->type = exif2byte(afield->type, dir->md.order);
prop->count = exif4byte(afield->count, dir->md.order);
/* XXX Makes dealing with two shorts somewhat messy. */
if ((prop->type == TIFF_SHORT || prop->type == TIFF_SSHORT) &&
prop->count <= 1)
prop->value = exif2byte(afield->value, dir->md.order);
else
prop->value = exif4byte(afield->value, dir->md.order);
/* IFD identifying info. */
prop->ifdseq = ifdseq;
prop->par = dir->par;
prop->tagset = dir->tagset;
/* Lookup the field name. */
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.
*
* 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) {
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 (tag != EXIF_T_MAKERNOTE) {
/*
* XXX Ignore UserComment -- a hack to get around an apparent
* WinXP Picture Viewer bug (err, liberty). When you rotate
* a picture in the viewer, it modifies the IFD1 (thumbnail)
* tags to UserComment without changing the type appropriately.
* (At least we're able to ID invalid comments...)
*/
if (prop->tagset[i].type && prop->tagset[i].type != prop->type
#ifdef WINXP_BUGS
&& prop->tag != EXIF_T_USERCOMMENT
#endif
)
exifwarn2("field type mismatch", prop->name);
/*
* Check the field count.
* XXX For whatever the reason, Sigma doesn't follow the
* spec on count for FileSource.
*/
if (prop->tagset[i].count && prop->tagset[i].count !=
#ifdef SIGMA_BUGS
prop->count && prop->tag != EXIF_T_FILESRC)
#else
prop->count)
#endif
exifwarn2("field count mismatch", prop->name);
}
/* Debuggage. */
dumpprop(prop, afield);
/*
* Do as much as we can with the tag at this point and add it
* to our list.
*/
parsetag(prop, dir, t, domkr);
if ((tmpprop = t->props)) {
while (tmpprop->next)
tmpprop = tmpprop->next;
tmpprop->next = prop;
} else
t->props = prop;
}
/*
* Process the Exif tags for each field of an IFD.
*
* Note that this function is only called once per IFD. Therefore, in order
* to associate an IFD sequence number with the property, we keep track of
* 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.
*/
static void
readtags(struct ifd *dir, int seq, struct exiftags *t, int domkr)
{
int i;
if (debug) {
/* XXX Byte order info can be off for maker notes. */
if (dir->par && dir->par->tag != EXIF_T_UNKNOWN) {
printf("Processing %s directory, %d entries, "
"%s-endian\n",
dir->par->name, dir->num, dir->md.order == BIG ?
"big" : "little");
} else
printf("Processing directory %d, %d entries, "
"%s-endian\n",
seq, dir->num, dir->md.order == BIG ? "big" :
"little");
}
for (i = 0; i < dir->num; i++)
readtag(&(dir->fields[i]), seq, dir, t, domkr);
if (debug)
printf("\n");
}
/*
* 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)
{
struct exifprop *tmpprop;
u_int16_t v;
u_int32_t val;
float fval;
enum byteorder o = t->md.order;
struct exifprop *h = t->props;
/*
* Process tags from special IFDs.
*/
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:
case EXIF_T_YRES:
case EXIF_T_FPXRES:
case EXIF_T_FPYRES:
if (prop->tag == EXIF_T_XRES || prop->tag == EXIF_T_YRES) {
if (!(tmpprop = findprop(h, tags, EXIF_T_RESUNITS)))
break;
} else {
if (!(tmpprop = findprop(h, tags, EXIF_T_FPRESUNITS)))
break;
}
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;
/*
* Shutter speed doesn't seem all that useful. It's usually the
* same as exposure time and when it's not, it's wrong.
* Exposure time overrides it.
*/
case EXIF_T_SHUTTER:
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",
(int)floor(pow(2, (double)fval) + 0.5));
prop->str[31] = '\0';
/* FALLTHROUGH */
case EXIF_T_EXPOSURE:
if (strlen(prop->str) > 27) break;
strcat(prop->str, " sec");
if (prop->tag == EXIF_T_EXPOSURE)
prop->override = EXIF_T_SHUTTER;
break;
case EXIF_T_FNUMBER:
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';
break;
case EXIF_T_LAPERTURE:
case EXIF_T_MAXAPERTURE:
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));
prop->str[31] = '\0';
break;
case EXIF_T_BRIGHTVAL:
if (exif4byte(t->md.btiff + prop->value, o) == 0xffffffff) {
strcpy(prop->str, "Unknown");
break;
}
/* FALLTHROUGH */
case EXIF_T_EXPBIASVAL:
if (strlen(prop->str) > 28) break;
strcat(prop->str, " EV");
break;
case EXIF_T_DISTANCE:
if (exif4byte(t->md.btiff + prop->value, o) == 0xffffffff) {
strcpy(prop->str, "Infinity");
break;
}
if (exif4byte(t->md.btiff + prop->value + 4, o) == 0) {
strcpy(prop->str, "Unknown");
break;
}
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';
break;
/* Flash consists of a number of bits, which expanded with v2.2. */
#define LFLSH 96
case EXIF_T_FLASH:
if (t->exifmaj <= 2 && t->exifmin < 20)
v = (u_int16_t)(prop->value & 0x7);
else
v = (u_int16_t)(prop->value & 0x7F);
exifstralloc(&prop->str, LFLSH);
/* Don't do anything else if there isn't a flash. */
if (catdescr(prop->str, flash_func, (u_int16_t)(v & 0x20),
LFLSH))
break;
catdescr(prop->str, flash_fire, (u_int16_t)(v & 0x01), LFLSH);
catdescr(prop->str, flash_mode, (u_int16_t)(v & 0x18), LFLSH);
catdescr(prop->str, flash_redeye, (u_int16_t)(v & 0x40), LFLSH);
catdescr(prop->str, flash_return, (u_int16_t)(v & 0x06), LFLSH);
break;
case EXIF_T_FOCALLEN:
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';
break;
/* Digital zoom: set to verbose if numerator is 0 or fraction = 1. */
case EXIF_T_DIGIZOOM:
if (!exif4byte(t->md.btiff + prop->value, o))
strcpy(prop->str, "Unused");
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:
exifstralloc(&prop->str, 16);
snprintf(prop->str, 15, "%d mm", prop->value);
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;
}
}
/*
* This gives us an opportunity to change the dump level based on
* property values after all properties are established.
*/
static void
tweaklvl(struct exifprop *prop, struct exiftags *t)
{
char *c;
struct exifprop *tmpprop;
/* Change any ASCII properties to verbose if they're empty. */
if (prop->type == TIFF_ASCII &&
(prop->lvl & (ED_CAM | ED_IMG | ED_PAS))) {
c = prop->str;
while (c && *c && (isspace((int)*c) ||
(unsigned char)*c < ' ')) c++;
if (!c || !*c)
prop->lvl = ED_VRB;
}
/*
* Don't let unprintable characters slip through -- we'll just replace
* them with '_'. (Can see this with some corrupt maker notes.)
* Remove trailing whitespace while we're at it.
*/
if (prop->str && prop->type == TIFF_ASCII) {
c = prop->str;
while (*c) {
/* Catch those pesky chars > 127. */
if ((unsigned char)*c < ' ')
*c = '_';
c++;
}
c = prop->str + strlen(prop->str);
while (c > prop->str && isspace((int)*(c - 1))) --c;
*c = '\0';
}
/*
* IFD1 refers to the thumbnail image; we don't really care.
* It seems that some images might not have an IFD1 (does FinePix
* Viewer strip it?), so make sure that the property doesn't have
* a parent association.
*/
if (prop->ifdseq == 1 && !prop->par && prop->lvl != ED_UNK)
prop->lvl = ED_VRB;
/* 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;
}
/*
* Fetch the data for an Exif tag.
*/
static void
parsetag(struct exifprop *prop, struct ifd *dir, struct exiftags *t, int domkr)
{
unsigned int i, len;
u_int16_t v = (u_int16_t)prop->value;
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; 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. */
case EXIF_T_EXIFIFD:
case EXIF_T_GPSIFD:
case EXIF_T_INTEROP:
/*
* Prevent looping when the tag refers to its own IFD...
* (Occurs in a screwed-up Agfa example.)
*/
if (prop->par && prop->tag == prop->par->tag) {
exifwarn2("IFD tag refers to itself", prop->name);
break;
}
md = &dir->md;
while (dir->next)
dir = dir->next;
/*
* XXX Olympus cameras don't seem to include a proper offset
* at the end of the ExifOffset IFD, so just read one IFD.
* Hopefully this won't cause us to miss anything...
*/
#ifdef OLYMPUS_BUGS
if (prop->tag == EXIF_T_EXIFIFD)
readifd(prop->value, &dir->next, tags, md);
else
#endif
if (prop->tag == EXIF_T_GPSIFD) {
dir->next = readifds(prop->value, gpstags, md);
} else {
dir->next = readifds(prop->value, tags, md);
}
if (!dir->next) {
/*
* XXX Ignore the case where interoperability offset
* is invalid. This appears to be the case with some
* Olympus cameras, and we don't want to abort things
* things on an IFD we don't really care about anyway.
*/
#ifdef OLYMPUS_BUGS
if (prop->tag == EXIF_T_INTEROP)
break;
#endif
exifwarn2("invalid Exif format: IFD length mismatch",
prop->name);
break;
}
/* XXX Doesn't catch multiple IFDs. */
dir->next->par = prop;
return;
/* Record the Exif version. */
case EXIF_T_VERSION:
byte4exif(prop->value, (unsigned char *)buf, o);
buf[4] = '\0';
t->exifmin = (short)atoi(buf + 2);
buf[2] = '\0';
t->exifmaj = (short)atoi(buf);
exifstralloc(&prop->str, 8);
snprintf(prop->str, 7, "%d.%02d", t->exifmaj, t->exifmin);
break;
/* Process a maker note. */
case EXIF_T_MAKERNOTE:
if (!domkr)
return;
/* Maker function can change metadata if necessary. */
t->mkrmd = dir->md;
md = &t->mkrmd;
while (dir->next)
dir = dir->next;
/*
* Try to process maker note IFDs using the function
* specified for the maker.
*
* XXX Note that for this to work right, we have to see
* the manufacturer tag first to figure out makerifd().
*/
if (makers[t->mkrval].ifdfun)
dir->next = makers[t->mkrval].ifdfun(prop->value, md);
else
exifwarn("maker note not supported");
if (!dir->next)
break;
/* XXX Doesn't catch multiple IFDs. */
dir->next->par = prop;
return;
/* Lookup functions for maker note. */
case EXIF_T_EQUIPMAKE:
/* Sanity check the offset. */
if (prop->value + prop->count >
(u_int32_t)(dir->md.etiff - btiff)) {
exifwarn2("invalid field offset", prop->name);
break;
}
strncpy(buf, (const char *)(btiff + prop->value), sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
for (c = buf; *c; c++) *c = tolower(*c);
for (i = 0; makers[i].val != EXIF_MKR_UNKNOWN; i++)
if (!strncmp(buf, makers[i].name,
strlen(makers[i].name)))
break;
t->mkrval = (short)i;
/* Keep processing (ASCII value). */
break;
/*
* 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.
*/
case 0x001b: /* GPSProcessingMethod */
case 0x001c: /* GPSAreaInformation */
/*
* 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:
/* Check for a comment type and sane offset. */
if (prop->count < 8 || (prop->value + prop->count >
(u_int32_t)(dir->md.etiff - btiff)))
break;
/* Ignore the 'comments' WinXP creates when rotating. */
#ifdef WINXP_BUGS
for (i = 0; tags[i].tag < EXIF_T_UNKNOWN &&
tags[i].tag != EXIF_T_USERCOMMENT; i++);
if (tags[i].type && tags[i].type != prop->type)
break;
#endif
/* Lookup the comment type. */
for (i = 0; ucomment[i].descr; i++)
if (!memcmp(ucomment[i].descr, btiff + prop->value, 8))
break;
/* Handle an ASCII comment; strip any trailing whitespace. */
if (ucomment[i].val == TIFF_ASCII) {
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;
exifstralloc(&prop->str, d - c + 1);
strncpy(prop->str, c, d - c);
prop->lvl = prop->str[0] ? ED_IMG : ED_VRB;
return;
}
break;
case EXIF_T_FILESRC:
/*
* This 'undefined' field is one byte; runs afoul of XP
* not zeroing out stuff.
*/
#ifdef WINXP_BUGS
prop->str = finddescr(filesrcs, (u_int16_t)(v & 0xFFU));
#else
prop->str = finddescr(filesrcs, v);
#endif
return;
}
/*
* ASCII types.
*/
if (prop->type == TIFF_ASCII) {
/* Should fit in the value field. */
if (prop->count < 5) {
exifstralloc(&prop->str, 5);
byte4exif(prop->value, (unsigned char *)prop->str, o);
return;
}
/* Sanity check the offset. */
if ((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;
}
}
/*
* Rational types. (Note that we'll redo some in our later pass.)
* We'll reduce and simplify the fraction.
*
* XXX Misses multiple rationals.
*/
if ((prop->type == TIFF_RTNL || prop->type == TIFF_SRTNL) &&
(prop->value + prop->count * 8 <=
(u_int32_t)(dir->md.etiff - btiff))) {
exifstralloc(&prop->str, 32);
if (prop->type == TIFF_RTNL) {
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(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;
}
/*
* Multiple short values.
* XXX For now, we're going to ignore tags with count > 8. Maker
* note tags frequently consist of many shorts; we don't really
* want to be spitting these out. (Plus, TransferFunction is huge.)
*
* XXX Note that this doesn't apply to two shorts, which are
* stuffed into the value.
*/
if ((prop->type == TIFF_SHORT || prop->type == TIFF_SSHORT) &&
prop->count > 2 && (prop->value + prop->count * 2 <=
(u_int32_t)(dir->md.etiff - btiff))) {
if (prop->count > 8)
return;
len = 8 * prop->count + 1;
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(btiff + prop->value +
(i * 2), o));
else
snprintf(prop->str + strlen(prop->str),
len - strlen(prop->str) - 1, "%d, ",
exif2sbyte(btiff + prop->value +
(i * 2), o));
}
prop->str[strlen(prop->str) - 2] = '\0';
return;
}
return;
}
/*
* Delete dynamic Exif property memory.
*/
void
exiffree(struct exiftags *t)
{
struct exifprop *tmpprop;
if (!t) return;
while ((tmpprop = t->props)) {
if (t->props->str) free(t->props->str);
t->props = t->props->next;
free(tmpprop);
}
free(t);
}
/*
* Scan the Exif section.
*/
struct exiftags *
exifscan(unsigned char *b, int len, int domkr)
{
int seq;
u_int32_t ifdoff;
struct exiftags *t;
struct ifd *curifd, *tmpifd;
/* Create and initialize our file info structure. */
t = (struct exiftags *)malloc(sizeof(struct exiftags));
if (!t) {
exifwarn2("can't allocate file info",
(const char *)strerror(errno));
return (NULL);
}
memset(t, 0, sizeof(struct exiftags));
seq = 0;
t->md.etiff = b + len; /* End of TIFF. */
/*
* Make sure we've got the proper Exif header. If not, we're
* looking at somebody else's APP1 (e.g., Photoshop).
*/
if (memcmp(b, "Exif\0\0", 6)) {
exiffree(t);
return (NULL);
}
b += 6;
/* Determine endianness of the TIFF data. */
if (!memcmp(b, "MM", 2))
t->md.order = BIG;
else if (!memcmp(b, "II", 2))
t->md.order = LITTLE;
else {
exifwarn("invalid TIFF header");
exiffree(t);
return (NULL);
}
t->md.btiff = b; /* Beginning of TIFF. */
b += 2;
/* Verify the TIFF header. */
if (exif2byte(b, t->md.order) != 42) {
exifwarn("invalid TIFF header");
exiffree(t);
return (NULL);
}
b += 2;
/* Get the 0th IFD, where all of the good stuff should start. */
ifdoff = exif4byte(b, t->md.order);
curifd = readifds(ifdoff, tags, &t->md);
if (!curifd) {
exifwarn("invalid Exif format (couldn't read IFD0)");
exiffree(t);
return (NULL);
}
/* Now, let's parse the fields... */
while ((tmpifd = curifd)) {
readtags(curifd, seq++, t, domkr);
curifd = curifd->next;
free(tmpifd); /* No need to keep it around... */
}
return (t);
}
/*
* Read the Exif section and prepare the data for output.
*/
struct exiftags *
exifparse(unsigned char *b, int len)
{
struct exiftags *t;
struct exifprop *curprop;
/* Find the section and scan it. */
if (!(t = exifscan(b, len, TRUE)))
return (NULL);
/* Make field values pretty. */
curprop = t->props;
while (curprop) {
postprop(curprop, t);
tweaklvl(curprop, t);
curprop = curprop->next;
}
return (t);
}