Merge pull request #4011 from fritsch/vdpau-settings
[vuplus_xbmc] / lib / libexif / IptcParse.cpp
1 /*
2  *      Copyright (C) 2005-2007 Team XboxMediaCenter
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with GNU Make; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 //--------------------------------------------------------------------------
23 // Module to pull IPTC information out of various types of digital images.
24 //--------------------------------------------------------------------------
25
26 //--------------------------------------------------------------------------
27 //  Process IPTC data.
28 //--------------------------------------------------------------------------
29 #ifndef _LINUX
30 #include <windows.h>
31 #else
32 #include <string.h>
33 #define min(a,b) (a)>(b)?(b):(a)
34 #endif
35 #include <stdio.h>
36 #include "IptcParse.h"
37 #include "ExifParse.h"
38
39 // Supported IPTC entry types
40 #define IPTC_RECORD_VERSION         0x00
41 #define IPTC_SUPLEMENTAL_CATEGORIES 0x14
42 #define IPTC_KEYWORDS               0x19
43 #define IPTC_CAPTION                0x78
44 #define IPTC_AUTHOR                 0x7A
45 #define IPTC_HEADLINE               0x69
46 #define IPTC_SPECIAL_INSTRUCTIONS   0x28
47 #define IPTC_CATEGORY               0x0F
48 #define IPTC_BYLINE                 0x50
49 #define IPTC_BYLINE_TITLE           0x55
50 #define IPTC_CREDIT                 0x6E
51 #define IPTC_SOURCE                 0x73
52 #define IPTC_COPYRIGHT_NOTICE       0x74
53 #define IPTC_OBJECT_NAME            0x05
54 #define IPTC_CITY                   0x5A
55 #define IPTC_STATE                  0x5F
56 #define IPTC_COUNTRY                0x65
57 #define IPTC_TRANSMISSION_REFERENCE 0x67
58 #define IPTC_DATE                   0x37
59 #define IPTC_URGENCY                0x0A
60 #define IPTC_COUNTRY_CODE           0x64
61 #define IPTC_REFERENCE_SERVICE      0x2D
62 #define IPTC_TIME_CREATED           0x3C
63 #define IPTC_SUB_LOCATION           0x5C
64 #define IPTC_IMAGE_TYPE             0x82
65
66
67 //--------------------------------------------------------------------------
68 //  Process IPTC marker. Return FALSE if unable to process marker.
69 //
70 //  IPTC block consists of:
71 //    - Marker:              1 byte   (0xED)
72 //    - Block length:        2 bytes
73 //    - IPTC Signature:     14 bytes    ("Photoshop 3.0\0")
74 //    - 8BIM Signature       4 bytes     ("8BIM")
75 //    - IPTC Block start     2 bytes     (0x04, 0x04)
76 //    - IPTC Header length   1 byte
77 //    - IPTC header         Header is padded to even length, counting the length byte
78 //    - Length               4 bytes
79 //    - IPTC Data which consists of a number of entries, each of which has the following format:
80 //            - Signature    2 bytes     (0x1C02)
81 //            - Entry type   1 byte   (for defined entry types, see #defines above)
82 //            - entry length 2 bytes
83 //            - entry data   'entry length' bytes
84 //
85 //--------------------------------------------------------------------------
86 bool CIptcParse::Process (const unsigned char* const Data, const unsigned short itemlen, IPTCInfo_t *info)
87 {
88   if (!info) return false;
89
90   const char IptcSignature1[] = "Photoshop 3.0";
91   const char IptcSignature2[] = "8BIM";
92   const char IptcSignature3[] = {0x04, 0x04};
93
94   // Check IPTC signatures
95   char* pos = (char*)(Data + sizeof(short));  // position data pointer after length field
96   char* maxpos = (char*)(Data+itemlen);
97   unsigned char headerLen = 0;
98   unsigned char dataLen = 0;
99   memset(info, 0, sizeof(IPTCInfo_t));
100
101   if (itemlen < 25) return false;
102
103   if (memcmp(pos, IptcSignature1, strlen(IptcSignature1)-1) != 0) return false;
104   pos += sizeof(IptcSignature1);          // move data pointer to the next field
105
106   if (memcmp(pos, IptcSignature2, strlen(IptcSignature2)-1) != 0) return false;
107   pos += sizeof(IptcSignature2)-1;              // move data pointer to the next field
108
109   while (memcmp(pos, IptcSignature3, sizeof(IptcSignature3)) != 0) { // loop on valid Photoshop blocks
110
111     pos += sizeof(IptcSignature3); // move data pointer to the Header Length
112     // Skip header
113     headerLen = *pos; // get header length and move data pointer to the next field
114     pos += (headerLen & 0xfe) + 2; // move data pointer to the next field (Header is padded to even length, counting the length byte)
115
116     pos += 3; // move data pointer to length, assume only one byte, TODO: use all 4 bytes
117
118     dataLen = *pos++;
119     pos += dataLen; // skip data section
120
121     if (memcmp(pos, IptcSignature2, sizeof(IptcSignature2) - 1) != 0) return false;
122     pos += sizeof(IptcSignature2) - 1; // move data pointer to the next field
123   }
124
125   pos += sizeof(IptcSignature3);          // move data pointer to the next field
126   if (pos >= maxpos) return false;
127
128   // IPTC section found
129
130   // Skip header
131   headerLen = *pos++;           // get header length and move data pointer to the next field
132   pos += headerLen + 1 - (headerLen % 2);     // move data pointer to the next field (Header is padded to even length, counting the length byte)
133
134   if (pos + 4 >= maxpos) return false;
135
136   pos += 4;                                   // move data pointer to the next field
137
138   // Now read IPTC data
139   while (pos < (char*)(Data + itemlen-5))
140   {
141     if (pos + 5 > maxpos) return false;
142
143     short signature = (*pos << 8) + (*(pos+1));
144
145     pos += 2;
146     if (signature != 0x1C01 && signature != 0x1C02)
147       break;
148
149     unsigned char  type = *pos++;
150     unsigned short length  = (*pos << 8) + (*(pos+1));
151     pos += 2;                   // Skip tag length
152
153     if (pos + length > maxpos) return false;
154
155     // Process tag here
156     char *tag = NULL;
157     if (signature == 0x1C02)
158     {
159       switch (type)
160       {
161         case IPTC_RECORD_VERSION:           tag = info->RecordVersion;           break;
162         case IPTC_SUPLEMENTAL_CATEGORIES:   tag = info->SupplementalCategories;  break;
163         case IPTC_KEYWORDS:                 tag = info->Keywords;                break;
164         case IPTC_CAPTION:                  tag = info->Caption;                 break;
165         case IPTC_AUTHOR:                   tag = info->Author;                  break;
166         case IPTC_HEADLINE:                 tag = info->Headline;                break;
167         case IPTC_SPECIAL_INSTRUCTIONS:     tag = info->SpecialInstructions;     break;
168         case IPTC_CATEGORY:                 tag = info->Category;                break;
169         case IPTC_BYLINE:                   tag = info->Byline;                  break;
170         case IPTC_BYLINE_TITLE:             tag = info->BylineTitle;             break;
171         case IPTC_CREDIT:                   tag = info->Credit;                  break;
172         case IPTC_SOURCE:                   tag = info->Source;                  break;
173         case IPTC_COPYRIGHT_NOTICE:         tag = info->CopyrightNotice;         break;
174         case IPTC_OBJECT_NAME:              tag = info->ObjectName;              break;
175         case IPTC_CITY:                     tag = info->City;                    break;
176         case IPTC_STATE:                    tag = info->State;                   break;
177         case IPTC_COUNTRY:                  tag = info->Country;                 break;
178         case IPTC_TRANSMISSION_REFERENCE:   tag = info->TransmissionReference;   break;
179         case IPTC_DATE:                     tag = info->Date;                    break;
180         case IPTC_URGENCY:                  tag = info->Urgency;                 break;
181         case IPTC_REFERENCE_SERVICE:        tag = info->ReferenceService;        break;
182         case IPTC_COUNTRY_CODE:             tag = info->CountryCode;             break;
183         case IPTC_TIME_CREATED:             tag = info->TimeCreated;             break;
184         case IPTC_SUB_LOCATION:             tag = info->SubLocation;             break;
185         case IPTC_IMAGE_TYPE:               tag = info->ImageType;               break;
186         default:
187           printf("IptcParse: Unrecognised IPTC tag: 0x%02x", type);
188           break;
189       }
190     }
191
192     if (tag)
193     {
194       if (type != IPTC_KEYWORDS || *tag == 0)
195       {
196         strncpy(tag, pos, min(length, MAX_IPTC_STRING - 1));
197         tag[min(length, MAX_IPTC_STRING - 1)] = 0;
198       }
199       else if (type == IPTC_KEYWORDS)
200       {
201         // there may be multiple keywords - lets join them
202         size_t maxLen = MAX_IPTC_STRING - strlen(tag);
203         if (maxLen > 2)
204         {
205           strcat(tag, ", ");
206           strncat(tag, pos, min(length, maxLen - 3));
207         }
208       }
209 /*      if (id == SLIDE_IPTC_CAPTION)
210       {
211         CExifParse::FixComment(m_IptcInfo[id]);     // Ensure comment is printable
212       }*/
213     }
214     pos += length;
215   }
216   return true;
217 }
218