1 // =================================================================================================
2 // Copyright 2002-2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in accordance with the terms
6 // of the Adobe license agreement accompanying it.
7 // =================================================================================================
8 
9 /**
10 * Demonstrates how to use the iteration utility in the XMPCore component to walk through property trees.
11 */
12 
13 #include <string>
14 
15 // Must be defined to instantiate template classes
16 #define TXMP_STRING_TYPE std::string
17 
18 // Must be defined to give access to XMPFiles
19 #define XMP_INCLUDE_XMPFILES 1
20 
21 // Ensure XMP templates are instantiated
22 #include "XMP.incl_cpp"
23 
24 // Provide access to the API
25 #include "XMP.hpp"
26 
27 #include <iostream>
28 
29 using namespace std;
30 
31 // Provide some custom XMP
32 static const char * rdf =
33 	"<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
34 	"  <rdf:Description rdf:about='' xmlns:xmpTest='http://ns.adobe.com/xmpTest/'>"
35 	""
36 	"	 <xmpTest:MySimpleProp rdf:parseType='Resource'>"
37 	"		<rdf:value>A Value</rdf:value>"
38 	"		<xmpTest:MyQual>Qual Value</xmpTest:MyQual>"
39 	"  </xmpTest:MySimpleProp>"
40 	""
41   "		<xmpTest:MyTopStruct rdf:parseType='Resource'>"
42   "			<xmpTest:MySecondStruct rdf:parseType='Resource'>"
43   "				<xmpTest:MyThirdStruct rdf:parseType='Resource'>"
44   "					<xmpTest:MyThirdStructField>Field Value 3</xmpTest:MyThirdStructField>"
45   "       </xmpTest:MyThirdStruct>"
46   "				<xmpTest:MySecondStructField>Field Value 2</xmpTest:MySecondStructField>"
47   "     </xmpTest:MySecondStruct>"
48   "    <xmpTest:MyTopStructField>Field Value 1</xmpTest:MyTopStructField>"
49   "   </xmpTest:MyTopStruct>"
50 
51   "   <xmpTest:MyArrayWithNestedArray>"
52   "			<rdf:Bag>"
53   "				<rdf:li>"
54   "					<rdf:Seq>"
55   "						<rdf:li>Item 1</rdf:li>"
56   "           <rdf:li>Item 2</rdf:li>"
57   "         </rdf:Seq>"
58   "				</rdf:li>"
59   "			</rdf:Bag>"
60   "   </xmpTest:MyArrayWithNestedArray>"
61 
62   "   <xmpTest:MyArrayWithStructures>"
63   "			<rdf:Seq>"
64   "				<rdf:li rdf:parseType='Resource'>"
65 	"					<rdf:value>Field Value 1</rdf:value>"
66 	"						<xmpTest:FirstQual>Qual Value 1</xmpTest:FirstQual>"
67   "           <xmpTest:SecondQual>Qual Value 2</xmpTest:SecondQual>"
68   "        </rdf:li>"
69   "        <rdf:li rdf:parseType='Resource'>"
70 	"					<rdf:value>Field Value 2</rdf:value>"
71 	"						<xmpTest:FirstQual>Qual Value 3</xmpTest:FirstQual>"
72   "           <xmpTest:SecondQual>Qual Value 4</xmpTest:SecondQual>"
73   "        </rdf:li>"
74   "     </rdf:Seq>"
75   "   </xmpTest:MyArrayWithStructures>"
76 	""
77   "		<xmpTest:MyStructureWithArray rdf:parseType='Resource'>"
78   "			<xmpTest:NestedArray>"
79   "				<rdf:Bag>"
80   "					<rdf:li>Item 3</rdf:li>"
81   "         <rdf:li>Item 4</rdf:li>"
82 	"					<rdf:li>Item 5</rdf:li>"
83 	"					<rdf:li>Item 6</rdf:li>"
84   "       </rdf:Bag>"
85   "     </xmpTest:NestedArray>"
86 	"			<xmpTest:NestedArray2>"
87   "				<rdf:Bag>"
88   "					<rdf:li>Item 66</rdf:li>"
89   "         <rdf:li>Item 46</rdf:li>"
90 	"					<rdf:li>Item 56</rdf:li>"
91 	"					<rdf:li>Item 66</rdf:li>"
92   "       </rdf:Bag>"
93   "     </xmpTest:NestedArray2>"
94   "   </xmpTest:MyStructureWithArray>"
95 	""
96   " </rdf:Description>"
97 	"</rdf:RDF>";
98 
99 // The namespace to be used.  This will be automatically registered
100 // when the RDF is parsed.
101 const XMP_StringPtr kXMP_NS_SDK = "http://ns.adobe.com/xmpTest/";
102 
103 /**
104 * Reads some metadata from a file and appends some custom XMP to it.  Then does several
105 * iterations, using various iterators.  Each iteration is displayed in the console window.
106 */
main()107 int main()
108 {
109 	if(SXMPMeta::Initialize())
110 	{
111 		SXMPFiles::Initialize();
112 
113 		bool ok;
114 		SXMPFiles myFile;
115 
116 		XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler;
117 		ok = myFile.OpenFile("../../../testfiles/Image1.jpg", kXMP_UnknownFile, opts);
118 		if(ok)
119 		{
120 			SXMPMeta xmp;
121 			myFile.GetXMP(&xmp);
122 
123 			// Add some custom metadata to the XMP object
124 			SXMPMeta custXMP(rdf, (XMP_StringLen) strlen(rdf));
125 			SXMPUtils::AppendProperties(custXMP, &xmp);
126 
127 			// Store any details from the iter.Next() call
128 			string schemaNS, propPath, propVal;
129 
130 			// Only visit the immediate children that are leaf properties of the Dublin Core schema
131 			SXMPIterator dcLeafIter(xmp, kXMP_NS_DC, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes));
132 			while(dcLeafIter.Next(&schemaNS, &propPath, &propVal))
133 			{
134 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
135 			}
136 
137 			cout << "----------------------------------" << endl;
138 
139 			// Visit one property from the XMP Basic schema
140 			SXMPIterator xmpKeywordsIter(xmp, kXMP_NS_XMP, "Keywords", kXMP_IterJustLeafNodes);
141 			while(xmpKeywordsIter.Next(&schemaNS, &propPath, &propVal))
142 			{
143 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
144 			}
145 
146 			cout << "----------------------------------" << endl;
147 
148 			// Visit the Dublin Core schema, omit any quailifiers and only
149 			// show the leaf properties
150 			SXMPIterator dcIter(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes));
151 			while(dcIter.Next(&schemaNS, &propPath, &propVal))
152 			{
153 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
154 			}
155 
156 			cout << "----------------------------------" << endl;
157 
158 			// Visit the Dublin Core schema, omit any quailifiers,
159 			// show the leaf properties but only return the leaf name and not the full path
160 			SXMPIterator dcIter2(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes | kXMP_IterJustLeafName));
161 			while(dcIter2.Next(&schemaNS, &propPath, &propVal))
162 			{
163 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
164 			}
165 
166 			cout << "----------------------------------" << endl;
167 
168 			// Iterate over a single namespace.  Show all properties within
169 			// the Photoshop schema
170 			SXMPIterator exifIter(xmp, kXMP_NS_Photoshop);
171 			while(exifIter.Next(&schemaNS, &propPath, &propVal))
172 			{
173 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
174 			}
175 
176 			cout << "----------------------------------" << endl;
177 
178 			// Just visit the leaf nodes of EXIF properties. That is just
179 			// properties that may have values.
180 			SXMPIterator exifLeafIter(xmp, kXMP_NS_EXIF, kXMP_IterJustLeafNodes);
181 			while(exifLeafIter.Next(&schemaNS, &propPath, &propVal))
182 			{
183 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
184 			}
185 
186 			cout << "----------------------------------" << endl;
187 
188 			// Iterate over all properties but skip the EXIF schema and skip the custom schema
189 			// and continue visiting nodes
190 			SXMPIterator skipExifIter (xmp);
191 			while(skipExifIter.Next(&schemaNS, &propPath, &propVal))
192 			{
193 				if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK)
194 				{
195 					skipExifIter.Skip(kXMP_IterSkipSubtree);
196 				}
197 				else
198 				{
199 					cout << schemaNS << "  " << propPath << " = " << propVal << endl;
200 				}
201 			}
202 
203 			cout << "----------------------------------" << endl;
204 
205 			// Iterate over all properties but skip the EXIF schema
206 			// and any remaining siblings of the current node.
207 			SXMPIterator stopAfterExifIter ( xmp );
208 			while(stopAfterExifIter.Next(&schemaNS, &propPath, &propVal))
209 			{
210 				if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK)
211 				{
212 					stopAfterExifIter.Skip(kXMP_IterSkipSiblings);
213 				}
214 				else
215 				{
216 					cout << schemaNS << "  " << propPath << " = " << propVal << endl;
217 				}
218 			}
219 
220 			cout << "----------------------------------" << endl;
221 
222 			//////////////////////////////////////////////////////////////////////////////////////
223 
224 			// Iterate over the custom XMP
225 
226 			// Visit the immediate children of this node.
227 			// No qualifiers are visisted as they are below the property being visisted.
228 			SXMPIterator justChildrenIter(xmp, kXMP_NS_SDK, kXMP_IterJustChildren);
229 			while(justChildrenIter.Next(&schemaNS, &propPath, &propVal))
230 			{
231 				cout << propPath << " = " << propVal << endl;
232 			}
233 
234 			cout << "----------------------------------" << endl;
235 
236 			// Visit the immediate children of this node but only those that may have values.
237 			// No qualifiers are visisted as they are below the property being visisted.
238 			SXMPIterator justChildrenAndLeafIter(xmp, kXMP_NS_SDK, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes));
239 			while(justChildrenAndLeafIter.Next(&schemaNS, &propPath, &propVal))
240 			{
241 				cout << propPath << " = " << propVal << endl;
242 			}
243 
244 			cout << "----------------------------------" << endl;
245 
246 			// Visit the leaf nodes of TopStructProperty
247 			SXMPIterator myTopStructIter(xmp, kXMP_NS_SDK, "MyTopStruct", kXMP_IterJustLeafNodes);
248 			while(myTopStructIter.Next(&schemaNS, &propPath, &propVal))
249 			{
250 				cout << propPath << " = " << propVal << endl;
251 			}
252 
253 			cout << "----------------------------------" << endl;
254 
255 			// Visit the leaf nodes of the TopStructProperty but only return the names for
256 			// the leaf components and not the full path
257 			SXMPIterator xmyTopStructIterShortNames(xmp, kXMP_NS_SDK, "MyTopStruct", (kXMP_IterJustLeafNodes | kXMP_IterJustLeafName));
258 			while(xmyTopStructIterShortNames.Next(&schemaNS, &propPath, &propVal))
259 			{
260 				cout << propPath << " = " << propVal << endl;
261 			}
262 
263 			cout << "----------------------------------" << endl;
264 
265 			// Visit a property and all of the qualifiers
266 			SXMPIterator iterArrayProp (xmp, kXMP_NS_SDK, "ArrayWithStructures", kXMP_IterJustLeafNodes );
267 			while(iterArrayProp.Next(&schemaNS, &propPath, &propVal))
268 			{
269 				cout << propPath << " = " << propVal << endl;
270 			}
271 
272 			cout << "----------------------------------" << endl;
273 
274 			// Visit a property and omit all of the qualifiers
275 			SXMPIterator iterArrayPropNoQual (xmp, kXMP_NS_SDK, "ArrayWithStructures", (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers));
276 			while(iterArrayPropNoQual.Next(&schemaNS, &propPath, &propVal))
277 			{
278 				cout << propPath << " = " << propVal << endl;
279 			}
280 
281 			cout << "----------------------------------" << endl;
282 
283 			// Skip a subtree and continue onwards.  Once 'Item 4' is found then the we can skip all of the
284 			// siblings of the current node.  If the the current node were a top level node the iteration
285 			// would be complete as all siblings would be skipped.  However, when 'Item 4' is found the current
286 			// node is not at the top level so there are other nodes further up the tree that still need to be
287 			// visited.
288 			SXMPIterator skipIter (xmp, kXMP_NS_SDK, (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers | kXMP_IterJustLeafName));
289 			while(skipIter.Next(&schemaNS, &propPath, &propVal))
290 			{
291 				if(propVal == "Item 4")
292 				{
293 					skipIter.Skip(kXMP_IterSkipSiblings);
294 				}
295 				else
296 				{
297 					cout << schemaNS << "  " << propPath << " = " << propVal << endl;
298 				}
299 			}
300 
301 			/*
302 			// Visit all properties and qualifiers
303 			SXMPIterator allPropsIter(xmp);
304 			while(allPropsIter.Next(&schemaNS, &propPath, &propVal))
305 			{
306 				cout << schemaNS << "  " << propPath << " = " << propVal << endl;
307 			}
308 			*/
309 		}
310 
311 	}
312 
313 	SXMPFiles::Terminate();
314 	SXMPMeta::Terminate();
315 
316 	return 0;
317 }
318 
319