205 lines
7.9 KiB
C
205 lines
7.9 KiB
C
//--------------------------------------------------------------------------
|
|
// Process IPTC data and XMP data.
|
|
//--------------------------------------------------------------------------
|
|
#include "jhead.h"
|
|
|
|
// IPTC entry types known to Jhead (there's many more defined)
|
|
#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_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
|
|
|
|
//--------------------------------------------------------------------------
|
|
// 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 += 4; // move data pointer to the next field
|
|
|
|
printf("======= IPTC data: =======\n");
|
|
|
|
// Now read IPTC data
|
|
while (pos < (Data + itemlen-5)) {
|
|
short signature;
|
|
unsigned char type = 0;
|
|
short length = 0;
|
|
char * description = NULL;
|
|
|
|
if (pos+5 > maxpos) goto corrupt;
|
|
|
|
signature = (*pos << 8) + (*(pos+1));
|
|
pos += 2;
|
|
|
|
if (signature != 0x1C02){
|
|
break;
|
|
}
|
|
|
|
type = *pos++;
|
|
length = (*pos << 8) + (*(pos+1));
|
|
pos += 2; // Skip tag length
|
|
|
|
if (pos+length > maxpos) goto corrupt;
|
|
// Process tag here
|
|
switch (type) {
|
|
case IPTC_RECORD_VERSION:
|
|
printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1)));
|
|
break;
|
|
|
|
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 = "Byline Title"; 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 = "Object Name"; 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 = "Country Code"; break;
|
|
case IPTC_COUNTRY_CODE: description = "Ref. Service"; break;
|
|
case IPTC_TIME_CREATED: description = "Time Created"; break;
|
|
case IPTC_SUB_LOCATION: description = "Sub Location"; break;
|
|
case IPTC_IMAGE_TYPE: description = "Image type"; break;
|
|
|
|
default:
|
|
if (ShowTags){
|
|
printf("Unrecognised IPTC tag: %d\n", type );
|
|
}
|
|
break;
|
|
}
|
|
if (description != NULL) {
|
|
char TempBuf[32];
|
|
memset(TempBuf, 0, sizeof(TempBuf));
|
|
memset(TempBuf, ' ', 14);
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Dump contents of XMP section
|
|
//--------------------------------------------------------------------------
|
|
void ShowXmp(Section_t XmpSection)
|
|
{
|
|
unsigned char * Data;
|
|
char OutLine[101];
|
|
int OutLineChars;
|
|
int NonBlank;
|
|
unsigned a;
|
|
NonBlank = 0;
|
|
Data = XmpSection.Data;
|
|
OutLineChars = 0;
|
|
|
|
|
|
for (a=0;a<XmpSection.Size;a++){
|
|
if (Data[a] >= 32 && Data[a] < 128){
|
|
OutLine[OutLineChars++] = Data[a];
|
|
if (Data[a] != ' ') NonBlank |= 1;
|
|
}else{
|
|
if (Data[a] != '\n'){
|
|
OutLine[OutLineChars++] = '?';
|
|
}
|
|
}
|
|
if (Data[a] == '\n' || OutLineChars >= 100){
|
|
OutLine[OutLineChars] = 0;
|
|
if (NonBlank){
|
|
puts(OutLine);
|
|
}
|
|
NonBlank = (NonBlank & 1) << 1;
|
|
OutLineChars = 0;
|
|
}
|
|
}
|
|
}
|