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 //--------------------------------------------------------------------------
show_IPTC(unsigned char * Data,unsigned int itemlen)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 //--------------------------------------------------------------------------
ShowXmp(Section_t XmpSection)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