summaryrefslogtreecommitdiff
path: root/gpr/source/lib/dng_sdk/dng_iptc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/lib/dng_sdk/dng_iptc.cpp')
-rw-r--r--gpr/source/lib/dng_sdk/dng_iptc.cpp987
1 files changed, 987 insertions, 0 deletions
diff --git a/gpr/source/lib/dng_sdk/dng_iptc.cpp b/gpr/source/lib/dng_sdk/dng_iptc.cpp
new file mode 100644
index 0000000..98c263d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_iptc.cpp
@@ -0,0 +1,987 @@
+/*****************************************************************************/
+// Copyright 2006-2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file in
+// accordance with the terms of the Adobe license agreement accompanying it.
+/*****************************************************************************/
+
+/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_iptc.cpp#1 $ */
+/* $DateTime: 2012/05/30 13:28:51 $ */
+/* $Change: 832332 $ */
+/* $Author: tknoll $ */
+
+/*****************************************************************************/
+
+#include "dng_iptc.h"
+
+#include "dng_assertions.h"
+#include "dng_auto_ptr.h"
+#include "dng_memory_stream.h"
+#include "dng_stream.h"
+#include "dng_utils.h"
+
+#include "stdc_includes.h"
+
+/*****************************************************************************/
+
+dng_iptc::dng_iptc ()
+
+ : fTitle ()
+
+ , fUrgency (-1)
+
+ , fCategory ()
+
+ , fSupplementalCategories ()
+
+ , fKeywords ()
+
+ , fInstructions ()
+
+ , fDateTimeCreated ()
+
+ , fDigitalCreationDateTime ()
+
+ , fAuthors ()
+ , fAuthorsPosition ()
+
+ , fCity ()
+ , fState ()
+ , fCountry ()
+ , fCountryCode ()
+
+ , fLocation ()
+
+ , fTransmissionReference ()
+
+ , fHeadline ()
+
+ , fCredit ()
+
+ , fSource ()
+
+ , fCopyrightNotice ()
+
+ , fDescription ()
+ , fDescriptionWriter ()
+
+ {
+
+ }
+
+/*****************************************************************************/
+
+dng_iptc::~dng_iptc ()
+ {
+
+ }
+
+/*****************************************************************************/
+
+bool dng_iptc::IsEmpty () const
+ {
+
+ if (fTitle.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fUrgency >= 0)
+ {
+ return false;
+ }
+
+ if (fCategory.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fSupplementalCategories.Count () > 0)
+ {
+ return false;
+ }
+
+ if (fKeywords.Count () > 0)
+ {
+ return false;
+ }
+
+ if (fInstructions.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fDateTimeCreated.IsValid ())
+ {
+ return false;
+ }
+
+ if (fDigitalCreationDateTime.IsValid ())
+ {
+ return false;
+ }
+
+ if (fAuthors.Count () != 0 ||
+ fAuthorsPosition.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCity .NotEmpty () ||
+ fState .NotEmpty () ||
+ fCountry.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCountryCode.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fLocation.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fTransmissionReference.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fHeadline.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCredit.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fSource.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fCopyrightNotice.NotEmpty ())
+ {
+ return false;
+ }
+
+ if (fDescription .NotEmpty () ||
+ fDescriptionWriter.NotEmpty ())
+ {
+ return false;
+ }
+
+ return true;
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::ParseString (dng_stream &stream,
+ dng_string &s,
+ CharSet charSet)
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ dng_memory_data buffer (length + 1);
+
+ char *c = buffer.Buffer_char ();
+
+ stream.Get (c, length);
+
+ c [length] = 0;
+
+ switch (charSet)
+ {
+
+ case kCharSetUTF8:
+ {
+ s.Set_UTF8 (c);
+ break;
+ }
+
+ default:
+ {
+ s.Set_SystemEncoding (c);
+ }
+
+ }
+
+ s.SetLineEndingsToNewLines ();
+
+ s.StripLowASCII ();
+
+ s.TrimTrailingBlanks ();
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::Parse (const void *blockData,
+ uint32 blockSize,
+ uint64 offsetInOriginalFile)
+ {
+
+ dng_stream stream (blockData,
+ blockSize,
+ offsetInOriginalFile);
+
+ stream.SetBigEndian ();
+
+ // Make a first pass though the data, trying to figure out the
+ // character set.
+
+ CharSet charSet = kCharSetUnknown;
+
+ bool isValidUTF8 = true;
+
+ bool hasEncodingMarker = false;
+
+ uint64 firstOffset = stream.Position ();
+
+ uint64 nextOffset = firstOffset;
+
+ while (nextOffset + 5 < stream.Length ())
+ {
+
+ stream.SetReadPosition (nextOffset);
+
+ uint8 firstByte = stream.Get_uint8 ();
+
+ if (firstByte != 0x1C) break;
+
+ uint8 record = stream.Get_uint8 ();
+ uint8 dataSet = stream.Get_uint8 ();
+ uint32 dataSize = stream.Get_uint16 ();
+
+ nextOffset = stream.Position () + dataSize;
+
+ if (record == 1)
+ {
+
+ switch (dataSet)
+ {
+
+ case 90:
+ {
+
+ hasEncodingMarker = true;
+
+ if (dataSize == 3)
+ {
+
+ uint32 byte1 = stream.Get_uint8 ();
+ uint32 byte2 = stream.Get_uint8 ();
+ uint32 byte3 = stream.Get_uint8 ();
+
+ if (byte1 == 27 /* Escape */ &&
+ byte2 == 0x25 &&
+ byte3 == 0x47)
+ {
+
+ charSet = kCharSetUTF8;
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ default:
+ break;
+
+ }
+
+ }
+
+ else if (record == 2)
+ {
+
+ dng_memory_data buffer (dataSize + 1);
+
+ char *s = buffer.Buffer_char ();
+
+ stream.Get (s, dataSize);
+
+ s [dataSize] = 0;
+
+ isValidUTF8 = isValidUTF8 && dng_string::IsUTF8 (s);
+
+ }
+
+ }
+
+ // If we don't have an encoding marker, and the data is valid
+ // UTF-8, then assume that it is UTF-8 (rather than system encoding).
+
+ if (!hasEncodingMarker && isValidUTF8)
+ {
+
+ charSet = kCharSetUTF8;
+
+ }
+
+ // Make a second pass though the data, actually reading the data.
+
+ nextOffset = firstOffset;
+
+ while (nextOffset + 5 < stream.Length ())
+ {
+
+ stream.SetReadPosition (nextOffset);
+
+ uint8 firstByte = stream.Get_uint8 ();
+
+ if (firstByte != 0x1C) break;
+
+ uint8 record = stream.Get_uint8 ();
+ uint8 dataSet = stream.Get_uint8 ();
+ uint32 dataSize = stream.Get_uint16 ();
+
+ nextOffset = stream.Position () + dataSize;
+
+ if (record == 2)
+ {
+
+ stream.SetReadPosition (stream.Position () - 2);
+
+ switch ((DataSet) dataSet)
+ {
+
+ case kObjectNameSet:
+ {
+ ParseString (stream, fTitle, charSet);
+ break;
+ }
+
+ case kUrgencySet:
+ {
+
+ int32 size = stream.Get_uint16 ();
+
+ if (size == 1)
+ {
+
+ char c = stream.Get_int8 ();
+
+ if (c >= '0' && c <= '9')
+ {
+ fUrgency = c - '0';
+ }
+
+ }
+
+ break;
+
+ }
+
+ case kCategorySet:
+ {
+ ParseString (stream, fCategory, charSet);
+ break;
+ }
+
+ case kSupplementalCategoriesSet:
+ {
+
+ dng_string category;
+
+ ParseString (stream, category, charSet);
+
+ if (category.NotEmpty ())
+ {
+ fSupplementalCategories.Append (category);
+ }
+
+ break;
+
+ }
+
+ case kKeywordsSet:
+ {
+
+ dng_string keyword;
+
+ ParseString (stream, keyword, charSet);
+
+ if (keyword.NotEmpty ())
+ {
+ fKeywords.Append (keyword);
+ }
+
+ break;
+
+ }
+
+ case kSpecialInstructionsSet:
+ {
+ ParseString (stream, fInstructions, charSet);
+ break;
+ }
+
+ case kDateCreatedSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length == 8)
+ {
+
+ char date [9];
+
+ stream.Get (date, 8);
+
+ date [8] = 0;
+
+ fDateTimeCreated.Decode_IPTC_Date (date);
+
+ }
+
+ break;
+
+ }
+
+ case kTimeCreatedSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length >= 4 && length <= 11)
+ {
+
+ char time [12];
+
+ stream.Get (time, length);
+
+ time [length] = 0;
+
+ fDateTimeCreated.Decode_IPTC_Time (time);
+
+ }
+
+ break;
+
+ }
+
+ case kDigitalCreationDateSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length == 8)
+ {
+
+ char date [9];
+
+ stream.Get (date, 8);
+
+ date [8] = 0;
+
+ fDigitalCreationDateTime.Decode_IPTC_Date (date);
+
+ }
+
+ break;
+
+ }
+
+ case kDigitalCreationTimeSet:
+ {
+
+ uint32 length = stream.Get_uint16 ();
+
+ if (length >= 4 && length <= 11)
+ {
+
+ char time [12];
+
+ stream.Get (time, length);
+
+ time [length] = 0;
+
+ fDigitalCreationDateTime.Decode_IPTC_Time (time);
+
+ }
+
+ break;
+
+ }
+
+ case kBylineSet:
+ {
+
+ dng_string author;
+
+ ParseString (stream, author, charSet);
+
+ if (author.NotEmpty ())
+ {
+ fAuthors.Append (author);
+ }
+
+ break;
+
+ }
+
+ case kBylineTitleSet:
+ {
+ ParseString (stream, fAuthorsPosition, charSet);
+ break;
+ }
+
+ case kCitySet:
+ {
+ ParseString (stream, fCity, charSet);
+ break;
+ }
+
+ case kProvinceStateSet:
+ {
+ ParseString (stream, fState, charSet);
+ break;
+ }
+
+ case kCountryNameSet:
+ {
+ ParseString (stream, fCountry, charSet);
+ break;
+ }
+
+ case kCountryCodeSet:
+ {
+ ParseString (stream, fCountryCode, charSet);
+ break;
+ }
+
+ case kSublocationSet:
+ {
+ ParseString (stream, fLocation, charSet);
+ break;
+ }
+
+ case kOriginalTransmissionReferenceSet:
+ {
+ ParseString (stream, fTransmissionReference, charSet);
+ break;
+ }
+
+ case kHeadlineSet:
+ {
+ ParseString (stream, fHeadline, charSet);
+ break;
+ }
+
+ case kCreditSet:
+ {
+ ParseString (stream, fCredit, charSet);
+ break;
+ }
+
+ case kSourceSet:
+ {
+ ParseString (stream, fSource, charSet);
+ break;
+ }
+
+ case kCopyrightNoticeSet:
+ {
+ ParseString (stream, fCopyrightNotice, charSet);
+ break;
+ }
+
+ case kCaptionSet:
+ {
+ ParseString (stream, fDescription, charSet);
+ break;
+ }
+
+ case kCaptionWriterSet:
+ {
+ ParseString (stream, fDescriptionWriter, charSet);
+ break;
+ }
+
+ // All other IPTC records are not part of the IPTC core
+ // and/or are not kept in sync with XMP tags, so we ignore
+ // them.
+
+ default:
+ break;
+
+ }
+
+ }
+
+ }
+
+ }
+
+/*****************************************************************************/
+
+void dng_iptc::SpoolString (dng_stream &stream,
+ const dng_string &s,
+ uint8 dataSet,
+ uint32 maxChars,
+ CharSet charSet)
+ {
+
+ if (s.IsEmpty ())
+ {
+ return;
+ }
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (dataSet);
+
+ dng_string ss (s);
+
+ ss.SetLineEndingsToReturns ();
+
+ if (charSet == kCharSetUTF8)
+ {
+
+ // UTF-8 encoding.
+
+ if (ss.Length () > maxChars)
+ {
+ ss.Truncate (maxChars);
+ }
+
+ uint32 len = ss.Length ();
+
+ stream.Put_uint16 ((uint16) len);
+
+ stream.Put (ss.Get (), len);
+
+ }
+
+ else
+ {
+
+ // System character set encoding.
+
+ dng_memory_data buffer;
+
+ uint32 len = ss.Get_SystemEncoding (buffer);
+
+ if (len > maxChars)
+ {
+
+ uint32 lower = 0;
+ uint32 upper = ss.Length () - 1;
+
+ while (upper > lower)
+ {
+
+ uint32 middle = (upper + lower + 1) >> 1;
+
+ dng_string sss (ss);
+
+ sss.Truncate (middle);
+
+ len = sss.Get_SystemEncoding (buffer);
+
+ if (len <= maxChars)
+ {
+
+ lower = middle;
+
+ }
+
+ else
+ {
+
+ upper = middle - 1;
+
+ }
+
+ }
+
+ ss.Truncate (lower);
+
+ len = ss.Get_SystemEncoding (buffer);
+
+ }
+
+ stream.Put_uint16 ((uint16) len);
+
+ stream.Put (buffer.Buffer_char (), len);
+
+ }
+
+ }
+/*****************************************************************************/
+
+dng_memory_block * dng_iptc::Spool (dng_memory_allocator &allocator,
+ bool padForTIFF)
+ {
+
+ uint32 j;
+
+ char s [64];
+
+ dng_memory_stream stream (allocator, NULL, 2048);
+
+ stream.SetBigEndian ();
+
+ // Medata working group - now we just always write UTF-8.
+
+ CharSet charSet = kCharSetUTF8;
+
+ // UTF-8 encoding marker.
+
+ if (charSet == kCharSetUTF8)
+ {
+
+ stream.Put_uint16 (0x1C01);
+ stream.Put_uint8 (90);
+ stream.Put_uint16 (3);
+ stream.Put_uint8 (27);
+ stream.Put_uint8 (0x25);
+ stream.Put_uint8 (0x47);
+
+ }
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kRecordVersionSet);
+ stream.Put_uint16 (2);
+ stream.Put_uint16 (4);
+
+ SpoolString (stream,
+ fTitle,
+ kObjectNameSet,
+ 64,
+ charSet);
+
+ if (fUrgency >= 0)
+ {
+
+ sprintf (s, "%1u", (unsigned) fUrgency);
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kUrgencySet);
+
+ stream.Put_uint16 (1);
+
+ stream.Put (s, 1);
+
+ }
+
+ SpoolString (stream,
+ fCategory,
+ kCategorySet,
+ 3,
+ charSet);
+
+ for (j = 0; j < fSupplementalCategories.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fSupplementalCategories [j],
+ kSupplementalCategoriesSet,
+ 32,
+ charSet);
+
+ }
+
+ for (j = 0; j < fKeywords.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fKeywords [j],
+ kKeywordsSet,
+ 64,
+ charSet);
+
+ }
+
+ SpoolString (stream,
+ fInstructions,
+ kSpecialInstructionsSet,
+ 255,
+ charSet);
+
+ if (fDateTimeCreated.IsValid ())
+ {
+
+ dng_string dateString = fDateTimeCreated.Encode_IPTC_Date ();
+
+ if (dateString.NotEmpty ())
+ {
+
+ DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDateCreatedSet);
+
+ stream.Put_uint16 (8);
+
+ stream.Put (dateString.Get (), 8);
+
+ }
+
+ dng_string timeString = fDateTimeCreated.Encode_IPTC_Time ();
+
+ if (timeString.NotEmpty ())
+ {
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kTimeCreatedSet);
+
+ stream.Put_uint16 ((uint16)timeString.Length ());
+
+ stream.Put (timeString.Get (), timeString.Length ());
+
+ }
+
+ }
+
+ if (fDigitalCreationDateTime.IsValid ())
+ {
+
+ dng_string dateString = fDigitalCreationDateTime.Encode_IPTC_Date ();
+
+ if (dateString.NotEmpty ())
+ {
+
+ DNG_ASSERT (dateString.Length () == 8, "Wrong length IPTC date");
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDigitalCreationDateSet);
+
+ stream.Put_uint16 (8);
+
+ stream.Put (dateString.Get (), 8);
+
+ }
+
+ dng_string timeString = fDigitalCreationDateTime.Encode_IPTC_Time ();
+
+ if (timeString.NotEmpty ())
+ {
+
+ stream.Put_uint16 (0x1C02);
+ stream.Put_uint8 (kDigitalCreationTimeSet);
+
+ stream.Put_uint16 ((uint16)timeString.Length ());
+
+ stream.Put (timeString.Get (), timeString.Length ());
+
+ }
+
+ }
+
+ for (j = 0; j < fAuthors.Count (); j++)
+ {
+
+ SpoolString (stream,
+ fAuthors [j],
+ kBylineSet,
+ 32,
+ charSet);
+
+ }
+
+ SpoolString (stream,
+ fAuthorsPosition,
+ kBylineTitleSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCity,
+ kCitySet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fLocation,
+ kSublocationSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fState,
+ kProvinceStateSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCountryCode,
+ kCountryCodeSet,
+ 3,
+ charSet);
+
+ SpoolString (stream,
+ fCountry,
+ kCountryNameSet,
+ 64,
+ charSet);
+
+ SpoolString (stream,
+ fTransmissionReference,
+ kOriginalTransmissionReferenceSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fHeadline,
+ kHeadlineSet,
+ 255,
+ charSet);
+
+ SpoolString (stream,
+ fCredit,
+ kCreditSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fSource,
+ kSourceSet,
+ 32,
+ charSet);
+
+ SpoolString (stream,
+ fCopyrightNotice,
+ kCopyrightNoticeSet,
+ 128,
+ charSet);
+
+ SpoolString (stream,
+ fDescription,
+ kCaptionSet,
+ 2000,
+ charSet);
+
+ SpoolString (stream,
+ fDescriptionWriter,
+ kCaptionWriterSet,
+ 32,
+ charSet);
+
+ if (padForTIFF)
+ {
+
+ while (stream.Length () & 3)
+ {
+ stream.Put_uint8 (0);
+ }
+
+ }
+
+ stream.Flush ();
+
+ return stream.AsMemoryBlock (allocator);
+
+ }
+
+/*****************************************************************************/