1 // ***************************************************************** -*- C++ -*-
2 /*
3  * Copyright (C) 2004-2017 Andreas Huggel <ahuggel@gmx.net>
4  *
5  * This program is part of the Exiv2 distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20  */
21 /*
22   File:      datasets.cpp
23   Version:   $Rev: 4719 $
24   Author(s): Brad Schick (brad) <brad@robotbattle.com>
25              Gilles Caulier (gc) <caulier dot gilles at gmail dot com>
26   History:   24-Jul-04, brad: created
27  */
28 // *****************************************************************************
29 #include "rcsid_int.hpp"
30 EXIV2_RCSID("@(#) $Id: datasets.cpp 4719 2017-03-08 20:42:28Z robinwmills $")
31 
32 // *****************************************************************************
33 // included header files
34 #include "datasets.hpp"
35 #include "error.hpp"
36 #include "types.hpp"
37 #include "value.hpp"
38 #include "metadatum.hpp"
39 #include "i18n.h"                // NLS support.
40 
41 #include <iostream>
42 #include <iomanip>
43 #include <sstream>
44 
45 // *****************************************************************************
46 // class member definitions
47 namespace Exiv2 {
48 
DataSet(uint16_t number,const char * name,const char * title,const char * desc,bool mandatory,bool repeatable,uint32_t minbytes,uint32_t maxbytes,TypeId type,uint16_t recordId,const char * photoshop)49     DataSet::DataSet(
50         uint16_t number,
51         const char* name,
52         const char* title,
53         const char* desc,
54         bool mandatory,
55         bool repeatable,
56         uint32_t minbytes,
57         uint32_t maxbytes,
58         TypeId type,
59         uint16_t recordId,
60         const char* photoshop
61     )
62         : number_(number), name_(name), title_(title), desc_(desc),
63           mandatory_(mandatory), repeatable_(repeatable), minbytes_(minbytes),
64           maxbytes_(maxbytes), type_(type), recordId_(recordId),
65           photoshop_(photoshop)
66     {
67     }
68 
RecordInfo(uint16_t recordId,const char * name,const char * desc)69     RecordInfo::RecordInfo(
70         uint16_t recordId,
71         const char* name,
72         const char* desc
73     )
74         : recordId_(recordId), name_(name), desc_(desc)
75     {
76     }
77 
78     const RecordInfo IptcDataSets::recordInfo_[] = {
79         RecordInfo(IptcDataSets::invalidRecord, "(invalid)", N_("(invalid)")),
80         RecordInfo(IptcDataSets::envelope, "Envelope", N_("IIM envelope record")),
81         RecordInfo(IptcDataSets::application2, "Application2", N_("IIM application record 2")),
82     };
83 
84     static const DataSet envelopeRecord[] = {
85         DataSet(IptcDataSets::ModelVersion, "ModelVersion", N_("Model Version"),
86                 N_("A binary number identifying the version of the Information "
87                 "Interchange Model, Part I, utilised by the provider. Version "
88                 "numbers are assigned by IPTC and NAA organizations."),
89                 true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
90         DataSet(IptcDataSets::Destination, "Destination", N_("Destination"),
91                 N_("This DataSet is to accommodate some providers who require "
92                 "routing information above the appropriate OSI layers."),
93                 false, true, 0, 1024, Exiv2::string, IptcDataSets::envelope, ""),
94         DataSet(IptcDataSets::FileFormat, "FileFormat", N_("File Format"),
95                 N_("A binary number representing the file format. The file format "
96                 "must be registered with IPTC or NAA with a unique number "
97                 "assigned to it. The information is used to route "
98                 "the data to the appropriate system and to allow the receiving "
99                 "system to perform the appropriate actions there to."),
100                 true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
101         DataSet(IptcDataSets::FileVersion, "FileVersion", N_("File Version"),
102                 N_("A binary number representing the particular version of the File "
103                 "Format specified by <FileFormat> tag."),
104                 true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
105         DataSet(IptcDataSets::ServiceId, "ServiceId", N_("Service Id"),
106                 N_("Identifies the provider and product"),
107                 true, false, 0, 10, Exiv2::string, IptcDataSets::envelope, ""),
108         DataSet(IptcDataSets::EnvelopeNumber, "EnvelopeNumber", N_("Envelope Number"),
109                 N_("The characters form a number that will be unique for the date "
110                 "specified in <DateSent> tag and for the Service Identifier "
111                 "specified by <ServiceIdentifier> tag. "
112                 "If identical envelope numbers appear with the same date and "
113                 "with the same Service Identifier, records 2-9 must be unchanged "
114                 "from the original. This is not intended to be a sequential serial "
115                 "number reception check."),
116                 true, false, 8, 8, Exiv2::string, IptcDataSets::envelope, ""),
117         DataSet(IptcDataSets::ProductId, "ProductId", N_("Product Id"),
118                 N_("Allows a provider to identify subsets of its overall service. Used "
119                 "to provide receiving organisation data on which to select, route, "
120                 "or otherwise handle data."),
121                 false, true, 0, 32, Exiv2::string, IptcDataSets::envelope, ""),
122         DataSet(IptcDataSets::EnvelopePriority, "EnvelopePriority", N_("Envelope Priority"),
123                 N_("Specifies the envelope handling priority and not the editorial "
124                 "urgency (see <Urgency> tag). \"1\" indicates the most urgent, \"5\" "
125                 "the normal urgency, and \"8\" the least urgent copy. The numeral "
126                 "\"9\" indicates a User Defined Priority. The numeral \"0\" is reserved "
127                 "for future use."),
128                 false, false, 1, 1, Exiv2::string, IptcDataSets::envelope, ""),
129         DataSet(IptcDataSets::DateSent, "DateSent", N_("Date Sent"),
130                 N_("Uses the format CCYYMMDD (century, year, month, day) as de-fined "
131                 "in ISO 8601 to indicate year, month and day the service sent the material."),
132                 true, false, 8, 8, Exiv2::date, IptcDataSets::envelope, ""),
133         DataSet(IptcDataSets::TimeSent, "TimeSent", N_("Time Sent"),
134                 N_("Uses the format HHMMSS:HHMM where HHMMSS refers to "
135                 "local hour, minute and seconds and HHMM refers to hours and "
136                 "minutes ahead (+) or behind (-) Universal Coordinated Time as "
137                 "described in ISO 8601. This is the time the service sent the material."),
138                 false, false, 11, 11, Exiv2::time, IptcDataSets::envelope, ""),
139         DataSet(IptcDataSets::CharacterSet, "CharacterSet", N_("Character Set"),
140                 N_("This tag consisting of one or more control functions used for the announcement, "
141                 "invocation or designation of coded character sets. The control functions follow "
142                 "the ISO 2022 standard and may consist of the escape control "
143                 "character and one or more graphic characters."),
144                 false, false, 0, 32, Exiv2::string, IptcDataSets::envelope, ""),
145         DataSet(IptcDataSets::UNO, "UNO", N_("Unique Name Object"),
146                 N_("This tag provide a globally unique "
147                 "identification for objects as specified in the IIM, independent of "
148                 "provider and for any media form. The provider must ensure the "
149                 "UNO is unique. Objects with the same UNO are identical."),
150                 false, false, 14, 80, Exiv2::string, IptcDataSets::envelope, ""),
151         DataSet(IptcDataSets::ARMId, "ARMId", N_("ARM Identifier"),
152                 N_("The DataSet identifies the Abstract Relationship Method identifier (ARM) "
153                 "which is described in a document registered by the originator of "
154                 "the ARM with the IPTC and NAA organizations."),
155                 false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
156         DataSet(IptcDataSets::ARMVersion, "ARMVersion", N_("ARM Version"),
157                 N_("This tag consisting of a binary number representing the particular "
158                 "version of the ARM specified by tag <ARMId>."),
159                 false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::envelope, ""),
160         DataSet(0xffff, "(Invalid)", "(Invalid)",
161                 "(Invalid)", false, false, 0, 0, Exiv2::unsignedShort, IptcDataSets::envelope, "")
162     };
163 
envelopeRecordList()164     const DataSet* IptcDataSets::envelopeRecordList()
165     {
166         return envelopeRecord;
167     }
168 
169     static const DataSet application2Record[] = {
170         DataSet(IptcDataSets::RecordVersion, "RecordVersion", N_("Record Version"),
171                 N_("A binary number identifying the version of the Information "
172                 "Interchange Model, Part II, utilised by the provider. "
173                 "Version numbers are assigned by IPTC and NAA organizations."),
174                 true, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""),
175         DataSet(IptcDataSets::ObjectType, "ObjectType", N_("Object Type"),
176                 N_("The Object Type is used to distinguish between different types "
177                 "of objects within the IIM. The first part is a number representing "
178                 "a language independent international reference to an Object Type "
179                 "followed by a colon separator. The second part, if used, is a text "
180                 "representation of the Object Type Number consisting of graphic "
181                 "characters plus spaces either in English or in the language of the "
182                 "service as indicated in tag <LanguageIdentifier>"),
183                 false, false, 3, 67, Exiv2::string, IptcDataSets::application2, ""),
184         DataSet(IptcDataSets::ObjectAttribute, "ObjectAttribute", N_("Object Attribute"),
185                 N_("The Object Attribute defines the nature of the object "
186                 "independent of the Subject. The first part is a number representing "
187                 "a language independent international reference to an Object Attribute "
188                 "followed by a colon separator. The second part, if used, is a text "
189                 "representation of the Object Attribute Number consisting of graphic "
190                 "characters plus spaces either in English, or in the language of the "
191                 "service as indicated in tag <LanguageIdentifier>"),
192                 false, true, 4, 68, Exiv2::string, IptcDataSets::application2, ""),
193         DataSet(IptcDataSets::ObjectName, "ObjectName", N_("Object Name"),
194                 N_("Used as a shorthand reference for the object. Changes to exist-ing "
195                 "data, such as updated stories or new crops on photos, should be "
196                 "identified in tag <EditStatus>."),
197                 false, false, 0, 64, Exiv2::string, IptcDataSets::application2,
198                 N_("Document Title")),
199         DataSet(IptcDataSets::EditStatus, "EditStatus", N_("Edit Status"),
200                 N_("Status of the object data, according to the practice of the provider."),
201                 false, false, 0, 64, Exiv2::string, IptcDataSets::application2, ""),
202         DataSet(IptcDataSets::EditorialUpdate, "EditorialUpdate", N_("Editorial Update"),
203                 N_("Indicates the type of update that this object provides to a "
204                 "previous object. The link to the previous object is made using "
205                 "the tags <ARMIdentifier> and <ARMVersion>, according to the practices of the provider."),
206                 false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
207         DataSet(IptcDataSets::Urgency, "Urgency", N_("Urgency"),
208                 N_("Specifies the editorial urgency of content and not necessarily the "
209                 "envelope handling priority (see tag <EnvelopePriority>). The \"1\" "
210                 "is most urgent, \"5\" normal and \"8\" denotes the least-urgent copy."),
211                 false, false, 1, 1, Exiv2::string, IptcDataSets::application2,
212                 N_("Urgency")),
213         DataSet(IptcDataSets::Subject, "Subject", N_("Subject"),
214                 N_("The Subject Reference is a structured definition of the subject matter."),
215                 false, true, 13, 236, Exiv2::string, IptcDataSets::application2, ""),
216         DataSet(IptcDataSets::Category, "Category", N_("Category"),
217                 N_("Identifies the subject of the object data in the opinion of the provider. "
218                 "A list of categories will be maintained by a regional registry, "
219                 "where available, otherwise by the provider."),
220                 false, false, 0, 3, Exiv2::string, IptcDataSets::application2,
221                 N_("Category")),
222         DataSet(IptcDataSets::SuppCategory, "SuppCategory", N_("Supplemental Category"),
223                 N_("Supplemental categories further refine the subject of an "
224                 "object data. A supplemental category may include "
225                 "any of the recognised categories as used in tag <Category>. Otherwise, "
226                 "selection of supplemental categories are left to the provider."),
227                 false, true, 0, 32, Exiv2::string, IptcDataSets::application2,
228                 N_("Supplemental Categories")),
229         DataSet(IptcDataSets::FixtureId, "FixtureId", N_("Fixture Id"),
230                 N_("Identifies object data that recurs often and predictably. Enables "
231                 "users to immediately find or recall such an object."),
232                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
233         DataSet(IptcDataSets::Keywords, "Keywords", N_("Keywords"),
234                 N_("Used to indicate specific information retrieval words. "
235                 "It is expected that a provider of various types of data that are related "
236                 "in subject matter uses the same keyword, enabling the receiving system "
237                 "or subsystems to search across all types of data for related material."),
238                 false, true, 0, 64, Exiv2::string, IptcDataSets::application2,
239                 N_("Keywords")),
240         DataSet(IptcDataSets::LocationCode, "LocationCode", N_("Location Code"),
241                 N_("Indicates the code of a country/geographical location referenced "
242                 "by the content of the object. Where ISO has established an appropriate "
243                 "country code under ISO 3166, that code will be used. When ISO 3166 does not "
244                 "adequately provide for identification of a location or a country, "
245                 "e.g. ships at sea, space, IPTC will assign an appropriate three-character "
246                 "code under the provisions of ISO 3166 to avoid conflicts."),
247                 false, true, 3, 3, Exiv2::string, IptcDataSets::application2, ""),
248         DataSet(IptcDataSets::LocationName, "LocationName", N_("Location Name"),
249                 N_("Provides a full, publishable name of a country/geographical "
250                 "location referenced by the content of the object, according to "
251                 "guidelines of the provider."),
252                 false, true, 0, 64, Exiv2::string, IptcDataSets::application2, ""),
253         DataSet(IptcDataSets::ReleaseDate, "ReleaseDate", N_("Release Date"),
254                 N_("Designates in the form CCYYMMDD the earliest date the "
255                 "provider intends the object to be used. Follows ISO 8601 standard."),
256                 false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
257         DataSet(IptcDataSets::ReleaseTime, "ReleaseTime", N_("Release Time"),
258                 N_("Designates in the form HHMMSS:HHMM the earliest time the "
259                 "provider intends the object to be used. Follows ISO 8601 standard."),
260                 false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""),
261         DataSet(IptcDataSets::ExpirationDate, "ExpirationDate", N_("Expiration Date"),
262                 N_("Designates in the form CCYYMMDD the latest date the provider "
263                 "or owner intends the object data to be used. Follows ISO 8601 standard."),
264                 false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
265         DataSet(IptcDataSets::ExpirationTime, "ExpirationTime", N_("ExpirationTime"),
266                 N_("Designates in the form HHMMSS:HHMM the latest time the "
267                 "provider or owner intends the object data to be used. Follows ISO 8601 standard."),
268                 false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""),
269         DataSet(IptcDataSets::SpecialInstructions, "SpecialInstructions", N_("Special Instructions"),
270                 N_("Other editorial instructions concerning the use of the object data, "
271                 "such as embargoes and warnings."),
272                 false, false, 0, 256, Exiv2::string, IptcDataSets::application2,
273                 N_("Instructions")),
274         DataSet(IptcDataSets::ActionAdvised, "ActionAdvised", N_("Action Advised"),
275                 N_("Indicates the type of action that this object provides to a "
276                 "previous object. The link to the previous object is made using "
277                 "tags <ARMIdentifier> and <ARMVersion>, according to the practices of the provider."),
278                 false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
279         DataSet(IptcDataSets::ReferenceService, "ReferenceService", N_("Reference Service"),
280                 N_("Identifies the Service Identifier of a prior envelope to which the "
281                 "current object refers."),
282                 false, true, 0, 10, Exiv2::string, IptcDataSets::application2, ""),
283         DataSet(IptcDataSets::ReferenceDate, "ReferenceDate", N_("Reference Date"),
284                 N_("Identifies the date of a prior envelope to which the current object refers."),
285                 false, true, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
286         DataSet(IptcDataSets::ReferenceNumber, "ReferenceNumber", N_("Reference Number"),
287                 N_("Identifies the Envelope Number of a prior envelope to which the current object refers."),
288                 false, true, 8, 8, Exiv2::string, IptcDataSets::application2, ""),
289         DataSet(IptcDataSets::DateCreated, "DateCreated", N_("Date Created"),
290                 N_("Represented in the form CCYYMMDD to designate the date the "
291                 "intellectual content of the object data was created rather than the "
292                 "date of the creation of the physical representation. Follows ISO 8601 standard."),
293                 false, false, 8, 8, Exiv2::date, IptcDataSets::application2,
294                 N_("Date Created")),
295         DataSet(IptcDataSets::TimeCreated, "TimeCreated", N_("Time Created"),
296                 N_("Represented in the form HHMMSS:HHMM to designate the "
297                 "time the intellectual content of the object data current source "
298                 "material was created rather than the creation of the physical "
299                 "representation. Follows ISO 8601 standard."),
300                 false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""),
301         DataSet(IptcDataSets::DigitizationDate, "DigitizationDate", N_("Digitization Date"),
302                 N_("Represented in the form CCYYMMDD to designate the date the "
303                 "digital representation of the object data was created. Follows ISO 8601 standard."),
304                 false, false, 8, 8, Exiv2::date, IptcDataSets::application2, ""),
305         DataSet(IptcDataSets::DigitizationTime, "DigitizationTime", N_("Digitization Time"),
306                 N_("Represented in the form HHMMSS:HHMM to designate the "
307                 "time the digital representation of the object data was created. "
308                 "Follows ISO 8601 standard."),
309                 false, false, 11, 11, Exiv2::time, IptcDataSets::application2, ""),
310         DataSet(IptcDataSets::Program, "Program", N_("Program"),
311                 N_("Identifies the type of program used to originate the object data."),
312                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
313         DataSet(IptcDataSets::ProgramVersion, "ProgramVersion", N_("Program Version"),
314                 N_("Used to identify the version of the program mentioned in tag <Program>."),
315                 false, false, 0, 10, Exiv2::string, IptcDataSets::application2, ""),
316         DataSet(IptcDataSets::ObjectCycle, "ObjectCycle", N_("Object Cycle"),
317                 N_("Used to identify the editorial cycle of object data."),
318                 false, false, 1, 1, Exiv2::string, IptcDataSets::application2, ""),
319         DataSet(IptcDataSets::Byline, "Byline", N_("By-line"),
320                 N_("Contains name of the creator of the object data, e.g. writer, photographer "
321                 "or graphic artist."),
322                 false, true, 0, 32, Exiv2::string, IptcDataSets::application2,
323                 N_("Author")),
324         DataSet(IptcDataSets::BylineTitle, "BylineTitle", N_("By-line Title"),
325                 N_("A by-line title is the title of the creator or creators of an "
326                 "object data. Where used, a by-line title should follow the by-line it modifies."),
327                 false, true, 0, 32, Exiv2::string, IptcDataSets::application2, "Authors Position"),
328         DataSet(IptcDataSets::City, "City", N_("City"),
329                 N_("Identifies city of object data origin according to guidelines established "
330                 "by the provider."),
331                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2,
332                 N_("City")),
333         DataSet(IptcDataSets::SubLocation, "SubLocation", N_("Sub Location"),
334                 N_("Identifies the location within a city from which the object data "
335                 "originates, according to guidelines established by the provider."),
336                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2, ""),
337         DataSet(IptcDataSets::ProvinceState, "ProvinceState", N_("Province State"),
338                 N_("Identifies Province/State of origin according to guidelines "
339                 "established by the provider."),
340                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2,
341                 N_("State/Province")),
342         DataSet(IptcDataSets::CountryCode, "CountryCode", N_("Country Code"),
343                 N_("Indicates the code of the country/primary location where the "
344                 "intellectual property of the object data was created, e.g. a photo "
345                 "was taken, an event occurred. Where ISO has established an appropriate "
346                 "country code under ISO 3166, that code will be used. When ISO 3166 does not "
347                 "adequately provide for identification of a location or a new "
348                 "country, e.g. ships at sea, space, IPTC will assign an "
349                 "appropriate three-character code under the provisions of "
350                 "ISO 3166 to avoid conflicts."),
351                 false, false, 3, 3, Exiv2::string, IptcDataSets::application2, ""),
352         DataSet(IptcDataSets::CountryName, "CountryName", N_("Country Name"),
353                 N_("Provides full, publishable, name of the country/primary location "
354                 "where the intellectual property of the object data was created, "
355                 "according to guidelines of the provider."),
356                 false, false, 0, 64, Exiv2::string, IptcDataSets::application2,
357                 N_("Country")),
358         DataSet(IptcDataSets::TransmissionReference, "TransmissionReference", N_("Transmission Reference"),
359                 N_("A code representing the location of original transmission according "
360                 "to practices of the provider."),
361                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2,
362                 N_("Transmission Reference")),
363         DataSet(IptcDataSets::Headline, "Headline", N_("Headline"),
364                 N_("A publishable entry providing a synopsis of the contents of the object data."),
365                 false, false, 0, 256, Exiv2::string, IptcDataSets::application2,
366                 N_("Headline")),
367         DataSet(IptcDataSets::Credit, "Credit", N_("Credit"),
368                 N_("Identifies the provider of the object data, not necessarily the owner/creator."),
369                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2,
370                 N_("Credit")),
371         DataSet(IptcDataSets::Source, "Source", N_("Source"),
372                 N_("Identifies the original owner of the intellectual content of the "
373                 "object data. This could be an agency, a member of an agency or an individual."),
374                 false, false, 0, 32, Exiv2::string, IptcDataSets::application2,
375                 N_("Source")),
376         DataSet(IptcDataSets::Copyright, "Copyright", N_("Copyright"),
377                 N_("Contains any necessary copyright notice."),
378                 false, false, 0, 128, Exiv2::string, IptcDataSets::application2,
379                 N_("Copyright Notice")),
380         DataSet(IptcDataSets::Contact, "Contact", N_("Contact"),
381                 N_("Identifies the person or organisation which can provide further "
382                 "background information on the object data."),
383                 false, true, 0, 128, Exiv2::string, IptcDataSets::application2, ""),
384         DataSet(IptcDataSets::Caption, "Caption", N_("Caption"),
385                 N_("A textual description of the object data."),
386                 false, false, 0, 2000, Exiv2::string, IptcDataSets::application2,
387                 N_("Description")),
388         DataSet(IptcDataSets::Writer, "Writer", N_("Writer"),
389                 N_("Identification of the name of the person involved in the writing, "
390                 "editing or correcting the object data or caption/abstract."),
391                 false, true, 0, 32, Exiv2::string, IptcDataSets::application2, "Description writer"),
392         DataSet(IptcDataSets::RasterizedCaption, "RasterizedCaption", N_("Rasterized Caption"),
393                 N_("Contains the rasterized object data description and is used "
394                 "where characters that have not been coded are required for the caption."),
395                 false, false, 7360, 7360, Exiv2::undefined, IptcDataSets::application2, ""),
396         DataSet(IptcDataSets::ImageType, "ImageType", N_("Image Type"),
397                 N_("Indicates the color components of an image."),
398                 false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
399         DataSet(IptcDataSets::ImageOrientation, "ImageOrientation", N_("Image Orientation"),
400                 N_("Indicates the layout of an image."),
401                 false, false, 1, 1, Exiv2::string, IptcDataSets::application2, ""),
402         DataSet(IptcDataSets::Language, "Language", N_("Language"),
403                 N_("Describes the major national language of the object, according "
404                 "to the 2-letter codes of ISO 639:1988. Does not define or imply "
405                 "any coded character set, but is used for internal routing, e.g. to "
406                 "various editorial desks."),
407                 false, false, 2, 3, Exiv2::string, IptcDataSets::application2, ""),
408         DataSet(IptcDataSets::AudioType, "AudioType", N_("Audio Type"),
409                 N_("Indicates the type of an audio content."),
410                 false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
411         DataSet(IptcDataSets::AudioRate, "AudioRate", N_("Audio Rate"),
412                 N_("Indicates the sampling rate in Hertz of an audio content."),
413                 false, false, 6, 6, Exiv2::string, IptcDataSets::application2, ""),
414         DataSet(IptcDataSets::AudioResolution, "AudioResolution", N_("Audio Resolution"),
415                 N_("Indicates the sampling resolution of an audio content."),
416                 false, false, 2, 2, Exiv2::string, IptcDataSets::application2, ""),
417         DataSet(IptcDataSets::AudioDuration, "AudioDuration", N_("Audio Duration"),
418                 N_("Indicates the duration of an audio content."),
419                 false, false, 6, 6, Exiv2::string, IptcDataSets::application2, ""),
420         DataSet(IptcDataSets::AudioOutcue, "AudioOutcue", N_("Audio Outcue"),
421                 N_("Identifies the content of the end of an audio object data, "
422                 "according to guidelines established by the provider."),
423                 false, false, 0, 64, Exiv2::string, IptcDataSets::application2, ""),
424         DataSet(IptcDataSets::PreviewFormat, "PreviewFormat", N_("Preview Format"),
425                 N_("A binary number representing the file format of the object data "
426                 "preview. The file format must be registered with IPTC or NAA organizations "
427                 "with a unique number assigned to it."),
428                 false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""),
429         DataSet(IptcDataSets::PreviewVersion, "PreviewVersion", N_("Preview Version"),
430                 N_("A binary number representing the particular version of the "
431                 "object data preview file format specified in tag <PreviewFormat>."),
432                 false, false, 2, 2, Exiv2::unsignedShort, IptcDataSets::application2, ""),
433         DataSet(IptcDataSets::Preview, "Preview", N_("Preview Data"),
434                 N_("Binary image preview data."),
435                 false, false, 0, 256000, Exiv2::undefined, IptcDataSets::application2, ""),
436         DataSet(0xffff, "(Invalid)", N_("(Invalid)"),
437                 N_("(Invalid)"),
438                 false, false, 0, 0, Exiv2::unsignedShort, IptcDataSets::application2, "")
439     };
440 
application2RecordList()441     const DataSet* IptcDataSets::application2RecordList()
442     {
443         return application2Record;
444     }
445 
446     static const DataSet unknownDataSet(0xffff, "Unknown dataset", N_("Unknown dataset"),
447                                         N_("Unknown dataset"),
448                                         false, true, 0, 0xffffffff, Exiv2::string,
449                                         IptcDataSets::invalidRecord,
450                                         N_("Unknown dataset"));
451 
452     // Dataset lookup lists.This is an array with pointers to one list per IIM4 Record.
453     // The record id is used as the index into the array.
454     const DataSet* IptcDataSets::records_[] = {
455         0,
456         envelopeRecord, application2Record,
457         0
458     };
459 
dataSetIdx(uint16_t number,uint16_t recordId)460     int IptcDataSets::dataSetIdx(uint16_t number, uint16_t recordId)
461     {
462         if( recordId != envelope && recordId != application2 ) return -1;
463         const DataSet* dataSet = records_[recordId];
464         if (dataSet == 0) return -1;
465         int idx;
466         for (idx = 0; dataSet[idx].number_ != number; ++idx) {
467             if (dataSet[idx].number_ == 0xffff) return -1;
468         }
469         return idx;
470     }
471 
dataSetIdx(const std::string & dataSetName,uint16_t recordId)472     int IptcDataSets::dataSetIdx(const std::string& dataSetName, uint16_t recordId)
473     {
474         if( recordId != envelope && recordId != application2 ) return -1;
475         const DataSet* dataSet = records_[recordId];
476         if (dataSet == 0) return -1;
477         int idx;
478         for (idx = 0; dataSet[idx].name_ != dataSetName; ++idx) {
479             if (dataSet[idx].number_ == 0xffff) return -1;
480         }
481         return idx;
482     }
483 
dataSetType(uint16_t number,uint16_t recordId)484     TypeId IptcDataSets::dataSetType(uint16_t number, uint16_t recordId)
485     {
486         int idx = dataSetIdx(number, recordId);
487         if (idx == -1) return unknownDataSet.type_;
488         return records_[recordId][idx].type_;
489     }
490 
dataSetName(uint16_t number,uint16_t recordId)491     std::string IptcDataSets::dataSetName(uint16_t number, uint16_t recordId)
492     {
493         int idx = dataSetIdx(number, recordId);
494         if (idx != -1) return records_[recordId][idx].name_;
495 
496         std::ostringstream os;
497         os << "0x" << std::setw(4) << std::setfill('0') << std::right
498            << std::hex << number;
499         return os.str();
500     }
501 
dataSetTitle(uint16_t number,uint16_t recordId)502     const char* IptcDataSets::dataSetTitle(uint16_t number, uint16_t recordId)
503     {
504         int idx = dataSetIdx(number, recordId);
505         if (idx == -1) return unknownDataSet.title_;
506         return records_[recordId][idx].title_;
507     }
508 
dataSetDesc(uint16_t number,uint16_t recordId)509     const char* IptcDataSets::dataSetDesc(uint16_t number, uint16_t recordId)
510     {
511         int idx = dataSetIdx(number, recordId);
512         if (idx == -1) return unknownDataSet.desc_;
513         return records_[recordId][idx].desc_;
514     }
515 
dataSetPsName(uint16_t number,uint16_t recordId)516     const char* IptcDataSets::dataSetPsName(uint16_t number, uint16_t recordId)
517     {
518         int idx = dataSetIdx(number, recordId);
519         if (idx == -1) return unknownDataSet.photoshop_;
520         return records_[recordId][idx].photoshop_;
521     }
522 
dataSetRepeatable(uint16_t number,uint16_t recordId)523     bool IptcDataSets::dataSetRepeatable(uint16_t number, uint16_t recordId)
524     {
525         int idx = dataSetIdx(number, recordId);
526         if (idx == -1) return unknownDataSet.repeatable_;
527         return records_[recordId][idx].repeatable_;
528     }
529 
dataSet(const std::string & dataSetName,uint16_t recordId)530     uint16_t IptcDataSets::dataSet(const std::string& dataSetName,
531                                    uint16_t recordId)
532     {
533         uint16_t dataSet;
534         int idx = dataSetIdx(dataSetName, recordId);
535         if (idx != -1) {
536             // dataSetIdx checks the range of recordId
537             dataSet = records_[recordId][idx].number_;
538         }
539         else {
540             if (!isHex(dataSetName, 4, "0x")) throw Error(4, dataSetName);
541             std::istringstream is(dataSetName);
542             is >> std::hex >> dataSet;
543         }
544         return dataSet;
545     }
546 
recordName(uint16_t recordId)547     std::string IptcDataSets::recordName(uint16_t recordId)
548     {
549         if (recordId == envelope || recordId == application2) {
550             return recordInfo_[recordId].name_;
551         }
552 
553         std::ostringstream os;
554         os << "0x" << std::setw(4) << std::setfill('0') << std::right
555            << std::hex << recordId;
556         return os.str();
557     }
558 
recordDesc(uint16_t recordId)559     const char* IptcDataSets::recordDesc(uint16_t recordId)
560     {
561         if (recordId != envelope && recordId != application2) {
562             return unknownDataSet.desc_;
563         }
564         return recordInfo_[recordId].desc_;
565     }
566 
recordId(const std::string & recordName)567     uint16_t IptcDataSets::recordId(const std::string& recordName)
568     {
569         uint16_t i;
570         for (i = application2; i > 0; --i) {
571             if (recordInfo_[i].name_ == recordName) break;
572         }
573         if (i == 0) {
574             if (!isHex(recordName, 4, "0x")) throw Error(5, recordName);
575             std::istringstream is(recordName);
576             is >> std::hex >> i;
577         }
578         return i;
579     }
580 
dataSetList(std::ostream & os)581     void IptcDataSets::dataSetList(std::ostream& os)
582     {
583         const int count = sizeof(records_)/sizeof(records_[0]);
584         for (int i=0; i < count; ++i) {
585             const DataSet *record = records_[i];
586             for (int j=0; record != 0 && record[j].number_ != 0xffff; ++j) {
587                 os << record[j] << "\n";
588             }
589         }
590     } // IptcDataSets::dataSetList
591 
592     const char* IptcKey::familyName_ = "Iptc";
593 
IptcKey(const std::string & key)594     IptcKey::IptcKey(const std::string& key)
595         : key_(key)
596     {
597         decomposeKey();
598     }
599 
IptcKey(uint16_t tag,uint16_t record)600     IptcKey::IptcKey(uint16_t tag, uint16_t record)
601         : tag_(tag), record_(record)
602     {
603         makeKey();
604     }
605 
IptcKey(const IptcKey & rhs)606     IptcKey::IptcKey(const IptcKey& rhs)
607         : Key(rhs), tag_(rhs.tag_), record_(rhs.record_), key_(rhs.key_)
608     {
609     }
610 
~IptcKey()611     IptcKey::~IptcKey()
612     {
613     }
614 
operator =(const IptcKey & rhs)615     IptcKey& IptcKey::operator=(const IptcKey& rhs)
616     {
617         if (this == &rhs) return *this;
618         Key::operator=(rhs);
619         tag_ = rhs.tag_;
620         record_ = rhs.record_;
621         key_ = rhs.key_;
622         return *this;
623     }
624 
key() const625     std::string IptcKey::key() const
626     {
627         return key_;
628     }
629 
familyName() const630     const char* IptcKey::familyName() const
631     {
632         return familyName_;
633     }
634 
groupName() const635     std::string IptcKey::groupName() const
636     {
637         return recordName();
638     }
639 
tagName() const640     std::string IptcKey::tagName() const
641     {
642         return IptcDataSets::dataSetName(tag_, record_);
643     }
644 
tagLabel() const645     std::string IptcKey::tagLabel() const
646     {
647         return IptcDataSets::dataSetTitle(tag_, record_);
648     }
649 
tag() const650     uint16_t IptcKey::tag() const
651     {
652         return tag_;
653     }
654 
recordName() const655     std::string IptcKey::recordName() const
656     {
657         return IptcDataSets::recordName(record_);
658     }
659 
record() const660     uint16_t IptcKey::record() const
661     {
662         return record_;
663     }
664 
clone() const665     IptcKey::AutoPtr IptcKey::clone() const
666     {
667         return AutoPtr(clone_());
668     }
669 
clone_() const670     IptcKey* IptcKey::clone_() const
671     {
672         return new IptcKey(*this);
673     }
674 
decomposeKey()675     void IptcKey::decomposeKey()
676     {
677         // Get the family name, record name and dataSet name parts of the key
678         std::string::size_type pos1 = key_.find('.');
679         if (pos1 == std::string::npos) throw Error(6, key_);
680         std::string familyName = key_.substr(0, pos1);
681         if (0 != strcmp(familyName.c_str(), familyName_)) {
682             throw Error(6, key_);
683         }
684         std::string::size_type pos0 = pos1 + 1;
685         pos1 = key_.find('.', pos0);
686         if (pos1 == std::string::npos) throw Error(6, key_);
687         std::string recordName = key_.substr(pos0, pos1 - pos0);
688         if (recordName == "") throw Error(6, key_);
689         std::string dataSetName = key_.substr(pos1 + 1);
690         if (dataSetName == "") throw Error(6, key_);
691 
692         // Use the parts of the key to find dataSet and recordId
693         uint16_t recId = IptcDataSets::recordId(recordName);
694         uint16_t dataSet = IptcDataSets::dataSet(dataSetName, recId);
695 
696         // Possibly translate hex name parts (0xabcd) to real names
697         recordName = IptcDataSets::recordName(recId);
698         dataSetName = IptcDataSets::dataSetName(dataSet, recId);
699 
700         tag_ = dataSet;
701         record_ = recId;
702         key_ = familyName + "." + recordName + "." + dataSetName;
703     } // IptcKey::decomposeKey
704 
makeKey()705     void IptcKey::makeKey()
706     {
707         key_ = std::string(familyName_)
708             + "." + IptcDataSets::recordName(record_)
709             + "." + IptcDataSets::dataSetName(tag_, record_);
710     }
711 
712     // *************************************************************************
713     // free functions
714 
operator <<(std::ostream & os,const DataSet & dataSet)715     std::ostream& operator<<(std::ostream& os, const DataSet& dataSet)
716     {
717         std::ios::fmtflags f( os.flags() );
718         IptcKey iptcKey(dataSet.number_, dataSet.recordId_);
719         os << dataSet.name_ << ", "
720            << std::dec << dataSet.number_ << ", "
721            << "0x" << std::setw(4) << std::setfill('0')
722            << std::right << std::hex << dataSet.number_ << ", "
723            << IptcDataSets::recordName(dataSet.recordId_) << ", "
724            << std::boolalpha << dataSet.mandatory_ << ", "
725            << dataSet.repeatable_ << ", "
726            << std::dec << dataSet.minbytes_ << ", "
727            << dataSet.maxbytes_ << ", "
728            << iptcKey.key() << ", "
729            << TypeInfo::typeName(
730               IptcDataSets::dataSetType(dataSet.number_,
731                                           dataSet.recordId_)) << ", "
732            << dataSet.desc_;
733         os.flags(f);
734         return os;
735     }
736 
737 }                                       // namespace Exiv2
738