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,  Dec 1999 - May 2002
8 //--------------------------------------------------------------------------
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <ctype.h>
16 
17 
18 #ifdef _WIN32
19     #include <sys/utime.h>
20 #else
21     #include <utime.h>
22     #include <sys/types.h>
23     #include <unistd.h>
24     #include <errno.h>
25     #include <limits.h>
26 #endif
27 
28 #include "jhead.h"
29 
30 static unsigned char * LastExifRefd;
31 static unsigned char * DirWithThumbnailPtrs;
32 static double FocalplaneXRes;
33 static double FocalplaneUnits;
34 static int ExifImageWidth;
35 static int MotorolaOrder = 0;
36 
37 typedef struct {
38     unsigned short Tag;
39     char * Desc;
40 }TagTable_t;
41 
42 
43 //--------------------------------------------------------------------------
44 // Describes format descriptor
45 static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
46 #define NUM_FORMATS 12
47 
48 #define FMT_BYTE       1
49 #define FMT_STRING     2
50 #define FMT_USHORT     3
51 #define FMT_ULONG      4
52 #define FMT_URATIONAL  5
53 #define FMT_SBYTE      6
54 #define FMT_UNDEFINED  7
55 #define FMT_SSHORT     8
56 #define FMT_SLONG      9
57 #define FMT_SRATIONAL 10
58 #define FMT_SINGLE    11
59 #define FMT_DOUBLE    12
60 
61 //--------------------------------------------------------------------------
62 // Describes tag values
63 
64 #define TAG_EXIF_OFFSET       0x8769
65 #define TAG_INTEROP_OFFSET    0xa005
66 
67 #define TAG_MAKE              0x010F
68 #define TAG_MODEL             0x0110
69 
70 #define TAG_ORIENTATION       0x0112
71 
72 #define TAG_EXPOSURETIME      0x829A
73 #define TAG_FNUMBER           0x829D
74 
75 #define TAG_SHUTTERSPEED      0x9201
76 #define TAG_APERTURE          0x9202
77 #define TAG_MAXAPERTURE       0x9205
78 #define TAG_FOCALLENGTH       0x920A
79 
80 #define TAG_DATETIME_ORIGINAL 0x9003
81 #define TAG_USERCOMMENT       0x9286
82 
83 #define TAG_SUBJECT_DISTANCE  0x9206
84 #define TAG_FLASH             0x9209
85 
86 #define TAG_FOCALPLANEXRES    0xa20E
87 #define TAG_FOCALPLANEUNITS   0xa210
88 #define TAG_EXIF_IMAGEWIDTH   0xA002
89 #define TAG_EXIF_IMAGELENGTH  0xA003
90 
91 // the following is added 05-jan-2001 vcs
92 #define TAG_EXPOSURE_BIAS     0x9204
93 #define TAG_WHITEBALANCE      0x9208
94 #define TAG_METERING_MODE     0x9207
95 #define TAG_EXPOSURE_PROGRAM  0x8822
96 #define TAG_ISO_EQUIVALENT    0x8827
97 #define TAG_COMPRESSION_LEVEL 0x9102
98 
99 #define TAG_THUMBNAIL_OFFSET  0x0201
100 #define TAG_THUMBNAIL_LENGTH  0x0202
101 
102 static TagTable_t TagTable[] = {
103   {   0x100,   "ImageWidth"},
104   {   0x101,   "ImageLength"},
105   {   0x102,   "BitsPerSample"},
106   {   0x103,   "Compression"},
107   {   0x106,   "PhotometricInterpretation"},
108   {   0x10A,   "FillOrder"},
109   {   0x10D,   "DocumentName"},
110   {   0x10E,   "ImageDescription"},
111   {   0x10F,   "Make"},
112   {   0x110,   "Model"},
113   {   0x111,   "StripOffsets"},
114   {   0x112,   "Orientation"},
115   {   0x115,   "SamplesPerPixel"},
116   {   0x116,   "RowsPerStrip"},
117   {   0x117,   "StripByteCounts"},
118   {   0x11A,   "XResolution"},
119   {   0x11B,   "YResolution"},
120   {   0x11C,   "PlanarConfiguration"},
121   {   0x128,   "ResolutionUnit"},
122   {   0x12D,   "TransferFunction"},
123   {   0x131,   "Software"},
124   {   0x132,   "DateTime"},
125   {   0x13B,   "Artist"},
126   {   0x13E,   "WhitePoint"},
127   {   0x13F,   "PrimaryChromaticities"},
128   {   0x156,   "TransferRange"},
129   {   0x200,   "JPEGProc"},
130   {   0x201,   "ThumbnailOffset"},
131   {   0x202,   "ThumbnailLength"},
132   {   0x211,   "YCbCrCoefficients"},
133   {   0x212,   "YCbCrSubSampling"},
134   {   0x213,   "YCbCrPositioning"},
135   {   0x214,   "ReferenceBlackWhite"},
136   {   0x828D,  "CFARepeatPatternDim"},
137   {   0x828E,  "CFAPattern"},
138   {   0x828F,  "BatteryLevel"},
139   {   0x8298,  "Copyright"},
140   {   0x829A,  "ExposureTime"},
141   {   0x829D,  "FNumber"},
142   {   0x83BB,  "IPTC/NAA"},
143   {   0x8769,  "ExifOffset"},
144   {   0x8773,  "InterColorProfile"},
145   {   0x8822,  "ExposureProgram"},
146   {   0x8824,  "SpectralSensitivity"},
147   {   0x8825,  "GPSInfo"},
148   {   0x8827,  "ISOSpeedRatings"},
149   {   0x8828,  "OECF"},
150   {   0x9000,  "ExifVersion"},
151   {   0x9003,  "DateTimeOriginal"},
152   {   0x9004,  "DateTimeDigitized"},
153   {   0x9101,  "ComponentsConfiguration"},
154   {   0x9102,  "CompressedBitsPerPixel"},
155   {   0x9201,  "ShutterSpeedValue"},
156   {   0x9202,  "ApertureValue"},
157   {   0x9203,  "BrightnessValue"},
158   {   0x9204,  "ExposureBiasValue"},
159   {   0x9205,  "MaxApertureValue"},
160   {   0x9206,  "SubjectDistance"},
161   {   0x9207,  "MeteringMode"},
162   {   0x9208,  "LightSource"},
163   {   0x9209,  "Flash"},
164   {   0x920A,  "FocalLength"},
165   {   0x927C,  "MakerNote"},
166   {   0x9286,  "UserComment"},
167   {   0x9290,  "SubSecTime"},
168   {   0x9291,  "SubSecTimeOriginal"},
169   {   0x9292,  "SubSecTimeDigitized"},
170   {   0xA000,  "FlashPixVersion"},
171   {   0xA001,  "ColorSpace"},
172   {   0xA002,  "ExifImageWidth"},
173   {   0xA003,  "ExifImageLength"},
174   {   0xA005,  "InteroperabilityOffset"},
175   {   0xA20B,  "FlashEnergy"},                 // 0x920B in TIFF/EP
176   {   0xA20C,  "SpatialFrequencyResponse"},  // 0x920C    -  -
177   {   0xA20E,  "FocalPlaneXResolution"},     // 0x920E    -  -
178   {   0xA20F,  "FocalPlaneYResolution"},      // 0x920F    -  -
179   {   0xA210,  "FocalPlaneResolutionUnit"},  // 0x9210    -  -
180   {   0xA214,  "SubjectLocation"},             // 0x9214    -  -
181   {   0xA215,  "ExposureIndex"},            // 0x9215    -  -
182   {   0xA217,  "SensingMethod"},            // 0x9217    -  -
183   {   0xA300,  "FileSource"},
184   {   0xA301,  "SceneType"},
185   {      0, NULL}
186 } ;
187 
188 
189 //--------------------------------------------------------------------------
190 // Convert a 16 bit unsigned value from file's native byte order
191 //--------------------------------------------------------------------------
Put16u(void * Short,unsigned short PutValue)192 static void Put16u(void * Short, unsigned short PutValue)
193 {
194     if (MotorolaOrder){
195         ((uchar *)Short)[0] = (uchar)(PutValue>>8);
196         ((uchar *)Short)[1] = (uchar)PutValue;
197     }else{
198         ((uchar *)Short)[0] = (uchar)PutValue;
199         ((uchar *)Short)[1] = (uchar)(PutValue>>8);
200     }
201 }
202 
203 
204 //--------------------------------------------------------------------------
205 // Convert a 16 bit unsigned value from file's native byte order
206 //--------------------------------------------------------------------------
Get16u(void * Short)207 static int Get16u(void * Short)
208 {
209     if (MotorolaOrder){
210         return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
211     }else{
212         return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
213     }
214 }
215 
216 //--------------------------------------------------------------------------
217 // Convert a 32 bit signed value from file's native byte order
218 //--------------------------------------------------------------------------
Get32s(void * Long)219 static int Get32s(void * Long)
220 {
221     if (MotorolaOrder){
222         return  ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
223               | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
224     }else{
225         return  ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
226               | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
227     }
228 }
229 
230 //--------------------------------------------------------------------------
231 // Convert a 32 bit unsigned value from file's native byte order
232 //--------------------------------------------------------------------------
Get32u(void * Long)233 static unsigned Get32u(void * Long)
234 {
235     return (unsigned)Get32s(Long) & 0xffffffff;
236 }
237 
238 //--------------------------------------------------------------------------
239 // Display a number as one of its many formats
240 //--------------------------------------------------------------------------
PrintFormatNumber(void * ValuePtr,int Format,int ByteCount)241 static void PrintFormatNumber(void * ValuePtr, int Format, int ByteCount)
242 {
243     switch(Format){
244         case FMT_SBYTE:
245         case FMT_BYTE:      printf("%02x\n",*(uchar *)ValuePtr);            break;
246         case FMT_USHORT:    printf("%d\n",Get16u(ValuePtr));                break;
247         case FMT_ULONG:
248         case FMT_SLONG:     printf("%d\n",Get32s(ValuePtr));                break;
249         case FMT_SSHORT:    printf("%hd\n",(signed short)Get16u(ValuePtr)); break;
250         case FMT_URATIONAL:
251         case FMT_SRATIONAL:
252            printf("%d/%d\n",Get32s(ValuePtr), Get32s(4+(char *)ValuePtr)); break;
253 
254         case FMT_SINGLE:    printf("%f\n",(double)*(float *)ValuePtr);   break;
255         case FMT_DOUBLE:    printf("%f\n",*(double *)ValuePtr);          break;
256         default:
257             printf("Unknown format %d:", Format);
258 
259     }
260 }
261 
262 
263 //--------------------------------------------------------------------------
264 // Evaluate number, be it int, rational, or float from directory.
265 //--------------------------------------------------------------------------
ConvertAnyFormat(void * ValuePtr,int Format)266 static double ConvertAnyFormat(void * ValuePtr, int Format)
267 {
268     double Value;
269     Value = 0;
270 
271     switch(Format){
272         case FMT_SBYTE:     Value = *(signed char *)ValuePtr;  break;
273         case FMT_BYTE:      Value = *(uchar *)ValuePtr;        break;
274 
275         case FMT_USHORT:    Value = Get16u(ValuePtr);          break;
276         case FMT_ULONG:     Value = Get32u(ValuePtr);          break;
277 
278         case FMT_URATIONAL:
279         case FMT_SRATIONAL:
280             {
281                 int Num,Den;
282                 Num = Get32s(ValuePtr);
283                 Den = Get32s(4+(char *)ValuePtr);
284                 if (Den == 0){
285                     Value = 0;
286                 }else{
287                     Value = (double)Num/Den;
288                 }
289                 break;
290             }
291 
292         case FMT_SSHORT:    Value = (signed short)Get16u(ValuePtr);  break;
293         case FMT_SLONG:     Value = Get32s(ValuePtr);                break;
294 
295         // Not sure if this is correct (never seen float used in Exif format)
296         case FMT_SINGLE:    Value = (double)*(float *)ValuePtr;      break;
297         case FMT_DOUBLE:    Value = *(double *)ValuePtr;             break;
298     }
299     return Value;
300 }
301 
302 //--------------------------------------------------------------------------
303 // Process one of the nested EXIF directories.
304 //--------------------------------------------------------------------------
ProcessExifDir(unsigned char * DirStart,unsigned char * OffsetBase,unsigned ExifLength)305 static void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength)
306 {
307     int de;
308     int a;
309     int NumDirEntries;
310     unsigned ThumbnailOffset = 0;
311     unsigned ThumbnailSize = 0;
312 
313     NumDirEntries = Get16u(DirStart);
314     #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
315 
316     {
317         unsigned char * DirEnd;
318         DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
319         if (DirEnd+4 > (OffsetBase+ExifLength)){
320             if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
321                 // Version 1.3 of jhead would truncate a bit too much.
322                 // This also caught later on as well.
323             }else{
324                 // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
325                 // might trigger this.
326                 ErrNonfatal("Illegally sized directory",0,0);
327                 return;
328             }
329         }
330         if (DirEnd > LastExifRefd) LastExifRefd = DirEnd;
331     }
332 
333     if (ShowTags){
334         printf("Directory with %d entries\n",NumDirEntries);
335     }
336 
337     for (de=0;de<NumDirEntries;de++){
338         int Tag, Format, Components;
339         unsigned char * ValuePtr;
340         int ByteCount;
341         char * DirEntry;
342         DirEntry = DIR_ENTRY_ADDR((char*)DirStart, de);
343 
344         Tag = Get16u(DirEntry);
345         Format = Get16u(DirEntry+2);
346         Components = Get32u(DirEntry+4);
347 
348         if ((Format-1) >= NUM_FORMATS) {
349             // (-1) catches illegal zero case as unsigned underflows to positive large.
350             ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
351             continue;
352         }
353 
354         ByteCount = Components * BytesPerFormat[Format];
355 
356         if (ByteCount > 4){
357             unsigned OffsetVal;
358             OffsetVal = Get32u(DirEntry+8);
359             // If its bigger than 4 bytes, the dir entry contains an offset.
360             if (OffsetVal+ByteCount > ExifLength){
361                 // Bogus pointer offset and / or bytecount value
362                 ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
363                 continue;
364             }
365             ValuePtr = OffsetBase+OffsetVal;
366         }else{
367             // 4 bytes or less and value is in the dir entry itself
368             ValuePtr = (unsigned char*)DirEntry+8;
369         }
370 
371         if (LastExifRefd < ValuePtr+ByteCount){
372             // Keep track of last byte in the exif header that was actually referenced.
373             // That way, we know where the discardable thumbnail data begins.
374             LastExifRefd = ValuePtr+ByteCount;
375 
376         }
377 
378         if (ShowTags){
379             // Show tag name
380             for (a=0;;a++){
381                 if (TagTable[a].Tag == 0){
382                     printf("  Unknown Tag %04x Value = ", Tag);
383                     break;
384                 }
385                 if (TagTable[a].Tag == Tag){
386                     printf("    %s = ",TagTable[a].Desc);
387                     break;
388                 }
389             }
390 
391             // Show tag value.
392             switch(Format){
393 
394                 case FMT_UNDEFINED:
395                     // Undefined is typically an ascii string.
396 
397                 case FMT_STRING:
398                     // String arrays printed without function call (different from int arrays)
399                     {
400                         int NoPrint = 0;
401                         printf("\"");
402                         for (a=0;a<ByteCount;a++){
403                             if (isprint((ValuePtr)[a])){
404                                 putchar((ValuePtr)[a]);
405                                 NoPrint = 0;
406                             }else{
407                                 // Avoiding indicating too many unprintable characters of proprietary
408                                 // bits of binary information this program may not know how to parse.
409                                 if (!NoPrint){
410                                     putchar('?');
411                                     NoPrint = 1;
412                                 }
413                             }
414                         }
415                         printf("\"\n");
416                     }
417                     break;
418 
419                 default:
420                     // Handle arrays of numbers later (will there ever be?)
421                     PrintFormatNumber(ValuePtr, Format, ByteCount);
422             }
423         }
424 
425         // Extract useful components of tag
426         switch(Tag){
427 
428             case TAG_MAKE:
429                 strncpy(ImageInfo.CameraMake, (char*)ValuePtr, 31);
430                 break;
431 
432             case TAG_MODEL:
433                 strncpy(ImageInfo.CameraModel, (char*)ValuePtr, 39);
434                 break;
435 
436             case TAG_DATETIME_ORIGINAL:
437                 strncpy(ImageInfo.DateTime, (char*)ValuePtr, 19);
438                 ImageInfo.DatePointer = (char*)ValuePtr;
439                 break;
440 
441             case TAG_USERCOMMENT:
442                 // Olympus has this padded with trailing spaces.  Remove these first.
443                 for (a=ByteCount;;){
444                     a--;
445                     if ((ValuePtr)[a] == ' '){
446                         (ValuePtr)[a] = '\0';
447                     }else{
448                         break;
449                     }
450                     if (a == 0) break;
451                 }
452 
453                 // Copy the comment
454                 if (memcmp(ValuePtr, "ASCII",5) == 0){
455                     for (a=5;a<10;a++){
456                         int c;
457                         c = (ValuePtr)[a];
458                         if (c != '\0' && c != ' '){
459                             strncpy(ImageInfo.Comments, a+(char*)ValuePtr, 199);
460                             break;
461                         }
462                     }
463 
464                 }else{
465                     strncpy(ImageInfo.Comments, (char*)ValuePtr, 199);
466                 }
467                 break;
468 
469             case TAG_FNUMBER:
470                 // Simplest way of expressing aperture, so I trust it the most.
471                 // (overwrite previously computd value if there is one)
472                 ImageInfo.ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
473                 break;
474 
475             case TAG_APERTURE:
476             case TAG_MAXAPERTURE:
477                 // More relevant info always comes earlier, so only use this field if we don't
478                 // have appropriate aperture information yet.
479                 if (ImageInfo.ApertureFNumber == 0){
480                     ImageInfo.ApertureFNumber
481                         = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);
482                 }
483                 break;
484 
485             case TAG_FOCALLENGTH:
486                 // Nice digital cameras actually save the focal length as a function
487                 // of how farthey are zoomed in.
488                 ImageInfo.FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
489                 break;
490 
491             case TAG_SUBJECT_DISTANCE:
492                 // Inidcates the distacne the autofocus camera is focused to.
493                 // Tends to be less accurate as distance increases.
494                 ImageInfo.Distance = (float)ConvertAnyFormat(ValuePtr, Format);
495                 break;
496 
497             case TAG_EXPOSURETIME:
498                 // Simplest way of expressing exposure time, so I trust it most.
499                 // (overwrite previously computd value if there is one)
500                 ImageInfo.ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
501                 break;
502 
503             case TAG_SHUTTERSPEED:
504                 // More complicated way of expressing exposure time, so only use
505                 // this value if we don't already have it from somewhere else.
506                 if (ImageInfo.ExposureTime == 0){
507                     ImageInfo.ExposureTime
508                         = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2)));
509                 }
510                 break;
511 
512             case TAG_FLASH:
513                 if (ConvertAnyFormat(ValuePtr, Format)){
514                     ImageInfo.FlashUsed = 1;
515                 }
516                 break;
517 
518             case TAG_ORIENTATION:
519                 ImageInfo.Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
520                 if (ImageInfo.Orientation < 1 || ImageInfo.Orientation > 8){
521                     ErrNonfatal("Undefined rotation value %d", ImageInfo.Orientation, 0);
522                     ImageInfo.Orientation = 0;
523                 }
524                 break;
525 
526             case TAG_EXIF_IMAGELENGTH:
527             case TAG_EXIF_IMAGEWIDTH:
528                 // Use largest of height and width to deal with images that have been
529                 // rotated to portrait format.
530                 a = (int)ConvertAnyFormat(ValuePtr, Format);
531                 if (ExifImageWidth < a) ExifImageWidth = a;
532                 break;
533 
534             case TAG_FOCALPLANEXRES:
535                 FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
536                 break;
537 
538             case TAG_FOCALPLANEUNITS:
539                 switch((int)ConvertAnyFormat(ValuePtr, Format)){
540                     case 1: FocalplaneUnits = 25.4; break; // inch
541                     case 2:
542                         // According to the information I was using, 2 means meters.
543                         // But looking at the Cannon powershot's files, inches is the only
544                         // sensible value.
545                         FocalplaneUnits = 25.4;
546                         break;
547 
548                     case 3: FocalplaneUnits = 10;   break;  // centimeter
549                     case 4: FocalplaneUnits = 1;    break;  // milimeter
550                     case 5: FocalplaneUnits = .001; break;  // micrometer
551                 }
552                 break;
553 
554                 // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
555 
556             case TAG_EXPOSURE_BIAS:
557                 ImageInfo.ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
558                 break;
559 
560             case TAG_WHITEBALANCE:
561                 ImageInfo.Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
562                 break;
563 
564             case TAG_METERING_MODE:
565                 ImageInfo.MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
566                 break;
567 
568             case TAG_EXPOSURE_PROGRAM:
569                 ImageInfo.ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
570                 break;
571 
572             case TAG_ISO_EQUIVALENT:
573                 ImageInfo.ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
574                 if ( ImageInfo.ISOequivalent < 50 ) ImageInfo.ISOequivalent *= 200;
575                 break;
576 
577             case TAG_COMPRESSION_LEVEL:
578                 ImageInfo.CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
579                 break;
580 
581             case TAG_THUMBNAIL_OFFSET:
582                 ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
583                 DirWithThumbnailPtrs = DirStart;
584                 break;
585 
586             case TAG_THUMBNAIL_LENGTH:
587                 ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
588                 break;
589 
590             case TAG_EXIF_OFFSET:
591             case TAG_INTEROP_OFFSET:
592                 {
593                     unsigned char * SubdirStart;
594                     SubdirStart = OffsetBase + Get32u(ValuePtr);
595                     if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength){
596                         ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
597                     }else{
598                         ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
599                     }
600                     continue;
601                 }
602         }
603     }
604 
605 
606     {
607         // In addition to linking to subdirectories via exif tags,
608         // there's also a potential link to another directory at the end of each
609         // directory.  this has got to be the result of a comitee!
610         unsigned char * SubdirStart;
611         unsigned Offset;
612 
613         if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
614             Offset = Get32u(DirStart+2+12*NumDirEntries);
615             if (Offset){
616                 SubdirStart = OffsetBase + Offset;
617                 if (SubdirStart > OffsetBase+ExifLength){
618                     if (SubdirStart < OffsetBase+ExifLength+20){
619                         // Jhead 1.3 or earlier would crop the whole directory!
620                         // As Jhead produces this form of format incorrectness,
621                         // I'll just let it pass silently
622                         if (ShowTags) printf("Thumbnail removed with Jhead 1.3 or earlier\n");
623                     }else{
624                         ErrNonfatal("Illegal subdirectory link",0,0);
625                     }
626                 }else{
627                     if (SubdirStart <= OffsetBase+ExifLength){
628                         ProcessExifDir(SubdirStart, OffsetBase, ExifLength);
629                     }
630                 }
631             }
632         }else{
633             // The exif header ends before the last next directory pointer.
634         }
635     }
636 
637 
638     if (ThumbnailSize && ThumbnailOffset){
639         if (ThumbnailSize + ThumbnailOffset <= ExifLength){
640             // The thumbnail pointer appears to be valid.  Store it.
641             ImageInfo.ThumbnailPointer = OffsetBase + ThumbnailOffset;
642             ImageInfo.ThumbnailSize = ThumbnailSize;
643 
644             if (ShowTags){
645                 printf("Thumbnail size: %d bytes\n",ThumbnailSize);
646             }
647         }
648     }
649 }
650 
651 //--------------------------------------------------------------------------
652 // Process a EXIF marker
653 // Describes all the drivel that most digital cameras include...
654 //--------------------------------------------------------------------------
process_EXIF(unsigned char * ExifSection,unsigned int length)655 void process_EXIF (unsigned char * ExifSection, unsigned int length)
656 {
657     ImageInfo.FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.
658 
659     FocalplaneXRes = 0;
660     FocalplaneUnits = 0;
661     ExifImageWidth = 0;
662 
663     if (ShowTags){
664         printf("Exif header %d bytes long\n",length);
665     }
666 
667     {   // Check the EXIF header component
668         static uchar ExifHeader[] = "Exif\0\0";
669         if (memcmp(ExifSection+2, ExifHeader,6)){
670             ErrNonfatal("Incorrect Exif header",0,0);
671             return;
672         }
673     }
674 
675     if (memcmp(ExifSection+8,"II",2) == 0){
676         if (ShowTags) printf("Exif section in Intel order\n");
677         MotorolaOrder = 0;
678     }else{
679         if (memcmp(ExifSection+8,"MM",2) == 0){
680             if (ShowTags) printf("Exif section in Motorola order\n");
681             MotorolaOrder = 1;
682         }else{
683             ErrNonfatal("Invalid Exif alignment marker.",0,0);
684             return;
685         }
686     }
687 
688     // Check the next two values for correctness.
689     if (Get16u(ExifSection+10) != 0x2a
690       || Get32u(ExifSection+12) != 0x08){
691         ErrNonfatal("Invalid Exif start (1)",0,0);
692         return;
693     }
694 
695     LastExifRefd = ExifSection;
696     DirWithThumbnailPtrs = NULL;
697 
698     // First directory starts 16 bytes in.  All offset are relative to 8 bytes in.
699     ProcessExifDir(ExifSection+16, ExifSection+8, length-6);
700 
701     // Compute the CCD width, in milimeters.
702     if (FocalplaneXRes != 0){
703         ImageInfo.CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
704     }
705 
706     if (ShowTags){
707         printf("Non settings part of Exif header: %ld bytes\n",
708                ExifSection+length-LastExifRefd);
709     }
710 }
711 
712 
713 
714 //--------------------------------------------------------------------------
715 // Remove thumbnail out of the exif image.
716 //--------------------------------------------------------------------------
RemoveThumbnail(unsigned char * ExifSection,unsigned int Length)717 int RemoveThumbnail(unsigned char * ExifSection, unsigned int Length)
718 {
719 
720     // Ensure pointers are up to date.
721     {
722         int ShowTagsTemp = ShowTags;
723         ShowTags = FALSE;
724         process_EXIF(ExifSection, Length);
725         ShowTags = ShowTagsTemp;
726     }
727 
728     if (DirWithThumbnailPtrs){
729         int de;
730         int NumDirEntries;
731         NumDirEntries = Get16u(DirWithThumbnailPtrs);
732 
733         for (de=0;de<NumDirEntries;de++){
734             int Tag;
735             char * DirEntry;
736             DirEntry = DIR_ENTRY_ADDR((char*)DirWithThumbnailPtrs, de);
737             Tag = Get16u(DirEntry);
738             if (Tag == TAG_THUMBNAIL_OFFSET || Tag == TAG_THUMBNAIL_LENGTH){
739                 // We remove data out of the exif directory by doing a memmove on the rest
740                 // of the directory to close the gap.
741                 // It would of course be far better to have a general purpose read/write
742                 // implementation of the filesystem in the exif header, but that would
743                 // be quite complicated and therefore very error prone.
744                 memmove(DirEntry,
745                         DIR_ENTRY_ADDR(DirWithThumbnailPtrs, de+1),
746                         (NumDirEntries-de-1)*12+4);
747                 NumDirEntries -= 1;
748                 de -= 1;
749             }
750         }
751         Put16u(DirWithThumbnailPtrs, (unsigned short)NumDirEntries);
752     }
753 
754     // This is how far the non thumbnail data went.
755     return LastExifRefd - ExifSection;
756 }
757 
758 
759 //--------------------------------------------------------------------------
760 // Convert exif time to Unix time structure
761 //--------------------------------------------------------------------------
Exif2tm(struct tm * timeptr,char * ExifTime)762 int Exif2tm(struct tm * timeptr, char * ExifTime)
763 {
764     int a;
765 
766     timeptr->tm_wday = -1;
767 
768     // Check for format: YYYY:MM:DD HH:MM:SS format.
769     a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d",
770             &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
771             &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
772 
773 
774     if (a == 6){
775         timeptr->tm_isdst = -1;
776         timeptr->tm_mon -= 1;      // Adjust for unix zero-based months
777         timeptr->tm_year -= 1900;  // Adjust for year starting at 1900
778         return TRUE; // worked.
779     }
780 
781     return FALSE; // Wasn't in Exif date format.
782 }
783 
784 // 1 - "The 0th row is at the visual top of the image,    and the 0th column is the visual left-hand side."
785 // 2 - "The 0th row is at the visual top of the image,    and the 0th column is the visual right-hand side."
786 // 3 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side."
787 // 4 - "The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side."
788 
789 // 5 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual top."
790 // 6 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual top."
791 // 7 - "The 0th row is the visual right-hand side of of the image, and the 0th column is the visual bottom."
792 // 8 - "The 0th row is the visual left-hand side of of the image,  and the 0th column is the visual bottom."
793 
794 // Note: The descriptions here are the same as the name of the command line
795 // ption to pass to jpegtran to right the image
796 char * OrientTab[9] = {
797     "Undefined",
798     "Normal",           // 1
799     "flip horizontal",  // left right reversed mirror
800     "rotate 180",       // 3
801     "flip vertical",    // upside down mirror
802     "transpose",        // Flipped about top-left <--> bottom-right axis.
803     "rotate 90",        // rotate 90 cw to right it.
804     "transverse",       // flipped about top-right <--> bottom-left axis
805     "rotate 270",       // rotate 270 to right it.
806 };
807 int OrientRot[9] = {
808     0, 0, 0, 180, 180, 180, 90, 180, 270
809 };
810 
811 #ifdef VERBOSE
812 //--------------------------------------------------------------------------
813 // Show the collected image info, displaying camera F-stop and shutter speed
814 // in a consistent and legible fashion.
815 //--------------------------------------------------------------------------
ShowImageInfo(void)816 void ShowImageInfo(void)
817 {
818     int a;
819     printf("File name    : %s\n",ImageInfo.FileName);
820     printf("File size    : %d bytes\n",ImageInfo.FileSize);
821 
822     {
823         char Temp[20];
824         struct tm ts;
825         ts = *localtime(&ImageInfo.FileDateTime);
826         strftime(Temp, 20, "%Y:%m:%d %H:%M:%S", &ts);
827         printf("File date    : %s\n",Temp);
828     }
829 
830     if (ImageInfo.CameraMake[0]){
831         printf("Camera make  : %s\n",ImageInfo.CameraMake);
832         printf("Camera model : %s\n",ImageInfo.CameraModel);
833     }
834     if (ImageInfo.DateTime[0]){
835         printf("Date/Time    : %s\n",ImageInfo.DateTime);
836     }
837     printf("Resolution   : %d x %d\n",ImageInfo.Width, ImageInfo.Height);
838 
839     if (ImageInfo.Orientation > 1){
840         // Only print orientation if one was supplied, and if its not 1 (normal orientation)
841 
842         printf("Orientation  : %s\n", OrientTab[ImageInfo.Orientation]);
843     }
844 
845     if (ImageInfo.IsColor == 0){
846         printf("Color/bw     : Black and white\n");
847     }
848     if (ImageInfo.FlashUsed >= 0){
849         printf("Flash used   : %s\n",ImageInfo.FlashUsed ? "Yes" :"No");
850     }
851     if (ImageInfo.FocalLength){
852         printf("Focal length : %4.1fmm",(double)ImageInfo.FocalLength);
853         if (ImageInfo.CCDWidth){
854             printf("  (35mm equivalent: %dmm)",
855                         (int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*36 + 0.5));
856         }
857         printf("\n");
858     }
859 
860     if (ImageInfo.CCDWidth){
861         printf("CCD width    : %4.2fmm\n",(double)ImageInfo.CCDWidth);
862     }
863 
864     if (ImageInfo.ExposureTime){
865         printf("Exposure time:%6.3f s ",(double)ImageInfo.ExposureTime);
866         if (ImageInfo.ExposureTime <= 0.5){
867             printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
868         }
869         printf("\n");
870     }
871     if (ImageInfo.ApertureFNumber){
872         printf("Aperture     : f/%3.1f\n",(double)ImageInfo.ApertureFNumber);
873     }
874     if (ImageInfo.Distance){
875         if (ImageInfo.Distance < 0){
876             printf("Focus dist.  : Infinite\n");
877         }else{
878             printf("Focus dist.  : %4.2fm\n",(double)ImageInfo.Distance);
879         }
880     }
881 
882 
883     if (ImageInfo.ISOequivalent){ // 05-jan-2001 vcs
884         printf("ISO equiv.   : %2d\n",(int)ImageInfo.ISOequivalent);
885     }
886     if (ImageInfo.ExposureBias){ // 05-jan-2001 vcs
887         printf("Exposure bias:%4.2f\n",(double)ImageInfo.ExposureBias);
888     }
889 
890     if (ImageInfo.Whitebalance){ // 05-jan-2001 vcs
891         switch(ImageInfo.Whitebalance) {
892         case 1:
893             printf("Whitebalance : sunny\n");
894             break;
895         case 2:
896             printf("Whitebalance : fluorescent\n");
897             break;
898         case 3:
899             printf("Whitebalance : incandescent\n");
900             break;
901         default:
902             printf("Whitebalance : cloudy\n");
903         }
904     }
905     if (ImageInfo.MeteringMode){ // 05-jan-2001 vcs
906         switch(ImageInfo.MeteringMode) {
907         case 2:
908             printf("Metering Mode: center weight\n");
909             break;
910         case 3:
911             printf("Metering Mode: spot\n");
912             break;
913         case 5:
914             printf("Metering Mode: matrix\n");
915             break;
916         }
917     }
918     if (ImageInfo.ExposureProgram){ // 05-jan-2001 vcs
919         switch(ImageInfo.ExposureProgram) {
920         case 2:
921             printf("Exposure     : program (auto)\n");
922             break;
923         case 3:
924             printf("Exposure     : aperture priority (semi-auto)\n");
925             break;
926         case 4:
927             printf("Exposure     : shutter priority (semi-auto)\n");
928             break;
929         }
930     }
931     if (ImageInfo.CompressionLevel){ // 05-jan-2001 vcs
932         switch(ImageInfo.CompressionLevel) {
933         case 1:
934             printf("Jpeg Quality : basic\n");
935             break;
936         case 2:
937             printf("Jpeg Quality : normal\n");
938             break;
939         case 4:
940             printf("Jpeg Quality : fine\n");
941             break;
942        }
943     }
944 
945 
946 
947     for (a=0;;a++){
948         if (ProcessTable[a].Tag == ImageInfo.Process || ProcessTable[a].Tag == 0){
949             printf("Jpeg process : %s\n",ProcessTable[a].Desc);
950             break;
951         }
952     }
953 
954 
955 
956     // Print the comment. Print 'Comment:' for each new line of comment.
957     if (ImageInfo.Comments[0]){
958         int a,c;
959         printf("Comment      : ");
960         for (a=0;a<MAX_COMMENT;a++){
961             c = ImageInfo.Comments[a];
962             if (c == '\0') break;
963             if (c == '\n'){
964                 // Do not start a new line if the string ends with a carriage return.
965                 if (ImageInfo.Comments[a+1] != '\0'){
966                     printf("\nComment      : ");
967                 }else{
968                     printf("\n");
969                 }
970             }else{
971                 putchar(c);
972             }
973         }
974     }
975 
976     printf("\n");
977 }
978 
979 
980 //--------------------------------------------------------------------------
981 // Summarize highlights of image info on one line (suitable for grep-ing)
982 //--------------------------------------------------------------------------
ShowConciseImageInfo(void)983 void ShowConciseImageInfo(void)
984 {
985     printf("\"%s\"",ImageInfo.FileName);
986 
987     printf(" %dx%d",ImageInfo.Width, ImageInfo.Height);
988 
989     if (ImageInfo.ExposureTime){
990         printf(" (1/%d)",(int)(0.5 + 1/ImageInfo.ExposureTime));
991     }
992 
993     if (ImageInfo.ApertureFNumber){
994         printf(" f/%3.1f",(double)ImageInfo.ApertureFNumber);
995     }
996 
997     if (ImageInfo.FocalLength){
998         if (ImageInfo.CCDWidth){
999             // 35 mm equivalent focal length.
1000             printf(" f(35)=%dmm",(int)(ImageInfo.FocalLength/ImageInfo.CCDWidth*35 + 0.5));
1001         }
1002     }
1003 
1004     if (ImageInfo.FlashUsed > 0){
1005         printf(" (flash)");
1006     }
1007 
1008     if (ImageInfo.IsColor == 0){
1009         printf(" (bw)");
1010     }
1011 
1012     printf("\n");
1013 }
1014 #endif /* VERBOSE */
1015