aboutsummaryrefslogtreecommitdiff
path: root/lib/libexif
diff options
context:
space:
mode:
authortheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
committertheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
commitc51b1189e3d5353e842991f5859ddcea0f73e426 (patch)
treeef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/libexif
parentbe61ebdc9e897fe40c6f371111724de79ddee8d5 (diff)
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history. Conflicts: xbmc/Util.cpp xbmc/cdrip/CDDARipper.cpp xbmc/filesystem/Directory.cpp xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/libexif')
-rw-r--r--lib/libexif/ExifParse.cpp888
-rw-r--r--lib/libexif/ExifParse.h38
-rw-r--r--lib/libexif/IptcParse.cpp178
-rw-r--r--lib/libexif/IptcParse.h12
-rw-r--r--lib/libexif/JpegParse.cpp324
-rw-r--r--lib/libexif/JpegParse.h57
-rw-r--r--lib/libexif/Makefile.in20
-rw-r--r--lib/libexif/libexif.cpp42
-rw-r--r--lib/libexif/libexif.h126
-rw-r--r--lib/libexif/libexif.sln24
-rw-r--r--lib/libexif/libexif.vcproj303
-rw-r--r--lib/libexif/libexif.vcxproj174
-rw-r--r--lib/libexif/libexif.vcxproj.filters45
13 files changed, 2231 insertions, 0 deletions
diff --git a/lib/libexif/ExifParse.cpp b/lib/libexif/ExifParse.cpp
new file mode 100644
index 0000000000..41690df245
--- /dev/null
+++ b/lib/libexif/ExifParse.cpp
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2005-2007 Team XboxMediaCenter
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+//--------------------------------------------------------------------------
+// Program to pull the EXIF information out of various types of digital
+// images and present it in a reasonably consistent way
+//
+// Original code pulled from 'jhead' by Matthias Wandel (http://www.sentex.net/~mwandel/) - jhead
+// Adapted for XBMC by DD.
+//--------------------------------------------------------------------------
+
+// Note: Jhead supports TAG_MAKER_NOTE exif field,
+// but that is ommited for now - to make porting easier and addition smaller
+#ifndef _LINUX
+#include <windows.h>
+#else
+#include <memory.h>
+#define min(a,b) (a)>(b)?(b):(a)
+#define max(a,b) (a)<(b)?(b):(a)
+#endif
+#include <math.h>
+#include <stdio.h>
+#include "ExifParse.h"
+
+
+// Prototypes for exif utility functions.
+static void ErrNonfatal(const char* const msg, int a1, int a2);
+
+#define DIR_ENTRY_ADDR(Start, Entry) ((Start)+2+12*(Entry))
+
+
+//--------------------------------------------------------------------------
+// Describes tag values
+#define TAG_DESCRIPTION 0x010E
+#define TAG_MAKE 0x010F
+#define TAG_MODEL 0x0110
+#define TAG_ORIENTATION 0x0112
+#define TAG_X_RESOLUTION 0x011A // Not processed. Format rational64u (see http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.76/html/TagNames/EXIF.html)
+#define TAG_Y_RESOLUTION 0x011B // Not processed. Format rational64u
+#define TAG_RESOLUTION_UNIT 0x0128 // Not processed. Format int16u. Values: 1-none; 2-inches; 3-cm
+#define TAG_SOFTWARE 0x0131
+#define TAG_DATETIME 0x0132
+#define TAG_THUMBNAIL_OFFSET 0x0201
+#define TAG_THUMBNAIL_LENGTH 0x0202
+#define TAG_Y_CB_CR_POS 0x0213 // Not processed. Format int16u. Values: 1-Centered; 2-Co-sited
+#define TAG_EXPOSURETIME 0x829A
+#define TAG_FNUMBER 0x829D
+#define TAG_EXIF_OFFSET 0x8769
+#define TAG_EXPOSURE_PROGRAM 0x8822
+#define TAG_GPSINFO 0x8825
+#define TAG_ISO_EQUIVALENT 0x8827
+#define TAG_EXIF_VERSION 0x9000 // Not processed.
+#define TAG_COMPONENT_CFG 0x9101 // Not processed.
+#define TAG_DATETIME_ORIGINAL 0x9003
+#define TAG_DATETIME_DIGITIZED 0x9004
+#define TAG_SHUTTERSPEED 0x9201
+#define TAG_APERTURE 0x9202
+#define TAG_EXPOSURE_BIAS 0x9204
+#define TAG_MAXAPERTURE 0x9205
+#define TAG_SUBJECT_DISTANCE 0x9206
+#define TAG_METERING_MODE 0x9207
+#define TAG_LIGHT_SOURCE 0x9208
+#define TAG_FLASH 0x9209
+#define TAG_FOCALLENGTH 0x920A
+#define TAG_MAKER_NOTE 0x927C // Not processed yet. Maybe in the future.
+#define TAG_USERCOMMENT 0x9286
+#define TAG_FLASHPIX_VERSION 0xA000 // Not processed.
+#define TAG_COLOUR_SPACE 0xA001 // Not processed. Format int16u. Values: 1-RGB; 2-Adobe RGB 65535-Uncalibrated
+#define TAG_EXIF_IMAGEWIDTH 0xa002
+#define TAG_EXIF_IMAGELENGTH 0xa003
+#define TAG_INTEROP_OFFSET 0xa005
+#define TAG_FOCALPLANEXRES 0xa20E
+#define TAG_FOCALPLANEUNITS 0xa210
+#define TAG_EXPOSURE_INDEX 0xa215
+#define TAG_EXPOSURE_MODE 0xa402
+#define TAG_WHITEBALANCE 0xa403
+#define TAG_DIGITALZOOMRATIO 0xA404
+#define TAG_FOCALLENGTH_35MM 0xa405
+
+#define TAG_GPS_LAT_REF 1
+#define TAG_GPS_LAT 2
+#define TAG_GPS_LONG_REF 3
+#define TAG_GPS_LONG 4
+#define TAG_GPS_ALT_REF 5
+#define TAG_GPS_ALT 6
+
+//--------------------------------------------------------------------------
+// Exif format descriptor stuff
+#define FMT_BYTE 1
+#define FMT_STRING 2
+#define FMT_USHORT 3
+#define FMT_ULONG 4
+#define FMT_URATIONAL 5
+#define FMT_SBYTE 6
+#define FMT_UNDEFINED 7
+#define FMT_SSHORT 8
+#define FMT_SLONG 9
+#define FMT_SRATIONAL 10
+#define FMT_SINGLE 11
+#define FMT_DOUBLE 12
+// NOTE: Remember to change NUM_FORMATS if you define a new format
+#define NUM_FORMATS 12
+
+//--------------------------------------------------------------------------
+// Internationalisation string IDs. The enum order must match that in the
+// language file (e.g. 'language/English/strings.xml', and EXIF_PARSE_STRING_ID_BASE
+// must match the ID of the first Exif string in that file.
+#define EXIF_PARSE_STRING_ID_BASE 21800
+enum {
+// Distance
+ ExifStrDistanceInfinite = EXIF_PARSE_STRING_ID_BASE,
+// Whitebalance et.al.
+ ExifStrManual,
+ ExifStrAuto,
+// Flash modes
+ ExifStrYes,
+ ExifStrNo,
+ ExifStrFlashNoStrobe,
+ ExifStrFlashStrobe,
+ ExifStrFlashManual,
+ ExifStrFlashManualNoReturn,
+ ExifStrFlashManualReturn,
+ ExifStrFlashAuto,
+ ExifStrFlashAutoNoReturn,
+ ExifStrFlashAutoReturn,
+ ExifStrFlashRedEye,
+ ExifStrFlashRedEyeNoReturn,
+ ExifStrFlashRedEyeReturn,
+ ExifStrFlashManualRedEye,
+ ExifStrFlashManualRedEyeNoReturn,
+ ExifStrFlashManualRedEyeReturn,
+ ExifStrFlashAutoRedEye,
+ ExifStrFlashAutoRedEyeNoReturn,
+ ExifStrFlashAutoRedEyeReturn,
+// Light sources
+ ExifStrDaylight,
+ ExifStrFluorescent,
+ ExifStrIncandescent,
+ ExifStrFlash,
+ ExifStrFineWeather,
+ ExifStrShade,
+// Metering Mode
+ ExifStrMeteringCenter,
+ ExifStrMeteringSpot,
+ ExifStrMeteringMatrix,
+// Exposure Program
+ ExifStrExposureProgram,
+ ExifStrExposureAperture,
+ ExifStrExposureShutter,
+ ExifStrExposureCreative,
+ ExifStrExposureAction,
+ ExifStrExposurePortrait,
+ ExifStrExposureLandscape,
+// Exposure mode
+ ExifStrExposureModeAuto,
+// ISO equivalent
+ ExifStrIsoEquivalent,
+// GPS latitude, longitude, altitude
+ ExifStrGpsLatitude,
+ ExifStrGpsLongitude,
+ ExifStrGpsAltitude,
+};
+
+
+
+
+//--------------------------------------------------------------------------
+// Report non fatal errors. Now that microsoft.net modifies exif headers,
+// there's corrupted ones, and there could be more in the future.
+//--------------------------------------------------------------------------
+static void ErrNonfatal(const char* const msg, int a1, int a2)
+{
+ printf("ExifParse - Nonfatal Error : %s %d %d", msg, a1, a2);
+}
+
+//--------------------------------------------------------------------------
+// Constructor.
+//--------------------------------------------------------------------------
+CExifParse::CExifParse () : m_FocalPlaneXRes(0.0),
+ m_FocalPlaneUnits(0.0), m_ExifImageWidth(0), m_MotorolaOrder(false),
+ m_DateFound(false)
+{
+ m_ExifInfo = NULL;
+}
+
+//--------------------------------------------------------------------------
+// Convert a 16 bit unsigned value from file's native byte order
+//--------------------------------------------------------------------------
+int CExifParse::Get16(const void* const Short, const bool motorolaOrder)
+{
+ if (motorolaOrder) {
+ return (((unsigned char *)Short)[0] << 8) | ((unsigned char *)Short)[1];
+ } else {
+ return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Short)[0];
+ }
+}
+
+//--------------------------------------------------------------------------
+// Convert a 32 bit signed value from file's native byte order
+//--------------------------------------------------------------------------
+int CExifParse::Get32(const void* const Long, const bool motorolaOrder)
+{
+ if (motorolaOrder) {
+ return ((( char *)Long)[0] << 24) | (((unsigned char *)Long)[1] << 16)
+ | (((unsigned char *)Long)[2] << 8 ) | (((unsigned char *)Long)[3] << 0 );
+ } else {
+ return ((( char *)Long)[3] << 24) | (((unsigned char *)Long)[2] << 16)
+ | (((unsigned char *)Long)[1] << 8 ) | (((unsigned char *)Long)[0] << 0 );
+ }
+}
+
+//--------------------------------------------------------------------------
+// It appears that CStdString constructor replaces "\n" with "\r\n" which results
+// in "\r\r\n" if there already is "\r\n", which in turn results in corrupted
+// display. So this is an attempt to undo effects of a smart constructor. Also,
+// replaces all nonprintable characters with "."
+//--------------------------------------------------------------------------
+/*void CExifParse::FixComment(CStdString& comment)
+{
+ comment.Replace("\r\r\n", "\r\n");
+ for (unsigned int i=0; i<comment.length(); i++)
+ {
+ if ((comment[i] < 32) && (comment[i] != '\n') && (comment[i] != '\t') && (comment[i] != '\r'))
+ {
+ comment[i] = '.';
+ }
+ }
+}*/
+
+//--------------------------------------------------------------------------
+// Evaluate number, be it int, rational, or float from directory.
+//--------------------------------------------------------------------------
+double CExifParse::ConvertAnyFormat(const void* const ValuePtr, int Format)
+{
+ double Value;
+ Value = 0;
+
+ switch(Format)
+ {
+ case FMT_SBYTE: Value = *( signed char*)ValuePtr; break;
+ case FMT_BYTE: Value = *(unsigned char*)ValuePtr; break;
+
+ case FMT_USHORT: Value = Get16(ValuePtr, m_MotorolaOrder); break;
+ case FMT_ULONG: Value = (unsigned)Get32(ValuePtr, m_MotorolaOrder); break;
+
+ case FMT_URATIONAL:
+ case FMT_SRATIONAL:
+ {
+ int Num,Den;
+ Num = Get32(ValuePtr, m_MotorolaOrder);
+ Den = Get32(4+(char *)ValuePtr, m_MotorolaOrder);
+
+ if (Den == 0) Value = 0;
+ else Value = (double)Num/Den;
+ }
+ break;
+
+ case FMT_SSHORT: Value = (signed short)Get16(ValuePtr, m_MotorolaOrder); break;
+ case FMT_SLONG: Value = Get32(ValuePtr, m_MotorolaOrder); break;
+
+ // Not sure if this is correct (never seen float used in Exif format)
+ case FMT_SINGLE: Value = (double)*(float*)ValuePtr; break;
+ case FMT_DOUBLE: Value = *(double*)ValuePtr; break;
+
+ default:
+ ErrNonfatal("Illegal format code %d",Format,0);
+ }
+ return Value;
+}
+
+//--------------------------------------------------------------------------
+// Exif date tag is stored as a fixed format string "YYYY:MM:DD HH:MM:SS".
+// If date is not set, then the string is filled with blanks and colons:
+// " : : : : ". We want this string localised.
+//--------------------------------------------------------------------------
+/*void CExifParse::LocaliseDate (void)
+{
+ if (m_ExifInfo[SLIDE_EXIF_DATE_TIME][0] != ' ')
+ {
+ int year = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(0, 4).c_str());
+ int month = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(5, 2).c_str());
+ int day = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(8, 2).c_str());
+ int hour = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(11,2).c_str());
+ int min = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(14,2).c_str());
+ int sec = atoi(m_ExifInfo[SLIDE_EXIF_DATE_TIME].substr(17,2).c_str());
+ CDateTime date(year, month, day, hour, min, sec);
+ m_ExifInfo[SLIDE_EXIF_DATE_TIME] = date.GetAsLocalizedDateTime();
+ }
+}*/
+
+
+//--------------------------------------------------------------------------
+// Convert exposure time into a human readable format
+//--------------------------------------------------------------------------
+/*void CExifParse::GetExposureTime(const float exposureTime, CStdString& outStr)
+{
+ if (exposureTime)
+ {
+ if (exposureTime < 0.010) outStr.Format("%6.4fs ", exposureTime);
+ else outStr.Format("%5.3fs ", exposureTime);
+ if (exposureTime <= 0.5) outStr.Format("%s (1/%d)", outStr, (int)(0.5 + 1/exposureTime));
+ }
+}*/
+
+//--------------------------------------------------------------------------
+// Process one of the nested EXIF directories.
+//--------------------------------------------------------------------------
+void CExifParse::ProcessDir(const unsigned char* const DirStart,
+ const unsigned char* const OffsetBase,
+ const unsigned ExifLength,
+ int NestingLevel)
+{
+ if (NestingLevel > 4)
+ {
+ ErrNonfatal("Maximum directory nesting exceeded (corrupt exif header)", 0,0);
+ return;
+ }
+
+ char IndentString[25];
+ memset(IndentString, ' ', 25);
+ IndentString[NestingLevel * 4] = '\0';
+
+
+ int NumDirEntries = Get16((void*)DirStart, m_MotorolaOrder);
+
+ const unsigned char* const DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
+ if (DirEnd+4 > (OffsetBase+ExifLength))
+ {
+ if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength)
+ {
+ // Version 1.3 of jhead would truncate a bit too much.
+ // This also caught later on as well.
+ }
+ else
+ {
+ ErrNonfatal("Illegally sized directory", 0,0);
+ return;
+ }
+ }
+
+ const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+
+
+ for (int de=0;de<NumDirEntries;de++)
+ {
+ int Tag, Format, Components;
+ unsigned char* ValuePtr;
+ int ByteCount;
+ const unsigned char* const DirEntry = DIR_ENTRY_ADDR(DirStart, de);
+
+ Tag = Get16(DirEntry, m_MotorolaOrder);
+ Format = Get16(DirEntry+2, m_MotorolaOrder);
+ Components = Get32(DirEntry+4, m_MotorolaOrder);
+
+ if ((Format-1) >= NUM_FORMATS)
+ {
+ // (-1) catches illegal zero case as unsigned underflows to positive large.
+ ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
+ continue;
+ }
+
+ if ((unsigned)Components > 0x10000)
+ {
+ ErrNonfatal("Illegal number of components %d for tag %04x", Components, Tag);
+ continue;
+ }
+
+ ByteCount = Components * BytesPerFormat[Format];
+
+ if (ByteCount > 4)
+ {
+ unsigned OffsetVal;
+ OffsetVal = (unsigned)Get32(DirEntry+8, m_MotorolaOrder);
+ // If its bigger than 4 bytes, the dir entry contains an offset.
+ if (OffsetVal+ByteCount > ExifLength)
+ {
+ // Bogus pointer offset and / or bytecount value
+ ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
+ continue;
+ }
+ ValuePtr = (unsigned char*)(OffsetBase+OffsetVal);
+
+ if (OffsetVal > m_LargestExifOffset)
+ {
+ m_LargestExifOffset = OffsetVal;
+ }
+
+ }
+ else {
+ // 4 bytes or less and value is in the dir entry itself
+ ValuePtr = (unsigned char*)(DirEntry+8);
+ }
+
+
+ // Extract useful components of tag
+ switch(Tag)
+ {
+// case TAG_DESCRIPTION: strncpy(m_ExifInfo->Description, ValuePtr, 5); break;
+ case TAG_MAKE: strncpy(m_ExifInfo->CameraMake, (char *)ValuePtr, 32); break;
+ case TAG_MODEL: strncpy(m_ExifInfo->CameraModel, (char *)ValuePtr, 40); break;
+// case TAG_SOFTWARE: strncpy(m_ExifInfo->Software, ValuePtr, 5); break;
+ case TAG_FOCALPLANEXRES: m_FocalPlaneXRes = ConvertAnyFormat(ValuePtr, Format); break;
+ case TAG_THUMBNAIL_OFFSET: m_ExifInfo->ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format); break;
+ case TAG_THUMBNAIL_LENGTH: m_ExifInfo->ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format); break;
+
+ case TAG_MAKER_NOTE:
+ continue;
+ break;
+
+ case TAG_DATETIME_ORIGINAL:
+ // If we get a DATETIME_ORIGINAL, we use that one.
+ strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20);
+ m_DateFound = true;
+ break;
+
+ case TAG_DATETIME_DIGITIZED:
+ case TAG_DATETIME:
+ if (m_DateFound == false)
+ {
+ // If we don't already have a DATETIME_ORIGINAL, use whatever
+ // time fields we may have.
+ strncpy(m_ExifInfo->DateTime, (char *)ValuePtr, 20);
+// LocaliseDate();
+ }
+ break;
+
+ case TAG_USERCOMMENT:
+ {
+ const int EXIF_COMMENT_HDR_LENGTH = 8; // All comment tags have 8 bytes of header info
+ int length = max(ByteCount - EXIF_COMMENT_HDR_LENGTH, 0);
+ length = min(length, 2000);
+ strncpy(m_ExifInfo->Comments, (char *)ValuePtr+EXIF_COMMENT_HDR_LENGTH, length);
+// FixComment(comment); // Ensure comment is printable
+ }
+ break;
+
+ case TAG_FNUMBER:
+ // Simplest way of expressing aperture, so I trust it the most.
+ // (overwrite previously computd value if there is one)
+ m_ExifInfo->ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_APERTURE:
+ case TAG_MAXAPERTURE:
+ // More relevant info always comes earlier, so only use this field if we don't
+ // have appropriate aperture information yet.
+ if (m_ExifInfo->ApertureFNumber == 0)
+ {
+ m_ExifInfo->ApertureFNumber = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
+ }
+ break;
+
+ case TAG_FOCALLENGTH:
+ // Nice digital cameras actually save the focal length as a function
+ // of how far they are zoomed in.
+ m_ExifInfo->FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_SUBJECT_DISTANCE:
+ // Inidcates the distacne the autofocus camera is focused to.
+ // Tends to be less accurate as distance increases.
+ {
+ float distance = (float)ConvertAnyFormat(ValuePtr, Format);
+ if (distance < 0)
+ m_ExifInfo->Distance = distance; // infinite
+ else
+ m_ExifInfo->Distance = distance;
+ }
+ break;
+
+ case TAG_EXPOSURETIME:
+ {
+ // Simplest way of expressing exposure time, so I trust it most.
+ // (overwrite previously computd value if there is one)
+ float expTime = (float)ConvertAnyFormat(ValuePtr, Format);
+ if (expTime)
+ m_ExifInfo->ExposureTime = expTime;
+ }
+ break;
+
+ case TAG_SHUTTERSPEED:
+ // More complicated way of expressing exposure time, so only use
+ // this value if we don't already have it from somewhere else.
+ if (m_ExifInfo->ExposureTime == 0)
+ {
+ m_ExifInfo->ExposureTime = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
+ }
+ break;
+
+ case TAG_FLASH:
+ m_ExifInfo->FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_ORIENTATION:
+ m_ExifInfo->Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
+ if (m_ExifInfo->Orientation < 0 || m_ExifInfo->Orientation > 8)
+ {
+ ErrNonfatal("Undefined rotation value %d", m_ExifInfo->Orientation, 0);
+ m_ExifInfo->Orientation = 0;
+ }
+ break;
+
+ case TAG_EXIF_IMAGELENGTH:
+ case TAG_EXIF_IMAGEWIDTH:
+ // Use largest of height and width to deal with images that have been
+ // rotated to portrait format.
+ {
+ int a = (int)ConvertAnyFormat(ValuePtr, Format);
+ if (m_ExifImageWidth < a) m_ExifImageWidth = a;
+ }
+ break;
+
+ case TAG_FOCALPLANEUNITS:
+ switch((int)ConvertAnyFormat(ValuePtr, Format))
+ {
+ // According to the information I was using, 2 means meters.
+ // But looking at the Cannon powershot's files, inches is the only
+ // sensible value.
+ case 1: m_FocalPlaneUnits = 25.4; break; // inch
+ case 2: m_FocalPlaneUnits = 25.4; break;
+ case 3: m_FocalPlaneUnits = 10; break; // centimeter
+ case 4: m_FocalPlaneUnits = 1; break; // millimeter
+ case 5: m_FocalPlaneUnits = .001; break; // micrometer
+ }
+ break;
+
+ case TAG_EXPOSURE_BIAS:
+ m_ExifInfo->ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_WHITEBALANCE:
+ m_ExifInfo->Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_LIGHT_SOURCE:
+ //Quercus: 17-1-2004 Added LightSource, some cams return this, whitebalance or both
+ m_ExifInfo->LightSource = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_METERING_MODE:
+ m_ExifInfo->MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXPOSURE_PROGRAM:
+ m_ExifInfo->ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXPOSURE_INDEX:
+ if (m_ExifInfo->ISOequivalent == 0)
+ {
+ // Exposure index and ISO equivalent are often used interchangeably,
+ // so we will do the same.
+ // http://photography.about.com/library/glossary/bldef_ei.htm
+ m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
+ }
+ break;
+
+ case TAG_ISO_EQUIVALENT:
+ m_ExifInfo->ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
+ if (m_ExifInfo->ISOequivalent < 50)
+ m_ExifInfo->ISOequivalent *= 200; // Fixes strange encoding on some older digicams.
+ break;
+
+ case TAG_EXPOSURE_MODE:
+ m_ExifInfo->ExposureMode = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_DIGITALZOOMRATIO:
+ m_ExifInfo->DigitalZoomRatio = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXIF_OFFSET:
+ case TAG_INTEROP_OFFSET:
+ {
+ const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder);
+ if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
+ {
+ ErrNonfatal("Illegal exif or interop ofset directory link",0,0);
+ }
+ else
+ {
+ ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
+ }
+ continue;
+ }
+ break;
+
+ case TAG_GPSINFO:
+ {
+ const unsigned char* const SubdirStart = OffsetBase + (unsigned)Get32(ValuePtr, m_MotorolaOrder);
+ if (SubdirStart < OffsetBase || SubdirStart > OffsetBase+ExifLength)
+ {
+ ErrNonfatal("Illegal GPS directory link",0,0);
+ }
+ else
+ {
+ ProcessGpsInfo(SubdirStart, ByteCount, OffsetBase, ExifLength);
+ }
+ continue;
+ }
+ break;
+
+ case TAG_FOCALLENGTH_35MM:
+ // The focal length equivalent 35 mm is a 2.2 tag (defined as of April 2002)
+ // if its present, use it to compute equivalent focal length instead of
+ // computing it from sensor geometry and actual focal length.
+ m_ExifInfo->FocalLength35mmEquiv = (unsigned)ConvertAnyFormat(ValuePtr, Format);
+ break;
+ }
+ }
+
+
+ // In addition to linking to subdirectories via exif tags,
+ // there's also a potential link to another directory at the end of each
+ // directory. this has got to be the result of a committee!
+ unsigned Offset;
+
+ if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength)
+ {
+ Offset = (unsigned)Get32(DirStart+2+12*NumDirEntries, m_MotorolaOrder);
+ if (Offset)
+ {
+ const unsigned char* const SubdirStart = OffsetBase + Offset;
+ if (SubdirStart > OffsetBase+ExifLength || SubdirStart < OffsetBase)
+ {
+ if (SubdirStart > OffsetBase && SubdirStart < OffsetBase+ExifLength+20)
+ {
+ // Jhead 1.3 or earlier would crop the whole directory!
+ // As Jhead produces this form of format incorrectness,
+ // I'll just let it pass silently
+ }
+ else
+ {
+ ErrNonfatal("Illegal subdirectory link",0,0);
+ }
+ }
+ else
+ {
+ if (SubdirStart <= OffsetBase+ExifLength)
+ {
+ ProcessDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
+ }
+ }
+ if (Offset > m_LargestExifOffset)
+ {
+ m_LargestExifOffset = Offset;
+ }
+ }
+ }
+ else
+ {
+ // The exif header ends before the last next directory pointer.
+ }
+
+ if (m_ExifInfo->ThumbnailOffset)
+ {
+ m_ExifInfo->ThumbnailAtEnd = false;
+
+ if (m_ExifInfo->ThumbnailOffset <= ExifLength)
+ {
+ if (m_ExifInfo->ThumbnailSize > ExifLength - m_ExifInfo->ThumbnailOffset)
+ {
+ // If thumbnail extends past exif header, only save the part that
+ // actually exists. Canon's EOS viewer utility will do this - the
+ // thumbnail extracts ok with this hack.
+ m_ExifInfo->ThumbnailSize = ExifLength - m_ExifInfo->ThumbnailOffset;
+ }
+ }
+ }
+}
+
+
+//--------------------------------------------------------------------------
+// Process a EXIF marker
+// Describes all the drivel that most digital cameras include...
+//--------------------------------------------------------------------------
+bool CExifParse::Process (const unsigned char* const ExifSection, const unsigned short length, ExifInfo_t *info)
+{
+ m_ExifInfo = info;
+ // EXIF signature: "Exif\0\0"
+ // Check EXIF signatures
+ const char ExifHeader[] = "Exif\0\0";
+ const char ExifAlignment0[] = "II";
+ const char ExifAlignment1[] = "MM";
+ const char ExifExtra = 0x2a;
+
+ char* pos = (char*)(ExifSection + sizeof(short)); // position data pointer after length field
+
+ if (memcmp(pos, ExifHeader,6))
+ {
+ printf("ExifParse: incorrect Exif header");
+ return false;
+ }
+ pos += 6;
+
+ if (memcmp(pos, ExifAlignment0, strlen(ExifAlignment0)) == 0)
+ {
+ m_MotorolaOrder = false;
+ }
+ else if (memcmp(pos, ExifAlignment1, strlen(ExifAlignment1)) == 0)
+ {
+ m_MotorolaOrder = true;
+ }
+ else
+ {
+ printf("ExifParse: invalid Exif alignment marker");
+ return false;
+ }
+ pos += strlen(ExifAlignment0);
+
+ // Check the next value for correctness.
+ if (Get16((void*)(pos), m_MotorolaOrder) != ExifExtra)
+ {
+ printf("ExifParse: invalid Exif start (1)");
+ return false;
+ }
+ pos += sizeof(short);
+
+ unsigned long FirstOffset = (unsigned)Get32((void*)pos, m_MotorolaOrder);
+ if (FirstOffset < 8 || FirstOffset > 16)
+ {
+ // Usually set to 8, but other values valid too.
+// CLog::Log(LOGERROR, "ExifParse: suspicious offset of first IFD value");
+ }
+
+
+
+ // First directory starts 16 bytes in. All offset are relative to 8 bytes in.
+ ProcessDir(ExifSection+8+FirstOffset, ExifSection+8, length-8, 0);
+
+ m_ExifInfo->ThumbnailAtEnd = m_ExifInfo->ThumbnailOffset >= m_LargestExifOffset ? true : false;
+
+ // Compute the CCD width, in millimeters.
+ if (m_FocalPlaneXRes != 0)
+ {
+ // Note: With some cameras, its not possible to compute this correctly because
+ // they don't adjust the indicated focal plane resolution units when using less
+ // than maximum resolution, so the CCDWidth value comes out too small. Nothing
+ // that Jhead can do about it - its a camera problem.
+ m_ExifInfo->CCDWidth = (float)(m_ExifImageWidth * m_FocalPlaneUnits / m_FocalPlaneXRes);
+ }
+
+ if (m_ExifInfo->FocalLength)
+ {
+ if (m_ExifInfo->FocalLength35mmEquiv == 0)
+ {
+ // Compute 35 mm equivalent focal length based on sensor geometry if we haven't
+ // already got it explicitly from a tag.
+ if (m_ExifInfo->CCDWidth != 0.0)
+ {
+ m_ExifInfo->FocalLength35mmEquiv = (int)(m_ExifInfo->FocalLength/m_ExifInfo->CCDWidth*36 + 0.5);
+ }
+ }
+ }
+ return true;
+}
+
+
+
+//--------------------------------------------------------------------------
+// GPS Lat/Long extraction helper function
+//--------------------------------------------------------------------------
+void CExifParse::GetLatLong(
+ const unsigned int Format,
+ const unsigned char* ValuePtr,
+ const int ComponentSize,
+ char *latLongString)
+{
+ if (Format != FMT_URATIONAL)
+ {
+ ErrNonfatal("Illegal number format %d for GPS Lat/Long", Format, 0);
+ }
+ else
+ {
+ double Values[3];
+ for (unsigned a=0; a<3 ;a++)
+ {
+ Values[a] = ConvertAnyFormat(ValuePtr+a*ComponentSize, Format);
+ }
+ char latLong[30];
+ sprintf(latLong, "%3.0fd %2.0f' %5.2f\"", Values[0], Values[1], Values[2]);
+ strcat(latLongString, latLong);
+ }
+}
+
+//--------------------------------------------------------------------------
+// Process GPS info directory
+//--------------------------------------------------------------------------
+void CExifParse::ProcessGpsInfo(
+ const unsigned char* const DirStart,
+ int ByteCountUnused,
+ const unsigned char* const OffsetBase,
+ unsigned ExifLength)
+{
+ int NumDirEntries = Get16(DirStart);
+
+ for (int de=0;de<NumDirEntries;de++)
+ {
+ const unsigned char* DirEntry = DIR_ENTRY_ADDR(DirStart, de);
+
+ unsigned Tag = Get16(DirEntry);
+ unsigned Format = Get16(DirEntry+2);
+ unsigned Components = (unsigned)Get32(DirEntry+4);
+ if ((Format-1) >= NUM_FORMATS)
+ {
+ // (-1) catches illegal zero case as unsigned underflows to positive large.
+ ErrNonfatal("Illegal number format %d for tag %04x", Format, Tag);
+ continue;
+ }
+
+ const int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+ int ComponentSize = BytesPerFormat[Format];
+ unsigned ByteCount = Components * ComponentSize;
+
+ const unsigned char* ValuePtr;
+
+ if (ByteCount > 4)
+ {
+ unsigned OffsetVal = (unsigned)Get32(DirEntry+8);
+ // If its bigger than 4 bytes, the dir entry contains an offset.
+ if (OffsetVal+ByteCount > ExifLength)
+ {
+ // Bogus pointer offset and / or bytecount value
+ ErrNonfatal("Illegal value pointer for tag %04x", Tag,0);
+ continue;
+ }
+ ValuePtr = OffsetBase+OffsetVal;
+ }
+ else
+ {
+ // 4 bytes or less and value is in the dir entry itself
+ ValuePtr = DirEntry+8;
+ }
+
+ switch(Tag)
+ {
+ case TAG_GPS_LAT_REF:
+ m_ExifInfo->GpsLat[0] = ValuePtr[0];
+ m_ExifInfo->GpsLat[1] = 0;
+ break;
+
+ case TAG_GPS_LONG_REF:
+ m_ExifInfo->GpsLong[0] = ValuePtr[0];
+ m_ExifInfo->GpsLong[1] = 0;
+ break;
+
+ case TAG_GPS_LAT:
+ GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLat);
+ break;
+ case TAG_GPS_LONG:
+ GetLatLong(Format, ValuePtr, ComponentSize, m_ExifInfo->GpsLong);
+ break;
+
+ case TAG_GPS_ALT_REF:
+ if (ValuePtr[0] != 0)
+ m_ExifInfo->GpsAlt[0] = '-';
+ m_ExifInfo->GpsAlt[1] = 0;
+ break;
+
+ case TAG_GPS_ALT:
+ {
+ char temp[18];
+ sprintf(temp,"%dm", Get32(ValuePtr));
+ strcat(m_ExifInfo->GpsAlt, temp);
+ }
+ break;
+ }
+ }
+}
+
diff --git a/lib/libexif/ExifParse.h b/lib/libexif/ExifParse.h
new file mode 100644
index 0000000000..94e6cd0fc2
--- /dev/null
+++ b/lib/libexif/ExifParse.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "libexif.h"
+
+class CExifParse
+{
+ public:
+ CExifParse ();
+ ~CExifParse (void) {}
+ bool Process (const unsigned char* const Data, const unsigned short length, ExifInfo_t *info);
+ static int Get16 (const void* const Short, const bool motorolaOrder=true);
+ static int Get32 (const void* const Long, const bool motorolaOrder=true);
+
+ private:
+ ExifInfo_t *m_ExifInfo;
+ double m_FocalPlaneXRes;
+ double m_FocalPlaneUnits;
+ unsigned m_LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end)
+ int m_ExifImageWidth;
+ bool m_MotorolaOrder;
+ bool m_DateFound;
+
+// void LocaliseDate (void);
+// void GetExposureTime (const float exposureTime);
+ double ConvertAnyFormat (const void* const ValuePtr, int Format);
+ void ProcessDir (const unsigned char* const DirStart,
+ const unsigned char* const OffsetBase,
+ const unsigned ExifLength, int NestingLevel);
+ void ProcessGpsInfo (const unsigned char* const DirStart,
+ int ByteCountUnused,
+ const unsigned char* const OffsetBase,
+ unsigned ExifLength);
+ void GetLatLong (const unsigned int Format,
+ const unsigned char* ValuePtr,
+ const int ComponentSize,
+ char *latlongString);
+};
+
diff --git a/lib/libexif/IptcParse.cpp b/lib/libexif/IptcParse.cpp
new file mode 100644
index 0000000000..732a2f3c8b
--- /dev/null
+++ b/lib/libexif/IptcParse.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2005-2007 Team XboxMediaCenter
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+//--------------------------------------------------------------------------
+// Module to pull IPTC information out of various types of digital images.
+//--------------------------------------------------------------------------
+
+//--------------------------------------------------------------------------
+// Process IPTC data.
+//--------------------------------------------------------------------------
+#ifndef _LINUX
+#include <windows.h>
+#else
+#include <string.h>
+#define min(a,b) (a)>(b)?(b):(a)
+#endif
+#include <stdio.h>
+#include "IptcParse.h"
+#include "ExifParse.h"
+
+// Supported IPTC entry types
+#define IPTC_SUPLEMENTAL_CATEGORIES 0x14
+#define IPTC_KEYWORDS 0x19
+#define IPTC_CAPTION 0x78
+#define IPTC_AUTHOR 0x7A
+#define IPTC_HEADLINE 0x69
+#define IPTC_SPECIAL_INSTRUCTIONS 0x28
+#define IPTC_CATEGORY 0x0F
+#define IPTC_BYLINE 0x50
+#define IPTC_BYLINE_TITLE 0x55
+#define IPTC_CREDIT 0x6E
+#define IPTC_SOURCE 0x73
+#define IPTC_COPYRIGHT_NOTICE 0x74
+#define IPTC_OBJECT_NAME 0x05
+#define IPTC_CITY 0x5A
+#define IPTC_STATE 0x5F
+#define IPTC_COUNTRY 0x65
+#define IPTC_TRANSMISSION_REFERENCE 0x67
+#define IPTC_DATE 0x37
+#define IPTC_COPYRIGHT 0x0A
+#define IPTC_COUNTRY_CODE 0x64
+#define IPTC_REFERENCE_SERVICE 0x2D
+
+
+//--------------------------------------------------------------------------
+// Process IPTC marker. Return FALSE if unable to process marker.
+//
+// IPTC block consists of:
+// - Marker: 1 byte (0xED)
+// - Block length: 2 bytes
+// - IPTC Signature: 14 bytes ("Photoshop 3.0\0")
+// - 8BIM Signature 4 bytes ("8BIM")
+// - IPTC Block start 2 bytes (0x04, 0x04)
+// - IPTC Header length 1 byte
+// - IPTC header Header is padded to even length, counting the length byte
+// - Length 4 bytes
+// - IPTC Data which consists of a number of entries, each of which has the following format:
+// - Signature 2 bytes (0x1C02)
+// - Entry type 1 byte (for defined entry types, see #defines above)
+// - entry length 2 bytes
+// - entry data 'entry length' bytes
+//
+//--------------------------------------------------------------------------
+bool CIptcParse::Process (const unsigned char* const Data, const unsigned short itemlen, IPTCInfo_t *info)
+{
+ if (!info) return false;
+
+ const char IptcSignature1[] = "Photoshop 3.0";
+ const char IptcSignature2[] = "8BIM";
+ const char IptcSignature3[] = {0x04, 0x04};
+
+ // Check IPTC signatures
+ char* pos = (char*)(Data + sizeof(short)); // position data pointer after length field
+
+ if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)) != 0) return false;
+ pos += strlen(IptcSignature1) + 1; // move data pointer to the next field
+
+ if (memcmp(pos, IptcSignature2, strlen(IptcSignature2)) != 0) return false;
+ pos += strlen(IptcSignature2); // move data pointer to the next field
+
+ if (memcmp(pos, IptcSignature3, sizeof(IptcSignature3)) != 0) return false;
+ pos += sizeof(IptcSignature3); // move data pointer to the next field
+
+ // IPTC section found
+
+ // Skip header
+ unsigned char headerLen = *pos++; // get header length and move data pointer to the next field
+ pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte)
+
+ // Get length (Motorola format)
+ unsigned long length = CExifParse::Get32(pos);
+ pos += sizeof(long); // move data pointer to the next field
+
+ // Now read IPTC data
+ while (pos < (char*)(Data + itemlen-5))
+ {
+ short signature = (*pos << 8) + (*(pos+1));
+
+ pos += sizeof(short);
+ if (signature != 0x1C02)
+ break;
+
+ unsigned char type = *pos++;
+ unsigned short length = (*pos << 8) + (*(pos+1));
+ pos += sizeof(short); // Skip tag length
+ // Process tag here
+ char *tag = NULL;
+ switch (type)
+ {
+ case IPTC_SUPLEMENTAL_CATEGORIES: tag = info->SupplementalCategories; break;
+ case IPTC_KEYWORDS: tag = info->Keywords; break;
+ case IPTC_CAPTION: tag = info->Caption; break;
+ case IPTC_AUTHOR: tag = info->Author; break;
+ case IPTC_HEADLINE: tag = info->Headline; break;
+ case IPTC_SPECIAL_INSTRUCTIONS: tag = info->SpecialInstructions; break;
+ case IPTC_CATEGORY: tag = info->Category; break;
+ case IPTC_BYLINE: tag = info->Byline; break;
+ case IPTC_BYLINE_TITLE: tag = info->BylineTitle; break;
+ case IPTC_CREDIT: tag = info->Credit; break;
+ case IPTC_SOURCE: tag = info->Source; break;
+ case IPTC_COPYRIGHT_NOTICE: tag = info->CopyrightNotice; break;
+ case IPTC_OBJECT_NAME: tag = info->ObjectName; break;
+ case IPTC_CITY: tag = info->City; break;
+ case IPTC_STATE: tag = info->State; break;
+ case IPTC_COUNTRY: tag = info->Country; break;
+ case IPTC_TRANSMISSION_REFERENCE: tag = info->TransmissionReference; break;
+ case IPTC_DATE: tag = info->Date; break;
+ case IPTC_COPYRIGHT: tag = info->Copyright; break;
+ case IPTC_REFERENCE_SERVICE: tag = info->ReferenceService; break;
+ case IPTC_COUNTRY_CODE: tag = info->CountryCode; break;
+ default:
+ printf("IptcParse: Unrecognised IPTC tag: 0x%02x", type);
+ break;
+ }
+
+ if (tag)
+ {
+ if (type != IPTC_KEYWORDS || *tag == 0)
+ {
+ strncpy(tag, pos, min(length, MAX_IPTC_STRING - 1));
+ tag[min(length, MAX_IPTC_STRING - 1)] = 0;
+ }
+ else if (type == IPTC_KEYWORDS)
+ {
+ // there may be multiple keywords - lets join them
+ size_t maxLen = MAX_IPTC_STRING - strlen(tag);
+ if (maxLen > 2)
+ strcat(tag, ", ");
+ strncat(tag, pos, min(length, MAX_IPTC_STRING - maxLen - 3));
+ }
+/* if (id == SLIDE_IPTC_CAPTION)
+ {
+ CExifParse::FixComment(m_IptcInfo[id]); // Ensure comment is printable
+ }*/
+ }
+ pos += length;
+ }
+ return true;
+}
+
diff --git a/lib/libexif/IptcParse.h b/lib/libexif/IptcParse.h
new file mode 100644
index 0000000000..e175ef769f
--- /dev/null
+++ b/lib/libexif/IptcParse.h
@@ -0,0 +1,12 @@
+#ifndef __IPTC_PARSE_H
+#define __IPTC_PARSE_H
+
+#include "libexif.h"
+
+class CIptcParse
+{
+ public:
+ static bool Process(const unsigned char* const Data, const unsigned short length, IPTCInfo_t *info);
+};
+
+#endif // __IPTC_H
diff --git a/lib/libexif/JpegParse.cpp b/lib/libexif/JpegParse.cpp
new file mode 100644
index 0000000000..87f0d6296b
--- /dev/null
+++ b/lib/libexif/JpegParse.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2005-2007 Team XboxMediaCenter
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Make; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+//--------------------------------------------------------------------------
+// This module gathers information about a digital image file. This includes:
+// - File name and path
+// - File size
+// - Resolution (if available)
+// - IPTC information (if available)
+// - EXIF information (if available)
+// All gathered information is stored in a vector of 'description' and 'value'
+// pairs (where both description and value fields are of CStdString types).
+//--------------------------------------------------------------------------
+
+#ifndef _LINUX
+#include <windows.h>
+#else
+#include <memory.h>
+#define min(a,b) (a)>(b)?(b):(a)
+typedef unsigned char BYTE;
+#endif
+#include "JpegParse.h"
+
+
+
+//--------------------------------------------------------------------------
+#define JPEG_PARSE_STRING_ID_BASE 21500
+enum {
+ ProcessUnknown = JPEG_PARSE_STRING_ID_BASE,
+ ProcessSof0,
+ ProcessSof1,
+ ProcessSof2,
+ ProcessSof3,
+ ProcessSof5,
+ ProcessSof6,
+ ProcessSof7,
+ ProcessSof9,
+ ProcessSof10,
+ ProcessSof11,
+ ProcessSof13,
+ ProcessSof14,
+ ProcessSof15,
+};
+
+
+
+
+//--------------------------------------------------------------------------
+// Constructor
+//--------------------------------------------------------------------------
+CJpegParse::CJpegParse():
+ m_SectionBuffer(NULL)
+{
+ memset(&m_ExifInfo, 0, sizeof(m_ExifInfo));
+ memset(&m_IPTCInfo, 0, sizeof(m_IPTCInfo));
+}
+
+//--------------------------------------------------------------------------
+// Process a SOFn marker. This is useful for the image dimensions
+//--------------------------------------------------------------------------
+void CJpegParse::ProcessSOFn (void)
+{
+ m_ExifInfo.Height = CExifParse::Get16(m_SectionBuffer+3);
+ m_ExifInfo.Width = CExifParse::Get16(m_SectionBuffer+5);
+
+ unsigned char num_components = m_SectionBuffer[7];
+ if (num_components != 3)
+ {
+ m_ExifInfo.IsColor = 0;
+ }
+ else
+ {
+ m_ExifInfo.IsColor = 1;
+ }
+}
+
+
+//--------------------------------------------------------------------------
+// Read a section from a JPEG file. Note that this function allocates memory.
+// It must be called in pair with ReleaseSection
+//--------------------------------------------------------------------------
+bool CJpegParse::GetSection (FILE *infile, const unsigned short sectionLength)
+{
+ m_SectionBuffer = new unsigned char[sectionLength];
+ if (m_SectionBuffer == NULL)
+ {
+ printf("JpgParse: could not allocate memory");
+ return false;
+ }
+ // Store first two pre-read bytes.
+ m_SectionBuffer[0] = (unsigned char)(sectionLength >> 8);
+ m_SectionBuffer[1] = (unsigned char)(sectionLength && 0x00FF);
+
+ unsigned int len = (unsigned int)sectionLength;
+
+ size_t bytesRead = fread(m_SectionBuffer+sizeof(sectionLength), 1, len-sizeof(sectionLength), infile);
+ if (bytesRead != sectionLength-sizeof(sectionLength))
+ {
+ printf("JpgParse: premature end of file?");
+ ReleaseSection();
+ return false;
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------------
+// Deallocate memory allocated in GetSection. This function must always
+// be paired by a preceeding GetSection call.
+//--------------------------------------------------------------------------
+void CJpegParse::ReleaseSection (void)
+{
+ delete[] m_SectionBuffer;
+ m_SectionBuffer = NULL;
+}
+
+//--------------------------------------------------------------------------
+// Parse the marker stream until SOS or EOI is seen; infile has already been
+// successfully open
+//--------------------------------------------------------------------------
+bool CJpegParse::ExtractInfo (FILE *infile)
+{
+ // Get file marker (two bytes - must be 0xFFD8 for JPEG files
+ BYTE a;
+ size_t bytesRead = fread(&a, 1, sizeof(BYTE), infile);
+ if ((bytesRead != sizeof(BYTE)) || (a != 0xFF))
+ {
+ return false;
+ }
+ bytesRead = fread(&a, 1, sizeof(BYTE), infile);
+ if ((bytesRead != sizeof(BYTE)) || (a != M_SOI))
+ {
+ return false;
+ }
+
+ for(;;)
+ {
+ BYTE marker = 0;
+ for (a=0; a<7; a++) {
+ bytesRead = fread(&marker, 1, sizeof(BYTE), infile);
+ if (marker != 0xFF)
+ break;
+
+ if (a >= 6)
+ {
+ printf("JpgParse: too many padding bytes");
+ return false;
+ }
+ marker = 0;
+ }
+
+ if (marker == 0xff)
+ {
+ // 0xff is legal padding, but if we get that many, something's wrong.
+ printf("JpgParse: too many padding bytes");
+ return false;
+ }
+
+ // Read the length of the section.
+ unsigned short itemlen = 0;
+ bytesRead = fread(&itemlen, 1, sizeof(itemlen), infile);
+ itemlen = CExifParse::Get16(&itemlen);
+
+ if ((bytesRead != sizeof(itemlen)) || (itemlen < sizeof(itemlen)))
+ {
+ printf("JpgParse: invalid marker");
+ return false;
+ }
+
+ switch(marker)
+ {
+ case M_SOS: // stop before hitting compressed data
+ return true;
+
+ case M_EOI: // in case it's a tables-only JPEG stream
+ printf("JpgParse: No image in jpeg!");
+ return false;
+ break;
+
+ case M_COM: // Comment section
+ GetSection(infile, itemlen);
+ if (m_SectionBuffer != NULL)
+ {
+ // CExifParse::FixComment(comment); // Ensure comment is printable
+ strncpy(m_ExifInfo.Comments, (char *)&m_SectionBuffer[2], min(itemlen-2, MAX_COMMENT));
+ }
+ ReleaseSection();
+ break;
+
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ GetSection(infile, itemlen);
+ if ((m_SectionBuffer != NULL) && (itemlen >= 7))
+ {
+ ProcessSOFn();
+ m_ExifInfo.Process = marker;
+ }
+ ReleaseSection();
+ break;
+
+ case M_IPTC:
+ GetSection(infile, itemlen);
+ if (m_SectionBuffer != NULL)
+ {
+ CIptcParse::Process(m_SectionBuffer, itemlen, &m_IPTCInfo);
+ }
+ ReleaseSection();
+ break;
+
+ case M_EXIF:
+ // Seen files from some 'U-lead' software with Vivitar scanner
+ // that uses marker 31 for non exif stuff. Thus make sure
+ // it says 'Exif' in the section before treating it as exif.
+ GetSection(infile, itemlen);
+ if (m_SectionBuffer != NULL)
+ {
+ CExifParse exif;
+ exif.Process(m_SectionBuffer, itemlen, &m_ExifInfo);
+ }
+ ReleaseSection();
+ break;
+
+ case M_JFIF:
+ // Regular jpegs always have this tag, exif images have the exif
+ // marker instead, althogh ACDsee will write images with both markers.
+ // this program will re-create this marker on absence of exif marker.
+ // hence no need to keep the copy from the file.
+ // fall through to default case
+ default:
+ // Skip any other sections.
+ GetSection(infile, itemlen);
+ ReleaseSection();
+ break;
+ }
+ }
+ return true;
+}
+
+//--------------------------------------------------------------------------
+// Process a file. Check if it is JPEG. Extract exif/iptc info if it is.
+//--------------------------------------------------------------------------
+bool CJpegParse::Process (const char *picFileName)
+{
+ FILE *file;
+
+ file = fopen(picFileName, "rb");
+ if (!file)
+ return false;
+
+ // File exists and successfully opened. Start processing
+ // Gather all information about the file
+
+/* // Get file name...
+ CStdString tmp, urlFName, path;
+ CURL url(picFileName);
+ url.GetURLWithoutUserDetails(urlFName);
+ CUtil::Split(urlFName, path, tmp);
+ m_JpegInfo[SLIDE_FILE_NAME] = tmp;
+ // ...then path...
+ m_JpegInfo[SLIDE_FILE_PATH] = path;
+
+ // ...then size...
+ __stat64 fileStat;
+ CFile::Stat(picFileName, &fileStat);
+ float fileSize = (float)fileStat.st_size;
+ tmp = "";
+ if (fileSize > 1024)
+ {
+ fileSize /= 1024;
+ tmp = "KB";
+ }
+ if (fileSize > 1024)
+ {
+ fileSize /= 1024;
+ tmp = "MB";
+ }
+ if (fileSize > 1024)
+ {
+ fileSize /= 1024;
+ tmp = "GB";
+ }
+ tmp.Format("%.2f %s", fileSize, tmp);
+ m_JpegInfo[SLIDE_FILE_SIZE] = tmp;
+
+ // ...then date and time...
+ CDateTime date((time_t)fileStat.st_mtime);
+ tmp.Format("%s %s", date.GetAsLocalizedDate(), date.GetAsLocalizedTime());
+ m_JpegInfo[SLIDE_FILE_DATE] = tmp;*/
+
+ bool result = ExtractInfo(file);
+ fclose(file);
+ if (result == false)
+ printf("JpgParse: Not a JPEG file %s", picFileName);
+ return result;
+}
+
diff --git a/lib/libexif/JpegParse.h b/lib/libexif/JpegParse.h
new file mode 100644
index 0000000000..1e9eeeb764
--- /dev/null
+++ b/lib/libexif/JpegParse.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "IptcParse.h"
+#include "ExifParse.h"
+#include "stdio.h"
+
+//--------------------------------------------------------------------------
+// JPEG markers consist of one or more 0xFF bytes, followed by a marker
+// code byte (which is not an FF). Here are the marker codes of interest
+// in this application.
+//--------------------------------------------------------------------------
+
+#define M_SOF0 0xC0 // Start Of Frame N
+#define M_SOF1 0xC1 // N indicates which compression process
+#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
+#define M_EOI 0xD9 // End Of Image (end of datastream)
+#define M_SOS 0xDA // Start Of Scan (begins compressed data)
+#define M_JFIF 0xE0 // Jfif marker
+#define M_EXIF 0xE1 // Exif marker
+#define M_COM 0xFE // COMment
+#define M_DQT 0xDB
+#define M_DHT 0xC4
+#define M_DRI 0xDD
+#define M_IPTC 0xED // IPTC marker
+
+
+class CJpegParse
+{
+ public:
+ CJpegParse ();
+ ~CJpegParse (void) {}
+ bool Process (const char *picFileName);
+ const ExifInfo_t * GetExifInfo() const { return &m_ExifInfo; };
+ const IPTCInfo_t * GetIptcInfo() const { return &m_IPTCInfo; };
+
+ private:
+ bool ExtractInfo (FILE *infile);
+ bool GetSection (FILE *infile, const unsigned short sectionLength);
+ void ReleaseSection (void);
+ void ProcessSOFn (void);
+
+ unsigned char* m_SectionBuffer;
+ ExifInfo_t m_ExifInfo;
+ IPTCInfo_t m_IPTCInfo;
+};
+
diff --git a/lib/libexif/Makefile.in b/lib/libexif/Makefile.in
new file mode 100644
index 0000000000..7e3d3e9dbf
--- /dev/null
+++ b/lib/libexif/Makefile.in
@@ -0,0 +1,20 @@
+ARCH=@ARCH@
+
+OBJS +=libexif.o ExifParse.o IptcParse.o JpegParse.o
+CFLAGS +=-D_LINUX -D_DLL -fPIC -O2
+CXXFLAGS +=-D_LINUX -D_DLL -fPIC -O2
+
+SYSDIR=@abs_top_srcdir@/system
+SO=libexif-$(ARCH).so
+SLIB=@abs_top_srcdir@/system/$(SO)
+
+$(SLIB): $(OBJS)
+ifeq ($(findstring osx,$(ARCH)), osx)
+ $(CXX) $(CFLAGS) -bundle -flat_namespace -undefined suppress -shared -fPIC -o $@ $(OBJS)
+ @abs_top_srcdir@/tools/Mach5/wrapper.rb $@;mv output.so $@
+else
+ $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $@ $(OBJS) \
+ `cat @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.def` @abs_top_srcdir@/xbmc/cores/DllLoader/exports/wrapper.o
+endif
+
+include @abs_top_srcdir@/Makefile.include
diff --git a/lib/libexif/libexif.cpp b/lib/libexif/libexif.cpp
new file mode 100644
index 0000000000..12e298c304
--- /dev/null
+++ b/lib/libexif/libexif.cpp
@@ -0,0 +1,42 @@
+// libexif.cpp : Defines the entry point for the console application.
+//
+
+#ifndef _LINUX
+#include <windows.h>
+#else
+#include <memory.h>
+#endif
+#include "JpegParse.h"
+#include "libexif.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool process_jpeg(const char *filename, ExifInfo_t *exifInfo, IPTCInfo_t *iptcInfo)
+{
+ if (!exifInfo || !iptcInfo) return false;
+ CJpegParse jpeg;
+ memset(exifInfo, 0, sizeof(ExifInfo_t));
+ memset(iptcInfo, 0, sizeof(IPTCInfo_t));
+ if (jpeg.Process(filename))
+ {
+ memcpy(exifInfo, jpeg.GetExifInfo(), sizeof(ExifInfo_t));
+ memcpy(iptcInfo, jpeg.GetIptcInfo(), sizeof(IPTCInfo_t));
+ return true;
+ }
+ return false;
+}
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef _DLL
+int main(int argc, char* argv[])
+{
+ ExifInfo_t exifInfo;
+ IPTCInfo_t iptcInfo;
+ process_jpeg("C:\\Documents and Settings\\jcmarsha\\My Documents\\My Pictures\\396179226_f09242e21e_o.jpg", &exifInfo, &iptcInfo);
+ return 0;
+}
+#endif
diff --git a/lib/libexif/libexif.h b/lib/libexif/libexif.h
new file mode 100644
index 0000000000..e889892a73
--- /dev/null
+++ b/lib/libexif/libexif.h
@@ -0,0 +1,126 @@
+#ifndef HAS_LIBEXIF_H
+#define HAS_LIBEXIF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _DLL
+#ifdef WIN32
+#define EXIF_EXPORT __declspec(dllexport)
+#else
+#define EXIF_EXPORT
+#endif
+#else
+#define EXIF_EXPORT
+#endif
+
+//--------------------------------------------------------------------------
+// JPEG markers consist of one or more 0xFF bytes, followed by a marker
+// code byte (which is not an FF). Here are the marker codes of interest
+// in this application.
+//--------------------------------------------------------------------------
+
+#define M_SOF0 0xC0 // Start Of Frame N
+#define M_SOF1 0xC1 // N indicates which compression process
+#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
+#define M_EOI 0xD9 // End Of Image (end of datastream)
+#define M_SOS 0xDA // Start Of Scan (begins compressed data)
+#define M_JFIF 0xE0 // Jfif marker
+#define M_EXIF 0xE1 // Exif marker
+#define M_COM 0xFE // COMment
+#define M_DQT 0xDB
+#define M_DHT 0xC4
+#define M_DRI 0xDD
+#define M_IPTC 0xED // IPTC marker
+
+#define MAX_IPTC_STRING 256
+
+typedef struct {
+ char SupplementalCategories[MAX_IPTC_STRING];
+ char Keywords[MAX_IPTC_STRING];
+ char Caption[MAX_IPTC_STRING];
+ char Author[MAX_IPTC_STRING];
+ char Headline[MAX_IPTC_STRING];
+ char SpecialInstructions[MAX_IPTC_STRING];
+ char Category[MAX_IPTC_STRING];
+ char Byline[MAX_IPTC_STRING];
+ char BylineTitle[MAX_IPTC_STRING];
+ char Credit[MAX_IPTC_STRING];
+ char Source[MAX_IPTC_STRING];
+ char CopyrightNotice[MAX_IPTC_STRING];
+ char ObjectName[MAX_IPTC_STRING];
+ char City[MAX_IPTC_STRING];
+ char State[MAX_IPTC_STRING];
+ char Country[MAX_IPTC_STRING];
+ char TransmissionReference[MAX_IPTC_STRING];
+ char Date[MAX_IPTC_STRING];
+ char Copyright[MAX_IPTC_STRING];
+ char ReferenceService[MAX_IPTC_STRING];
+ char CountryCode[MAX_IPTC_STRING];
+} IPTCInfo_t;
+
+#define MAX_COMMENT 2000
+#define MAX_DATE_COPIES 10
+
+typedef struct {
+ char CameraMake [32];
+ char CameraModel [40];
+ char DateTime [20];
+ int Height, Width;
+ int Orientation;
+ int IsColor;
+ int Process;
+ int FlashUsed;
+ float FocalLength;
+ float ExposureTime;
+ float ApertureFNumber;
+ float Distance;
+ float CCDWidth;
+ float ExposureBias;
+ float DigitalZoomRatio;
+ int FocalLength35mmEquiv; // Exif 2.2 tag - usually not present.
+ int Whitebalance;
+ int MeteringMode;
+ int ExposureProgram;
+ int ExposureMode;
+ int ISOequivalent;
+ int LightSource;
+ char Comments[MAX_COMMENT];
+
+ unsigned ThumbnailOffset; // Exif offset to thumbnail
+ unsigned ThumbnailSize; // Size of thumbnail.
+ unsigned LargestExifOffset; // Last exif data referenced (to check if thumbnail is at end)
+
+ char ThumbnailAtEnd; // Exif header ends with the thumbnail
+ // (we can only modify the thumbnail if its at the end)
+ int ThumbnailSizeOffset;
+
+ int DateTimeOffsets[MAX_DATE_COPIES];
+ int numDateTimeTags;
+
+ int GpsInfoPresent;
+ char GpsLat[31];
+ char GpsLong[31];
+ char GpsAlt[20];
+} ExifInfo_t;
+
+EXIF_EXPORT bool process_jpeg(const char *filename, ExifInfo_t *exifInfo, IPTCInfo_t *iptcInfo);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lib/libexif/libexif.sln b/lib/libexif/libexif.sln
new file mode 100644
index 0000000000..4c85df300a
--- /dev/null
+++ b/lib/libexif/libexif.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libexif", "libexif.vcproj", "{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ Release (DLL) = Release (DLL)
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Debug.ActiveCfg = Debug|Win32
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Debug.Build.0 = Debug|Win32
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release.ActiveCfg = Release|Win32
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release.Build.0 = Release|Win32
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release (DLL).ActiveCfg = Release (DLL)|Win32
+ {AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}.Release (DLL).Build.0 = Release (DLL)|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/lib/libexif/libexif.vcproj b/lib/libexif/libexif.vcproj
new file mode 100644
index 0000000000..90eaac7fb5
--- /dev/null
+++ b/lib/libexif/libexif.vcproj
@@ -0,0 +1,303 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="libexif_dll"
+ ProjectGUID="{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}"
+ RootNamespace="libexif_dll"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/libexif.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(OutDir)/libexif.pdb"
+ SubSystem="1"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/libexif.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release (DLL)|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_DLL;_CRT_SECURE_NO_WARNINGS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="..\..\..\system\libexif.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetName).pdb"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ ProfileGuidedDatabase=""
+ RandomizedBaseAddress="2"
+ DataExecutionPrevention="0"
+ ImportLibrary="$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\ExifParse.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ExifParse.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IptcParse.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\IptcParse.h"
+ >
+ </File>
+ <File
+ RelativePath=".\JpegParse.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\JpegParse.h"
+ >
+ </File>
+ <File
+ RelativePath=".\libexif.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <File
+ RelativePath=".\ReadMe.txt"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/lib/libexif/libexif.vcxproj b/lib/libexif/libexif.vcxproj
new file mode 100644
index 0000000000..cd65ac93c8
--- /dev/null
+++ b/lib/libexif/libexif.vcxproj
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release (DLL)|Win32">
+ <Configuration>Release (DLL)</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>libexif_dll</ProjectName>
+ <ProjectGuid>{AD20A3E2-09CB-42DB-9A70-27F7CDC886CE}</ProjectGuid>
+ <RootNamespace>libexif_dll</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">false</LinkIncremental>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">libexif</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">libexif</TargetName>
+ <CustomBuildAfterTargets Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">Build</CustomBuildAfterTargets>
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt>
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">.dll</TargetExt>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">libexif</TargetName>
+ <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)libexif.exe</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(OutDir)libexif.pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)libexif.exe</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release (DLL)|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_DLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <ProfileGuidedDatabase>
+ </ProfileGuidedDatabase>
+ <RandomizedBaseAddress>true</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ <ImportLibrary>$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <PostBuildEvent>
+ <Command>
+ </Command>
+ </PostBuildEvent>
+ <CustomBuildStep>
+ <Command>copy /B /Y "$(TargetPath)" "$(SolutionDir)..\..\system\$(TargetFileName)"</Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>Copy output</Message>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Outputs>$(SolutionDir)..\..\system\$(TargetFileName)</Outputs>
+ <Inputs>$(TargetPath)</Inputs>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="ExifParse.cpp" />
+ <ClCompile Include="IptcParse.cpp" />
+ <ClCompile Include="JpegParse.cpp" />
+ <ClCompile Include="libexif.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ExifParse.h" />
+ <ClInclude Include="IptcParse.h" />
+ <ClInclude Include="JpegParse.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/lib/libexif/libexif.vcxproj.filters b/lib/libexif/libexif.vcxproj.filters
new file mode 100644
index 0000000000..5ca80ed9aa
--- /dev/null
+++ b/lib/libexif/libexif.vcxproj.filters
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="ExifParse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="IptcParse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="JpegParse.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="libexif.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="ExifParse.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IptcParse.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ <ClInclude Include="JpegParse.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+</Project> \ No newline at end of file