Merge pull request #4852 from FernetMenta/aefixes
[vuplus_xbmc] / lib / libexif / ExifParse.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with GNU Make; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 //--------------------------------------------------------------------------
23 // Program to pull the EXIF information out of various types of digital
24 // images and present it in a reasonably consistent way
25 //
26 // Original code pulled from 'jhead' by Matthias Wandel (http://www.sentex.net/~mwandel/) - jhead
27 // Adapted for XBMC by DD.
28 //--------------------------------------------------------------------------
29
30 // Note: Jhead supports TAG_MAKER_NOTE exif field,
31 //       but that is ommited for now - to make porting easier and addition smaller
32 #ifndef _LINUX
33 #include <windows.h>
34 #else
35 #include <memory.h>
36 #include <cstring>
37 #define min(a,b) (a)>(b)?(b):(a)
38 #define max(a,b) (a)<(b)?(b):(a)
39 #endif
40 #include <math.h>
41 #include <stdio.h>
42 #include "ExifParse.h"
43
44
45 // Prototypes for exif utility functions.
46 static void ErrNonfatal(const char* const msg, int a1, int a2);
47
48 #define DIR_ENTRY_ADDR(Start, Entry) ((Start)+2+12*(Entry))
49
50
51 //--------------------------------------------------------------------------
52 // Describes tag values
53 #define TAG_DESCRIPTION        0x010E
54 #define TAG_MAKE               0x010F
55 #define TAG_MODEL              0x0110
56 #define TAG_ORIENTATION        0x0112
57 #define TAG_X_RESOLUTION       0x011A           // Not processed. Format rational64u (see http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.76/html/TagNames/EXIF.html)
58 #define TAG_Y_RESOLUTION       0x011B           // Not processed. Format rational64u
59 #define TAG_RESOLUTION_UNIT    0x0128           // Not processed. Format int16u. Values: 1-none; 2-inches; 3-cm
60 #define TAG_SOFTWARE           0x0131
61 #define TAG_DATETIME           0x0132
62 #define TAG_THUMBNAIL_OFFSET   0x0201
63 #define TAG_THUMBNAIL_LENGTH   0x0202
64 #define TAG_Y_CB_CR_POS        0x0213           // Not processed. Format int16u. Values: 1-Centered; 2-Co-sited
65 #define TAG_EXPOSURETIME       0x829A
66 #define TAG_FNUMBER            0x829D
67 #define TAG_EXIF_OFFSET        0x8769
68 #define TAG_EXPOSURE_PROGRAM   0x8822
69 #define TAG_GPSINFO            0x8825
70 #define TAG_ISO_EQUIVALENT     0x8827
71 #define TAG_EXIF_VERSION       0x9000           // Not processed.
72 #define TAG_COMPONENT_CFG      0x9101           // Not processed.
73 #define TAG_DATETIME_ORIGINAL  0x9003
74 #define TAG_DATETIME_DIGITIZED 0x9004
75 #define TAG_SHUTTERSPEED       0x9201
76 #define TAG_APERTURE           0x9202
77 #define TAG_EXPOSURE_BIAS      0x9204
78 #define TAG_MAXAPERTURE        0x9205
79 #define TAG_SUBJECT_DISTANCE   0x9206
80 #define TAG_METERING_MODE      0x9207
81 #define TAG_LIGHT_SOURCE       0x9208
82 #define TAG_FLASH              0x9209
83 #define TAG_FOCALLENGTH        0x920A
84 #define TAG_MAKER_NOTE         0x927C           // Not processed yet. Maybe in the future.
85 #define TAG_USERCOMMENT        0x9286
86 #define TAG_FLASHPIX_VERSION   0xA000           // Not processed.
87 #define TAG_COLOUR_SPACE       0xA001           // Not processed. Format int16u. Values: 1-RGB; 2-Adobe RGB 65535-Uncalibrated
88 #define TAG_EXIF_IMAGEWIDTH    0xa002
89 #define TAG_EXIF_IMAGELENGTH   0xa003
90 #define TAG_INTEROP_OFFSET     0xa005
91 #define TAG_FOCALPLANEXRES     0xa20E
92 #define TAG_FOCALPLANEUNITS    0xa210
93 #define TAG_EXPOSURE_INDEX     0xa215
94 #define TAG_EXPOSURE_MODE      0xa402
95 #define TAG_WHITEBALANCE       0xa403
96 #define TAG_DIGITALZOOMRATIO   0xA404
97 #define TAG_FOCALLENGTH_35MM   0xa405
98
99 #define TAG_GPS_LAT_REF        1
100 #define TAG_GPS_LAT            2
101 #define TAG_GPS_LONG_REF       3
102 #define TAG_GPS_LONG           4
103 #define TAG_GPS_ALT_REF        5
104 #define TAG_GPS_ALT            6
105
106 //--------------------------------------------------------------------------
107 // Exif format descriptor stuff
108 #define FMT_BYTE       1
109 #define FMT_STRING     2
110 #define FMT_USHORT     3
111 #define FMT_ULONG      4
112 #define FMT_URATIONAL  5
113 #define FMT_SBYTE      6
114 #define FMT_UNDEFINED  7
115 #define FMT_SSHORT     8
116 #define FMT_SLONG      9
117 #define FMT_SRATIONAL 10
118 #define FMT_SINGLE    11
119 #define FMT_DOUBLE    12
120 // NOTE: Remember to change NUM_FORMATS if you define a new format
121 #define NUM_FORMATS   12
122
123 //--------------------------------------------------------------------------
124 // Internationalisation string IDs. The enum order must match that in the
125 // language file (e.g. 'language/English/strings.xml', and EXIF_PARSE_STRING_ID_BASE
126 // must match the ID of the first Exif string in that file.
127 #define EXIF_PARSE_STRING_ID_BASE       21800
128 enum {
129 // Distance
130   ExifStrDistanceInfinite = EXIF_PARSE_STRING_ID_BASE,
131 // Whitebalance et.al.
132   ExifStrManual,
133   ExifStrAuto,
134 // Flash modes
135   ExifStrYes,
136   ExifStrNo,
137   ExifStrFlashNoStrobe,
138   ExifStrFlashStrobe,
139   ExifStrFlashManual,
140   ExifStrFlashManualNoReturn,
141   ExifStrFlashManualReturn,
142   ExifStrFlashAuto,
143   ExifStrFlashAutoNoReturn,
144   ExifStrFlashAutoReturn,
145   ExifStrFlashRedEye,
146   ExifStrFlashRedEyeNoReturn,
147   ExifStrFlashRedEyeReturn,
148   ExifStrFlashManualRedEye,
149   ExifStrFlashManualRedEyeNoReturn,
150   ExifStrFlashManualRedEyeReturn,
151   ExifStrFlashAutoRedEye,
152   ExifStrFlashAutoRedEyeNoReturn,
153   ExifStrFlashAutoRedEyeReturn,
154 // Light sources
155   ExifStrDaylight,
156   ExifStrFluorescent,
157   ExifStrIncandescent,
158   ExifStrFlash,
159   ExifStrFineWeather,
160   ExifStrShade,
161 // Metering Mode
162   ExifStrMeteringCenter,
163   ExifStrMeteringSpot,
164   ExifStrMeteringMatrix,
165 // Exposure Program
166   ExifStrExposureProgram,
167   ExifStrExposureAperture,
168   ExifStrExposureShutter,
169   ExifStrExposureCreative,
170   ExifStrExposureAction,
171   ExifStrExposurePortrait,
172   ExifStrExposureLandscape,
173 // Exposure mode
174   ExifStrExposureModeAuto,
175 // ISO equivalent
176   ExifStrIsoEquivalent,
177 // GPS latitude, longitude, altitude
178   ExifStrGpsLatitude,
179   ExifStrGpsLongitude,
180   ExifStrGpsAltitude,
181 };
182
183
184
185
186 //--------------------------------------------------------------------------
187 // Report non fatal errors.  Now that microsoft.net modifies exif headers,
188 // there's corrupted ones, and there could be more in the future.
189 //--------------------------------------------------------------------------
190 static void ErrNonfatal(const char* const msg, int a1, int a2)
191 {
192   printf("ExifParse - Nonfatal Error : %s %d %d", msg, a1, a2);
193 }
194
195 //--------------------------------------------------------------------------
196 // Constructor.
197 //--------------------------------------------------------------------------
198 CExifParse::CExifParse () : m_FocalPlaneXRes(0.0),
199         m_FocalPlaneUnits(0.0), m_ExifImageWidth(0), m_MotorolaOrder(false),
200         m_DateFound(false)
201 {
202   m_ExifInfo = NULL;
203 }
204
205 //--------------------------------------------------------------------------
206 // Convert a 16 bit unsigned value from file's native byte order
207 //--------------------------------------------------------------------------
208 int CExifParse::Get16(const void* const Short, const bool motorolaOrder)
209 {
210     if (motorolaOrder) {
211         return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
212     } else {
213         return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
214     }
215 }
216
217 //--------------------------------------------------------------------------
218 // Convert a 32 bit signed value from file's native byte order
219 //--------------------------------------------------------------------------
220 int CExifParse::Get32(const void* const Long, const bool motorolaOrder)
221 {
222     if (motorolaOrder) {
223         return  ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
224           | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
225     } else {
226         return  ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
227           | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
228     }
229 }
230
231 //--------------------------------------------------------------------------
232 // It appears that CStdString constructor replaces "\n" with "\r\n" which results
233 // in "\r\r\n" if there already is "\r\n", which in turn results in corrupted
234 // display. So this is an attempt to undo effects of a smart constructor. Also,
235 // replaces all nonprintable characters with "."
236 //--------------------------------------------------------------------------
237 /*void CExifParse::FixComment(CStdString& comment)
238 {
239   comment.Replace("\r\r\n", "\r\n");
240   for (unsigned int i=0; i<comment.length(); i++)
241   {
242     if ((comment[i] < 32) && (comment[i] != '\n') && (comment[i] != '\t') && (comment[i] != '\r'))
243     {
244       comment[i] = '.';
245     }
246   }
247 }*/
248
249 //--------------------------------------------------------------------------
250 // Evaluate number, be it int, rational, or float from directory.
251 //--------------------------------------------------------------------------
252 double CExifParse::ConvertAnyFormat(const void* const ValuePtr, int Format)
253 {
254   double Value;
255   Value = 0;
256
257   switch(Format)
258   {
259     case FMT_SBYTE:     Value = *(  signed char*)ValuePtr;          break;
260     case FMT_BYTE:      Value = *(unsigned char*)ValuePtr;          break;
261
262     case FMT_USHORT:    Value = Get16(ValuePtr, m_MotorolaOrder);   break;
263     case FMT_ULONG:     Value = (unsigned)Get32(ValuePtr, m_MotorolaOrder);   break;
264
265     case FMT_URATIONAL:
266     case FMT_SRATIONAL:
267     {
268       int Num,Den;
269       Num = Get32(ValuePtr, m_MotorolaOrder);
270       Den = Get32(4+(char *)ValuePtr, m_MotorolaOrder);
271
272       if (Den == 0)    Value = 0;
273       else             Value = (double)Num/Den;
274     }
275     break;
276
277     case FMT_SSHORT:    Value = (signed short)Get16(ValuePtr, m_MotorolaOrder);    break;
278     case FMT_SLONG:     Value = Get32(ValuePtr, m_MotorolaOrder);                  break;
279
280     // Not sure if this is correct (never seen float used in Exif format)
281     case FMT_SINGLE:    Value = (double)*(float*)ValuePtr;          break;
282     case FMT_DOUBLE:    Value = *(double*)ValuePtr;                 break;
283
284     default:
285       ErrNonfatal("Illegal format code %d",Format,0);
286   }
287   return Value;
288 }
289
290 //--------------------------------------------------------------------------
291 // Exif date tag is stored as a fixed format string "YYYY:MM:DD HH:MM:SS".
292 // If date is not set, then the string is filled with blanks and colons:
293 // "    :  :     :  :  ". We want this string localised.
294 //--------------------------------------------------------------------------
295 /*void CExifParse::LocaliseDate (void)
296 {
297     if (m_ExifInfo[SLIDE_EXIF_DATE_TIME][0] != ' ')
298     {
299         int year  = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(0, 4).c_str());
300         int month = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(5, 2).c_str());
301         int day   = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(8, 2).c_str());
302         int hour  = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(11,2).c_str());
303         int min   = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(14,2).c_str());
304         int sec   = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(17,2).c_str());
305         CDateTime date(year, month, day, hour, min, sec);
306         m_ExifInfo[SLIDE_EXIF_DATE_TIME] = date.GetAsLocalizedDateTime();
307     }
308 }*/
309
310
311 //--------------------------------------------------------------------------
312 // Convert exposure time into a human readable format
313 //--------------------------------------------------------------------------
314 /*void CExifParse::GetExposureTime(const float exposureTime, CStdString& outStr)
315 {
316   if (exposureTime)
317   {
318     if (exposureTime < 0.010)   outStr.Format("%6.4fs ", exposureTime);
319     else                        outStr.Format("%5.3fs ", exposureTime);
320     if (exposureTime <= 0.5)    outStr.Format("%s (1/%d)", outStr, (int)(0.5 + 1/exposureTime));
321   }
322 }*/
323
324 //--------------------------------------------------------------------------
325 // Process one of the nested EXIF directories.
326 //--------------------------------------------------------------------------
327 void CExifParse::ProcessDir(const unsigned char* const DirStart,
328                             const unsigned char* const OffsetBase,
329                             const unsigned ExifLength,
330                             int NestingLevel)
331 {
332   if (NestingLevel > 4)
333   {
334     ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
335     return;
336   }
337
338   char IndentString[25];
339   memset(IndentString, ' ', 25);
340   IndentString[NestingLevel * 4] = '\0';
341
342
343   int NumDirEntries = Get16((void*)DirStart, m_MotorolaOrder);
344
345   const unsigned char* const DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
346   if (DirEnd+4 > (OffsetBase+ExifLength))
347   {
348     if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength)
349     {
350       // Version 1.3 of jhead would truncate a bit too much.
351       // This also caught later on as well.
352     }
353     else
354     {
355       ErrNonfatal("Illegally sized directory", 0,0);
356       return;
357     }
358   }
359
360   const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
361
362
363   for (int de=0;de<NumDirEntries;de++)
364   {
365     int Tag, Format, Components;
366     unsigned char* ValuePtr;
367     int ByteCount;
368     const unsigned char* const DirEntry = DIR_ENTRY_ADDR(DirStart, de);
369
370     Tag = Get16(DirEntry, m_MotorolaOrder);
371     Format = Get16(DirEntry+2, m_MotorolaOrder);
372     Components = Get32(DirEntry+4, m_MotorolaOrder);
373
374     if ((Format-1) >= NUM_FORMATS)
375     {
376       // (-1) catches illegal zero case as unsigned underflows to positive large.
377       ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
378       continue;
379     }
380
381     if ((unsigned)Components > 0x10000)
382     {
383       ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
384       continue;
385     }
386
387     ByteCount = Components * BytesPerFormat[Format];
388
389     if (ByteCount > 4)
390     {
391       unsigned OffsetVal;
392       OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder);
393       // If its bigger than 4 bytes, the dir entry contains an offset.
394       if (OffsetVal+ByteCount > ExifLength)
395       {
396         // Bogus pointer offset and / or bytecount value
397         ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
398         continue;
399       }
400       ValuePtr = (unsigned char*)(OffsetBase+OffsetVal);
401
402       if (OffsetVal > m_LargestExifOffset)
403       {
404         m_LargestExifOffset = OffsetVal;
405       }
406
407     }
408     else {
409       // 4 bytes or less and value is in the dir entry itself
410       ValuePtr = (unsigned char*)(DirEntry+8);
411     }
412
413
414     // Extract useful components of tag
415     switch(Tag)
416     {
417       case TAG_DESCRIPTION:
418       {
419         int length = max(ByteCount, 0);
420         length = min(length, MAX_COMMENT);
421         strncpy(m_ExifInfo->Description, (char *)ValuePtr, length);
422         break;
423       }
424       case TAG_MAKE:              strncpy(m_ExifInfo->CameraMake, (char *)ValuePtr, 32);    break;
425       case TAG_MODEL:             strncpy(m_ExifInfo->CameraModel, (char *)ValuePtr, 40);    break;
426 //      case TAG_SOFTWARE:          strncpy(m_ExifInfo->Software, ValuePtr, 5);    break;
427       case TAG_FOCALPLANEXRES:    m_FocalPlaneXRes  = ConvertAnyFormat(ValuePtr, Format);               break;
428       case TAG_THUMBNAIL_OFFSET:  m_ExifInfo->ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);     break;
429       case TAG_THUMBNAIL_LENGTH:  m_ExifInfo->ThumbnailSize   = (unsigned)ConvertAnyFormat(ValuePtr, Format);     break;
430
431       case TAG_MAKER_NOTE:
432         continue;
433       break;
434
435       case TAG_DATETIME_ORIGINAL:
436         // If we get a DATETIME_ORIGINAL, we use that one.
437         strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20);
438         m_DateFound = true;
439       break;
440
441       case TAG_DATETIME_DIGITIZED:
442       case TAG_DATETIME:
443         if (m_DateFound == false)
444         {
445           // If we don't already have a DATETIME_ORIGINAL, use whatever
446           // time fields we may have.
447           strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20);
448 //          LocaliseDate();
449         }
450       break;
451
452       case TAG_USERCOMMENT:
453       {
454         // The UserComment allows comments without the charset limitations of ImageDescription.
455         // Therefore the UserComment field is prefixed by a CharacterCode field (8 Byte):
456         //  - ASCII:         'ASCII\0\0\0'
457         //  - Unicode:       'UNICODE\0'
458         //  - JIS X208-1990: 'JIS\0\0\0\0\0'
459         //  - Unknown:       '\0\0\0\0\0\0\0\0' (application specific)
460
461         m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNKNOWN;
462
463         const int EXIF_COMMENT_CHARSET_LENGTH = 8;
464         if (ByteCount >= EXIF_COMMENT_CHARSET_LENGTH)
465         {
466           // As some implementations use spaces instead of \0 for the padding,
467           // we're not so strict and check only the prefix.
468           if (memcmp(ValuePtr, "ASCII", 5) == 0)
469             m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_ASCII;
470           else if (memcmp(ValuePtr, "UNICODE", 7) == 0)
471             m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_UNICODE;
472           else if (memcmp(ValuePtr, "JIS", 3) == 0)
473             m_ExifInfo->CommentsCharset = EXIF_COMMENT_CHARSET_JIS;
474
475           int length = ByteCount - EXIF_COMMENT_CHARSET_LENGTH;
476           length = min(length, MAX_COMMENT);
477           memcpy(m_ExifInfo->Comments, ValuePtr + EXIF_COMMENT_CHARSET_LENGTH, length);
478 //          FixComment(comment);                          // Ensure comment is printable
479         }
480       }
481       break;
482
483       case TAG_FNUMBER:
484         // Simplest way of expressing aperture, so I trust it the most.
485         // (overwrite previously computd value if there is one)
486         m_ExifInfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
487       break;
488
489       case TAG_APERTURE:
490       case TAG_MAXAPERTURE:
491         // More relevant info always comes earlier, so only use this field if we don't
492         // have appropriate aperture information yet.
493         if (m_ExifInfo->ApertureFNumber == 0)
494         {
495           m_ExifInfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
496         }
497       break;
498
499       case TAG_FOCALLENGTH:
500         // Nice digital cameras actually save the focal length as a function
501         // of how far they are zoomed in.
502         m_ExifInfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
503       break;
504
505       case TAG_SUBJECT_DISTANCE:
506         // Inidcates the distacne the autofocus camera is focused to.
507         // Tends to be less accurate as distance increases.
508         {
509           float distance = (float)ConvertAnyFormat(ValuePtr, Format);
510           if (distance < 0)
511             m_ExifInfo->Distance = distance; // infinite
512           else             
513             m_ExifInfo->Distance = distance;
514         }
515       break;
516
517       case TAG_EXPOSURETIME:
518         {
519         // Simplest way of expressing exposure time, so I trust it most.
520         // (overwrite previously computd value if there is one)
521         float expTime = (float)ConvertAnyFormat(ValuePtr, Format);
522         if (expTime)
523           m_ExifInfo->ExposureTime = expTime;
524         }
525       break;
526
527       case TAG_SHUTTERSPEED:
528         // More complicated way of expressing exposure time, so only use
529         // this value if we don't already have it from somewhere else.
530         if (m_ExifInfo->ExposureTime == 0)
531         {
532           m_ExifInfo->ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
533         }
534       break;
535
536       case TAG_FLASH:
537         m_ExifInfo->FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format);
538       break;
539
540       case TAG_ORIENTATION:
541         m_ExifInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
542         if (m_ExifInfo->Orientation < 0 || m_ExifInfo->Orientation > 8)
543         {
544           ErrNonfatal("Undefined rotation value %d", m_ExifInfo->Orientation, 0);
545           m_ExifInfo->Orientation = 0;
546         }
547       break;
548
549       case TAG_EXIF_IMAGELENGTH:
550       case TAG_EXIF_IMAGEWIDTH:
551         // Use largest of height and width to deal with images that have been
552         // rotated to portrait format.
553         {
554           int a = (int)ConvertAnyFormat(ValuePtr, Format);
555           if (m_ExifImageWidth < a) m_ExifImageWidth = a;
556         }
557       break;
558
559       case TAG_FOCALPLANEUNITS:
560         switch((int)ConvertAnyFormat(ValuePtr, Format))
561         {
562           // According to the information I was using, 2 means meters.
563           // But looking at the Cannon powershot's files, inches is the only
564           // sensible value.
565           case 1: m_FocalPlaneUnits = 25.4; break;  // inch
566           case 2: m_FocalPlaneUnits = 25.4; break;
567           case 3: m_FocalPlaneUnits = 10;   break;  // centimeter
568           case 4: m_FocalPlaneUnits = 1;    break;  // millimeter
569           case 5: m_FocalPlaneUnits = .001; break;  // micrometer
570         }
571       break;
572
573       case TAG_EXPOSURE_BIAS:
574         m_ExifInfo->ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
575       break;
576
577       case TAG_WHITEBALANCE:
578         m_ExifInfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
579       break;
580
581       case TAG_LIGHT_SOURCE:
582         //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both
583         m_ExifInfo->LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
584       break;
585
586       case TAG_METERING_MODE:
587         m_ExifInfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
588       break;
589
590       case TAG_EXPOSURE_PROGRAM:
591         m_ExifInfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
592       break;
593
594       case TAG_EXPOSURE_INDEX:
595         if (m_ExifInfo->ISOequivalent == 0)
596         {
597           // Exposure index and ISO equivalent are often used interchangeably,
598           // so we will do the same.
599           // http://photography.about.com/library/glossary/bldef_ei.htm
600           m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
601         }
602       break;
603
604       case TAG_ISO_EQUIVALENT:
605         m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
606         if (m_ExifInfo->ISOequivalent < 50)
607           m_ExifInfo->ISOequivalent *= 200;          // Fixes strange encoding on some older digicams.
608       break;
609
610       case TAG_EXPOSURE_MODE:
611         m_ExifInfo->ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
612       break;
613
614       case TAG_DIGITALZOOMRATIO:
615         m_ExifInfo->DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
616       break;
617
618       case TAG_EXIF_OFFSET:
619       case TAG_INTEROP_OFFSET:
620       {
621         const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder);
622         if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
623         {
624           ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
625         }
626         else
627         {
628           ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
629         }
630         continue;
631       }
632       break;
633
634       case TAG_GPSINFO:
635       {
636         const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder);
637         if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
638         {
639           ErrNonfatal("Illegal GPS directory link",0,0);
640         }
641         else
642         {
643           ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
644         }
645         continue;
646       }
647       break;
648
649       case TAG_FOCALLENGTH_35MM:
650         // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002)
651         // if its present, use it to compute equivalent focal length instead of
652         // computing it from sensor geometry and actual focal length.
653         m_ExifInfo->FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
654       break;
655     }
656   }
657
658
659   // In addition to linking to subdirectories via exif tags,
660   // there's also a potential link to another directory at the end of each
661   // directory.  this has got to be the result of a committee!
662   unsigned Offset;
663
664   if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength)
665   {
666     Offset = (unsigned)Get32(DirStart+2+12*NumDirEntries, m_MotorolaOrder);
667     if (Offset)
668     {
669       const unsigned char* const SubdirStart = OffsetBase + Offset;
670       if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase)
671       {
672         if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20)
673         {
674           // Jhead 1.3 or earlier would crop the whole directory!
675           // As Jhead produces this form of format incorrectness,
676           // I'll just let it pass silently
677         }
678         else
679         {
680           ErrNonfatal("Illegal subdirectory link",0,0);
681         }
682       }
683       else
684       {
685         if (SubdirStart <= OffsetBase+ExifLength)
686         {
687           ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
688         }
689       }
690       if (Offset > m_LargestExifOffset)
691       {
692         m_LargestExifOffset = Offset;
693       }
694     }
695   }
696   else
697   {
698     // The exif header ends before the last next directory pointer.
699   }
700
701   if (m_ExifInfo->ThumbnailOffset)
702   {
703     m_ExifInfo->ThumbnailAtEnd = false;
704
705     if (m_ExifInfo->ThumbnailOffset <= ExifLength)
706     {
707       if (m_ExifInfo->ThumbnailSize > ExifLength - m_ExifInfo->ThumbnailOffset)
708       {
709         // If thumbnail extends past exif header, only save the part that
710         // actually exists.  Canon's EOS viewer utility will do this - the
711         // thumbnail extracts ok with this hack.
712         m_ExifInfo->ThumbnailSize = ExifLength - m_ExifInfo->ThumbnailOffset;
713       }
714     }
715   }
716 }
717
718
719 //--------------------------------------------------------------------------
720 // Process a EXIF marker
721 // Describes all the drivel that most digital cameras include...
722 //--------------------------------------------------------------------------
723 bool CExifParse::Process (const unsigned char* const ExifSection, const unsigned short length, ExifInfo_t *info)
724 {
725   m_ExifInfo = info;
726   // EXIF signature: "Exif\0\0"
727   // Check EXIF signatures
728   const char ExifHeader[]     = "Exif\0\0";
729   const char ExifAlignment0[] = "II";
730   const char ExifAlignment1[] = "MM";
731   const char ExifExtra        = 0x2a;
732
733   char* pos = (char*)(ExifSection + sizeof(short));   // position data pointer after length field
734
735   if (memcmp(pos, ExifHeader,6))
736   {
737     printf("ExifParse: incorrect Exif header");
738     return false;
739   }
740   pos += 6;
741
742   if (memcmp(pos, ExifAlignment0, strlen(ExifAlignment0)) == 0)
743   {
744     m_MotorolaOrder = false;
745   }
746   else if (memcmp(pos, ExifAlignment1, strlen(ExifAlignment1)) == 0)
747   {
748     m_MotorolaOrder = true;
749   }
750   else
751   {
752     printf("ExifParse: invalid Exif alignment marker");
753     return false;
754   }
755   pos += strlen(ExifAlignment0);
756
757   // Check the next value for correctness.
758   if (Get16((void*)(pos), m_MotorolaOrder) != ExifExtra)
759   {
760     printf("ExifParse: invalid Exif start (1)");
761     return false;
762   }
763   pos += sizeof(short);
764
765   unsigned long FirstOffset = (unsigned)Get32((void*)pos, m_MotorolaOrder);
766   if (FirstOffset < 8 || FirstOffset > 16)
767   {
768     // Usually set to 8, but other values valid too.
769 //  CLog::Log(LOGERROR, "ExifParse: suspicious offset of first IFD value");
770   }
771
772
773
774   // First directory starts 16 bytes in.  All offset are relative to 8 bytes in.
775   ProcessDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0);
776
777   m_ExifInfo->ThumbnailAtEnd = m_ExifInfo->ThumbnailOffset >= m_LargestExifOffset ? true : false;
778
779   // Compute the CCD width, in millimeters.
780   if (m_FocalPlaneXRes != 0)
781   {
782     // Note: With some cameras, its not possible to compute this correctly because
783     // they don't adjust the indicated focal plane resolution units when using less
784     // than maximum resolution, so the CCDWidth value comes out too small.  Nothing
785     // that Jhead can do about it - its a camera problem.
786     m_ExifInfo->CCDWidth = (float)(m_ExifImageWidth * m_FocalPlaneUnits / m_FocalPlaneXRes);
787   }
788
789   if (m_ExifInfo->FocalLength)
790   {
791     if (m_ExifInfo->FocalLength35mmEquiv == 0)
792     {
793       // Compute 35 mm equivalent focal length based on sensor geometry if we haven't
794       // already got it explicitly from a tag.
795       if (m_ExifInfo->CCDWidth != 0.0)
796       {
797         m_ExifInfo->FocalLength35mmEquiv = (int)(m_ExifInfo->FocalLength/m_ExifInfo->CCDWidth*36 + 0.5);
798       }
799     }
800   }
801   return true;
802 }
803
804
805
806 //--------------------------------------------------------------------------
807 // GPS Lat/Long extraction helper function
808 //--------------------------------------------------------------------------
809 void CExifParse::GetLatLong(
810         const unsigned int Format,
811         const unsigned char* ValuePtr,
812         const int ComponentSize,
813         char *latLongString)
814 {
815   if (Format != FMT_URATIONAL)
816   {
817     ErrNonfatal("Illegal number format %d for GPS Lat/Long", Format, 0);
818   }
819   else
820   {
821     double Values[3];
822     for (unsigned a=0; a<3 ;a++)
823     {
824       Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format);
825     }
826     char latLong[30];
827     sprintf(latLong, "%3.0fd %2.0f' %5.2f\"", Values[0], Values[1], Values[2]);
828     strcat(latLongString, latLong);
829   }
830 }
831
832 //--------------------------------------------------------------------------
833 // Process GPS info directory
834 //--------------------------------------------------------------------------
835 void CExifParse::ProcessGpsInfo(
836                     const unsigned char* const DirStart,
837                     int ByteCountUnused,
838                     const unsigned char* const OffsetBase,
839                     unsigned ExifLength)
840 {
841   int NumDirEntries = Get16(DirStart, m_MotorolaOrder);
842
843   for (int de=0;de<NumDirEntries;de++)
844   {
845     const unsigned char* DirEntry = DIR_ENTRY_ADDR(DirStart, de);
846
847     unsigned Tag        = Get16(DirEntry, m_MotorolaOrder);
848     unsigned Format     = Get16(DirEntry+2, m_MotorolaOrder);
849     unsigned Components = (unsigned)Get32(DirEntry+4, m_MotorolaOrder);
850     if ((Format-1) >= NUM_FORMATS)
851     {
852       // (-1) catches illegal zero case as unsigned underflows to positive large.
853       ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
854       continue;
855     }
856
857     const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
858     int ComponentSize  = BytesPerFormat[Format];
859     unsigned ByteCount = Components * ComponentSize;
860
861     const unsigned char* ValuePtr;
862
863     if (ByteCount > 4)
864     {
865       unsigned OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder);
866       // If its bigger than 4 bytes, the dir entry contains an offset.
867       if (OffsetVal+ByteCount > ExifLength)
868       {
869         // Bogus pointer offset and / or bytecount value
870         ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
871         continue;
872       }
873       ValuePtr = OffsetBase+OffsetVal;
874     }
875     else
876     {
877       // 4 bytes or less and value is in the dir entry itself
878       ValuePtr = DirEntry+8;
879     }
880
881     switch(Tag)
882     {
883       case TAG_GPS_LAT_REF:
884         m_ExifInfo->GpsLat[0] = ValuePtr[0];
885         m_ExifInfo->GpsLat[1] = 0;
886       break;
887
888       case TAG_GPS_LONG_REF:
889         m_ExifInfo->GpsLong[0] = ValuePtr[0];
890         m_ExifInfo->GpsLong[1] = 0;
891       break;
892
893       case TAG_GPS_LAT:
894         GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLat);
895       break;
896       case TAG_GPS_LONG:
897         GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLong);
898       break;
899
900       case TAG_GPS_ALT_REF:
901         if (ValuePtr[0] != 0)
902           m_ExifInfo->GpsAlt[0] = '-';
903         m_ExifInfo->GpsAlt[1] = 0;
904       break;
905
906       case TAG_GPS_ALT:
907         {
908           char temp[18];
909           sprintf(temp,"%dm", Get32(ValuePtr, m_MotorolaOrder));
910           strcat(m_ExifInfo->GpsAlt, temp);
911         }
912       break;
913     }
914   }
915 }
916