1 //-------------------------------------------------------------------------- 2 // Process IPTC data and XMP data. 3 //-------------------------------------------------------------------------- 4 #include "jhead.h" 5 6 // IPTC entry types known to Jhead (there's many more defined) 7 #define IPTC_RECORD_VERSION 0x00 8 #define IPTC_SUPLEMENTAL_CATEGORIES 0x14 9 #define IPTC_KEYWORDS 0x19 10 #define IPTC_CAPTION 0x78 11 #define IPTC_AUTHOR 0x7A 12 #define IPTC_HEADLINE 0x69 13 #define IPTC_SPECIAL_INSTRUCTIONS 0x28 14 #define IPTC_CATEGORY 0x0F 15 #define IPTC_BYLINE 0x50 16 #define IPTC_BYLINE_TITLE 0x55 17 #define IPTC_CREDIT 0x6E 18 #define IPTC_SOURCE 0x73 19 #define IPTC_COPYRIGHT_NOTICE 0x74 20 #define IPTC_OBJECT_NAME 0x05 21 #define IPTC_CITY 0x5A 22 #define IPTC_STATE 0x5F 23 #define IPTC_COUNTRY 0x65 24 #define IPTC_TRANSMISSION_REFERENCE 0x67 25 #define IPTC_DATE 0x37 26 #define IPTC_COPYRIGHT 0x0A 27 #define IPTC_COUNTRY_CODE 0x64 28 #define IPTC_REFERENCE_SERVICE 0x2D 29 #define IPTC_TIME_CREATED 0x3C 30 #define IPTC_SUB_LOCATION 0x5C 31 #define IPTC_IMAGE_TYPE 0x82 32 33 //-------------------------------------------------------------------------- 34 // Process and display IPTC marker. 35 // 36 // IPTC block consists of: 37 // - Marker: 1 byte (0xED) 38 // - Block length: 2 bytes 39 // - IPTC Signature: 14 bytes ("Photoshop 3.0\0") 40 // - 8BIM Signature 4 bytes ("8BIM") 41 // - IPTC Block start 2 bytes (0x04, 0x04) 42 // - IPTC Header length 1 byte 43 // - IPTC header Header is padded to even length, counting the length byte 44 // - Length 4 bytes 45 // - IPTC Data which consists of a number of entries, each of which has the following format: 46 // - Signature 2 bytes (0x1C02) 47 // - Entry type 1 byte (for defined entry types, see #defines above) 48 // - entry length 2 bytes 49 // - entry data 'entry length' bytes 50 // 51 //-------------------------------------------------------------------------- 52 void show_IPTC (unsigned char* Data, unsigned int itemlen) 53 { 54 const char IptcSig1[] = "Photoshop 3.0"; 55 const char IptcSig2[] = "8BIM"; 56 const char IptcSig3[] = {0x04, 0x04}; 57 58 unsigned char * pos = Data + sizeof(short); // position data pointer after length field 59 unsigned char * maxpos = Data+itemlen; 60 char headerLen = 0; 61 62 if (itemlen < 25) goto corrupt; 63 64 // Check IPTC signatures 65 if (memcmp(pos, IptcSig1, sizeof(IptcSig1)-1) != 0) goto badsig; 66 pos += sizeof(IptcSig1); // move data pointer to the next field 67 68 if (memcmp(pos, IptcSig2, sizeof(IptcSig2)-1) != 0) goto badsig; 69 pos += sizeof(IptcSig2)-1; // move data pointer to the next field 70 71 if (memcmp(pos, IptcSig3, sizeof(IptcSig3)) != 0){ 72 badsig: 73 if (ShowTags){ 74 ErrNonfatal("IPTC type signature mismatch\n",0,0); 75 } 76 return; 77 } 78 pos += sizeof(IptcSig3); // move data pointer to the next field 79 80 if (pos >= maxpos) goto corrupt; 81 82 // IPTC section found 83 84 // Skip header 85 headerLen = *pos++; // get header length and move data pointer to the next field 86 pos += headerLen + 1 - (headerLen % 2); // move data pointer to the next field (Header is padded to even length, counting the length byte) 87 88 if (pos+4 >= maxpos) goto corrupt; 89 90 // Get length (from motorola format) 91 //length = (*pos << 24) | (*(pos+1) << 16) | (*(pos+2) << 8) | *(pos+3); 92 93 pos += 4; // move data pointer to the next field 94 95 printf("======= IPTC data: =======\n"); 96 97 // Now read IPTC data 98 while (pos < (Data + itemlen-5)) { 99 short signature; 100 unsigned char type = 0; 101 short length = 0; 102 char * description = NULL; 103 104 if (pos+5 > maxpos) goto corrupt; 105 106 signature = (*pos << 8) + (*(pos+1)); 107 pos += 2; 108 109 if (signature != 0x1C02){ 110 break; 111 } 112 113 type = *pos++; 114 length = (*pos << 8) + (*(pos+1)); 115 pos += 2; // Skip tag length 116 117 if (pos+length > maxpos) goto corrupt; 118 // Process tag here 119 switch (type) { 120 case IPTC_RECORD_VERSION: 121 printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1))); 122 break; 123 124 case IPTC_SUPLEMENTAL_CATEGORIES: description = "SuplementalCategories"; break; 125 case IPTC_KEYWORDS: description = "Keywords"; break; 126 case IPTC_CAPTION: description = "Caption"; break; 127 case IPTC_AUTHOR: description = "Author"; break; 128 case IPTC_HEADLINE: description = "Headline"; break; 129 case IPTC_SPECIAL_INSTRUCTIONS: description = "Spec. Instr."; break; 130 case IPTC_CATEGORY: description = "Category"; break; 131 case IPTC_BYLINE: description = "Byline"; break; 132 case IPTC_BYLINE_TITLE: description = "Byline Title"; break; 133 case IPTC_CREDIT: description = "Credit"; break; 134 case IPTC_SOURCE: description = "Source"; break; 135 case IPTC_COPYRIGHT_NOTICE: description = "(C)Notice"; break; 136 case IPTC_OBJECT_NAME: description = "Object Name"; break; 137 case IPTC_CITY: description = "City"; break; 138 case IPTC_STATE: description = "State"; break; 139 case IPTC_COUNTRY: description = "Country"; break; 140 case IPTC_TRANSMISSION_REFERENCE: description = "OriginalTransmissionReference"; break; 141 case IPTC_DATE: description = "DateCreated"; break; 142 case IPTC_COPYRIGHT: description = "(C)Flag"; break; 143 case IPTC_REFERENCE_SERVICE: description = "Country Code"; break; 144 case IPTC_COUNTRY_CODE: description = "Ref. Service"; break; 145 case IPTC_TIME_CREATED: description = "Time Created"; break; 146 case IPTC_SUB_LOCATION: description = "Sub Location"; break; 147 case IPTC_IMAGE_TYPE: description = "Image type"; break; 148 149 default: 150 if (ShowTags){ 151 printf("Unrecognised IPTC tag: %d\n", type ); 152 } 153 break; 154 } 155 if (description != NULL) { 156 char TempBuf[32]; 157 memset(TempBuf, 0, sizeof(TempBuf)); 158 memset(TempBuf, ' ', 14); 159 memcpy(TempBuf, description, strlen(description)); 160 strcat(TempBuf, ":"); 161 printf("%s %*.*s\n", TempBuf, length, length, pos); 162 } 163 pos += length; 164 } 165 return; 166 corrupt: 167 ErrNonfatal("Pointer corruption in IPTC\n",0,0); 168 } 169 170 171 172 //-------------------------------------------------------------------------- 173 // Dump contents of XMP section 174 //-------------------------------------------------------------------------- 175 void ShowXmp(Section_t XmpSection) 176 { 177 unsigned char * Data; 178 char OutLine[101]; 179 int OutLineChars; 180 int NonBlank; 181 unsigned a; 182 NonBlank = 0; 183 Data = XmpSection.Data; 184 OutLineChars = 0; 185 186 187 for (a=0;a<XmpSection.Size;a++){ 188 if (Data[a] >= 32 && Data[a] < 128){ 189 OutLine[OutLineChars++] = Data[a]; 190 if (Data[a] != ' ') NonBlank |= 1; 191 }else{ 192 if (Data[a] != '\n'){ 193 OutLine[OutLineChars++] = '?'; 194 } 195 } 196 if (Data[a] == '\n' || OutLineChars >= 100){ 197 OutLine[OutLineChars] = 0; 198 if (NonBlank){ 199 puts(OutLine); 200 } 201 NonBlank = (NonBlank & 1) << 1; 202 OutLineChars = 0; 203 } 204 } 205 } 206