Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2006-2012 Adobe Systems Incorporated
      3 // All Rights Reserved.
      4 //
      5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
      6 // accordance with the terms of the Adobe license agreement accompanying it.
      7 /*****************************************************************************/
      8 
      9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_xmp_sdk.cpp#4 $ */
     10 /* $DateTime: 2012/09/05 12:31:51 $ */
     11 /* $Change: 847652 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_xmp_sdk.h"
     17 
     18 #include "dng_auto_ptr.h"
     19 #include "dng_assertions.h"
     20 #include "dng_exceptions.h"
     21 #include "dng_flags.h"
     22 #include "dng_host.h"
     23 #include "dng_memory.h"
     24 #include "dng_string.h"
     25 #include "dng_string_list.h"
     26 #include "dng_utils.h"
     27 
     28 /*****************************************************************************/
     29 
     30 #if qMacOS
     31 #ifndef MAC_ENV
     32 #define MAC_ENV 1
     33 #endif
     34 #endif
     35 
     36 #if qWinOS
     37 #ifndef WIN_ENV
     38 #define WIN_ENV 1
     39 #endif
     40 #endif
     41 
     42 #include <new>
     43 #include <string>
     44 
     45 #define TXMP_STRING_TYPE std::string
     46 
     47 #define XMP_INCLUDE_XMPFILES qDNGXMPFiles
     48 
     49 #define XMP_StaticBuild 1
     50 
     51 #include "XMP.incl_cpp"
     52 
     53 /*****************************************************************************/
     54 
     55 const char *XMP_NS_TIFF	      = "http://ns.adobe.com/tiff/1.0/";
     56 const char *XMP_NS_EXIF	      = "http://ns.adobe.com/exif/1.0/";
     57 const char *XMP_NS_PHOTOSHOP  = "http://ns.adobe.com/photoshop/1.0/";
     58 const char *XMP_NS_XAP        = "http://ns.adobe.com/xap/1.0/";
     59 const char *XMP_NS_XAP_RIGHTS = "http://ns.adobe.com/xap/1.0/rights/";
     60 const char *XMP_NS_DC		  = "http://purl.org/dc/elements/1.1/";
     61 const char *XMP_NS_XMP_NOTE   = "http://ns.adobe.com/xmp/note/";
     62 const char *XMP_NS_MM         = "http://ns.adobe.com/xap/1.0/mm/";
     63 
     64 const char *XMP_NS_CRS		  = "http://ns.adobe.com/camera-raw-settings/1.0/";
     65 const char *XMP_NS_CRSS		  = "http://ns.adobe.com/camera-raw-saved-settings/1.0/";
     66 const char *XMP_NS_AUX		  = "http://ns.adobe.com/exif/1.0/aux/";
     67 
     68 const char *XMP_NS_LCP		  = "http://ns.adobe.com/photoshop/1.0/camera-profile";
     69 
     70 const char *XMP_NS_IPTC		  = "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/";
     71 const char *XMP_NS_IPTC_EXT   = "http://iptc.org/std/Iptc4xmpExt/2008-02-29/";
     72 
     73 const char *XMP_NS_CRX 		  = "http://ns.adobe.com/lightroom-settings-experimental/1.0/";
     74 
     75 const char *XMP_NS_DNG		  = "http://ns.adobe.com/dng/1.0/";
     76 
     77 /******************************************************************************/
     78 
     79 #define CATCH_XMP(routine, fatal)\
     80 	\
     81 	catch (std::bad_alloc &)\
     82 		{\
     83 		DNG_REPORT ("Info: XMP " routine " threw memory exception");\
     84 		ThrowMemoryFull ();\
     85 		}\
     86 	\
     87 	catch (XMP_Error &error)\
     88 		{\
     89 		const char *errMessage = error.GetErrMsg ();\
     90 		if (errMessage && strlen (errMessage) <= 128)\
     91 			{\
     92 			char errBuffer [256];\
     93 			sprintf (errBuffer, "Info: XMP " routine " threw '%s' exception", errMessage);\
     94 			DNG_REPORT ( errBuffer);\
     95 			}\
     96 		else\
     97 			{\
     98 			DNG_REPORT ("Info: XMP " routine " threw unnamed exception");\
     99 			}\
    100 		if (fatal) ThrowProgramError ();\
    101 		}\
    102 	\
    103 	catch (...)\
    104 		{\
    105 		DNG_REPORT ("Info: XMP " routine " threw unknown exception");\
    106 		if (fatal) ThrowProgramError ();\
    107 		}
    108 
    109 /*****************************************************************************/
    110 
    111 class dng_xmp_private
    112 	{
    113 
    114 	public:
    115 
    116 		SXMPMeta *fMeta;
    117 
    118 		dng_xmp_private ()
    119 			:	fMeta (NULL)
    120 			{
    121 			}
    122 
    123 		dng_xmp_private (const dng_xmp_private &xmp);
    124 
    125 		~dng_xmp_private ()
    126 			{
    127 			if (fMeta)
    128 				{
    129 				delete fMeta;
    130 				}
    131 			}
    132 
    133 	private:
    134 
    135 		// Hidden assignment operator.
    136 
    137 		dng_xmp_private & operator= (const dng_xmp_private &xmp);
    138 
    139 	};
    140 
    141 /*****************************************************************************/
    142 
    143 dng_xmp_private::dng_xmp_private (const dng_xmp_private &xmp)
    144 
    145 	:	fMeta (NULL)
    146 
    147 	{
    148 
    149 	if (xmp.fMeta)
    150 		{
    151 
    152 		fMeta = new SXMPMeta (xmp.fMeta->Clone (0));
    153 
    154 		if (!fMeta)
    155 			{
    156 			ThrowMemoryFull ();
    157 			}
    158 
    159 		}
    160 
    161 	}
    162 
    163 /*****************************************************************************/
    164 
    165 dng_xmp_sdk::dng_xmp_sdk ()
    166 
    167 	:	fPrivate (NULL)
    168 
    169 	{
    170 
    171 	fPrivate = new dng_xmp_private;
    172 
    173 	if (!fPrivate)
    174 		{
    175 		ThrowMemoryFull ();
    176 		}
    177 
    178 	}
    179 
    180 /*****************************************************************************/
    181 
    182 dng_xmp_sdk::dng_xmp_sdk (const dng_xmp_sdk &sdk)
    183 
    184 	:	fPrivate (NULL)
    185 
    186 	{
    187 
    188 	fPrivate = new dng_xmp_private (*sdk.fPrivate);
    189 
    190 	if (!fPrivate)
    191 		{
    192 		ThrowMemoryFull ();
    193 		}
    194 
    195 	}
    196 
    197 /*****************************************************************************/
    198 
    199 dng_xmp_sdk::~dng_xmp_sdk ()
    200 	{
    201 
    202 	if (fPrivate)
    203 		{
    204 		delete fPrivate;
    205 		}
    206 
    207 	}
    208 
    209 /*****************************************************************************/
    210 
    211 static bool gInitializedXMP = false;
    212 
    213 /*****************************************************************************/
    214 
    215 void dng_xmp_sdk::InitializeSDK (dng_xmp_namespace * extraNamespaces,
    216 								 const char *software)
    217 	{
    218 
    219 	if (!gInitializedXMP)
    220 		{
    221 
    222 		try
    223 			{
    224 
    225 			if (!SXMPMeta::Initialize ())
    226 				{
    227 				ThrowProgramError ();
    228 				}
    229 
    230 			// Register Lightroom beta settings namespace.
    231 			// We no longer read this but I don't want to cut it out this close
    232 			// to a release. [bruzenak]
    233 
    234 				{
    235 
    236 				TXMP_STRING_TYPE ss;
    237 
    238 				SXMPMeta::RegisterNamespace (XMP_NS_CRX,
    239 											 "crx",
    240 											 &ss);
    241 
    242 				}
    243 
    244 			// Register CRSS snapshots namespace
    245 
    246 				{
    247 
    248 				TXMP_STRING_TYPE ss;
    249 
    250 				SXMPMeta::RegisterNamespace (XMP_NS_CRSS,
    251 											 "crss",
    252 											 &ss);
    253 
    254 				}
    255 
    256 			// Register LCP (lens correction profiles) namespace
    257 
    258 				{
    259 
    260 				TXMP_STRING_TYPE ss;
    261 
    262 				SXMPMeta::RegisterNamespace (XMP_NS_LCP,
    263 											 "stCamera",
    264 											 &ss);
    265 
    266 				}
    267 
    268 			// Register DNG format metadata namespace
    269 
    270 				{
    271 
    272 				TXMP_STRING_TYPE ss;
    273 
    274 				SXMPMeta::RegisterNamespace (XMP_NS_DNG,
    275 											 "dng",
    276 											 &ss);
    277 
    278 				}
    279 
    280 			// Register extra namespaces.
    281 
    282 			if (extraNamespaces != NULL)
    283 				{
    284 
    285 				for (; extraNamespaces->fullName != NULL; ++extraNamespaces)
    286 					{
    287 
    288 					TXMP_STRING_TYPE ss;
    289 
    290 					SXMPMeta::RegisterNamespace (extraNamespaces->fullName,
    291 												 extraNamespaces->shortName,
    292 												 &ss);
    293 
    294 					}
    295 
    296 				}
    297 
    298 			#if qDNGXMPFiles
    299 
    300 			#if qLinux
    301             if (!SXMPFiles::Initialize (kXMPFiles_IgnoreLocalText))
    302         	#else
    303             if (!SXMPFiles::Initialize ())
    304        	 	#endif
    305 				{
    306 				ThrowProgramError ();
    307 				}
    308 
    309 			#endif
    310 
    311 			#if qDNGXMPDocOps
    312 
    313 			if (software)
    314 				{
    315 
    316 				SXMPDocOps::SetAppName (software);
    317 
    318 				}
    319 
    320 			#else
    321 
    322 			(void) software;
    323 
    324 			#endif
    325 
    326 			}
    327 
    328 		CATCH_XMP ("Initialization", true)
    329 
    330 	    gInitializedXMP = true;
    331 
    332 		}
    333 
    334 	}
    335 
    336 /******************************************************************************/
    337 
    338 void dng_xmp_sdk::TerminateSDK ()
    339 	{
    340 
    341 	if (gInitializedXMP)
    342 		{
    343 
    344 		try
    345 			{
    346 
    347 			#if qDNGXMPFiles
    348 
    349 			SXMPFiles::Terminate ();
    350 
    351 			#endif
    352 
    353 			SXMPMeta::Terminate ();
    354 
    355 			}
    356 
    357 		catch (...)
    358 			{
    359 
    360 			}
    361 
    362 		gInitializedXMP = false;
    363 
    364 		}
    365 
    366 	}
    367 
    368 /******************************************************************************/
    369 
    370 bool dng_xmp_sdk::HasMeta () const
    371 	{
    372 
    373 	if (fPrivate->fMeta)
    374 		{
    375 
    376 		return true;
    377 
    378 		}
    379 
    380 	return false;
    381 
    382 	}
    383 
    384 /******************************************************************************/
    385 
    386 void dng_xmp_sdk::ClearMeta ()
    387 	{
    388 
    389 	if (HasMeta ())
    390 		{
    391 
    392 		delete fPrivate->fMeta;
    393 
    394 		fPrivate->fMeta = NULL;
    395 
    396 		}
    397 
    398 	}
    399 
    400 /******************************************************************************/
    401 
    402 void dng_xmp_sdk::MakeMeta ()
    403 	{
    404 
    405 	ClearMeta ();
    406 
    407 	InitializeSDK ();
    408 
    409 	try
    410 		{
    411 
    412 		fPrivate->fMeta = new SXMPMeta;
    413 
    414 		if (!fPrivate->fMeta)
    415 			{
    416 
    417 			ThrowMemoryFull ();
    418 
    419 			}
    420 
    421 		}
    422 
    423 	CATCH_XMP ("MakeMeta", true)
    424 
    425 	}
    426 
    427 /******************************************************************************/
    428 
    429 void dng_xmp_sdk::NeedMeta ()
    430 	{
    431 
    432 	if (!HasMeta ())
    433 		{
    434 
    435 		MakeMeta ();
    436 
    437 		}
    438 
    439 	}
    440 
    441 /******************************************************************************/
    442 
    443 void * dng_xmp_sdk::GetPrivateMeta ()
    444 	{
    445 
    446 	NeedMeta ();
    447 
    448 	return (void *) fPrivate->fMeta;
    449 
    450 	}
    451 
    452 /******************************************************************************/
    453 
    454 void dng_xmp_sdk::Parse (dng_host &host,
    455 						 const char *buffer,
    456 						 uint32 count)
    457 	{
    458 
    459 	MakeMeta ();
    460 
    461 	try
    462 		{
    463 
    464 		try
    465 			{
    466 
    467 			fPrivate->fMeta->ParseFromBuffer (buffer, count);
    468 
    469 			}
    470 
    471 	    CATCH_XMP ("ParseFromBuffer", true)
    472 
    473 	    }
    474 
    475 	catch (dng_exception &except)
    476 		{
    477 
    478 		ClearMeta ();
    479 
    480 		if (host.IsTransientError (except.ErrorCode ()))
    481 			{
    482 
    483 			throw;
    484 
    485 			}
    486 
    487 		ThrowBadFormat ();
    488 
    489 		}
    490 
    491 	}
    492 
    493 /*****************************************************************************/
    494 
    495 void dng_xmp_sdk::AppendArrayItem (const char *ns,
    496 								   const char *arrayName,
    497 								   const char *itemValue,
    498 								   bool isBag,
    499 								   bool propIsStruct)
    500 	{
    501 
    502 	NeedMeta();
    503 
    504 	try
    505 		{
    506 
    507 		fPrivate->fMeta->AppendArrayItem (ns,
    508 										  arrayName,
    509 										  isBag ? kXMP_PropValueIsArray
    510 												: kXMP_PropArrayIsOrdered,
    511 										  itemValue,
    512 										  propIsStruct ? kXMP_PropValueIsStruct
    513 													   : 0);
    514 
    515 		}
    516 	CATCH_XMP ("AppendArrayItem", true )
    517 
    518 	}
    519 
    520 /*****************************************************************************/
    521 
    522 int32 dng_xmp_sdk::CountArrayItems (const char *ns,
    523 								    const char *path) const
    524 	{
    525 
    526 	if (HasMeta ())
    527 		{
    528 
    529 		try
    530 			{
    531 
    532 			return fPrivate->fMeta->CountArrayItems (ns, path);
    533 
    534 			}
    535 
    536 		CATCH_XMP ("CountArrayItems", false)
    537 
    538 		}
    539 
    540 	return 0;
    541 
    542 	}
    543 
    544 /*****************************************************************************/
    545 
    546 bool dng_xmp_sdk::Exists (const char *ns,
    547 					 	  const char *path) const
    548 	{
    549 
    550 	if (HasMeta ())
    551 		{
    552 
    553 		try
    554 			{
    555 
    556 			return fPrivate->fMeta->DoesPropertyExist (ns, path);
    557 
    558 			}
    559 
    560 		catch (...)
    561 			{
    562 
    563 			// Does not exist...
    564 
    565 			}
    566 
    567 		}
    568 
    569 	return false;
    570 
    571 	}
    572 
    573 /*****************************************************************************/
    574 
    575 bool dng_xmp_sdk::HasNameSpace (const char *ns) const
    576 	{
    577 
    578 	bool result = false;
    579 
    580 	if (HasMeta ())
    581 		{
    582 
    583 		try
    584 			{
    585 
    586 			SXMPIterator iter (*fPrivate->fMeta, ns);
    587 
    588 			TXMP_STRING_TYPE nsTemp;
    589 			TXMP_STRING_TYPE prop;
    590 
    591 			if (iter.Next (&nsTemp,
    592 						   &prop,
    593 						   NULL,
    594 						   NULL))
    595 				{
    596 
    597 				result = true;
    598 
    599 				}
    600 
    601 			}
    602 
    603 		CATCH_XMP ("HasNameSpace", true)
    604 
    605 		}
    606 
    607 	return result;
    608 
    609 	}
    610 
    611 /*****************************************************************************/
    612 
    613 void dng_xmp_sdk::Remove (const char *ns,
    614 				     	  const char *path)
    615 	{
    616 
    617 	if (HasMeta ())
    618 		{
    619 
    620 		try
    621 			{
    622 
    623 			fPrivate->fMeta->DeleteProperty (ns, path);
    624 
    625 			}
    626 
    627 		CATCH_XMP ("DeleteProperty", false)
    628 
    629 		}
    630 
    631 	}
    632 
    633 /*****************************************************************************/
    634 
    635 void dng_xmp_sdk::RemoveProperties (const char *ns)
    636 	{
    637 
    638 	if (HasMeta ())
    639 		{
    640 
    641 		try
    642 			{
    643 
    644 			SXMPUtils::RemoveProperties (fPrivate->fMeta,
    645 										 ns,
    646 										 NULL,
    647 										 kXMPUtil_DoAllProperties);
    648 
    649 			}
    650 
    651 		catch (...)
    652 			{
    653 
    654 			}
    655 
    656 		}
    657 
    658 	}
    659 
    660 /*****************************************************************************/
    661 
    662 bool dng_xmp_sdk::IsEmptyString (const char *ns,
    663 								 const char *path)
    664 	{
    665 
    666 	if (HasMeta ())
    667 		{
    668 
    669 		try
    670 			{
    671 
    672 			TXMP_STRING_TYPE ss;
    673 
    674 			XMP_OptionBits options = 0;
    675 
    676 			if (fPrivate->fMeta->GetProperty (ns,
    677 											  path,
    678 											  &ss,
    679 											  &options))
    680 				{
    681 
    682 				// Item must be simple.
    683 
    684 				if (XMP_PropIsSimple (options))
    685 					{
    686 
    687 					// Check for null strings.
    688 
    689 					return (ss.c_str ()     == 0 ||
    690 							ss.c_str () [0] == 0);
    691 
    692 					}
    693 
    694 				}
    695 
    696 			}
    697 
    698 		CATCH_XMP ("IsEmptyString", false)
    699 
    700 		}
    701 
    702 	return false;
    703 
    704 	}
    705 
    706 /*****************************************************************************/
    707 
    708 bool dng_xmp_sdk::IsEmptyArray (const char *ns,
    709 								const char *path)
    710 	{
    711 
    712 	if (HasMeta ())
    713 		{
    714 
    715 		try
    716 			{
    717 
    718 			TXMP_STRING_TYPE ss;
    719 
    720 			XMP_OptionBits options = 0;
    721 
    722 			if (fPrivate->fMeta->GetProperty (ns,
    723 											  path,
    724 											  &ss,
    725 											  &options))
    726 				{
    727 
    728 				if (XMP_PropIsArray (options))
    729 					{
    730 
    731 					if (fPrivate->fMeta->GetArrayItem (ns,
    732 													   path,
    733 													   1,
    734 													   &ss,
    735 													   &options))
    736 						{
    737 
    738 						// If the first item is a null string...
    739 
    740 						if (XMP_PropIsSimple (options))
    741 							{
    742 
    743 							if ((ss.c_str ()     == 0 ||
    744 								 ss.c_str () [0] == 0))
    745 								{
    746 
    747 								// And there is no second item.
    748 
    749 								if (!fPrivate->fMeta->GetArrayItem (ns,
    750 																	path,
    751 																	2,
    752 																	&ss,
    753 																	&options))
    754 									{
    755 
    756 									// Then we have an empty array.
    757 
    758 									return true;
    759 
    760 									}
    761 
    762 								}
    763 
    764 							}
    765 
    766 						}
    767 
    768 					else
    769 						{
    770 
    771 						// Unable to get first item, so array is empty.
    772 
    773 						return true;
    774 
    775 						}
    776 
    777 					}
    778 
    779 				}
    780 
    781 			}
    782 
    783 		CATCH_XMP ("IsEmptyArray", false)
    784 
    785 		}
    786 
    787 	return false;
    788 
    789 	}
    790 
    791 /*****************************************************************************/
    792 
    793 void dng_xmp_sdk::ComposeArrayItemPath (const char *ns,
    794 										const char *arrayName,
    795 										int32 index,
    796 										dng_string &s) const
    797 	{
    798 
    799 	try
    800 		{
    801 
    802 		std::string ss;
    803 
    804 		SXMPUtils::ComposeArrayItemPath (ns, arrayName, index, &ss);
    805 
    806 		s.Set (ss.c_str ());
    807 
    808 		return;
    809 
    810 		}
    811 
    812 	CATCH_XMP ("ComposeArrayItemPath", true)
    813 
    814 	}
    815 
    816 /*****************************************************************************/
    817 
    818 void dng_xmp_sdk::ComposeStructFieldPath (const char *ns,
    819 										  const char *structName,
    820 										  const char *fieldNS,
    821 										  const char *fieldName,
    822 										  dng_string &s) const
    823 	{
    824 
    825 	try
    826 		{
    827 
    828 		std::string ss;
    829 
    830 		SXMPUtils::ComposeStructFieldPath (ns,
    831 										   structName,
    832 										   fieldNS,
    833 										   fieldName,
    834 										   &ss);
    835 
    836 		s.Set (ss.c_str ());
    837 
    838 		return;
    839 
    840 		}
    841 
    842 	CATCH_XMP ("ComposeStructFieldPath", true)
    843 
    844 	}
    845 
    846 /*****************************************************************************/
    847 
    848 bool dng_xmp_sdk::GetNamespacePrefix (const char *uri,
    849 									  dng_string &s) const
    850 	{
    851 
    852 	bool result = false;
    853 
    854 	if (HasMeta ())
    855 		{
    856 
    857 		try
    858 			{
    859 
    860 			std::string ss;
    861 
    862 			fPrivate->fMeta->GetNamespacePrefix (uri, &ss);
    863 
    864 			s.Set (ss.c_str ());
    865 
    866 			result = true;
    867 
    868 			}
    869 
    870 		CATCH_XMP ("GetNamespacePrefix", false)
    871 
    872 		}
    873 
    874 	return result;
    875 
    876 	}
    877 
    878 /*****************************************************************************/
    879 
    880 bool dng_xmp_sdk::GetString (const char *ns,
    881 				   		     const char *path,
    882 				   		     dng_string &s) const
    883 	{
    884 
    885 	bool result = false;
    886 
    887 	if (HasMeta ())
    888 		{
    889 
    890 		try
    891 			{
    892 
    893 			TXMP_STRING_TYPE ss;
    894 
    895 			if (fPrivate->fMeta->GetProperty (ns, path, &ss, NULL))
    896 				{
    897 
    898 				s.Set (ss.c_str ());
    899 
    900 				result = true;
    901 
    902 				}
    903 
    904 			}
    905 
    906 		CATCH_XMP ("GetProperty", false)
    907 
    908 		}
    909 
    910 	return result;
    911 
    912 	}
    913 
    914 /*****************************************************************************/
    915 
    916 void dng_xmp_sdk::ValidateStringList (const char *ns,
    917 								      const char *path)
    918 	{
    919 
    920 	if (Exists (ns, path))
    921 		{
    922 
    923 		bool bogus = true;
    924 
    925 		try
    926 			{
    927 
    928 			XMP_Index index = 1;
    929 
    930 			TXMP_STRING_TYPE ss;
    931 
    932 			while (fPrivate->fMeta->GetArrayItem (ns,
    933 												  path,
    934 												  index++,
    935 												  &ss,
    936 												  NULL))
    937 				{
    938 
    939 				}
    940 
    941 			bogus = false;
    942 
    943 			}
    944 
    945 		CATCH_XMP ("GetArrayItem", false)
    946 
    947 		if (bogus)
    948 			{
    949 
    950 			Remove (ns, path);
    951 
    952 			}
    953 
    954 		}
    955 
    956 	}
    957 
    958 /*****************************************************************************/
    959 
    960 bool dng_xmp_sdk::GetStringList (const char *ns,
    961 								 const char *path,
    962 								 dng_string_list &list) const
    963 	{
    964 
    965 	bool result = false;
    966 
    967 	if (HasMeta ())
    968 		{
    969 
    970 		try
    971 			{
    972 
    973 			XMP_Index index = 1;
    974 
    975 			TXMP_STRING_TYPE ss;
    976 
    977 			while (fPrivate->fMeta->GetArrayItem (ns,
    978 												  path,
    979 												  index++,
    980 												  &ss,
    981 												  NULL))
    982 				{
    983 
    984 				dng_string s;
    985 
    986 				s.Set (ss.c_str ());
    987 
    988 				list.Append (s);
    989 
    990 				result = true;
    991 
    992 				}
    993 
    994 			}
    995 
    996 		CATCH_XMP ("GetArrayItem", false)
    997 
    998 		}
    999 
   1000 	return result;
   1001 
   1002 	}
   1003 
   1004 /*****************************************************************************/
   1005 
   1006 bool dng_xmp_sdk::GetAltLangDefault (const char *ns,
   1007 									 const char *path,
   1008 									 dng_string &s) const
   1009 	{
   1010 
   1011 	bool result = false;
   1012 
   1013 	if (HasMeta ())
   1014 		{
   1015 
   1016 		try
   1017 			{
   1018 
   1019 			TXMP_STRING_TYPE ss;
   1020 
   1021 			if (fPrivate->fMeta->GetLocalizedText (ns,
   1022 												   path,
   1023 												   "x-default",
   1024 									  	   		   "x-default",
   1025 												   NULL,
   1026 									  	  		   &ss,
   1027 												   NULL))
   1028 				{
   1029 
   1030 				s.Set (ss.c_str ());
   1031 
   1032 				result = true;
   1033 
   1034 				}
   1035 			//
   1036 			// Special Case: treat the following two representation equivalently.
   1037 			// The first is an empty alt lang array; the second is an array with
   1038 			// an empty item. It seems that xmp lib could be generating both under
   1039 			// some circumstances!
   1040 			//
   1041 			// <dc:description>
   1042 			//	<rdf:Alt/>
   1043 			// </dc:description>
   1044 			//
   1045 			// and
   1046 			//
   1047 			// <dc:description>
   1048 			//  <rdf:Alt>
   1049 			//   <rdf:li xml:lang="x-default"/>
   1050 			//  </rdf:Alt>
   1051 			// </dc:description>
   1052 			//
   1053 			else if (fPrivate->fMeta->GetProperty (ns,
   1054 												   path,
   1055 												   &ss,
   1056 												   NULL))
   1057 				{
   1058 
   1059 				if (ss.empty ())
   1060 					{
   1061 
   1062 					s.Clear ();
   1063 
   1064 					result = true;
   1065 
   1066 					}
   1067 
   1068 				}
   1069 
   1070 			}
   1071 
   1072 		CATCH_XMP ("GetLocalizedText", false)
   1073 
   1074 		}
   1075 
   1076 	return result;
   1077 
   1078 	}
   1079 
   1080 /*****************************************************************************/
   1081 
   1082 bool dng_xmp_sdk::GetStructField (const char *ns,
   1083 								  const char *path,
   1084 								  const char *fieldNS,
   1085 								  const char *fieldName,
   1086 								  dng_string &s) const
   1087 	{
   1088 
   1089 	bool result = false;
   1090 
   1091 	if (HasMeta ())
   1092 		{
   1093 
   1094 		try
   1095 			{
   1096 
   1097 			TXMP_STRING_TYPE ss;
   1098 
   1099 			if (fPrivate->fMeta->GetStructField (ns,
   1100 												 path,
   1101 												 fieldNS,
   1102 												 fieldName,
   1103 												 &ss,
   1104 												 NULL))
   1105 				{
   1106 
   1107 				s.Set (ss.c_str ());
   1108 
   1109 				result = true;
   1110 
   1111 				}
   1112 
   1113 			}
   1114 
   1115 		CATCH_XMP ("GetStructField", false)
   1116 
   1117 		}
   1118 
   1119 	return result;
   1120 
   1121 	}
   1122 
   1123 /*****************************************************************************/
   1124 
   1125 void dng_xmp_sdk::Set (const char *ns,
   1126 				  	   const char *path,
   1127 				  	   const char *text)
   1128 	{
   1129 
   1130 	NeedMeta ();
   1131 
   1132 	try
   1133 		{
   1134 
   1135 		fPrivate->fMeta->SetProperty (ns, path, text);
   1136 
   1137 		return;
   1138 
   1139 		}
   1140 
   1141 	catch (...)
   1142 		{
   1143 
   1144 		// Failed for some reason.
   1145 
   1146 		}
   1147 
   1148 	// Remove existing value and try again.
   1149 
   1150 	Remove (ns, path);
   1151 
   1152 	try
   1153 		{
   1154 
   1155 		fPrivate->fMeta->SetProperty (ns, path, text);
   1156 
   1157 		}
   1158 
   1159 	CATCH_XMP ("SetProperty", true)
   1160 
   1161 	}
   1162 
   1163 /*****************************************************************************/
   1164 
   1165 void dng_xmp_sdk::SetString (const char *ns,
   1166 				  			 const char *path,
   1167 				  			 const dng_string &s)
   1168 	{
   1169 
   1170 	dng_string ss (s);
   1171 
   1172 	ss.SetLineEndings ('\n');
   1173 
   1174 	ss.StripLowASCII ();
   1175 
   1176 	Set (ns, path, ss.Get ());
   1177 
   1178 	}
   1179 
   1180 /*****************************************************************************/
   1181 
   1182 void dng_xmp_sdk::SetStringList (const char *ns,
   1183 				  		    	 const char *path,
   1184 				  		    	 const dng_string_list &list,
   1185 				  		    	 bool isBag)
   1186 	{
   1187 
   1188 	// Remove any existing structure.
   1189 
   1190 	Remove (ns, path);
   1191 
   1192 	// If list is not empty, add the items.
   1193 
   1194 	if (list.Count ())
   1195 		{
   1196 
   1197 		NeedMeta ();
   1198 
   1199 		for (uint32 index = 0; index < list.Count (); index++)
   1200 			{
   1201 
   1202 			dng_string s (list [index]);
   1203 
   1204 			s.SetLineEndings ('\n');
   1205 
   1206 			s.StripLowASCII ();
   1207 
   1208 			try
   1209 				{
   1210 
   1211 				fPrivate->fMeta->AppendArrayItem (ns,
   1212 												  path,
   1213 												  isBag ? kXMP_PropValueIsArray
   1214 														: kXMP_PropArrayIsOrdered,
   1215 												  s.Get ());
   1216 
   1217 				}
   1218 
   1219 			CATCH_XMP ("AppendArrayItem", true)
   1220 
   1221 			}
   1222 
   1223 		}
   1224 
   1225 	}
   1226 
   1227 /*****************************************************************************/
   1228 
   1229 void dng_xmp_sdk::SetAltLangDefault (const char *ns,
   1230 									 const char *path,
   1231 									 const dng_string &s)
   1232 	{
   1233 
   1234 	NeedMeta ();
   1235 
   1236 	Remove (ns, path);
   1237 
   1238 	dng_string ss (s);
   1239 
   1240 	ss.SetLineEndings ('\n');
   1241 
   1242 	ss.StripLowASCII ();
   1243 
   1244 	try
   1245 		{
   1246 
   1247 		fPrivate->fMeta->SetLocalizedText (ns,
   1248 									  	   path,
   1249 									  	   "x-default",
   1250 									  	   "x-default",
   1251 									  	   ss.Get ());
   1252 
   1253 		}
   1254 
   1255 	CATCH_XMP ("SetLocalizedText", true)
   1256 
   1257 	}
   1258 
   1259 /*****************************************************************************/
   1260 
   1261 void dng_xmp_sdk::SetStructField (const char *ns,
   1262 								  const char *path,
   1263 								  const char *fieldNS,
   1264 								  const char *fieldName,
   1265 								  const char *text)
   1266 	{
   1267 
   1268 	NeedMeta ();
   1269 
   1270 	try
   1271 		{
   1272 
   1273 		fPrivate->fMeta->SetStructField (ns,
   1274 							  			 path,
   1275 							  			 fieldNS,
   1276 							  			 fieldName,
   1277 							  			 text);
   1278 
   1279 		}
   1280 
   1281 	CATCH_XMP ("SetStructField", true)
   1282 
   1283 	}
   1284 
   1285 /*****************************************************************************/
   1286 
   1287 void dng_xmp_sdk::DeleteStructField (const char *ns,
   1288 									 const char *structName,
   1289 									 const char *fieldNS,
   1290 						             const char *fieldName)
   1291 	{
   1292 
   1293 	if (HasMeta ())
   1294 		{
   1295 
   1296 		try
   1297 			{
   1298 
   1299 			fPrivate->fMeta->DeleteStructField (ns, structName, fieldNS, fieldName);
   1300 
   1301 			}
   1302 
   1303 		catch (...)
   1304 			{
   1305 
   1306 			}
   1307 
   1308 		}
   1309 
   1310 	}
   1311 
   1312 /*****************************************************************************/
   1313 
   1314 dng_memory_block * dng_xmp_sdk::Serialize (dng_memory_allocator &allocator,
   1315 									       bool asPacket,
   1316 									       uint32 targetBytes,
   1317 									       uint32 padBytes,
   1318 									       bool forJPEG,
   1319 										   bool compact) const
   1320 	{
   1321 
   1322 	// The largest XMP packet you can embed in JPEG using normal methods:
   1323 
   1324 	const uint32 kJPEG_XMP_Limit = 65504;
   1325 
   1326 	if (HasMeta ())
   1327 		{
   1328 
   1329 		TXMP_STRING_TYPE s;
   1330 
   1331 		bool havePacket = false;
   1332 
   1333 		// Note that the XMP lib is changing its default to compact format
   1334 		// in the future, so the following line will need to change.
   1335 
   1336 		uint32 formatOption = compact ? kXMP_UseCompactFormat : 0;
   1337 
   1338 	    if (asPacket && targetBytes)
   1339 	    	{
   1340 
   1341 	    	try
   1342 	    		{
   1343 
   1344 	    		fPrivate->fMeta->SerializeToBuffer (&s,
   1345 	    											formatOption | kXMP_ExactPacketLength,
   1346 	    											targetBytes,
   1347 	    											"",
   1348 													" ");
   1349 
   1350 				havePacket = true;
   1351 
   1352 	    		}
   1353 
   1354 	    	catch (...)
   1355 	    		{
   1356 
   1357 	    		// Most likely the packet cannot fit in the target
   1358 	    		// byte count.  So try again without the limit.
   1359 
   1360 	    		}
   1361 
   1362 	    	}
   1363 
   1364 		if (!havePacket)
   1365 			{
   1366 
   1367 			try
   1368 				{
   1369 
   1370 				fPrivate->fMeta->SerializeToBuffer (&s,
   1371 													formatOption |
   1372 													(asPacket ? 0
   1373 															  : kXMP_OmitPacketWrapper),
   1374 													(asPacket ? padBytes
   1375 															  : 0),
   1376 													"",
   1377 													" ");
   1378 
   1379 				}
   1380 
   1381 			CATCH_XMP ("SerializeToBuffer", true)
   1382 
   1383 			}
   1384 
   1385 		uint32 packetLen = (uint32) s.size ();
   1386 
   1387 		if (forJPEG && asPacket && padBytes > 0 && targetBytes <= kJPEG_XMP_Limit &&
   1388 												   packetLen   >  kJPEG_XMP_Limit)
   1389 			{
   1390 
   1391 			uint32 overLimitCount = packetLen - kJPEG_XMP_Limit;
   1392 
   1393 			if (overLimitCount > padBytes)
   1394 				{
   1395 				padBytes = 0;
   1396 				}
   1397 			else
   1398 				{
   1399 				padBytes -= overLimitCount;
   1400 				}
   1401 
   1402 			try
   1403 				{
   1404 
   1405 				fPrivate->fMeta->SerializeToBuffer (&s,
   1406 													formatOption,
   1407 													padBytes,
   1408 													"",
   1409 													" ");
   1410 
   1411 				}
   1412 
   1413 			CATCH_XMP ("SerializeToBuffer", true)
   1414 
   1415 			packetLen = (uint32) s.size ();
   1416 
   1417 			}
   1418 
   1419 		if (packetLen)
   1420 			{
   1421 
   1422 			AutoPtr<dng_memory_block> buffer (allocator.Allocate (packetLen));
   1423 
   1424 			memcpy (buffer->Buffer (), s.c_str (), packetLen);
   1425 
   1426 			return buffer.Release ();
   1427 
   1428 			}
   1429 
   1430 		}
   1431 
   1432 	return NULL;
   1433 
   1434 	}
   1435 
   1436 /*****************************************************************************/
   1437 
   1438 void dng_xmp_sdk::PackageForJPEG (dng_memory_allocator &allocator,
   1439 								  AutoPtr<dng_memory_block> &stdBlock,
   1440 								  AutoPtr<dng_memory_block> &extBlock,
   1441 								  dng_string &extDigest) const
   1442 	{
   1443 
   1444 	if (HasMeta ())
   1445 		{
   1446 
   1447 		TXMP_STRING_TYPE stdStr;
   1448 		TXMP_STRING_TYPE extStr;
   1449 		TXMP_STRING_TYPE digestStr;
   1450 
   1451 		try
   1452 			{
   1453 
   1454 			SXMPUtils::PackageForJPEG (*fPrivate->fMeta,
   1455 									   &stdStr,
   1456 									   &extStr,
   1457 									   &digestStr);
   1458 
   1459 			}
   1460 
   1461 		CATCH_XMP ("PackageForJPEG", true)
   1462 
   1463 		uint32 stdLen = (uint32) stdStr.size ();
   1464 		uint32 extLen = (uint32) extStr.size ();
   1465 
   1466 		if (stdLen)
   1467 			{
   1468 
   1469 			stdBlock.Reset (allocator.Allocate (stdLen));
   1470 
   1471 			memcpy (stdBlock->Buffer (), stdStr.c_str (), stdLen);
   1472 
   1473 			}
   1474 
   1475 		if (extLen)
   1476 			{
   1477 
   1478 			extBlock.Reset (allocator.Allocate (extLen));
   1479 
   1480 			memcpy (extBlock->Buffer (), extStr.c_str (), extLen);
   1481 
   1482 			if (digestStr.size () != 32)
   1483 				{
   1484 				ThrowProgramError ();
   1485 				}
   1486 
   1487 			extDigest.Set (digestStr.c_str ());
   1488 
   1489 			}
   1490 
   1491 		}
   1492 
   1493 	}
   1494 
   1495 /*****************************************************************************/
   1496 
   1497 void dng_xmp_sdk::MergeFromJPEG (const dng_xmp_sdk *xmp)
   1498 	{
   1499 
   1500 	if (xmp && xmp->HasMeta ())
   1501 		{
   1502 
   1503 		NeedMeta ();
   1504 
   1505 		try
   1506 			{
   1507 
   1508 			SXMPUtils::MergeFromJPEG (fPrivate->fMeta,
   1509 									  *xmp->fPrivate->fMeta);
   1510 
   1511 			}
   1512 
   1513 		CATCH_XMP ("MergeFromJPEG", true)
   1514 
   1515 		}
   1516 
   1517 	}
   1518 
   1519 /*****************************************************************************/
   1520 
   1521 void dng_xmp_sdk::ReplaceXMP (dng_xmp_sdk *xmp)
   1522 	{
   1523 
   1524 	ClearMeta ();
   1525 
   1526 	if (xmp && xmp->HasMeta ())
   1527 		{
   1528 
   1529 		fPrivate->fMeta = xmp->fPrivate->fMeta;
   1530 
   1531 		xmp->fPrivate->fMeta = NULL;
   1532 
   1533 		}
   1534 
   1535 	}
   1536 
   1537 /*****************************************************************************/
   1538 
   1539 bool dng_xmp_sdk::IteratePaths (IteratePathsCallback *callback,
   1540 						        void *callbackData,
   1541 								const char* startingNS,
   1542 								const char* startingPath)
   1543 	{
   1544 
   1545 	if (HasMeta ())
   1546 		{
   1547 
   1548 		try
   1549 			{
   1550 
   1551 			SXMPIterator iter (*fPrivate->fMeta, startingNS, startingPath);
   1552 
   1553 			TXMP_STRING_TYPE ns;
   1554 			TXMP_STRING_TYPE prop;
   1555 
   1556 			while (iter.Next (&ns,
   1557 							  &prop,
   1558 							  NULL,
   1559 							  NULL))
   1560 				{
   1561 
   1562 				if (!callback (ns  .c_str (),
   1563 						  	   prop.c_str (),
   1564 						  	   callbackData))
   1565 					{
   1566 
   1567 					return false;
   1568 
   1569 					}
   1570 
   1571 				}
   1572 
   1573 			}
   1574 
   1575 		CATCH_XMP ("IteratePaths", true)
   1576 
   1577 		}
   1578 
   1579 	return true;
   1580 
   1581 	}
   1582 
   1583 /*****************************************************************************/
   1584 
   1585 #if qDNGXMPDocOps
   1586 
   1587 /*****************************************************************************/
   1588 
   1589 void dng_xmp_sdk::DocOpsOpenXMP (const char *srcMIMI)
   1590 	{
   1591 
   1592 	if (srcMIMI [0])
   1593 		{
   1594 
   1595 		NeedMeta ();
   1596 
   1597 		try
   1598 			{
   1599 
   1600 			SXMPDocOps docOps;
   1601 
   1602 			docOps.OpenXMP (fPrivate->fMeta,
   1603 							srcMIMI);
   1604 
   1605 			}
   1606 
   1607 		CATCH_XMP ("DocOpsOpenXMP", false)
   1608 
   1609 		Set (XMP_NS_DC,
   1610 			 "format",
   1611 			 srcMIMI);
   1612 
   1613 		}
   1614 
   1615 	}
   1616 
   1617 /*****************************************************************************/
   1618 
   1619 void dng_xmp_sdk::DocOpsPrepareForSave (const char *srcMIMI,
   1620 										const char *dstMIMI,
   1621 										bool newPath)
   1622 	{
   1623 
   1624 	NeedMeta ();
   1625 
   1626 	try
   1627 		{
   1628 
   1629 		SXMPDocOps docOps;
   1630 
   1631 		docOps.OpenXMP (fPrivate->fMeta,
   1632 						srcMIMI,
   1633 						"old path");
   1634 
   1635 		docOps.NoteChange (kXMP_Part_All);
   1636 
   1637 		docOps.PrepareForSave (dstMIMI,
   1638 							   newPath ? "new path" : "old path");
   1639 
   1640 		}
   1641 
   1642 	CATCH_XMP ("DocOpsPrepareForSave", false)
   1643 
   1644 	Set (XMP_NS_DC,
   1645 		 "format",
   1646 		 dstMIMI);
   1647 
   1648 	}
   1649 
   1650 /*****************************************************************************/
   1651 
   1652 void dng_xmp_sdk::DocOpsUpdateMetadata (const char *srcMIMI)
   1653 	{
   1654 
   1655 	NeedMeta ();
   1656 
   1657 	try
   1658 		{
   1659 
   1660 		SXMPDocOps docOps;
   1661 
   1662 		docOps.OpenXMP (fPrivate->fMeta,
   1663 						srcMIMI);
   1664 
   1665 		docOps.NoteChange (kXMP_Part_Metadata);
   1666 
   1667 		docOps.PrepareForSave (srcMIMI);
   1668 
   1669 		}
   1670 
   1671 	CATCH_XMP ("DocOpsUpdateMetadata", false)
   1672 
   1673 	}
   1674 
   1675 /*****************************************************************************/
   1676 
   1677 #endif
   1678 
   1679 /*****************************************************************************/
   1680