blob: 37f7127017052dfbf14dbdba6e556dc14747994c [file] [log] [blame]
//--------------------------------------------------------------------------
// Process IPTC data.
//--------------------------------------------------------------------------
#include "jhead.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 and display IPTC 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
//
//--------------------------------------------------------------------------
void show_IPTC (unsigned char* Data, unsigned int itemlen)
{
const char IptcSig1[] = "Photoshop 3.0";
const char IptcSig2[] = "8BIM";
const char IptcSig3[] = {0x04, 0x04};
unsigned char * pos = Data + sizeof(short); // position data pointer after length field
unsigned char * maxpos = Data+itemlen;
char headerLen = 0;
if (itemlen < 25) goto corrupt;
// Check IPTC signatures
if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig;
pos += sizeof(IptcSig1); // move data pointer to the next field
if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig;
pos += sizeof(IptcSig2)-1; // move data pointer to the next field
if (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0){
badsig:
if (ShowTags){
ErrNonfatal("IPTC type signature mismatch\n",0,0);
}
return;
}
pos += sizeof(IptcSig3); // move data pointer to the next field
if (pos >= maxpos) goto corrupt;
// 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) goto corrupt;
// Get length (from motorola format)
//length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3);
pos += sizeof(long); // move data pointer to the next field
printf("======= IPTC data: =======\n");
// Now read IPTC data
while (pos < (Data + itemlen-5)) {
short signature;
char type = 0;
short length = 0;
char * description = NULL;
if (pos+5 > maxpos) goto corrupt;
signature = (*pos << 8) + (*(pos+1));
pos += sizeof(short);
if (signature != 0x1C02){
break;
}
type = *pos++;
length = (*pos << 8) + (*(pos+1));
pos += sizeof(short); // Skip tag length
if (pos+length > maxpos) goto corrupt;
// Process tag here
switch (type) {
case IPTC_SUPLEMENTAL_CATEGORIES: description = "SuplementalCategories"; break;
case IPTC_KEYWORDS: description = "Keywords"; break;
case IPTC_CAPTION: description = "Caption"; break;
case IPTC_AUTHOR: description = "Author"; break;
case IPTC_HEADLINE: description = "Headline"; break;
case IPTC_SPECIAL_INSTRUCTIONS: description = "Spec.Instr."; break;
case IPTC_CATEGORY: description = "Category"; break;
case IPTC_BYLINE: description = "Byline"; break;
case IPTC_BYLINE_TITLE: description = "BylineTitle"; break;
case IPTC_CREDIT: description = "Credit"; break;
case IPTC_SOURCE: description = "Source"; break;
case IPTC_COPYRIGHT_NOTICE: description = "(C)Notice"; break;
case IPTC_OBJECT_NAME: description = "ObjectName"; break;
case IPTC_CITY: description = "City"; break;
case IPTC_STATE: description = "State"; break;
case IPTC_COUNTRY: description = "Country"; break;
case IPTC_TRANSMISSION_REFERENCE: description = "OriginalTransmissionReference"; break;
case IPTC_DATE: description = "DateCreated"; break;
case IPTC_COPYRIGHT: description = "(C)Flag"; break;
case IPTC_REFERENCE_SERVICE: description = "CountryCode"; break;
case IPTC_COUNTRY_CODE: description = "Ref.Service"; break;
default:
if (ShowTags){
printf("Unrecognised IPTC tag: 0x%02x \n", type);
}
break;
}
if (description != NULL) {
char TempBuf[32];
memset(TempBuf, 0, sizeof(TempBuf));
memset(TempBuf, ' ', 13);
memcpy(TempBuf, description, strlen(description));
strcat(TempBuf, ":");
printf("%s %*.*s\n", TempBuf, length, length, pos);
}
pos += length;
}
return;
corrupt:
ErrNonfatal("Pointer corruption in IPTC\n",0,0);
}