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
dng_xmp_private()118 dng_xmp_private ()
119 : fMeta (NULL)
120 {
121 }
122
123 dng_xmp_private (const dng_xmp_private &xmp);
124
~dng_xmp_private()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
dng_xmp_private(const dng_xmp_private & xmp)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
dng_xmp_sdk()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
dng_xmp_sdk(const dng_xmp_sdk & sdk)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
~dng_xmp_sdk()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
InitializeSDK(dng_xmp_namespace * extraNamespaces,const char * software)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
TerminateSDK()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
HasMeta() const370 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
ClearMeta()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
MakeMeta()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
NeedMeta()429 void dng_xmp_sdk::NeedMeta ()
430 {
431
432 if (!HasMeta ())
433 {
434
435 MakeMeta ();
436
437 }
438
439 }
440
441 /******************************************************************************/
442
GetPrivateMeta()443 void * dng_xmp_sdk::GetPrivateMeta ()
444 {
445
446 NeedMeta ();
447
448 return (void *) fPrivate->fMeta;
449
450 }
451
452 /******************************************************************************/
453
Parse(dng_host & host,const char * buffer,uint32 count)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
AppendArrayItem(const char * ns,const char * arrayName,const char * itemValue,bool isBag,bool propIsStruct)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
CountArrayItems(const char * ns,const char * path) const522 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
Exists(const char * ns,const char * path) const546 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
HasNameSpace(const char * ns) const575 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
Remove(const char * ns,const char * path)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
RemoveProperties(const char * ns)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
IsEmptyString(const char * ns,const char * path)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
IsEmptyArray(const char * ns,const char * path)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
ComposeArrayItemPath(const char * ns,const char * arrayName,int32 index,dng_string & s) const793 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
ComposeStructFieldPath(const char * ns,const char * structName,const char * fieldNS,const char * fieldName,dng_string & s) const818 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
GetNamespacePrefix(const char * uri,dng_string & s) const848 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
GetString(const char * ns,const char * path,dng_string & s) const880 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
ValidateStringList(const char * ns,const char * path)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
GetStringList(const char * ns,const char * path,dng_string_list & list) const960 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
GetAltLangDefault(const char * ns,const char * path,dng_string & s) const1006 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
GetStructField(const char * ns,const char * path,const char * fieldNS,const char * fieldName,dng_string & s) const1082 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
Set(const char * ns,const char * path,const char * text)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
SetString(const char * ns,const char * path,const dng_string & s)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
SetStringList(const char * ns,const char * path,const dng_string_list & list,bool isBag)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
SetAltLangDefault(const char * ns,const char * path,const dng_string & s)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
SetStructField(const char * ns,const char * path,const char * fieldNS,const char * fieldName,const char * text)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
DeleteStructField(const char * ns,const char * structName,const char * fieldNS,const char * fieldName)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
Serialize(dng_memory_allocator & allocator,bool asPacket,uint32 targetBytes,uint32 padBytes,bool forJPEG,bool compact) const1314 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
PackageForJPEG(dng_memory_allocator & allocator,AutoPtr<dng_memory_block> & stdBlock,AutoPtr<dng_memory_block> & extBlock,dng_string & extDigest) const1438 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
MergeFromJPEG(const dng_xmp_sdk * xmp)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
ReplaceXMP(dng_xmp_sdk * xmp)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
IteratePaths(IteratePathsCallback * callback,void * callbackData,const char * startingNS,const char * startingPath)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
DocOpsOpenXMP(const char * srcMIMI)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
DocOpsPrepareForSave(const char * srcMIMI,const char * dstMIMI,bool newPath)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
DocOpsUpdateMetadata(const char * srcMIMI)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