aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorArne Morten Kvarving <spiff@xbmc.org>2012-03-27 14:31:23 -0700
committerArne Morten Kvarving <spiff@xbmc.org>2012-03-27 14:31:23 -0700
commit42399911e2255cfe00a800f58a59e50c771c063d (patch)
treee2b0ac30d088358ace924142f91cc291c4f4f7ff /lib
parent08f3227778134ca5833dee42d03bfe04571a8964 (diff)
parenta12dc4ad32a4f6627487861508831fd3bfeabfed (diff)
Merge pull request #508 from fetzerch/pictures-metadata-fixes
Updated metadata parsing for pictures The relevant (but hard to read) spec would be the Photoshop File Format which references IPTC IIM: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_pgfId-1037504- http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf
Diffstat (limited to 'lib')
-rw-r--r--lib/libexif/ExifParse.cpp10
-rw-r--r--lib/libexif/IptcParse.cpp112
-rw-r--r--lib/libexif/libexif.h5
3 files changed, 88 insertions, 39 deletions
diff --git a/lib/libexif/ExifParse.cpp b/lib/libexif/ExifParse.cpp
index 74ecbbef78..2386fd3dab 100644
--- a/lib/libexif/ExifParse.cpp
+++ b/lib/libexif/ExifParse.cpp
@@ -413,7 +413,13 @@ void CExifParse::ProcessDir(const unsigned char* const DirStart,
// Extract useful components of tag
switch(Tag)
{
-// case TAG_DESCRIPTION: strncpy(m_ExifInfo->Description, ValuePtr, 5); break;
+ case TAG_DESCRIPTION:
+ {
+ int length = max(ByteCount, 0);
+ length = min(length, MAX_COMMENT);
+ strncpy(m_ExifInfo->Description, (char *)ValuePtr, length);
+ 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;
@@ -446,7 +452,7 @@ void CExifParse::ProcessDir(const unsigned char* const DirStart,
{
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);
+ length = min(length, MAX_COMMENT);
strncpy(m_ExifInfo->Comments, (char *)ValuePtr+EXIF_COMMENT_HDR_LENGTH, length);
// FixComment(comment); // Ensure comment is printable
}
diff --git a/lib/libexif/IptcParse.cpp b/lib/libexif/IptcParse.cpp
index 9b21c64e9d..b58e1f0189 100644
--- a/lib/libexif/IptcParse.cpp
+++ b/lib/libexif/IptcParse.cpp
@@ -37,6 +37,7 @@
#include "ExifParse.h"
// Supported IPTC entry types
+#define IPTC_RECORD_VERSION 0x00
#define IPTC_SUPLEMENTAL_CATEGORIES 0x14
#define IPTC_KEYWORDS 0x19
#define IPTC_CAPTION 0x78
@@ -58,6 +59,9 @@
#define IPTC_COPYRIGHT 0x0A
#define IPTC_COUNTRY_CODE 0x64
#define IPTC_REFERENCE_SERVICE 0x2D
+#define IPTC_TIME_CREATED 0x3C
+#define IPTC_SUB_LOCATION 0x5C
+#define IPTC_IMAGE_TYPE 0x82
//--------------------------------------------------------------------------
@@ -89,66 +93,100 @@ bool CIptcParse::Process (const unsigned char* const Data, const unsigned short
// Check IPTC signatures
char* pos = (char*)(Data + sizeof(short)); // position data pointer after length field
+ char* maxpos = (char*)(Data+itemlen);
+ unsigned char headerLen = 0;
+ unsigned char dataLen = 0;
+ memset(info, 0, sizeof(IPTCInfo_t));
- if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)) != 0) return false;
- pos += strlen(IptcSignature1) + 1; // move data pointer to the next field
+ if (itemlen < 25) return false;
- if (memcmp(pos, IptcSignature2, strlen(IptcSignature2)) != 0) return false;
- pos += strlen(IptcSignature2); // move data pointer to the next field
+ if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)-1) != 0) return false;
+ pos += sizeof(IptcSignature1); // 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
+ if (memcmp(pos, IptcSignature2, strlen(IptcSignature2)-1) != 0) return false;
+ pos += sizeof(IptcSignature2)-1; // move data pointer to the next field
+
+ while (memcmp(pos, IptcSignature3, sizeof(IptcSignature3)) != 0) { // loop on valid Photoshop blocks
+
+ pos += sizeof(IptcSignature3); // move data pointer to the Header Length
+ // Skip header
+ headerLen = *pos; // get header length and move data pointer to the next field
+ pos += (headerLen & 0xfe) + 2; // move data pointer to the next field (Header is padded to even length, counting the length byte)
+
+ pos += 3; // move data pointer to length, assume only one byte, TODO: use all 4 bytes
+
+ dataLen = *pos++;
+ pos += dataLen; // skip data section
+
+ if (memcmp(pos, IptcSignature2, sizeof(IptcSignature2) - 1) != 0) return false;
+ pos += sizeof(IptcSignature2) - 1; // move data pointer to the next field
+ }
+
+ pos += sizeof(IptcSignature3); // move data pointer to the next field
+ if (pos >= maxpos) return false;
// IPTC section found
// Skip header
- unsigned char headerLen = *pos++; // get header length and move data pointer to the next field
+ 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);
+ if (pos + 4 >= maxpos) return false;
+
pos += 4; // move data pointer to the next field
// Now read IPTC data
while (pos < (char*)(Data + itemlen-5))
{
+ if (pos + 5 > maxpos) return false;
+
short signature = (*pos << 8) + (*(pos+1));
- pos += sizeof(short);
- if (signature != 0x1C02)
+ pos += 2;
+ if (signature != 0x1C01 && signature != 0x1C02)
break;
unsigned char type = *pos++;
unsigned short length = (*pos << 8) + (*(pos+1));
- pos += sizeof(short); // Skip tag length
+ pos += 2; // Skip tag length
+
+ if (pos + length > maxpos) return false;
+
// Process tag here
char *tag = NULL;
- switch (type)
+ if (signature == 0x1C02)
{
- 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;
+ switch (type)
+ {
+ case IPTC_RECORD_VERSION: tag = info->RecordVersion; break;
+ 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;
+ case IPTC_TIME_CREATED: tag = info->TimeCreated; break;
+ case IPTC_SUB_LOCATION: tag = info->SubLocation; break;
+ case IPTC_IMAGE_TYPE: tag = info->ImageType; break;
+ default:
+ printf("IptcParse: Unrecognised IPTC tag: 0x%02x", type);
+ break;
+ }
}
if (tag)
diff --git a/lib/libexif/libexif.h b/lib/libexif/libexif.h
index e889892a73..f7dc532f0d 100644
--- a/lib/libexif/libexif.h
+++ b/lib/libexif/libexif.h
@@ -48,6 +48,7 @@ extern "C" {
#define MAX_IPTC_STRING 256
typedef struct {
+ char RecordVersion[MAX_IPTC_STRING];
char SupplementalCategories[MAX_IPTC_STRING];
char Keywords[MAX_IPTC_STRING];
char Caption[MAX_IPTC_STRING];
@@ -69,6 +70,9 @@ typedef struct {
char Copyright[MAX_IPTC_STRING];
char ReferenceService[MAX_IPTC_STRING];
char CountryCode[MAX_IPTC_STRING];
+ char TimeCreated[MAX_IPTC_STRING];
+ char SubLocation[MAX_IPTC_STRING];
+ char ImageType[MAX_IPTC_STRING];
} IPTCInfo_t;
#define MAX_COMMENT 2000
@@ -98,6 +102,7 @@ typedef struct {
int ISOequivalent;
int LightSource;
char Comments[MAX_COMMENT];
+ char Description[MAX_COMMENT];
unsigned ThumbnailOffset; // Exif offset to thumbnail
unsigned ThumbnailSize; // Size of thumbnail.