1 //--------------------------------------------------------------------------
2 // Program to pull the information out of various types of EXIF digital
3 // camera files and show it in a reasonably consistent way
4 //
5 // This module parses the very complicated exif structures.
6 //
7 // Matthias Wandel
8 //--------------------------------------------------------------------------
9 #include "jhead.h"
10 
11 #include <math.h>
12 #include <ctype.h>
13 #include <utils/Log.h>
14 
15 static unsigned char * DirWithThumbnailPtrs;
16 static double FocalplaneXRes;
17 static double FocalplaneUnits;
18 static int ExifImageWidth;
19 static int MotorolaOrder = 0;
20 
21 // for fixing the rotation.
22 static void * OrientationPtr[2];
23 static int    OrientationNumFormat[2];
24 int NumOrientations = 0;
25 
26 
27 // Define the line below to turn on poor man's debugging output
28 #undef SUPERDEBUG
29 
30 #ifdef SUPERDEBUG
31 #define printf ALOGE
32 #endif
33 
34 //--------------------------------------------------------------------------
35 // Table of Jpeg encoding process names
36 static const TagTable_t ProcessTable[] = {
37     { M_SOF0,   "Baseline", 0, 0},
38     { M_SOF1,   "Extended sequential", 0, 0},
39     { M_SOF2,   "Progressive", 0, 0},
40     { M_SOF3,   "Lossless", 0, 0},
41     { M_SOF5,   "Differential sequential", 0, 0},
42     { M_SOF6,   "Differential progressive", 0, 0},
43     { M_SOF7,   "Differential lossless", 0, 0},
44     { M_SOF9,   "Extended sequential, arithmetic coding", 0, 0},
45     { M_SOF10,  "Progressive, arithmetic coding", 0, 0},
46     { M_SOF11,  "Lossless, arithmetic coding", 0, 0},
47     { M_SOF13,  "Differential sequential, arithmetic coding", 0, 0},
48     { M_SOF14,  "Differential progressive, arithmetic coding", 0, 0},
49     { M_SOF15,  "Differential lossless, arithmetic coding", 0, 0},
50 };
51 
52 #define PROCESS_TABLE_SIZE  (sizeof(ProcessTable) / sizeof(TagTable_t))
53 
54 // 1 - "The 0th row is at the visual top of the image,    and the 0th column is the visual left-hand side."
55 // 2 - "The 0th row is at the visual top of the image,    and the 0th column is the visual right-hand side."
56 // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
57 // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
58 
59 // 5 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual top."
60 // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
61 // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
62 // 8 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual bottom."
63 
64 // Note: The descriptions here are the same as the name of the command line
65 // option to pass to jpegtran to right the image
66 
67 static const char * OrientTab[9] = {
68     "Undefined",
69     "Normal",           // 1
70     "flip horizontal",  // left right reversed mirror
71     "rotate 180",       // 3
72     "flip vertical",    // upside down mirror
73     "transpose",        // Flipped about top-left <--> bottom-right axis.
74     "rotate 90",        // rotate 90 cw to right it.
75     "transverse",       // flipped about top-right <--> bottom-left axis
76     "rotate 270",       // rotate 270 to right it.
77 };
78 
79 const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
80 
81 //--------------------------------------------------------------------------
82 // Describes tag values
83 
84 #define TAG_INTEROP_INDEX          0x0001
85 #define TAG_INTEROP_VERSION        0x0002
86 #define TAG_IMAGE_WIDTH            0x0100
87 #define TAG_IMAGE_LENGTH           0x0101
88 #define TAG_BITS_PER_SAMPLE        0x0102
89 #define TAG_COMPRESSION            0x0103
90 #define TAG_PHOTOMETRIC_INTERP     0x0106
91 #define TAG_FILL_ORDER             0x010A
92 #define TAG_DOCUMENT_NAME          0x010D
93 #define TAG_IMAGE_DESCRIPTION      0x010E
94 #define TAG_MAKE                   0x010F
95 #define TAG_MODEL                  0x0110
96 #define TAG_SRIP_OFFSET            0x0111
97 #define TAG_ORIENTATION            0x0112
98 #define TAG_SAMPLES_PER_PIXEL      0x0115
99 #define TAG_ROWS_PER_STRIP         0x0116
100 #define TAG_STRIP_BYTE_COUNTS      0x0117
101 #define TAG_X_RESOLUTION           0x011A
102 #define TAG_Y_RESOLUTION           0x011B
103 #define TAG_PLANAR_CONFIGURATION   0x011C
104 #define TAG_RESOLUTION_UNIT        0x0128
105 #define TAG_TRANSFER_FUNCTION      0x012D
106 #define TAG_SOFTWARE               0x0131
107 #define TAG_DATETIME               0x0132
108 #define TAG_ARTIST                 0x013B
109 #define TAG_WHITE_POINT            0x013E
110 #define TAG_PRIMARY_CHROMATICITIES 0x013F
111 #define TAG_TRANSFER_RANGE         0x0156
112 #define TAG_JPEG_PROC              0x0200
113 #define TAG_THUMBNAIL_OFFSET       0x0201
114 #define TAG_THUMBNAIL_LENGTH       0x0202
115 #define TAG_Y_CB_CR_COEFFICIENTS   0x0211
116 #define TAG_Y_CB_CR_SUB_SAMPLING   0x0212
117 #define TAG_Y_CB_CR_POSITIONING    0x0213
118 #define TAG_REFERENCE_BLACK_WHITE  0x0214
119 #define TAG_RELATED_IMAGE_WIDTH    0x1001
120 #define TAG_RELATED_IMAGE_LENGTH   0x1002
121 #define TAG_CFA_REPEAT_PATTERN_DIM 0x828D
122 #define TAG_CFA_PATTERN1           0x828E
123 #define TAG_BATTERY_LEVEL          0x828F
124 #define TAG_COPYRIGHT              0x8298
125 #define TAG_EXPOSURETIME           0x829A
126 #define TAG_FNUMBER                0x829D
127 #define TAG_IPTC_NAA               0x83BB
128 #define TAG_EXIF_OFFSET            0x8769
129 #define TAG_INTER_COLOR_PROFILE    0x8773
130 #define TAG_EXPOSURE_PROGRAM       0x8822
131 #define TAG_SPECTRAL_SENSITIVITY   0x8824
132 #define TAG_GPSINFO                0x8825
133 #define TAG_ISO_EQUIVALENT         0x8827
134 #define TAG_OECF                   0x8828
135 #define TAG_EXIF_VERSION           0x9000
136 #define TAG_DATETIME_ORIGINAL      0x9003
137 #define TAG_DATETIME_DIGITIZED     0x9004
138 #define TAG_COMPONENTS_CONFIG      0x9101
139 #define TAG_CPRS_BITS_PER_PIXEL    0x9102
140 #define TAG_SHUTTERSPEED           0x9201
141 #define TAG_APERTURE               0x9202
142 #define TAG_BRIGHTNESS_VALUE       0x9203
143 #define TAG_EXPOSURE_BIAS          0x9204
144 #define TAG_MAXAPERTURE            0x9205
145 #define TAG_SUBJECT_DISTANCE       0x9206
146 #define TAG_METERING_MODE          0x9207
147 #define TAG_LIGHT_SOURCE           0x9208
148 #define TAG_FLASH                  0x9209
149 #define TAG_FOCALLENGTH            0x920A
150 #define TAG_MAKER_NOTE             0x927C
151 #define TAG_USERCOMMENT            0x9286
152 #define TAG_SUBSEC_TIME            0x9290
153 #define TAG_SUBSEC_TIME_ORIG       0x9291
154 #define TAG_SUBSEC_TIME_DIG        0x9292
155 
156 #define TAG_WINXP_TITLE            0x9c9b // Windows XP - not part of exif standard.
157 #define TAG_WINXP_COMMENT          0x9c9c // Windows XP - not part of exif standard.
158 #define TAG_WINXP_AUTHOR           0x9c9d // Windows XP - not part of exif standard.
159 #define TAG_WINXP_KEYWORDS         0x9c9e // Windows XP - not part of exif standard.
160 #define TAG_WINXP_SUBJECT          0x9c9f // Windows XP - not part of exif standard.
161 
162 #define TAG_FLASH_PIX_VERSION      0xA000
163 #define TAG_COLOR_SPACE            0xA001
164 #define TAG_EXIF_IMAGEWIDTH        0xA002
165 #define TAG_EXIF_IMAGELENGTH       0xA003
166 #define TAG_RELATED_AUDIO_FILE     0xA004
167 #define TAG_INTEROP_OFFSET         0xA005
168 #define TAG_FLASH_ENERGY           0xA20B
169 #define TAG_SPATIAL_FREQ_RESP      0xA20C
170 #define TAG_FOCAL_PLANE_XRES       0xA20E
171 #define TAG_FOCAL_PLANE_YRES       0xA20F
172 #define TAG_FOCAL_PLANE_UNITS      0xA210
173 #define TAG_SUBJECT_LOCATION       0xA214
174 #define TAG_EXPOSURE_INDEX         0xA215
175 #define TAG_SENSING_METHOD         0xA217
176 #define TAG_FILE_SOURCE            0xA300
177 #define TAG_SCENE_TYPE             0xA301
178 #define TAG_CFA_PATTERN            0xA302
179 #define TAG_CUSTOM_RENDERED        0xA401
180 #define TAG_EXPOSURE_MODE          0xA402
181 #define TAG_WHITEBALANCE           0xA403
182 #define TAG_DIGITALZOOMRATIO       0xA404
183 #define TAG_FOCALLENGTH_35MM       0xA405
184 #define TAG_SCENE_CAPTURE_TYPE     0xA406
185 #define TAG_GAIN_CONTROL           0xA407
186 #define TAG_CONTRAST               0xA408
187 #define TAG_SATURATION             0xA409
188 #define TAG_SHARPNESS              0xA40A
189 #define TAG_DISTANCE_RANGE         0xA40C
190 
191 // TODO: replace the ", 0" values in this table with the correct format, e.g. ", FMT_USHORT"
192 static const TagTable_t TagTable[] = {
193   { TAG_INTEROP_INDEX,          "InteropIndex", 0, 0},
194   { TAG_INTEROP_VERSION,        "InteropVersion", 0, 0},
195   { TAG_IMAGE_WIDTH,            "ImageWidth", FMT_USHORT, 1},
196   { TAG_IMAGE_LENGTH,           "ImageLength", FMT_USHORT, 1},
197   { TAG_BITS_PER_SAMPLE,        "BitsPerSample", FMT_USHORT, 3},
198   { TAG_COMPRESSION,            "Compression", FMT_USHORT, 1},
199   { TAG_PHOTOMETRIC_INTERP,     "PhotometricInterpretation", FMT_USHORT, 1},
200   { TAG_FILL_ORDER,             "FillOrder", 0, 0},
201   { TAG_DOCUMENT_NAME,          "DocumentName", 0, 0},
202   { TAG_IMAGE_DESCRIPTION,      "ImageDescription", 0, 0 },
203   { TAG_MAKE,                   "Make", FMT_STRING, -1},
204   { TAG_MODEL,                  "Model", FMT_STRING, -1},
205   { TAG_SRIP_OFFSET,            "StripOffsets", FMT_USHORT, 1},
206   { TAG_ORIENTATION,            "Orientation", FMT_USHORT, 1},
207   { TAG_SAMPLES_PER_PIXEL,      "SamplesPerPixel", FMT_USHORT, 3},
208   { TAG_ROWS_PER_STRIP,         "RowsPerStrip", FMT_USHORT, 1},
209   { TAG_STRIP_BYTE_COUNTS,      "StripByteCounts", FMT_USHORT, 1},
210   { TAG_X_RESOLUTION,           "XResolution", FMT_URATIONAL, 1},
211   { TAG_Y_RESOLUTION,           "YResolution", FMT_URATIONAL, 1},
212   { TAG_PLANAR_CONFIGURATION,   "PlanarConfiguration", FMT_USHORT, 1},
213   { TAG_RESOLUTION_UNIT,        "ResolutionUnit", FMT_USHORT, 1},
214   { TAG_TRANSFER_FUNCTION,      "TransferFunction", FMT_USHORT, 768},
215   { TAG_SOFTWARE,               "Software", FMT_STRING, -1},
216   { TAG_DATETIME,               "DateTime", FMT_STRING, 20},
217   { TAG_ARTIST,                 "Artist", FMT_STRING, -1},
218   { TAG_WHITE_POINT,            "WhitePoint", FMT_SRATIONAL, 2},
219   { TAG_PRIMARY_CHROMATICITIES, "PrimaryChromaticities", FMT_SRATIONAL, 6},
220   { TAG_TRANSFER_RANGE,         "TransferRange", 0, 0},
221   { TAG_JPEG_PROC,              "JPEGProc", 0, 0},
222   { TAG_THUMBNAIL_OFFSET,       "ThumbnailOffset", 0, 0},
223   { TAG_THUMBNAIL_LENGTH,       "ThumbnailLength", 0, 0},
224   { TAG_Y_CB_CR_COEFFICIENTS,   "YCbCrCoefficients", FMT_SRATIONAL, 3},
225   { TAG_Y_CB_CR_SUB_SAMPLING,   "YCbCrSubSampling", FMT_USHORT, 2},
226   { TAG_Y_CB_CR_POSITIONING,    "YCbCrPositioning", FMT_USHORT, 1},
227   { TAG_REFERENCE_BLACK_WHITE,  "ReferenceBlackWhite", FMT_SRATIONAL, 6},
228   { TAG_RELATED_IMAGE_WIDTH,    "RelatedImageWidth", 0, 0},
229   { TAG_RELATED_IMAGE_LENGTH,   "RelatedImageLength", 0, 0},
230   { TAG_CFA_REPEAT_PATTERN_DIM, "CFARepeatPatternDim", 0, 0},
231   { TAG_CFA_PATTERN1,           "CFAPattern", 0, 0},
232   { TAG_BATTERY_LEVEL,          "BatteryLevel", 0, 0},
233   { TAG_COPYRIGHT,              "Copyright", FMT_STRING, -1},
234   { TAG_EXPOSURETIME,           "ExposureTime", FMT_SRATIONAL, 1},
235   { TAG_FNUMBER,                "FNumber", FMT_SRATIONAL, 1},
236   { TAG_IPTC_NAA,               "IPTC/NAA", 0, 0},
237   { TAG_EXIF_OFFSET,            "ExifOffset", 0, 0},
238   { TAG_INTER_COLOR_PROFILE,    "InterColorProfile", 0, 0},
239   { TAG_EXPOSURE_PROGRAM,       "ExposureProgram", FMT_SSHORT, 1},
240   { TAG_SPECTRAL_SENSITIVITY,   "SpectralSensitivity", FMT_STRING, -1},
241   { TAG_GPSINFO,                "GPS Dir offset", 0, 0},
242   { TAG_ISO_EQUIVALENT,         "ISOSpeedRatings", FMT_SSHORT, -1},
243   { TAG_OECF,                   "OECF", 0, 0},
244   { TAG_EXIF_VERSION,           "ExifVersion", FMT_BYTE, 4},
245   { TAG_DATETIME_ORIGINAL,      "DateTimeOriginal", FMT_STRING, 20},
246   { TAG_DATETIME_DIGITIZED,     "DateTimeDigitized", FMT_STRING, 20},
247   { TAG_COMPONENTS_CONFIG,      "ComponentsConfiguration", FMT_BYTE, 4},
248   { TAG_CPRS_BITS_PER_PIXEL,    "CompressedBitsPerPixel", FMT_SRATIONAL, 1},
249   { TAG_SHUTTERSPEED,           "ShutterSpeedValue", FMT_SRATIONAL, 1},
250   { TAG_APERTURE,               "ApertureValue", FMT_URATIONAL, 1},
251   { TAG_BRIGHTNESS_VALUE,       "BrightnessValue", FMT_SRATIONAL, 1},
252   { TAG_EXPOSURE_BIAS,          "ExposureBiasValue", FMT_SRATIONAL, 1},
253   { TAG_MAXAPERTURE,            "MaxApertureValue", FMT_URATIONAL, 1},
254   { TAG_SUBJECT_DISTANCE,       "SubjectDistance", FMT_URATIONAL, 1},
255   { TAG_METERING_MODE,          "MeteringMode", FMT_USHORT, 1},
256   { TAG_LIGHT_SOURCE,           "LightSource", FMT_USHORT, 1},
257   { TAG_FLASH,                  "Flash", FMT_USHORT, 1},
258   { TAG_FOCALLENGTH,            "FocalLength", FMT_URATIONAL, 1},
259   { TAG_MAKER_NOTE,             "MakerNote", FMT_STRING, -1},
260   { TAG_USERCOMMENT,            "UserComment", FMT_STRING, -1},
261   { TAG_SUBSEC_TIME,            "SubSecTime", FMT_STRING, -1},
262   { TAG_SUBSEC_TIME_ORIG,       "SubSecTimeOriginal", FMT_STRING, -1},
263   { TAG_SUBSEC_TIME_DIG,        "SubSecTimeDigitized", FMT_STRING, -1},
264   { TAG_WINXP_TITLE,            "Windows-XP Title", 0, 0},
265   { TAG_WINXP_COMMENT,          "Windows-XP comment", 0, 0},
266   { TAG_WINXP_AUTHOR,           "Windows-XP author", 0, 0},
267   { TAG_WINXP_KEYWORDS,         "Windows-XP keywords", 0, 0},
268   { TAG_WINXP_SUBJECT,          "Windows-XP subject", 0, 0},
269   { TAG_FLASH_PIX_VERSION,      "FlashPixVersion", FMT_BYTE, 4},
270   { TAG_COLOR_SPACE,            "ColorSpace", FMT_USHORT, 1},
271   { TAG_EXIF_IMAGEWIDTH,        "ExifImageWidth", 0, 0},
272   { TAG_EXIF_IMAGELENGTH,       "ExifImageLength", 0, 0},
273   { TAG_RELATED_AUDIO_FILE,     "RelatedAudioFile", 0, 0},
274   { TAG_INTEROP_OFFSET,         "InteroperabilityOffset", 0, 0},
275   { TAG_FLASH_ENERGY,           "FlashEnergy", FMT_URATIONAL, 1},
276   { TAG_SPATIAL_FREQ_RESP,      "SpatialFrequencyResponse", FMT_STRING, -1},
277   { TAG_FOCAL_PLANE_XRES,       "FocalPlaneXResolution", FMT_URATIONAL, 1},
278   { TAG_FOCAL_PLANE_YRES,       "FocalPlaneYResolution", FMT_URATIONAL, 1},
279   { TAG_FOCAL_PLANE_UNITS,      "FocalPlaneResolutionUnit", FMT_USHORT, 1},
280   { TAG_SUBJECT_LOCATION,       "SubjectLocation", FMT_USHORT, 2},
281   { TAG_EXPOSURE_INDEX,         "ExposureIndex", FMT_URATIONAL, 1},
282   { TAG_SENSING_METHOD,         "SensingMethod", FMT_USHORT, 1},
283   { TAG_FILE_SOURCE,            "FileSource", 0, 1},
284   { TAG_SCENE_TYPE,             "SceneType", 0, 1},
285   { TAG_CFA_PATTERN,            "CFA Pattern", 0, -1},
286   { TAG_CUSTOM_RENDERED,        "CustomRendered", FMT_USHORT, 1},
287   { TAG_EXPOSURE_MODE,          "ExposureMode", FMT_USHORT, 1},
288   { TAG_WHITEBALANCE,           "WhiteBalance", FMT_USHORT, 1},
289   { TAG_DIGITALZOOMRATIO,       "DigitalZoomRatio", FMT_URATIONAL, 1},
290   { TAG_FOCALLENGTH_35MM,       "FocalLengthIn35mmFilm", FMT_USHORT, 1},
291   { TAG_SCENE_CAPTURE_TYPE,     "SceneCaptureType", FMT_USHORT, 1},
292   { TAG_GAIN_CONTROL,           "GainControl", FMT_URATIONAL, 1},
293   { TAG_CONTRAST,               "Contrast", FMT_USHORT, 1},
294   { TAG_SATURATION,             "Saturation", FMT_USHORT, 1},
295   { TAG_SHARPNESS,              "Sharpness", FMT_USHORT, 1},
296   { TAG_DISTANCE_RANGE,         "SubjectDistanceRange", FMT_USHORT, 1},
297 } ;
298 
299 #define TAG_TABLE_SIZE  (sizeof(TagTable) / sizeof(TagTable_t))
300 
TagNameToValue(const char * tagName)301 int TagNameToValue(const char* tagName)
302 {
303     unsigned int i;
304     for (i = 0; i < TAG_TABLE_SIZE; i++) {
305         if (strcmp(TagTable[i].Desc, tagName) == 0) {
306             printf("found tag %s val %d", TagTable[i].Desc, TagTable[i].Tag);
307             return TagTable[i].Tag;
308         }
309     }
310     printf("tag %s NOT FOUND", tagName);
311     return -1;
312 }
313 
IsDateTimeTag(unsigned short tag)314 int IsDateTimeTag(unsigned short tag)
315 {
316     return ((tag == TAG_DATETIME)? TRUE: FALSE);
317 }
318 
319 //--------------------------------------------------------------------------
320 // Convert a 16 bit unsigned value to file's native byte order
321 //--------------------------------------------------------------------------
Put16u(void * Short,unsigned short PutValue)322 static void Put16u(void * Short, unsigned short PutValue)
323 {
324     if (MotorolaOrder){
325         ((uchar *)Short)[0] = (uchar)(PutValue>>8);
326         ((uchar *)Short)[1] = (uchar)PutValue;
327     }else{
328         ((uchar *)Short)[0] = (uchar)PutValue;
329         ((uchar *)Short)[1] = (uchar)(PutValue>>8);
330     }
331 }
332 
333 //--------------------------------------------------------------------------
334 // Convert a 16 bit unsigned value from file's native byte order
335 //--------------------------------------------------------------------------
Get16u(void * Short)336 int Get16u(void * Short)
337 {
338     if (MotorolaOrder){
339         return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
340     }else{
341         return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
342     }
343 }
344 
345 //--------------------------------------------------------------------------
346 // Convert a 32 bit signed value from file's native byte order
347 //--------------------------------------------------------------------------
Get32s(void * Long)348 int Get32s(void * Long)
349 {
350     if (MotorolaOrder){
351         return  ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
352               | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
353     }else{
354         return  ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
355               | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
356     }
357 }
358 
359 //--------------------------------------------------------------------------
360 // Convert a 32 bit unsigned value to file's native byte order
361 //--------------------------------------------------------------------------
Put32u(void * Value,unsigned PutValue)362 void Put32u(void * Value, unsigned PutValue)
363 {
364     if (MotorolaOrder){
365         ((uchar *)Value)[0] = (uchar)(PutValue>>24);
366         ((uchar *)Value)[1] = (uchar)(PutValue>>16);
367         ((uchar *)Value)[2] = (uchar)(PutValue>>8);
368         ((uchar *)Value)[3] = (uchar)PutValue;
369     }else{
370         ((uchar *)Value)[0] = (uchar)PutValue;
371         ((uchar *)Value)[1] = (uchar)(PutValue>>8);
372         ((uchar *)Value)[2] = (uchar)(PutValue>>16);
373         ((uchar *)Value)[3] = (uchar)(PutValue>>24);
374     }
375 }
376 
377 //--------------------------------------------------------------------------
378 // Convert a 32 bit unsigned value from file's native byte order
379 //--------------------------------------------------------------------------
Get32u(void * Long)380 unsigned Get32u(void * Long)
381 {
382     return (unsigned)Get32s(Long) & 0xffffffff;
383 }
384 
385 //--------------------------------------------------------------------------
386 // Display a number as one of its many formats
387 //--------------------------------------------------------------------------
PrintFormatNumber(void * ValuePtr,int Format,int ByteCount)388 void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount)
389 {
390     int s,n;
391 
392     for(n=0;n<16;n++){
393         switch(Format){
394             case FMT_SBYTE:
395             case FMT_BYTE:      printf("%02x",*(uchar *)ValuePtr); s=1;  break;
396             case FMT_USHORT:    printf("%d",Get16u(ValuePtr)); s=2;      break;
397             case FMT_ULONG:
398             case FMT_SLONG:     printf("%d",Get32s(ValuePtr)); s=4;      break;
399             case FMT_SSHORT:    printf("%hd",(signed short)Get16u(ValuePtr)); s=2; break;
400             case FMT_URATIONAL:
401             case FMT_SRATIONAL:
402                printf("%d/%d",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr));
403                s = 8;
404                break;
405 
406             case FMT_SINGLE:    printf("%f",(double)*(float *)ValuePtr); s=8; break;
407             case FMT_DOUBLE:    printf("%f",*(double *)ValuePtr);        s=8; break;
408             default:
409                 printf("Unknown format %d:", Format);
410                 return;
411         }
412         ByteCount -= s;
413         if (ByteCount <= 0) break;
414         printf(", ");
415         ValuePtr = (void *)((char *)ValuePtr + s);
416 
417     }
418     if (n >= 16) printf("...");
419 }
420 
421 
422 //--------------------------------------------------------------------------
423 // Evaluate number, be it int, rational, or float from directory.
424 //--------------------------------------------------------------------------
ConvertAnyFormat(void * ValuePtr,int Format)425 double ConvertAnyFormat(void * ValuePtr, int Format)
426 {
427     double Value;
428     Value = 0;
429 
430     switch(Format){
431         case FMT_SBYTE:     Value = *(signed char *)ValuePtr;  break;
432         case FMT_BYTE:      Value = *(uchar *)ValuePtr;        break;
433 
434         case FMT_USHORT:    Value = Get16u(ValuePtr);          break;
435         case FMT_ULONG:     Value = Get32u(ValuePtr);          break;
436 
437         case FMT_URATIONAL:
438         case FMT_SRATIONAL:
439             {
440                 int Num,Den;
441                 Num = Get32s(ValuePtr);
442                 Den = Get32s(4+(char *)ValuePtr);
443                 if (Den == 0){
444                     Value = 0;
445                 }else{
446                     Value = (double)Num/Den;
447                 }
448                 break;
449             }
450 
451         case FMT_SSHORT:    Value = (signed short)Get16u(ValuePtr);  break;
452         case FMT_SLONG:     Value = Get32s(ValuePtr);                break;
453 
454         // Not sure if this is correct (never seen float used in Exif format)
455         case FMT_SINGLE:    Value = (double)*(float *)ValuePtr;      break;
456         case FMT_DOUBLE:    Value = *(double *)ValuePtr;             break;
457 
458         default:
459             ErrNonfatal("Illegal format code %d",Format,0);
460     }
461     return Value;
462 }
463 
464 //--------------------------------------------------------------------------
465 // Convert a double value into a signed or unsigned rational number.
466 //--------------------------------------------------------------------------
float2urat(double value,unsigned int max,unsigned int * numerator,unsigned int * denominator)467 static void float2urat(double value, unsigned int max, unsigned int *numerator,
468                        unsigned int *denominator) {
469     if (value <= 0) {
470         *numerator = 0;
471         *denominator = 1;
472         return;
473     }
474 
475     if (value > max) {
476         *numerator = max;
477         *denominator = 1;
478         return;
479     }
480 
481     // For values less than 1e-9, scale as much as possible
482     if (value < 1e-9) {
483         unsigned int n = (unsigned int)(value * max);
484         if (n == 0) {
485             *numerator = 0;
486             *denominator = 1;
487         } else {
488             *numerator = n;
489             *denominator = max;
490         }
491         return;
492     }
493 
494     // Try to use a denominator of 1e9, 1e8, ..., until the numerator fits
495     unsigned int d;
496     for (d = 1000000000; d >= 1; d /= 10) {
497         double s = value * d;
498         if (s <= max) {
499             // Remove the trailing zeros from both.
500             unsigned int n = (unsigned int)s;
501             while (n % 10 == 0 && d >= 10) {
502                 n /= 10;
503                 d /= 10;
504             }
505             *numerator = n;
506             *denominator = d;
507             return;
508         }
509     }
510 
511     // Shouldn't reach here because the denominator 1 should work
512     // above. But just in case.
513     *numerator = 0;
514     *denominator = 1;
515 }
516 
ConvertDoubleToURational(double value,unsigned int * numerator,unsigned int * denominator)517 static void ConvertDoubleToURational(double value, unsigned int *numerator,
518                                      unsigned int *denominator) {
519     float2urat(value, 0xFFFFFFFFU, numerator, denominator);
520 }
521 
ConvertDoubleToSRational(double value,int * numerator,int * denominator)522 static void ConvertDoubleToSRational(double value, int *numerator,
523                                      int *denominator) {
524     int negative = 0;
525 
526     if (value < 0) {
527         value = -value;
528         negative = 1;
529     }
530 
531     unsigned int n, d;
532     float2urat(value, 0x7FFFFFFFU, &n, &d);
533     *numerator = (int)n;
534     *denominator = (int)d;
535     if (negative) {
536         *numerator = -*numerator;
537     }
538 }
539 
540 //--------------------------------------------------------------------------
541 // Process one of the nested EXIF directories.
542 //--------------------------------------------------------------------------
ProcessExifDir(unsigned char * DirStart,unsigned char * OffsetBase,unsigned ExifLength,int NestingLevel)543 static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase,
544         unsigned ExifLength, int NestingLevel)
545 {
546     int de;
547     int a;
548     int NumDirEntries;
549     unsigned ThumbnailOffset = 0;
550     unsigned ThumbnailSize = 0;
551     char IndentString[25];
552 
553     printf("ProcessExifDir");
554     if (NestingLevel > 4){
555         ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
556         return;
557     }
558 
559     memset(IndentString, ' ', 25);
560     IndentString[NestingLevel * 4] = '\0';
561 
562 
563     NumDirEntries = Get16u(DirStart);
564     #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
565 
566     {
567         unsigned char * DirEnd;
568         DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
569         if (DirEnd+4 > (OffsetBase+ExifLength)){
570             if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
571                 // Version 1.3 of jhead would truncate a bit too much.
572                 // This also caught later on as well.
573             }else{
574                 ErrNonfatal("Illegally sized exif subdirectory (%d entries)",NumDirEntries,0);
575                 return;
576             }
577         }
578         if (DumpExifMap){
579             printf("Map: %05d-%05d: Directory\n",(int)(DirStart-OffsetBase), (int)(DirEnd+4-OffsetBase));
580         }
581 
582 
583     }
584 
585     if (ShowTags){
586         printf("(dir has %d entries)\n",NumDirEntries);
587     }
588 
589     for (de=0;de<NumDirEntries;de++){
590         int Tag, Format, Components;
591         unsigned char * ValuePtr;
592         int ByteCount;
593         unsigned char * DirEntry;
594         DirEntry = DIR_ENTRY_ADDR(DirStart, de);
595 
596         Tag = Get16u(DirEntry);
597         Format = Get16u(DirEntry+2);
598         Components = Get32u(DirEntry+4);
599 
600         if ((Format-1) >= NUM_FORMATS) {
601             // (-1) catches illegal zero case as unsigned underflows to positive large.
602             ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
603             continue;
604         }
605 
606         if ((unsigned)Components > 0x10000){
607             ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
608             continue;
609         }
610 
611         ByteCount = Components * BytesPerFormat[Format];
612 
613         if (ByteCount > 4){
614             unsigned OffsetVal;
615             OffsetVal = Get32u(DirEntry+8);
616             // If its bigger than 4 bytes, the dir entry contains an offset.
617             if (OffsetVal > UINT32_MAX - ByteCount || OffsetVal+ByteCount > ExifLength){
618                 // Bogus pointer offset and / or bytecount value
619                 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
620                 continue;
621             }
622             ValuePtr = OffsetBase+OffsetVal;
623 
624             if (OffsetVal > ImageInfo.LargestExifOffset){
625                 ImageInfo.LargestExifOffset = OffsetVal;
626             }
627 
628             if (DumpExifMap){
629                 printf("Map: %05d-%05d:   Data for tag %04x\n",OffsetVal, OffsetVal+ByteCount, Tag);
630             }
631         }else{
632             // 4 bytes or less and value is in the dir entry itself
633             ValuePtr = DirEntry+8;
634         }
635 
636         if (Tag == TAG_MAKER_NOTE){
637             if (ShowTags){
638                 printf("%s    Maker note: ",IndentString);
639             }
640             ProcessMakerNote(ValuePtr, ByteCount, OffsetBase, ExifLength);
641             continue;
642         }
643 
644         if (ShowTags){
645             // Show tag name
646             for (a=0;;a++){
647                 if (a >= (int)TAG_TABLE_SIZE){
648                     printf("%s", IndentString);
649                     printf("    Unknown Tag %04x Value = ", Tag);
650                     break;
651                 }
652                 if (TagTable[a].Tag == Tag){
653                     printf("%s", IndentString);
654                     printf("    %s = ",TagTable[a].Desc);
655                     break;
656                 }
657             }
658 
659             // Show tag value.
660             switch(Format){
661                 case FMT_BYTE:
662                     if(ByteCount>1){
663                         printf("%.*ls\n", ByteCount/2, (wchar_t *)ValuePtr);
664                     }else{
665                         PrintFormatNumber(ValuePtr, Format, ByteCount);
666                         printf("\n");
667                     }
668                     break;
669 
670                 case FMT_UNDEFINED:
671                     // Undefined is typically an ascii string.
672 
673                 case FMT_STRING:
674                     // String arrays printed without function call (different from int arrays)
675                     {
676                           printf("\"%s\"", ValuePtr);
677 //                        int NoPrint = 0;
678 //                        printf("\"");
679 //                        for (a=0;a<ByteCount;a++){
680 //                            if (ValuePtr[a] >= 32){
681 //                                putchar(ValuePtr[a]);
682 //                                NoPrint = 0;
683 //                            }else{
684 //                                // Avoiding indicating too many unprintable characters of proprietary
685 //                                // bits of binary information this program may not know how to parse.
686 //                                if (!NoPrint && a != ByteCount-1){
687 //                                    putchar('?');
688 //                                    NoPrint = 1;
689 //                                }
690 //                            }
691 //                        }
692 //                        printf("\"\n");
693                     }
694                     break;
695 
696                 default:
697                     // Handle arrays of numbers later (will there ever be?)
698                     PrintFormatNumber(ValuePtr, Format, ByteCount);
699                     printf("\n");
700             }
701         }
702 
703         // Extract useful components of tag
704         switch(Tag){
705 
706             case TAG_MAKE:
707                 strncpy(ImageInfo.CameraMake, (char *)ValuePtr, ByteCount < 31 ? ByteCount : 31);
708                 break;
709 
710             case TAG_MODEL:
711                 strncpy(ImageInfo.CameraModel, (char *)ValuePtr, ByteCount < 39 ? ByteCount : 39);
712                 break;
713 
714             case TAG_SUBSEC_TIME:
715                 strlcpy(ImageInfo.SubSecTime, (char *)ValuePtr, sizeof(ImageInfo.SubSecTime));
716                 break;
717 
718             case TAG_SUBSEC_TIME_ORIG:
719                 strlcpy(ImageInfo.SubSecTimeOrig, (char *)ValuePtr,
720                         sizeof(ImageInfo.SubSecTimeOrig));
721                 break;
722 
723             case TAG_SUBSEC_TIME_DIG:
724                 strlcpy(ImageInfo.SubSecTimeDig, (char *)ValuePtr,
725                         sizeof(ImageInfo.SubSecTimeDig));
726                 break;
727 
728             case TAG_DATETIME_DIGITIZED:
729                 strlcpy(ImageInfo.DigitizedTime, (char *)ValuePtr,
730                         sizeof(ImageInfo.DigitizedTime));
731 
732                 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
733                     ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
734                     break;
735                 }
736                 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
737                     (char *)ValuePtr - (char *)OffsetBase;
738                 break;
739 
740             case TAG_DATETIME_ORIGINAL:
741                 // If we get a DATETIME_ORIGINAL, we use that one.
742                 strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
743                 // Fallthru...
744 
745             case TAG_DATETIME:
746                 if (!isdigit(ImageInfo.DateTime[0])){
747                     // If we don't already have a DATETIME_ORIGINAL, use whatever
748                     // time fields we may have.
749                     strncpy(ImageInfo.DateTime, (char *)ValuePtr, 19);
750                 }
751 
752                 if (ImageInfo.numDateTimeTags >= MAX_DATE_COPIES){
753                     ErrNonfatal("More than %d date fields!  This is nuts", MAX_DATE_COPIES, 0);
754                     break;
755                 }
756                 ImageInfo.DateTimeOffsets[ImageInfo.numDateTimeTags++] =
757                     (char *)ValuePtr - (char *)OffsetBase;
758                 break;
759 
760             case TAG_WINXP_COMMENT:
761                 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
762                     // Already have a comment (probably windows comment), skip this one.
763                     if (ShowTags) printf("Windows XP commend and other comment in header\n");
764                     break; // Already have a windows comment, skip this one.
765                 }
766 
767                 if (ByteCount > 1){
768                     if (ByteCount > MAX_COMMENT_SIZE) ByteCount = MAX_COMMENT_SIZE;
769                     memcpy(ImageInfo.Comments, ValuePtr, ByteCount);
770                     ImageInfo.CommentWidchars = ByteCount/2;
771                 }
772                 break;
773 
774             case TAG_USERCOMMENT:
775                 if (ImageInfo.Comments[0]){ // We already have a jpeg comment.
776                     // Already have a comment (probably windows comment), skip this one.
777                     if (ShowTags) printf("Multiple comments in exif header\n");
778                     break; // Already have a windows comment, skip this one.
779                 }
780 
781                 // Comment is often padded with trailing spaces.  Remove these first.
782                 for (a=ByteCount;;){
783                     a--;
784                     if ((ValuePtr)[a] == ' '){
785                         (ValuePtr)[a] = '\0';
786                     }else{
787                         break;
788                     }
789                     if (a == 0) break;
790                 }
791 
792                 // Copy the comment
793                 {
794                     // We want to set copied comment length (msize) to be the
795                     // minimum of:
796                     // (1) The space still available in Exif
797                     // (2) The given comment length (ByteCount)
798                     // (3) MAX_COMMENT_SIZE - 1
799                     int msiz = ExifLength - (ValuePtr-OffsetBase);
800                     if (msiz > ByteCount) msiz = ByteCount;
801                     if (msiz > MAX_COMMENT_SIZE - 1) msiz = MAX_COMMENT_SIZE - 1;
802                     if (msiz > 5 && memcmp(ValuePtr, "ASCII", 5) == 0) {
803                         for (a = 5; a < 10 && a < msiz; a++) {
804                             int c = (ValuePtr)[a];
805                             if (c != '\0' && c != ' ') {
806                                 strncpy(ImageInfo.Comments,
807                                         (char *)ValuePtr + a, msiz - a);
808                                 break;
809                             }
810                         }
811                     } else {
812                         strncpy(ImageInfo.Comments, (char *)ValuePtr, msiz);
813                     }
814                 }
815                 break;
816 
817             case TAG_FNUMBER:
818                 // Simplest way of expressing aperture, so I trust it the most.
819                 // (overwrite previously computd value if there is one)
820                 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
821                 break;
822 
823             case TAG_APERTURE:
824             case TAG_MAXAPERTURE:
825                 // More relevant info always comes earlier, so only use this field if we don't
826                 // have appropriate aperture information yet.
827                 if (ImageInfo.ApertureFNumber == 0){
828                     ImageInfo.ApertureFNumber
829                         = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
830                 }
831                 break;
832 
833             case TAG_FOCALLENGTH:
834                 // Nice digital cameras actually save the focal length as a function
835                 // of how farthey are zoomed in.
836                 ImageInfo.FocalLength.num = Get32u(ValuePtr);
837                 ImageInfo.FocalLength.denom = Get32u(4+(char *)ValuePtr);
838                 break;
839 
840             case TAG_SUBJECT_DISTANCE:
841                 // Inidcates the distacne the autofocus camera is focused to.
842                 // Tends to be less accurate as distance increases.
843                 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
844                 break;
845 
846             case TAG_EXPOSURETIME:
847                 // Simplest way of expressing exposure time, so I trust it most.
848                 // (overwrite previously computd value if there is one)
849                 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
850                 break;
851 
852             case TAG_SHUTTERSPEED:
853                 // More complicated way of expressing exposure time, so only use
854                 // this value if we don't already have it from somewhere else.
855                 if (ImageInfo.ExposureTime == 0){
856                     ImageInfo.ExposureTime
857                         = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
858                 }
859                 break;
860 
861 
862             case TAG_FLASH:
863                 ImageInfo.FlashUsed=(int)ConvertAnyFormat(ValuePtr, Format);
864                 break;
865 
866             case TAG_ORIENTATION:
867                 if (NumOrientations >= 2){
868                     // Can have another orientation tag for the thumbnail, but if there's
869                     // a third one, things are stringae.
870                     ErrNonfatal("More than two orientation tags!",0,0);
871                     break;
872                 }
873                 OrientationPtr[NumOrientations] = ValuePtr;
874                 OrientationNumFormat[NumOrientations] = Format;
875                 if (NumOrientations == 0){
876                     ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
877                 }
878                 if (ImageInfo.Orientation < 0 || ImageInfo.Orientation > 8){
879                     ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
880                     ImageInfo.Orientation = 0;
881                 }
882                 NumOrientations += 1;
883                 break;
884 
885             case TAG_EXIF_IMAGELENGTH:
886             case TAG_EXIF_IMAGEWIDTH:
887                 // Use largest of height and width to deal with images that have been
888                 // rotated to portrait format.
889                 a = (int)ConvertAnyFormat(ValuePtr, Format);
890                 if (ExifImageWidth < a) ExifImageWidth = a;
891                 break;
892 
893             case TAG_FOCAL_PLANE_XRES:
894                 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
895                 break;
896 
897             case TAG_FOCAL_PLANE_UNITS:
898                 switch((int)ConvertAnyFormat(ValuePtr, Format)){
899                     case 1: FocalplaneUnits = 25.4; break; // inch
900                     case 2:
901                         // According to the information I was using, 2 means meters.
902                         // But looking at the Cannon powershot's files, inches is the only
903                         // sensible value.
904                         FocalplaneUnits = 25.4;
905                         break;
906 
907                     case 3: FocalplaneUnits = 10;   break;  // centimeter
908                     case 4: FocalplaneUnits = 1;    break;  // millimeter
909                     case 5: FocalplaneUnits = .001; break;  // micrometer
910                 }
911                 break;
912 
913             case TAG_EXPOSURE_BIAS:
914                 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
915                 break;
916 
917             case TAG_WHITEBALANCE:
918                 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
919                 break;
920 
921             case TAG_LIGHT_SOURCE:
922                 ImageInfo.LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
923                 break;
924 
925             case TAG_METERING_MODE:
926                 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
927                 break;
928 
929             case TAG_EXPOSURE_PROGRAM:
930                 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
931                 break;
932 
933             case TAG_EXPOSURE_INDEX:
934                 if (ImageInfo.ISOequivalent == 0){
935                     // Exposure index and ISO equivalent are often used interchangeably,
936                     // so we will do the same in jhead.
937                     // http://photography.about.com/library/glossary/bldef_ei.htm
938                     ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
939                 }
940                 break;
941 
942             case TAG_EXPOSURE_MODE:
943                 ImageInfo.ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
944                 break;
945 
946             case TAG_ISO_EQUIVALENT:
947                 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
948                 break;
949 
950             case TAG_DIGITALZOOMRATIO:
951                 ImageInfo.DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
952                 break;
953 
954             case TAG_THUMBNAIL_OFFSET:
955                 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
956                 DirWithThumbnailPtrs = DirStart;
957                 break;
958 
959             case TAG_THUMBNAIL_LENGTH:
960                 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
961                 ImageInfo.ThumbnailSizeOffset = ValuePtr-OffsetBase;
962                 break;
963 
964             case TAG_EXIF_OFFSET:
965                 if (ShowTags) printf("%s    Exif Dir:",IndentString);
966 
967             case TAG_INTEROP_OFFSET:
968                 if (Tag == TAG_INTEROP_OFFSET && ShowTags) printf("%s    Interop Dir:",IndentString);
969                 {
970                     unsigned char * SubdirStart;
971                     SubdirStart = OffsetBase + Get32u(ValuePtr);
972                     if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
973                         ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
974                     }else{
975                         ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
976                     }
977                     continue;
978                 }
979                 break;
980 
981             case TAG_GPSINFO:
982                 if (ShowTags) printf("%s    GPS info dir:",IndentString);
983                 {
984                     unsigned char * SubdirStart;
985                     SubdirStart = OffsetBase + Get32u(ValuePtr);
986                     if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
987                         ErrNonfatal("Illegal GPS directory link",0,0);
988                     }else{
989                         ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
990                     }
991                     continue;
992                 }
993                 break;
994 
995             case TAG_FOCALLENGTH_35MM:
996                 // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002)
997                 // if its present, use it to compute equivalent focal length instead of
998                 // computing it from sensor geometry and actual focal length.
999                 ImageInfo.FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
1000                 break;
1001 
1002             case TAG_DISTANCE_RANGE:
1003                 // Three possible standard values:
1004                 //   1 = macro, 2 = close, 3 = distant
1005                 ImageInfo.DistanceRange = (int)ConvertAnyFormat(ValuePtr, Format);
1006                 break;
1007         }
1008     }
1009 
1010 
1011     {
1012         // In addition to linking to subdirectories via exif tags,
1013         // there's also a potential link to another directory at the end of each
1014         // directory.  this has got to be the result of a committee!
1015         unsigned char * SubdirStart;
1016         unsigned Offset;
1017 
1018         if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
1019             printf("DirStart %p offset from dirstart %d", DirStart, 2+12*NumDirEntries);
1020             Offset = Get32u(DirStart+2+12*NumDirEntries);
1021             if (Offset){
1022                 SubdirStart = OffsetBase + Offset;
1023                 if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase){
1024                     printf("SubdirStart %p OffsetBase %p ExifLength %d Offset %d",
1025                         SubdirStart, OffsetBase, ExifLength, Offset);
1026                     if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20){
1027                         // Jhead 1.3 or earlier would crop the whole directory!
1028                         // As Jhead produces this form of format incorrectness,
1029                         // I'll just let it pass silently
1030                         if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
1031                     }else{
1032                         ErrNonfatal("Illegal subdirectory link",0,0);
1033                     }
1034                 }else{
1035                     if (SubdirStart <= OffsetBase+ExifLength){
1036                         if (ShowTags) printf("%s    Continued directory ",IndentString);
1037                         ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
1038                     }
1039                 }
1040                 if (Offset > ImageInfo.LargestExifOffset){
1041                     ImageInfo.LargestExifOffset = Offset;
1042                 }
1043             }
1044         }else{
1045             // The exif header ends before the last next directory pointer.
1046         }
1047     }
1048 
1049     if (ThumbnailOffset){
1050         ImageInfo.ThumbnailAtEnd = FALSE;
1051 
1052         if (DumpExifMap){
1053             printf("Map: %05d-%05d: Thumbnail\n",ThumbnailOffset, ThumbnailOffset+ThumbnailSize);
1054         }
1055 
1056         if (ThumbnailOffset <= ExifLength){
1057             if (ThumbnailSize > ExifLength-ThumbnailOffset){
1058                 // If thumbnail extends past exif header, only save the part that
1059                 // actually exists.  Canon's EOS viewer utility will do this - the
1060                 // thumbnail extracts ok with this hack.
1061                 ThumbnailSize = ExifLength-ThumbnailOffset;
1062                 if (ShowTags) printf("Thumbnail incorrectly placed in header\n");
1063 
1064             }
1065             // The thumbnail pointer appears to be valid.  Store it.
1066             ImageInfo.ThumbnailOffset = ThumbnailOffset;
1067             ImageInfo.ThumbnailSize = ThumbnailSize;
1068 
1069             if (ShowTags){
1070                 printf("Thumbnail size: %d bytes\n",ThumbnailSize);
1071             }
1072         }
1073     }
1074     printf("returning from ProcessExifDir");
1075 }
1076 
1077 
1078 //--------------------------------------------------------------------------
1079 // Process a EXIF marker
1080 // Describes all the drivel that most digital cameras include...
1081 //--------------------------------------------------------------------------
process_EXIF(unsigned char * ExifSection,unsigned int length)1082 void process_EXIF (unsigned char * ExifSection, unsigned int length)
1083 {
1084     unsigned FirstOffset;
1085 
1086     FocalplaneXRes = 0;
1087     FocalplaneUnits = 0;
1088     ExifImageWidth = 0;
1089     NumOrientations = 0;
1090 
1091     if (ShowTags){
1092         printf("Exif header %d bytes long\n",length);
1093     }
1094 
1095     {   // Check the EXIF header component
1096         static uchar ExifHeader[] = "Exif\0\0";
1097         if (memcmp(ExifSection+2, ExifHeader,6)){
1098             ErrNonfatal("Incorrect Exif header",0,0);
1099             return;
1100         }
1101     }
1102 
1103     if (memcmp(ExifSection+8,"II",2) == 0){
1104         if (ShowTags) printf("Exif section in Intel order\n");
1105         MotorolaOrder = 0;
1106     }else{
1107         if (memcmp(ExifSection+8,"MM",2) == 0){
1108             if (ShowTags) printf("Exif section in Motorola order\n");
1109             MotorolaOrder = 1;
1110         }else{
1111             ErrNonfatal("Invalid Exif alignment marker.",0,0);
1112             return;
1113         }
1114     }
1115 
1116     // Check the next value for correctness.
1117     if (Get16u(ExifSection+10) != 0x2a){
1118         ErrNonfatal("Invalid Exif start (1)",0,0);
1119         return;
1120     }
1121 
1122     FirstOffset = Get32u(ExifSection+12);
1123     if (FirstOffset < 8 || FirstOffset+8 >= length) {
1124         ErrNonfatal("Invalid offset of first IFD value: %u", FirstOffset, 0);
1125         return;
1126     }
1127 
1128     DirWithThumbnailPtrs = NULL;
1129 
1130 
1131     // First directory starts 16 bytes in.  All offset are relative to 8 bytes in.
1132     ProcessExifDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0);
1133 
1134     ImageInfo.ThumbnailAtEnd = ImageInfo.ThumbnailOffset >= ImageInfo.LargestExifOffset ? TRUE : FALSE;
1135 #ifdef SUPERDEBUG
1136     printf("Thumbnail %s end", (ImageInfo.ThumbnailAtEnd ? "at" : "NOT at"));
1137 #endif
1138     if (DumpExifMap){
1139         unsigned a,b;
1140         printf("Map: %05d- End of exif\n",length-8);
1141 //        for (a=0;a<length-8;a+= 10){
1142 //            printf("Map: %05d ",a);
1143 //            for (b=0;b<10;b++) printf(" %02x",*(ExifSection+8+a+b));
1144 //            printf("\n");
1145 //        }
1146         for (a = 0; a < length - 8; ++a) {
1147             unsigned char c = *(ExifSection+8+a);
1148             unsigned pc = isprint(c) ? c : ' ';
1149             printf("Map: %4d %02x %c", a, c, pc);
1150         }
1151     }
1152 
1153 
1154     // Compute the CCD width, in millimeters.
1155     if (FocalplaneXRes != 0){
1156         // Note: With some cameras, its not possible to compute this correctly because
1157         // they don't adjust the indicated focal plane resolution units when using less
1158         // than maximum resolution, so the CCDWidth value comes out too small.  Nothing
1159         // that Jhad can do about it - its a camera problem.
1160         ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
1161 
1162         if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0
1163             && ImageInfo.FocalLength35mmEquiv == 0){
1164             // Compute 35 mm equivalent focal length based on sensor geometry if we haven't
1165             // already got it explicitly from a tag.
1166             ImageInfo.FocalLength35mmEquiv = (int)(
1167                 (double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom
1168                 / ImageInfo.CCDWidth * 36 + 0.5);
1169         }
1170     }
1171 }
1172 
TagToTagTableEntry(unsigned short tag)1173 static const TagTable_t* TagToTagTableEntry(unsigned short tag)
1174 {
1175     unsigned int i;
1176     for (i = 0; i < TAG_TABLE_SIZE; i++) {
1177         if (TagTable[i].Tag == tag) {
1178             printf("found tag %d", tag);
1179             int format = TagTable[i].Format;
1180             if (format == 0) {
1181                 printf("tag %s format not defined ***** YOU MUST ADD THE FORMAT TO THE TagTable in exif.c!!!!", TagTable[i].Desc);
1182                 return NULL;
1183             }
1184             return &TagTable[i];
1185         }
1186     }
1187     printf("tag %d NOT FOUND", tag);
1188     return NULL;
1189 }
1190 
writeExifTagAndData(int tag,int format,long components,long value,int valueInString,char * Buffer,int * DirIndex,int * DataWriteIndex)1191 static void writeExifTagAndData(int tag,
1192                                 int format,
1193                                 long components,
1194                                 long value,
1195                                 int valueInString,
1196                                 char* Buffer,
1197                                 int* DirIndex,
1198                                 int* DataWriteIndex) {
1199     void* componentsPosition = NULL; // for saving component position
1200 
1201     Put16u(Buffer+ (*DirIndex), tag);                    // Tag
1202     Put16u(Buffer+(*DirIndex) + 2, format);              // Format
1203     if (format == FMT_STRING && components == -1) {
1204         components = strlen((char*)value) + 1;                 // account for null terminator
1205         if (components & 1) ++components;               // no odd lengths
1206     } else if (format == FMT_SSHORT && components == -1) {
1207         // jhead only supports reading one SSHORT anyway
1208         components = 1;
1209     }
1210     if (format == FMT_UNDEFINED && components == -1) {
1211         // check if this UNDEFINED format is actually ASCII (as it usually is)
1212         // if so, we can calculate the size
1213         if(memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0) {
1214             components = sizeof(ExifAsciiPrefix) +
1215                          strlen((char*)value + sizeof(ExifAsciiPrefix)) + 1;
1216             if (components & 1) ++components;               // no odd lengths
1217         }
1218     }
1219     Put32u(Buffer+(*DirIndex) + 4, components);         // Components
1220     componentsPosition = Buffer+(*DirIndex) + 4; // components # can change for lists
1221     printf("# components: %ld", components);
1222     if (format == FMT_STRING) {
1223         // short strings can fit right in the long, otherwise have to
1224         // go in the data area
1225         if (components <= 4) {
1226             strcpy(Buffer+(*DirIndex) + 8, (char*)value);
1227         } else {
1228             Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
1229             printf("copying value %s to %d", (char*)value, (*DataWriteIndex));
1230             strncpy(Buffer+(*DataWriteIndex), (char*)value, components);
1231             (*DataWriteIndex) += components;
1232         }
1233     } else if ((format == FMT_UNDEFINED) &&
1234                (memcmp((char*)value, ExifAsciiPrefix, sizeof(ExifAsciiPrefix)) == 0)) {
1235         // short strings can fit right in the long, otherwise have to
1236         // go in the data area
1237         if (components <= 4) {
1238             memcpy(Buffer+(*DirIndex) + 8, (char*)value, components);
1239         } else {
1240             Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
1241             printf("copying %s to %d", (char*)value + sizeof(ExifAsciiPrefix), (*DataWriteIndex));
1242             memcpy(Buffer+(*DataWriteIndex), (char*)value, components);
1243             (*DataWriteIndex) += components;
1244         }
1245     } else if (!valueInString) {
1246         Put32u(Buffer+(*DirIndex) + 8, value);   // Value
1247     } else {
1248         Put32u(Buffer+(*DirIndex) + 8, (*DataWriteIndex)-8);   // Pointer
1249         // Usually the separator is ',', but sometimes ':' is used, like
1250         // TAG_GPS_TIMESTAMP.
1251         char* curElement = strtok((char*)value, ",:");
1252         int i;
1253 
1254         // (components == -1) Need to handle lists with unknown length too
1255         for (i = 0; ((i < components) || (components == -1)) && curElement != NULL; i++) {
1256 #ifdef SUPERDEBUG
1257             printf("processing component %s format %s", curElement, formatStr(format));
1258 #endif
1259             // elements are separated by commas
1260             if (format == FMT_URATIONAL) {
1261                 unsigned int numerator;
1262                 unsigned int denominator;
1263                 char* separator = strchr(curElement, '/');
1264                 if (separator) {
1265                     numerator = atoi(curElement);
1266                     denominator = atoi(separator + 1);
1267                 } else {
1268                     double value = atof(curElement);
1269                     ConvertDoubleToURational(value, &numerator, &denominator);
1270                 }
1271                 Put32u(Buffer+(*DataWriteIndex), numerator);
1272                 Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
1273                 (*DataWriteIndex) += 8;
1274             } else if (format == FMT_SRATIONAL) {
1275                 int numerator;
1276                 int denominator;
1277                 char* separator = strchr(curElement, '/');
1278                 if (separator) {
1279                     numerator = atoi(curElement);
1280                     denominator = atoi(separator + 1);
1281                 } else {
1282                     double value = atof(curElement);
1283                     ConvertDoubleToSRational(value, &numerator, &denominator);
1284                 }
1285                 Put32u(Buffer+(*DataWriteIndex), numerator);
1286                 Put32u(Buffer+(*DataWriteIndex) + 4, denominator);
1287                 (*DataWriteIndex) += 8;
1288             } else if ((components == -1) && ((format == FMT_USHORT) || (format == FMT_SSHORT))) {
1289                 // variable components need to go into data write area
1290                 value = atoi(curElement);
1291                 Put16u(Buffer+(*DataWriteIndex), value);
1292                 (*DataWriteIndex) += 4;
1293             } else {
1294                 // TODO: doesn't handle multiple components yet -- if more than one, have to put in data write area.
1295                 value = atoi(curElement);
1296                 Put32u(Buffer+(*DirIndex) + 8, value);   // Value
1297             }
1298             curElement = strtok(NULL, ",:");
1299         }
1300         if (components == -1) Put32u(componentsPosition, i); // update component # for unknowns
1301     }
1302     (*DirIndex) += 12;
1303 }
1304 
1305 #ifdef SUPERDEBUG
formatStr(int format)1306 char* formatStr(int format) {
1307     switch (format) {
1308         case FMT_BYTE: return "FMT_BYTE"; break;
1309         case FMT_STRING: return "FMT_STRING"; break;
1310         case FMT_USHORT: return "FMT_USHORT"; break;
1311         case FMT_ULONG: return "FMT_ULONG"; break;
1312         case FMT_URATIONAL: return "FMT_URATIONAL"; break;
1313         case FMT_SBYTE: return "FMT_SBYTE"; break;
1314         case FMT_UNDEFINED: return "FMT_UNDEFINED"; break;
1315         case FMT_SSHORT: return "FMT_SSHORT"; break;
1316         case FMT_SLONG: return "FMT_SLONG"; break;
1317         case FMT_SRATIONAL: return "FMT_SRATIONAL"; break;
1318         case FMT_SINGLE: return "FMT_SINGLE"; break;
1319         case FMT_DOUBLE: return "FMT_SINGLE"; break;
1320         default: return "UNKNOWN";
1321     }
1322 }
1323 #endif
1324 
1325 //--------------------------------------------------------------------------
1326 // Create minimal exif header - just date and thumbnail pointers,
1327 // so that date and thumbnail may be filled later.
1328 //--------------------------------------------------------------------------
create_EXIF_internal(ExifElement_t * elements,int exifTagCount,int gpsTagCount,int hasDateTimeTag,char * Buffer)1329 static void create_EXIF_internal(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag, char* Buffer)
1330 {
1331     unsigned short NumEntries;
1332     int DataWriteIndex;
1333     int DirIndex;
1334     int DirExifLink = 0;
1335 
1336 #ifdef SUPERDEBUG
1337     ALOGE("create_EXIF %d exif elements, %d gps elements", exifTagCount, gpsTagCount);
1338 #endif
1339 
1340     MotorolaOrder = 0;
1341 
1342     memcpy(Buffer+2, "Exif\0\0II",8);
1343     Put16u(Buffer+10, 0x2a);
1344 
1345     DataWriteIndex = 16;
1346     Put32u(Buffer+12, DataWriteIndex-8); // first IFD offset.  Means start 16 bytes in.
1347 
1348     {
1349         DirIndex = DataWriteIndex;
1350         NumEntries = 1 + exifTagCount;  // the extra is the thumbnail
1351         if (gpsTagCount) {
1352             ++NumEntries;       // allow for the GPS info tag
1353         }
1354         if (!hasDateTimeTag) {
1355             // We have to write extra date time tag. The entry number should be
1356             // adjusted.
1357             ++NumEntries;
1358         }
1359         DataWriteIndex += 2 + NumEntries*12 + 4;
1360 
1361         Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1362         DirIndex += 2;
1363 
1364         // Entries go here...
1365         if (!hasDateTimeTag) {
1366             // Date/time entry
1367             char* dateTime = NULL;
1368             char dateBuf[20];
1369             if (ImageInfo.numDateTimeTags) {
1370                 // If we had a pre-existing exif header, use time from that.
1371                 dateTime = ImageInfo.DateTime;
1372             } else {
1373                 // Oterwise, use the file's timestamp.
1374                 FileTimeAsString(dateBuf);
1375                 dateTime = dateBuf;
1376             }
1377             writeExifTagAndData(TAG_DATETIME,
1378                                 FMT_STRING,
1379                                 20,
1380                                 (long)(char*)dateBuf,
1381                                 FALSE,
1382                                 Buffer,
1383                                 &DirIndex,
1384                                 &DataWriteIndex);
1385 
1386         }
1387         if (exifTagCount > 0) {
1388             int i;
1389             for (i = 0; i < exifTagCount + gpsTagCount; i++) {
1390                 if (elements[i].GpsTag) {
1391                     continue;
1392                 }
1393                 const TagTable_t* entry = TagToTagTableEntry(elements[i].Tag);
1394                 if (entry == NULL) {
1395                     continue;
1396                 }
1397 #ifdef SUPERDEBUG
1398                 ALOGE("create_EXIF saving tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
1399 #endif
1400                 writeExifTagAndData(elements[i].Tag,
1401                                     entry->Format,
1402                                     entry->DataLength,
1403                                     (long)elements[i].Value,
1404                                     TRUE,
1405                                     Buffer,
1406                                     &DirIndex,
1407                                     &DataWriteIndex);
1408             }
1409 
1410             if (gpsTagCount) {
1411                 // Link to gps dir entry
1412                 writeExifTagAndData(TAG_GPSINFO,
1413                                     FMT_ULONG,
1414                                     1,
1415                                     DataWriteIndex-8,
1416                                     FALSE,
1417                                     Buffer,
1418                                     &DirIndex,
1419                                     &DataWriteIndex);
1420             }
1421 
1422             // Link to exif dir entry
1423             int exifDirPtr = DataWriteIndex-8;
1424             if (gpsTagCount) {
1425                 exifDirPtr += 2 + gpsTagCount*12 + 4;
1426             }
1427             DirExifLink = DirIndex;
1428             writeExifTagAndData(TAG_EXIF_OFFSET,
1429                                 FMT_ULONG,
1430                                 1,
1431                                 exifDirPtr,
1432                                 FALSE,
1433                                 Buffer,
1434                                 &DirIndex,
1435                                 &DataWriteIndex);
1436         }
1437 
1438         // End of directory - contains optional link to continued directory.
1439         Put32u(Buffer+DirIndex, 0);
1440         printf("Ending Exif section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1441     }
1442 
1443 
1444     // GPS Section
1445     if (gpsTagCount) {
1446         DirIndex = DataWriteIndex;
1447         printf("Starting GPS section DirIndex = %d", DirIndex);
1448         NumEntries = gpsTagCount;
1449         DataWriteIndex += 2 + NumEntries*12 + 4;
1450 
1451         Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1452         DirIndex += 2;
1453         {
1454             int i;
1455             for (i = 0; i < exifTagCount + gpsTagCount; i++) {
1456                 if (!elements[i].GpsTag) {
1457                     continue;
1458                 }
1459                 const TagTable_t* entry = GpsTagToTagTableEntry(elements[i].Tag);
1460                 if (entry == NULL) {
1461                     continue;
1462                 }
1463 #ifdef SUPERDEBUG
1464                 ALOGE("create_EXIF saving GPS tag %x value \"%s\"",elements[i].Tag, elements[i].Value);
1465 #endif
1466                 writeExifTagAndData(elements[i].Tag,
1467                                     entry->Format,
1468                                     entry->DataLength,
1469                                     (long)elements[i].Value,
1470                                     TRUE,
1471                                     Buffer,
1472                                     &DirIndex,
1473                                     &DataWriteIndex);
1474             }
1475         }
1476 
1477         // End of directory - contains optional link to continued directory.
1478         Put32u(Buffer+DirIndex, 0);
1479         printf("Ending GPS section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1480     }
1481 
1482     {
1483         // Overwriting TAG_EXIF_OFFSET which links to this directory
1484         Put32u(Buffer+DirExifLink+8, DataWriteIndex-8);
1485 
1486         printf("Starting Thumbnail section DirIndex = %d", DirIndex);
1487         DirIndex = DataWriteIndex;
1488         NumEntries = 2;
1489         DataWriteIndex += 2 + NumEntries*12 + 4;
1490 
1491         Put16u(Buffer+DirIndex, NumEntries); // Number of entries
1492         DirIndex += 2;
1493         {
1494             // Link to exif dir entry
1495             writeExifTagAndData(TAG_THUMBNAIL_OFFSET,
1496                                 FMT_ULONG,
1497                                 1,
1498                                 DataWriteIndex-8,
1499                                 FALSE,
1500                                 Buffer,
1501                                 &DirIndex,
1502                                 &DataWriteIndex);
1503         }
1504 
1505         {
1506             // Link to exif dir entry
1507             writeExifTagAndData(TAG_THUMBNAIL_LENGTH,
1508                                 FMT_ULONG,
1509                                 1,
1510                                 0,
1511                                 FALSE,
1512                                 Buffer,
1513                                 &DirIndex,
1514                                 &DataWriteIndex);
1515         }
1516 
1517         // End of directory - contains optional link to continued directory.
1518         Put32u(Buffer+DirIndex, 0);
1519         printf("Ending Thumbnail section DirIndex = %d DataWriteIndex %d", DirIndex, DataWriteIndex);
1520     }
1521 
1522 
1523     Buffer[0] = (unsigned char)(DataWriteIndex >> 8);
1524     Buffer[1] = (unsigned char)DataWriteIndex;
1525 
1526     // Remove old exif section, if there was one.
1527     RemoveSectionType(M_EXIF);
1528 
1529     {
1530         // Sections need malloced buffers, so do that now, especially because
1531         // we now know how big it needs to be allocated.
1532         unsigned char * NewBuf = malloc(DataWriteIndex);
1533         if (NewBuf == NULL){
1534             ErrFatal("Could not allocate memory");
1535         }
1536         memcpy(NewBuf, Buffer, DataWriteIndex);
1537 
1538         CreateSection(M_EXIF, NewBuf, DataWriteIndex);
1539 
1540         // Re-parse new exif section, now that its in place
1541         // otherwise, we risk touching data that has already been freed.
1542         process_EXIF(NewBuf, DataWriteIndex);
1543     }
1544 }
1545 
create_EXIF(ExifElement_t * elements,int exifTagCount,int gpsTagCount,int hasDateTimeTag)1546 void create_EXIF(ExifElement_t* elements, int exifTagCount, int gpsTagCount, int hasDateTimeTag)
1547 {
1548     // It is hard to calculate exact necessary size for editing the exif
1549     // header dynamically, so we are using the maximum size of EXIF, 64K
1550     const int EXIF_MAX_SIZE = 1024*64;
1551     char* Buffer = malloc(EXIF_MAX_SIZE);
1552 
1553     if (Buffer != NULL) {
1554         create_EXIF_internal(elements, exifTagCount, gpsTagCount, hasDateTimeTag, Buffer);
1555         free(Buffer);
1556     } else {
1557         ErrFatal("Could not allocate memory");
1558     }
1559 }
1560 
1561 //--------------------------------------------------------------------------
1562 // Cler the rotation tag in the exif header to 1.
1563 //--------------------------------------------------------------------------
ClearOrientation(void)1564 const char * ClearOrientation(void)
1565 {
1566     int a;
1567     if (NumOrientations == 0) return NULL;
1568 
1569     for (a=0;a<NumOrientations;a++){
1570         switch(OrientationNumFormat[a]){
1571             case FMT_SBYTE:
1572             case FMT_BYTE:
1573                 *(uchar *)(OrientationPtr[a]) = 1;
1574                 break;
1575 
1576             case FMT_USHORT:
1577                 Put16u(OrientationPtr[a], 1);
1578                 break;
1579 
1580             case FMT_ULONG:
1581             case FMT_SLONG:
1582                 memset(OrientationPtr, 0, 4);
1583                 // Can't be bothered to write  generic Put32 if I only use it once.
1584                 if (MotorolaOrder){
1585                     ((uchar *)OrientationPtr[a])[3] = 1;
1586                 }else{
1587                     ((uchar *)OrientationPtr[a])[0] = 1;
1588                 }
1589                 break;
1590 
1591             default:
1592                 return NULL;
1593         }
1594     }
1595 
1596     return OrientTab[ImageInfo.Orientation];
1597 }
1598 
1599 
1600 
1601 //--------------------------------------------------------------------------
1602 // Remove thumbnail out of the exif image.
1603 //--------------------------------------------------------------------------
RemoveThumbnail(unsigned char * ExifSection)1604 int RemoveThumbnail(unsigned char * ExifSection)
1605 {
1606     if (!DirWithThumbnailPtrs ||
1607         ImageInfo.ThumbnailOffset == 0 ||
1608         ImageInfo.ThumbnailSize == 0){
1609         // No thumbnail, or already deleted it.
1610         return 0;
1611     }
1612     if (ImageInfo.ThumbnailAtEnd == FALSE){
1613         ErrNonfatal("Thumbnail is not at end of header, can't chop it off", 0, 0);
1614         return 0;
1615     }
1616 
1617     {
1618         int de;
1619         int NumDirEntries;
1620         NumDirEntries = Get16u(DirWithThumbnailPtrs);
1621 
1622         for (de=0;de<NumDirEntries;de++){
1623             int Tag;
1624             unsigned char * DirEntry;
1625             DirEntry = DIR_ENTRY_ADDR(DirWithThumbnailPtrs, de);
1626             Tag = Get16u(DirEntry);
1627             if (Tag == TAG_THUMBNAIL_LENGTH){
1628                 // Set length to zero.
1629                 if (Get16u(DirEntry+2) != FMT_ULONG){
1630                     // non standard format encoding.  Can't do it.
1631                     ErrNonfatal("Can't remove thumbnail", 0, 0);
1632                     return 0;
1633                 }
1634                 Put32u(DirEntry+8, 0);
1635             }
1636         }
1637     }
1638 
1639     // This is how far the non thumbnail data went.
1640     return ImageInfo.ThumbnailOffset+8;
1641 
1642 }
1643 
1644 
1645 //--------------------------------------------------------------------------
1646 // Convert exif time to Unix time structure
1647 //--------------------------------------------------------------------------
Exif2tm(struct tm * timeptr,char * ExifTime)1648 int Exif2tm(struct tm * timeptr, char * ExifTime)
1649 {
1650     int a;
1651 
1652     timeptr->tm_wday = -1;
1653 
1654     // Check for format: YYYY:MM:DD HH:MM:SS format.
1655     // Date and time normally separated by a space, but also seen a ':' there, so
1656     // skip the middle space with '%*c' so it can be any character.
1657     a = sscanf(ExifTime, "%d%*c%d%*c%d%*c%d:%d:%d",
1658             &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
1659             &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
1660 
1661 
1662     if (a == 6){
1663         timeptr->tm_isdst = -1;
1664         timeptr->tm_mon -= 1;      // Adjust for unix zero-based months
1665         timeptr->tm_year -= 1900;  // Adjust for year starting at 1900
1666         return TRUE; // worked.
1667     }
1668 
1669     return FALSE; // Wasn't in Exif date format.
1670 }
1671 
1672 
1673 //--------------------------------------------------------------------------
1674 // Show the collected image info, displaying camera F-stop and shutter speed
1675 // in a consistent and legible fashion.
1676 //--------------------------------------------------------------------------
ShowImageInfo(int ShowFileInfo)1677 void ShowImageInfo(int ShowFileInfo)
1678 {
1679     if (ShowFileInfo){
1680         printf("File name    : %s\n",ImageInfo.FileName);
1681         printf("File size    : %d bytes\n",ImageInfo.FileSize);
1682 
1683         {
1684             char Temp[20];
1685             FileTimeAsString(Temp);
1686             printf("File date    : %s\n",Temp);
1687         }
1688     }
1689 
1690     if (ImageInfo.CameraMake[0]){
1691         printf("Camera make  : %s\n",ImageInfo.CameraMake);
1692         printf("Camera model : %s\n",ImageInfo.CameraModel);
1693     }
1694     if (ImageInfo.DateTime[0]){
1695         printf("Date/Time    : %s\n",ImageInfo.DateTime);
1696     }
1697     printf("Resolution   : %d x %d\n",ImageInfo.Width, ImageInfo.Height);
1698 
1699     if (ImageInfo.Orientation > 1){
1700         // Only print orientation if one was supplied, and if its not 1 (normal orientation)
1701         printf("Orientation  : %s\n", OrientTab[ImageInfo.Orientation]);
1702     }
1703 
1704     if (ImageInfo.IsColor == 0){
1705         printf("Color/bw     : Black and white\n");
1706     }
1707 
1708     if (ImageInfo.FlashUsed >= 0){
1709         if (ImageInfo.FlashUsed & 1){
1710             printf("Flash used   : Yes");
1711             switch (ImageInfo.FlashUsed){
1712 	            case 0x5: printf(" (Strobe light not detected)"); break;
1713 	            case 0x7: printf(" (Strobe light detected) "); break;
1714 	            case 0x9: printf(" (manual)"); break;
1715 	            case 0xd: printf(" (manual, return light not detected)"); break;
1716 	            case 0xf: printf(" (manual, return light  detected)"); break;
1717 	            case 0x19:printf(" (auto)"); break;
1718 	            case 0x1d:printf(" (auto, return light not detected)"); break;
1719 	            case 0x1f:printf(" (auto, return light detected)"); break;
1720 	            case 0x41:printf(" (red eye reduction mode)"); break;
1721 	            case 0x45:printf(" (red eye reduction mode return light not detected)"); break;
1722 	            case 0x47:printf(" (red eye reduction mode return light  detected)"); break;
1723 	            case 0x49:printf(" (manual, red eye reduction mode)"); break;
1724 	            case 0x4d:printf(" (manual, red eye reduction mode, return light not detected)"); break;
1725 	            case 0x4f:printf(" (red eye reduction mode, return light detected)"); break;
1726 	            case 0x59:printf(" (auto, red eye reduction mode)"); break;
1727 	            case 0x5d:printf(" (auto, red eye reduction mode, return light not detected)"); break;
1728 	            case 0x5f:printf(" (auto, red eye reduction mode, return light detected)"); break;
1729             }
1730         }else{
1731             printf("Flash used   : No");
1732             switch (ImageInfo.FlashUsed){
1733 	            case 0x18:printf(" (auto)"); break;
1734             }
1735         }
1736         printf("\n");
1737     }
1738 
1739 
1740     if (ImageInfo.FocalLength.num != 0 && ImageInfo.FocalLength.denom != 0) {
1741         printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength.num / ImageInfo.FocalLength.denom);
1742         if (ImageInfo.FocalLength35mmEquiv){
1743             printf("  (35mm equivalent: %dmm)", ImageInfo.FocalLength35mmEquiv);
1744         }
1745         printf("\n");
1746     }
1747 
1748     if (ImageInfo.DigitalZoomRatio > 1){
1749         // Digital zoom used.  Shame on you!
1750         printf("Digital Zoom : %5.3fx\n", (double)ImageInfo.DigitalZoomRatio);
1751     }
1752 
1753     if (ImageInfo.CCDWidth){
1754         printf("CCD width    : %4.2fmm\n",(double)ImageInfo.CCDWidth);
1755     }
1756 
1757     if (ImageInfo.ExposureTime){
1758         if (ImageInfo.ExposureTime < 0.010){
1759             printf("Exposure time: %6.4f s ",(double)ImageInfo.ExposureTime);
1760         }else{
1761             printf("Exposure time: %5.3f s ",(double)ImageInfo.ExposureTime);
1762         }
1763         if (ImageInfo.ExposureTime <= 0.5){
1764             printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
1765         }
1766         printf("\n");
1767     }
1768     if (ImageInfo.ApertureFNumber){
1769         printf("Aperture     : f/%5.3f\n",(double)ImageInfo.ApertureFNumber);
1770     }
1771     if (ImageInfo.Distance){
1772         if (ImageInfo.Distance < 0){
1773             printf("Focus dist.  : Infinite\n");
1774         }else{
1775             printf("Focus dist.  : %4.2fm\n",(double)ImageInfo.Distance);
1776         }
1777     }
1778 
1779     if (ImageInfo.ISOequivalent){
1780         printf("ISO equiv.   : %2d\n",(int)ImageInfo.ISOequivalent);
1781     }
1782 
1783     if (ImageInfo.ExposureBias){
1784         // If exposure bias was specified, but set to zero, presumably its no bias at all,
1785         // so only show it if its nonzero.
1786         printf("Exposure bias: %4.2f\n",(double)ImageInfo.ExposureBias);
1787     }
1788 
1789     switch(ImageInfo.Whitebalance) {
1790         case 1:
1791             printf("Whitebalance : Manual\n");
1792             break;
1793         case 0:
1794             printf("Whitebalance : Auto\n");
1795             break;
1796     }
1797 
1798     //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both
1799     switch(ImageInfo.LightSource) {
1800         case 1:
1801             printf("Light Source : Daylight\n");
1802             break;
1803         case 2:
1804             printf("Light Source : Fluorescent\n");
1805             break;
1806         case 3:
1807             printf("Light Source : Incandescent\n");
1808             break;
1809         case 4:
1810             printf("Light Source : Flash\n");
1811             break;
1812         case 9:
1813             printf("Light Source : Fine weather\n");
1814             break;
1815         case 11:
1816             printf("Light Source : Shade\n");
1817             break;
1818         default:; //Quercus: 17-1-2004 There are many more modes for this, check Exif2.2 specs
1819             // If it just says 'unknown' or we don't know it, then
1820             // don't bother showing it - it doesn't add any useful information.
1821     }
1822 
1823     if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs
1824         switch(ImageInfo.MeteringMode) {
1825         case 2:
1826             printf("Metering Mode: center weight\n");
1827             break;
1828         case 3:
1829             printf("Metering Mode: spot\n");
1830             break;
1831         case 5:
1832             printf("Metering Mode: matrix\n");
1833             break;
1834         }
1835     }
1836 
1837     if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs
1838         switch(ImageInfo.ExposureProgram) {
1839         case 1:
1840             printf("Exposure     : Manual\n");
1841             break;
1842         case 2:
1843             printf("Exposure     : program (auto)\n");
1844             break;
1845         case 3:
1846             printf("Exposure     : aperture priority (semi-auto)\n");
1847             break;
1848         case 4:
1849             printf("Exposure     : shutter priority (semi-auto)\n");
1850             break;
1851         case 5:
1852             printf("Exposure     : Creative Program (based towards depth of field)\n");
1853             break;
1854         case 6:
1855             printf("Exposure     : Action program (based towards fast shutter speed)\n");
1856             break;
1857         case 7:
1858             printf("Exposure     : Portrait Mode\n");
1859             break;
1860         case 8:
1861             printf("Exposure     : LandscapeMode \n");
1862             break;
1863         default:
1864             break;
1865         }
1866     }
1867     switch(ImageInfo.ExposureMode){
1868         case 0: // Automatic (not worth cluttering up output for)
1869             break;
1870         case 1: printf("Exposure Mode: Manual\n");
1871             break;
1872         case 2: printf("Exposure Mode: Auto bracketing\n");
1873             break;
1874     }
1875 
1876     if (ImageInfo.DistanceRange) {
1877         printf("Focus range  : ");
1878         switch(ImageInfo.DistanceRange) {
1879             case 1:
1880                 printf("macro");
1881                 break;
1882             case 2:
1883                 printf("close");
1884                 break;
1885             case 3:
1886                 printf("distant");
1887                 break;
1888         }
1889         printf("\n");
1890     }
1891 
1892 
1893 
1894     if (ImageInfo.Process != M_SOF0){
1895         // don't show it if its the plain old boring 'baseline' process, but do
1896         // show it if its something else, like 'progressive' (used on web sometimes)
1897         int a;
1898         for (a=0;;a++){
1899             if (a >= (int)PROCESS_TABLE_SIZE){
1900                 // ran off the end of the table.
1901                 printf("Jpeg process : Unknown\n");
1902                 break;
1903             }
1904             if (ProcessTable[a].Tag == ImageInfo.Process){
1905                 printf("Jpeg process : %s\n",ProcessTable[a].Desc);
1906                 break;
1907             }
1908         }
1909     }
1910 
1911     if (ImageInfo.GpsInfoPresent){
1912         printf("GPS Latitude : %s\n",ImageInfo.GpsLat);
1913         printf("GPS Longitude: %s\n",ImageInfo.GpsLong);
1914         if (ImageInfo.GpsAlt[0]) printf("GPS Altitude : %s\n",ImageInfo.GpsAlt);
1915     }
1916 
1917     // Print the comment. Print 'Comment:' for each new line of comment.
1918     if (ImageInfo.Comments[0]){
1919         int a,c;
1920         printf("Comment      : ");
1921         if (!ImageInfo.CommentWidchars){
1922             for (a=0;a<MAX_COMMENT_SIZE;a++){
1923                 c = ImageInfo.Comments[a];
1924                 if (c == '\0') break;
1925                 if (c == '\n'){
1926                     // Do not start a new line if the string ends with a carriage return.
1927                     if (ImageInfo.Comments[a+1] != '\0'){
1928                         printf("\nComment      : ");
1929                     }else{
1930                         printf("\n");
1931                     }
1932                 }else{
1933                     putchar(c);
1934                 }
1935             }
1936             printf("\n");
1937         }else{
1938             printf("%.*ls\n", ImageInfo.CommentWidchars, (wchar_t *)ImageInfo.Comments);
1939         }
1940     }
1941     if (ImageInfo.ThumbnailOffset){
1942         printf("Map: %05d-%05d: Thumbnail\n",ImageInfo.ThumbnailOffset, ImageInfo.ThumbnailOffset+ImageInfo.ThumbnailSize);
1943     } else {
1944         printf("NO thumbnail");
1945     }
1946 }
1947 
1948 
1949 //--------------------------------------------------------------------------
1950 // Summarize highlights of image info on one line (suitable for grep-ing)
1951 //--------------------------------------------------------------------------
ShowConciseImageInfo(void)1952 void ShowConciseImageInfo(void)
1953 {
1954     printf("\"%s\"",ImageInfo.FileName);
1955 
1956     printf(" %dx%d",ImageInfo.Width, ImageInfo.Height);
1957 
1958     if (ImageInfo.ExposureTime){
1959         if (ImageInfo.ExposureTime <= 0.5){
1960             printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
1961         }else{
1962             printf(" (%3.1f)",ImageInfo.ExposureTime);
1963         }
1964     }
1965 
1966     if (ImageInfo.ApertureFNumber){
1967         printf(" f/%3.1f",(double)ImageInfo.ApertureFNumber);
1968     }
1969 
1970     if (ImageInfo.FocalLength35mmEquiv){
1971         printf(" f(35)=%dmm",ImageInfo.FocalLength35mmEquiv);
1972     }
1973 
1974     if (ImageInfo.FlashUsed >= 0 && ImageInfo.FlashUsed & 1){
1975         printf(" (flash)");
1976     }
1977 
1978     if (ImageInfo.IsColor == 0){
1979         printf(" (bw)");
1980     }
1981 
1982     printf("\n");
1983 }
1984