summaryrefslogtreecommitdiffstats
path: root/xbmc/pictures/IptcParse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/pictures/IptcParse.cpp')
-rw-r--r--xbmc/pictures/IptcParse.cpp212
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;
+}
+