diff options
author | Arne Morten Kvarving <spiff@xbmc.org> | 2012-03-27 14:31:23 -0700 |
---|---|---|
committer | Arne Morten Kvarving <spiff@xbmc.org> | 2012-03-27 14:31:23 -0700 |
commit | 42399911e2255cfe00a800f58a59e50c771c063d (patch) | |
tree | e2b0ac30d088358ace924142f91cc291c4f4f7ff /lib | |
parent | 08f3227778134ca5833dee42d03bfe04571a8964 (diff) | |
parent | a12dc4ad32a4f6627487861508831fd3bfeabfed (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.cpp | 10 | ||||
-rw-r--r-- | lib/libexif/IptcParse.cpp | 112 | ||||
-rw-r--r-- | lib/libexif/libexif.h | 5 |
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. |