blob: 93d6f34bd28aa4a7264d7ef9f97cbc05c8e81ced [file] [log] [blame]
The Android Open Source Project34a25642009-03-03 19:30:03 -08001//--------------------------------------------------------------------------
Chih-Chung Changd6a02c32009-03-24 20:34:28 -07002// Process IPTC data and XMP data.
The Android Open Source Project34a25642009-03-03 19:30:03 -08003//--------------------------------------------------------------------------
4#include "jhead.h"
5
Chih-Chung Changd6a02c32009-03-24 20:34:28 -07006// IPTC entry types known to Jhead (there's many more defined)
7#define IPTC_RECORD_VERSION 0x00
The Android Open Source Project34a25642009-03-03 19:30:03 -08008#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
Chih-Chung Changd6a02c32009-03-24 20:34:28 -070029#define IPTC_TIME_CREATED 0x3C
30#define IPTC_SUB_LOCATION 0x5C
31#define IPTC_IMAGE_TYPE 0x82
The Android Open Source Project34a25642009-03-03 19:30:03 -080032
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//--------------------------------------------------------------------------
52void 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){
72badsig:
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
Chih-Chung Changd6a02c32009-03-24 20:34:28 -070093 pos += 4; // move data pointer to the next field
The Android Open Source Project34a25642009-03-03 19:30:03 -080094
95 printf("======= IPTC data: =======\n");
96
97 // Now read IPTC data
98 while (pos < (Data + itemlen-5)) {
99 short signature;
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700100 unsigned char type = 0;
The Android Open Source Project34a25642009-03-03 19:30:03 -0800101 short length = 0;
102 char * description = NULL;
103
104 if (pos+5 > maxpos) goto corrupt;
105
106 signature = (*pos << 8) + (*(pos+1));
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700107 pos += 2;
The Android Open Source Project34a25642009-03-03 19:30:03 -0800108
109 if (signature != 0x1C02){
110 break;
111 }
112
113 type = *pos++;
114 length = (*pos << 8) + (*(pos+1));
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700115 pos += 2; // Skip tag length
The Android Open Source Project34a25642009-03-03 19:30:03 -0800116
117 if (pos+length > maxpos) goto corrupt;
118 // Process tag here
119 switch (type) {
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700120 case IPTC_RECORD_VERSION:
121 printf("Record vers. : %d\n", (*pos << 8) + (*(pos+1)));
122 break;
123
The Android Open Source Project34a25642009-03-03 19:30:03 -0800124 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;
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700129 case IPTC_SPECIAL_INSTRUCTIONS: description = "Spec. Instr."; break;
The Android Open Source Project34a25642009-03-03 19:30:03 -0800130 case IPTC_CATEGORY: description = "Category"; break;
131 case IPTC_BYLINE: description = "Byline"; break;
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700132 case IPTC_BYLINE_TITLE: description = "Byline Title"; break;
The Android Open Source Project34a25642009-03-03 19:30:03 -0800133 case IPTC_CREDIT: description = "Credit"; break;
134 case IPTC_SOURCE: description = "Source"; break;
135 case IPTC_COPYRIGHT_NOTICE: description = "(C)Notice"; break;
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700136 case IPTC_OBJECT_NAME: description = "Object Name"; break;
The Android Open Source Project34a25642009-03-03 19:30:03 -0800137 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;
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700143 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
The Android Open Source Project34a25642009-03-03 19:30:03 -0800149 default:
150 if (ShowTags){
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700151 printf("Unrecognised IPTC tag: %d\n", type );
The Android Open Source Project34a25642009-03-03 19:30:03 -0800152 }
153 break;
154 }
155 if (description != NULL) {
156 char TempBuf[32];
157 memset(TempBuf, 0, sizeof(TempBuf));
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700158 memset(TempBuf, ' ', 14);
The Android Open Source Project34a25642009-03-03 19:30:03 -0800159 memcpy(TempBuf, description, strlen(description));
160 strcat(TempBuf, ":");
161 printf("%s %*.*s\n", TempBuf, length, length, pos);
162 }
163 pos += length;
164 }
165 return;
166corrupt:
167 ErrNonfatal("Pointer corruption in IPTC\n",0,0);
168}
Chih-Chung Changd6a02c32009-03-24 20:34:28 -0700169
170
171
172//--------------------------------------------------------------------------
173// Dump contents of XMP section
174//--------------------------------------------------------------------------
175void 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}