diff options
Diffstat (limited to 'xbmc/pictures/IptcParse.cpp')
-rw-r--r-- | xbmc/pictures/IptcParse.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/xbmc/pictures/IptcParse.cpp b/xbmc/pictures/IptcParse.cpp new file mode 100644 index 0000000..dc66f27 --- /dev/null +++ b/xbmc/pictures/IptcParse.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +//-------------------------------------------------------------------------- +// Module to pull IPTC information out of various types of digital images. +//-------------------------------------------------------------------------- + +//-------------------------------------------------------------------------- +// Process IPTC data. +//-------------------------------------------------------------------------- + +#include "IptcParse.h" + +#include "ExifParse.h" + +#ifdef TARGET_WINDOWS +#include <windows.h> +#else +#include <string.h> +#endif + +#include <stdio.h> + +#ifndef min +#define min(a,b) (a)>(b)?(b):(a) +#endif + +// Supported IPTC entry types +#define IPTC_RECORD_VERSION 0x00 +#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_URGENCY 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 + + +//-------------------------------------------------------------------------- +// 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 + const char* pos = (const char*)(Data + sizeof(short)); // position data pointer after length field + const char* maxpos = (const char*)(Data+itemlen); + unsigned char headerLen = 0; + unsigned char dataLen = 0; + memset(info, 0, sizeof(IPTCInfo_t)); + + if (itemlen < 25) return false; + + if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)-1) != 0) return false; + pos += sizeof(IptcSignature1); // 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 + 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) + + if (pos + 4 >= maxpos) return false; + + pos += 4; // move data pointer to the next field + + // Now read IPTC data + while (pos < (const char*)(Data + itemlen-5)) + { + if (pos + 5 > maxpos) return false; + + short signature = (*pos << 8) + (*(pos+1)); + + pos += 2; + if (signature != 0x1C01 && signature != 0x1C02) + break; + + unsigned char type = *pos++; + unsigned short length = (*pos << 8) + (*(pos+1)); + pos += 2; // Skip tag length + + if (pos + length > maxpos) return false; + + // Process tag here + char *tag = NULL; + if (signature == 0x1C02) + { + 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_URGENCY: tag = info->Urgency; 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) + { + 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, maxLen - 3)); + } + } +/* if (id == SLIDESHOW_IPTC_CAPTION) + { + CExifParse::FixComment(m_IptcInfo[id]); // Ensure comment is printable + }*/ + } + pos += length; + } + return true; +} + |