-
Notifications
You must be signed in to change notification settings - Fork 29
/
makernote.c
198 lines (177 loc) · 7.28 KB
/
makernote.c
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);
}
}
}