1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
//--------------------------------------------------------------------------
// Parse some maker specific information.
// (Very limited right now - add maker specific stuff to this module)
//--------------------------------------------------------------------------
#include "jhead.h"
extern int MotorolaOrder;
//--------------------------------------------------------------------------
// Process exif format directory, as used by Cannon maker note
//--------------------------------------------------------------------------
static void ProcessCanonMakerNoteDir(unsigned char * DirStart, unsigned char * OffsetBase,
unsigned ExifLength)
{
int de;
int a;
int NumDirEntries;
NumDirEntries = Get16u(DirStart);
#define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
{
unsigned char * DirEnd;
DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
if (DirEnd > (OffsetBase+ExifLength)){
ErrNonfatal("Illegally sized Exif makernote subdir (%d entries)",NumDirEntries,0);
return;
}
if (DumpExifMap){
printf("Map: %05u-%05u: Directory (makernote)\n",(int)(DirStart-OffsetBase), (int)(DirEnd-OffsetBase));
}
}
if (ShowTags){
printf("(dir has %d entries)\n",NumDirEntries);
}
for (de=0;de<NumDirEntries;de++){
int Tag, Format, Components;
unsigned char * ValuePtr;
int ByteCount;
unsigned char * DirEntry;
DirEntry = DIR_ENTRY_ADDR(DirStart, de);
Tag = Get16u(DirEntry);
Format = Get16u(DirEntry+2);
Components = Get32u(DirEntry+4);
if (Components > 0x10000){
//Components count too large could cause overflow on subsequent check
ErrNonfatal("Bad components count %x", Components,0);
continue;
}
if ((Format-1) >= NUM_FORMATS) {
// (-1) catches illegal zero case as unsigned underflows to positive large.
ErrNonfatal("Illegal Exif number format %d for maker tag %04x", Format, Tag);
continue;
}
if ((unsigned)Components > 0x10000){
ErrNonfatal("Too many components (%d) for Exif maker tag %04x", Components, Tag);
continue;
}
ByteCount = Components * BytesPerFormat[Format];
if (ByteCount > 4){
unsigned OffsetVal;
OffsetVal = Get32u(DirEntry+8);
// If its bigger than 4 bytes, the dir entry contains an offset.
if (OffsetVal+ByteCount > (unsigned)ExifLength || OffsetVal > 65536){
// Bogus pointer offset and / or bytecount value
ErrNonfatal("Illegal value pointer for Exif maker tag %04x", Tag,0);
continue;
}
ValuePtr = OffsetBase+OffsetVal;
if (DumpExifMap){
printf("Map: %05d-%05d: Data for makernote tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
}
}else{
// 4 bytes or less and value is in the dir entry itself
ValuePtr = DirEntry+8;
}
if (ShowTags){
// Show tag name
printf(" Canon maker tag %04x Value = ", Tag);
}
// Show tag value.
switch(Format){
case FMT_UNDEFINED:
// Undefined is typically an ascii string.
case FMT_STRING:
// String arrays printed without function call (different from int arrays)
if (ShowTags){
printf("\"");
for (a=0;a<ByteCount;a++){
int ZeroSkipped = 0;
if (ValuePtr[a] >= 32){
if (ZeroSkipped){
printf("?");
ZeroSkipped = 0;
}
putchar(ValuePtr[a]);
}else{
if (ValuePtr[a] == 0){
ZeroSkipped = 1;
}
}
}
printf("\"\n");
}
break;
default:
if (ShowTags){
PrintFormatNumber(ValuePtr, Format, ByteCount);
printf("\n");
}
}
if (Tag == 1 && Components > 16){
int IsoCode;
if (ByteCount < 17 * sizeof(short)) continue; // Fuzztest -- not enough allocated.
IsoCode = Get16u(ValuePtr + 16*sizeof(unsigned short));
if (IsoCode >= 16 && IsoCode <= 24){
ImageInfo.ISOequivalent = 50 << (IsoCode-16);
}
}
if (Tag == 4 && Format == FMT_USHORT){
if (ByteCount < 20 * sizeof(short)) continue; // Fuzztest -- not enough allocated.
if (Components > 7){
int WhiteBalance = Get16u(ValuePtr + 7*sizeof(unsigned short));
switch(WhiteBalance){
// 0=Auto, 6=Custom
case 1: ImageInfo.LightSource = 1; break; // Sunny
case 2: ImageInfo.LightSource = 1; break; // Cloudy
case 3: ImageInfo.LightSource = 3; break; // Thungsten
case 4: ImageInfo.LightSource = 2; break; // Fourescent
case 5: ImageInfo.LightSource = 4; break; // Flash
}
}
if (Components > 19 && ImageInfo.Distance <= 0) {
// Indicates the distance the autofocus camera is focused to.
// Tends to be less accurate as distance increases.
int temp_dist = Get16u(ValuePtr + 19*sizeof(unsigned short));
if (temp_dist != 65535){
ImageInfo.Distance = (float)temp_dist/100;
}else{
ImageInfo.Distance = -1 /* infinity */;
}
}
}
}
}
//--------------------------------------------------------------------------
// Show generic maker note - just hex bytes.
//--------------------------------------------------------------------------
static void ShowMakerNoteGeneric(unsigned char * ValuePtr, int ByteCount)
{
int a;
for (a=0;a<ByteCount;a++){
if (a > 10){
printf("...");
break;
}
printf(" %02x",ValuePtr[a]);
}
printf(" (%d bytes)", ByteCount);
printf("\n");
}
//--------------------------------------------------------------------------
// Process maker note - to the limited extent that its supported.
//--------------------------------------------------------------------------
void ProcessMakerNote(unsigned char * ValuePtr, int ByteCount,
unsigned char * OffsetBase, unsigned ExifLength)
{
if (strstr(ImageInfo.CameraMake, "Canon")){
// So it turns out that some canons cameras use big endian, others use little
// endian in the main exif header. But the maker note is always little endian.
static int MotorolaOrderSave;
MotorolaOrderSave = MotorolaOrder;
MotorolaOrder = 0; // Temporarily switch to little endian.
ProcessCanonMakerNoteDir(ValuePtr, OffsetBase, ExifLength);
MotorolaOrder = MotorolaOrderSave;
}else{
if (ShowTags){
ShowMakerNoteGeneric(ValuePtr, ByteCount);
}
}
}
|