/src/bag/api/bag_metadata_import.cpp
Line  | Count  | Source  | 
1  |  | //************************************************************************  | 
2  |  | //  | 
3  |  | //      Open Navigation Surface Working Group, 2013  | 
4  |  | //  | 
5  |  | //************************************************************************  | 
6  |  | #include "bag_errors.h"  | 
7  |  | #include "bag_legacy_crs.h"  | 
8  |  | #include "bag_metadata_import.h"  | 
9  |  | #include "bag_metadatatypes.h"  | 
10  |  |  | 
11  |  | #include <cstring>  | 
12  |  | #include <iostream>  | 
13  |  | #include <libxml/parser.h>  | 
14  |  | #include <libxml/xmlschemas.h>  | 
15  |  | #include <libxml/xpath.h>  | 
16  |  | #include <libxml/xpathInternals.h>  | 
17  |  | #include <sstream>  | 
18  |  | #include <string>  | 
19  |  | #include <sys/stat.h>  | 
20  |  | #include <sys/types.h>  | 
21  |  | #include <vector>  | 
22  |  |  | 
23  |  |  | 
24  |  | namespace { | 
25  |  |  | 
26  |  | //! The location of the BAG home folder.  | 
27  |  | static std::string bagHomeFolder;  | 
28  |  |  | 
29  |  | //! The relative path from the BAG home folder, to the Bag schema file.  | 
30  |  | static std::string ons_schema_location = "ISO19139/bag/bag.xsd";  | 
31  |  |  | 
32  |  | //! Utility class to convert an encoded XML string.  | 
33  |  | class EncodedString final  | 
34  |  | { | 
35  |  | public:  | 
36  |  |     //************************************************************************  | 
37  |  |     //! Constructor  | 
38  |  |     /*!  | 
39  |  |     \param doc  | 
40  |  |         \li The XML document that the string is from.  | 
41  |  |     \param string  | 
42  |  |         \li The string to be converted.  | 
43  |  |     */  | 
44  |  |     //************************************************************************  | 
45  |  |     EncodedString(xmlDoc& doc, const char* string) noexcept  | 
46  | 14.6k  |     { | 
47  | 14.6k  |         this->m_pEncodedString = xmlEncodeEntitiesReentrant(&doc,  | 
48  | 14.6k  |             reinterpret_cast<const xmlChar*>(string));  | 
49  | 14.6k  |     }  | 
50  |  |  | 
51  |  |     EncodedString(const EncodedString&) = delete;  | 
52  |  |     EncodedString(EncodedString&&) = delete;  | 
53  |  |     EncodedString& operator=(const EncodedString&) = delete;  | 
54  |  |     EncodedString& operator=(EncodedString&&) = delete;  | 
55  |  |  | 
56  |  |     //************************************************************************  | 
57  |  |     //! Destructor.  | 
58  |  |     //************************************************************************  | 
59  |  |     ~EncodedString() noexcept  | 
60  | 14.6k  |     { | 
61  | 14.6k  |         xmlFree(this->m_pEncodedString);  | 
62  | 14.6k  |     }  | 
63  |  |  | 
64  |  |     //************************************************************************  | 
65  |  |     //! Conversion operator.  | 
66  |  |     /*!  | 
67  |  |     \return  | 
68  |  |         \li The encoded string.  | 
69  |  |     */  | 
70  |  |     //************************************************************************  | 
71  |  |     operator xmlChar*() const noexcept  | 
72  | 14.6k  |     { | 
73  | 14.6k  |         return this->m_pEncodedString;  | 
74  | 14.6k  |     }  | 
75  |  |  | 
76  |  | private:  | 
77  |  |     //! The encoded string.  | 
78  |  |     xmlChar* m_pEncodedString = nullptr;  | 
79  |  | };  | 
80  |  |  | 
81  |  | //************************************************************************  | 
82  |  | //! Convert a string to a double value.  | 
83  |  | /*!  | 
84  |  | \param value  | 
85  |  |     \li The input string to be converted.  | 
86  |  | \return  | 
87  |  |     \li The double value.  | 
88  |  | */  | 
89  |  | //************************************************************************  | 
90  |  | double toDouble(const std::string& value)  | 
91  | 1.11k  | { | 
92  | 1.11k  |     std::stringstream lineStream;  | 
93  | 1.11k  |     (void)lineStream.imbue(std::locale::classic());  | 
94  | 1.11k  |     lineStream << value;  | 
95  |  |  | 
96  | 1.11k  |     double dblValue = 0.0;  | 
97  | 1.11k  |     lineStream >> dblValue;  | 
98  |  |  | 
99  | 1.11k  |     return dblValue;  | 
100  | 1.11k  | }  | 
101  |  |  | 
102  |  | //************************************************************************  | 
103  |  | //! Get the name of a node.  | 
104  |  | /*!  | 
105  |  | \param value  | 
106  |  |     \li The input string to be converted.  | 
107  |  | \return  | 
108  |  |     \li The node name.  | 
109  |  | */  | 
110  |  | //************************************************************************  | 
111  |  | std::string getNodeName(const xmlNode& node)  | 
112  | 200  | { | 
113  | 200  |     std::string name;  | 
114  |  |  | 
115  |  |     // append the namespace prefix  | 
116  | 200  |     const xmlNs* nameSpace = node.ns;  | 
117  | 200  |     if (nameSpace)  | 
118  | 200  |     { | 
119  | 200  |         name = reinterpret_cast<const char*>(nameSpace->prefix);  | 
120  | 200  |         name += ':';  | 
121  | 200  |     }  | 
122  |  |  | 
123  | 200  |     name += reinterpret_cast<const char*>(node.name);  | 
124  |  |  | 
125  | 200  |     return name;  | 
126  | 200  | }  | 
127  |  |  | 
128  |  | //************************************************************************  | 
129  |  | //! Find all the nodes matching the supplied xpath pattern.  | 
130  |  | /*!  | 
131  |  | \param relativeNode  | 
132  |  |     \li The node to start searching from.  | 
133  |  | \param searchString  | 
134  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
135  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
136  |  | \return  | 
137  |  |     \li The list of XML nodes that match \e searchString  | 
138  |  | */  | 
139  |  | //************************************************************************  | 
140  |  | std::vector<xmlNode*> findNodes(  | 
141  |  |     xmlNode& relativeNode,  | 
142  |  |     const char* searchString)  | 
143  | 14.4k  | { | 
144  |  |     //Get the root node of the document.  | 
145  | 14.4k  |     const xmlNode* pRoot = xmlDocGetRootElement(relativeNode.doc);  | 
146  | 14.4k  |     if (!pRoot)  | 
147  | 0  |         return {}; | 
148  |  |  | 
149  |  |     //If the xPath context has not been initialized yet, do it now.  | 
150  | 14.4k  |     xmlXPathContext* pContext = xmlXPathNewContext(relativeNode.doc);  | 
151  | 14.4k  |     if (!pContext)  | 
152  | 0  |         return {}; | 
153  |  |  | 
154  | 14.4k  |     pContext->node = &relativeNode;  | 
155  |  |  | 
156  |  |     //Register any namespaces with the xPath context.  | 
157  | 14.4k  |     const xmlNs* xmlNameSpace = pRoot->nsDef;  | 
158  |  |  | 
159  | 114k  |     while (xmlNameSpace)  | 
160  | 99.7k  |     { | 
161  | 99.7k  |         if (xmlNameSpace->prefix)  | 
162  | 99.7k  |         { | 
163  | 99.7k  |             const int ret = xmlXPathRegisterNs(pContext, xmlNameSpace->prefix,  | 
164  | 99.7k  |                 xmlNameSpace->href);  | 
165  | 99.7k  |             if (ret != 0)  | 
166  | 0  |             { | 
167  |  |                 //Error  | 
168  | 0  |                  xmlXPathFreeContext(pContext);  | 
169  | 0  |                  return {}; | 
170  | 0  |             }  | 
171  | 99.7k  |         }  | 
172  |  |  | 
173  | 99.7k  |         xmlNameSpace = xmlNameSpace->next;  | 
174  | 99.7k  |     }  | 
175  |  |  | 
176  |  |     //Encode the specified search string.  | 
177  | 14.4k  |     const EncodedString encodedSearch{*relativeNode.doc, searchString}; | 
178  |  |  | 
179  |  |     //Evaluate the expression.  | 
180  | 14.4k  |     xmlXPathObject* pPathObject = xmlXPathEvalExpression(encodedSearch, pContext);  | 
181  | 14.4k  |     if (!pPathObject)  | 
182  | 1.75k  |     { | 
183  |  |         //Error  | 
184  | 1.75k  |         xmlXPathFreeContext(pContext);  | 
185  | 1.75k  |         return {}; | 
186  | 1.75k  |     }  | 
187  |  |  | 
188  | 12.7k  |     std::vector<xmlNode*> retList;  | 
189  |  |  | 
190  |  |     //Add each value that was returned.  | 
191  | 12.7k  |     if (pPathObject->nodesetval)  | 
192  | 11.4k  |     { | 
193  | 11.4k  |         retList.reserve(pPathObject->nodesetval->nodeNr);  | 
194  |  |  | 
195  | 22.8k  |         for (int i = 0; i < pPathObject->nodesetval->nodeNr; i++)  | 
196  | 11.3k  |             retList.push_back(pPathObject->nodesetval->nodeTab[i]);  | 
197  | 11.4k  |     }  | 
198  |  |  | 
199  | 12.7k  |     xmlXPathFreeObject(pPathObject);  | 
200  | 12.7k  |     xmlXPathFreeContext(pContext);  | 
201  |  |  | 
202  | 12.7k  |     return retList;  | 
203  | 14.4k  | }  | 
204  |  |  | 
205  |  | //************************************************************************  | 
206  |  | //! Find a single node matching the given xpath pattern.  | 
207  |  | /*!  | 
208  |  | \param relativeNode  | 
209  |  |     \li The node to start searching from.  | 
210  |  | \param searchString  | 
211  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
212  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
213  |  | \return  | 
214  |  |     \li The first XML node that matches \e searchString  | 
215  |  | */  | 
216  |  | //************************************************************************  | 
217  |  | xmlNode* findNode(  | 
218  |  |     xmlNode& relativeNode,  | 
219  |  |     const char* searchString)  | 
220  | 13.4k  | { | 
221  | 13.4k  |     auto retList = findNodes(relativeNode, searchString);  | 
222  | 13.4k  |     if (retList.empty())  | 
223  | 3.06k  |         return nullptr;  | 
224  |  |  | 
225  | 10.3k  |     return retList.front();  | 
226  | 13.4k  | }  | 
227  |  |  | 
228  |  | //************************************************************************  | 
229  |  | //! Get the named property from an XML node.  | 
230  |  | /*!  | 
231  |  | \param current  | 
232  |  |     \li The node to retrieve the property from.  | 
233  |  | \param propertyName  | 
234  |  |     \li The name of the property to be retrieved.  | 
235  |  | \return  | 
236  |  |     \li The property matching \e propertyName from \e current.  | 
237  |  | */  | 
238  |  | //************************************************************************  | 
239  |  | std::string getProperty(  | 
240  |  |     const xmlNode& current,  | 
241  |  |     const char* propertyName)  | 
242  | 159  | { | 
243  |  |      // Retrieve the property.  | 
244  | 159  |     xmlChar* temp = xmlGetProp(¤t, EncodedString{*current.doc, | 
245  | 159  |         propertyName});  | 
246  | 159  |     if (!temp)  | 
247  | 5  |         return {}; | 
248  |  |  | 
249  | 154  |     const std::string value(reinterpret_cast<char*>(temp));  | 
250  |  |  | 
251  |  |     // Free the memory allocated by xmlGetProp().  | 
252  | 154  |     xmlFree(temp);  | 
253  |  |  | 
254  | 154  |     return value;  | 
255  | 159  | }  | 
256  |  |  | 
257  |  | //************************************************************************  | 
258  |  | //! Get the contents of an XML node.  | 
259  |  | /*!  | 
260  |  | \param current  | 
261  |  |     \li The node to retrieve the contents from.  | 
262  |  | \return  | 
263  |  |     \li The contents of \e current.  | 
264  |  | */  | 
265  |  | //************************************************************************  | 
266  |  | std::string getContents(const xmlNode& current)  | 
267  | 8.63k  | { | 
268  | 8.63k  |     std::string contents;  | 
269  |  |  | 
270  |  |     // Get the children of the current element.  | 
271  | 8.63k  |     const xmlNode* text = current.children;  | 
272  |  |  | 
273  |  |     // Concatenate all the text elements.  | 
274  | 17.3k  |     while (text)  | 
275  | 8.73k  |     { | 
276  | 8.73k  |         if (text->type == XML_TEXT_NODE && text->content)  | 
277  | 8.64k  |             contents += reinterpret_cast<const char*>(text->content);  | 
278  |  |  | 
279  | 8.73k  |         text = text->next;  | 
280  | 8.73k  |     }  | 
281  |  |  | 
282  | 8.63k  |     return contents;  | 
283  | 8.63k  | }  | 
284  |  |  | 
285  |  | //************************************************************************  | 
286  |  | //! Get the named property from an XML node as a string.  | 
287  |  | /*!  | 
288  |  | \param node  | 
289  |  |     \li The node to begin searching from.  | 
290  |  | \param searchPath  | 
291  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
292  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
293  |  | \param propertyName  | 
294  |  |     \li The name of the property to be retrieved from the node matching  | 
295  |  |         \e searchPath  | 
296  |  | \return  | 
297  |  |     \li The specified property as a string value.  NULL is returned if  | 
298  |  |         a node matching \e searchPath cannot be found.  | 
299  |  | */  | 
300  |  | //************************************************************************  | 
301  |  | char* getPropertyAsString(  | 
302  |  |     xmlNode& node,  | 
303  |  |     const char* searchPath,  | 
304  |  |     const char* propertyName)  | 
305  | 200  | { | 
306  | 200  |     const xmlNode* pNode = findNode(node, searchPath);  | 
307  | 200  |     if (!pNode)  | 
308  | 41  |         return nullptr;  | 
309  |  |  | 
310  | 159  |     const std::string value = getProperty(*pNode, propertyName);  | 
311  |  |  | 
312  | 159  |     char* result = new char[value.size() + 1];  | 
313  | 159  |     strcpy(result, value.c_str());  | 
314  | 159  |     result[value.size()] = '\0';  | 
315  |  |  | 
316  | 159  |     return result;  | 
317  |  |  | 
318  | 200  | }  | 
319  |  |  | 
320  |  | //************************************************************************  | 
321  |  | //! Get the contents of an XML node as a string.  | 
322  |  | /*!  | 
323  |  | \param node  | 
324  |  |     \li The node to begin searching from.  | 
325  |  | \param searchPath  | 
326  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
327  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
328  |  | \return  | 
329  |  |     \li The contents of \e node as a string value.  NULL is returned if  | 
330  |  |         a node matching \e searchPath cannot be found.  | 
331  |  | */  | 
332  |  | //************************************************************************  | 
333  |  | std::string getContentsAsString(  | 
334  |  |     xmlNode& node,  | 
335  |  |     const char* searchPath)  | 
336  | 9.46k  | { | 
337  | 9.46k  |     const xmlNode* pNode = findNode(node, searchPath);  | 
338  | 9.46k  |     if (!pNode)  | 
339  | 2.52k  |         return {}; | 
340  |  |  | 
341  | 6.94k  |     return getContents(*pNode);  | 
342  | 9.46k  | }  | 
343  |  |  | 
344  |  | char* copyString(const char* source)  | 
345  | 9.46k  | { | 
346  | 9.46k  |     if (!source || strlen(source) == 0)  | 
347  | 2.52k  |         return nullptr;  | 
348  |  |  | 
349  | 6.94k  |     char* result = new char[strlen(source) + 1];  | 
350  | 6.94k  |     strcpy(result, source);  | 
351  |  |  | 
352  | 6.94k  |     return result;  | 
353  | 9.46k  | }  | 
354  |  |  | 
355  |  | char* getContentsAsCharStar(  | 
356  |  |     xmlNode& node,  | 
357  |  |     const char* searchPath)  | 
358  | 9.46k  | { | 
359  | 9.46k  |     return copyString(getContentsAsString(node, searchPath).c_str());  | 
360  | 9.46k  | }  | 
361  |  |  | 
362  |  | //************************************************************************  | 
363  |  | //! Get the contents of an XML node as an integer.  | 
364  |  | /*!  | 
365  |  | \param node  | 
366  |  |     \li The node to begin searching from.  | 
367  |  | \param searchPath  | 
368  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
369  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
370  |  | \return  | 
371  |  |     \li The contents of \e node as an integer value.  0 is returned if  | 
372  |  |         a node matching \e searchPath cannot be found.  | 
373  |  | */  | 
374  |  | //************************************************************************  | 
375  |  | int32_t getContentsAsInt(  | 
376  |  |     xmlNode& node,  | 
377  |  |     const char* searchPath)  | 
378  | 400  | { | 
379  | 400  |     auto* pNode = findNode(node, searchPath);  | 
380  | 400  |     if (!pNode)  | 
381  | 78  |         return 0;  | 
382  |  |  | 
383  | 322  |     return static_cast<int32_t>(toDouble(getContents(*pNode)));  | 
384  | 400  | }  | 
385  |  |  | 
386  |  | //************************************************************************  | 
387  |  | //! Get the contents of an XML node as a 64 bit floating point value.  | 
388  |  | /*!  | 
389  |  | \param node  | 
390  |  |     \li The node to begin searching from.  | 
391  |  | \param searchPath  | 
392  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
393  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
394  |  | \return  | 
395  |  |     \li The contents of \e node as a 64 bit floating point value.  | 
396  |  |         0.0 is returned if a node matching \e searchPath cannot be found.  | 
397  |  | */  | 
398  |  | //************************************************************************  | 
399  |  | double getContentsAsFloat(  | 
400  |  |     xmlNode& node,  | 
401  |  |     const char* searchPath)  | 
402  | 1.20k  | { | 
403  | 1.20k  |     const xmlNode* pNode = findNode(node, searchPath);  | 
404  | 1.20k  |     if (!pNode)  | 
405  | 408  |         return 0.0;  | 
406  |  |  | 
407  | 792  |     return toDouble(getContents(*pNode));  | 
408  | 1.20k  | }  | 
409  |  |  | 
410  |  | //************************************************************************  | 
411  |  | //! Get the contents of an XML node as a boolean value.  | 
412  |  | /*!  | 
413  |  | \param node  | 
414  |  |     \li The node to begin searching from.  | 
415  |  | \param searchPath  | 
416  |  |     \li The pattern to be searched for.  The string conforms to the xpath  | 
417  |  |         searching syntax.  For detailed information, see http://www.w3schools.com/xpath/xpath_syntax.asp  | 
418  |  | \return  | 
419  |  |     \li The contents of \e node as boolean value.  False is returned if a node  | 
420  |  |     matching \e searchPath cannot be found.  | 
421  |  | */  | 
422  |  | //************************************************************************  | 
423  |  | bool getContentsAsBool(  | 
424  |  |     xmlNode& node,  | 
425  |  |     const char* searchPath)  | 
426  | 400  | { | 
427  | 400  |     const xmlNode* pNode = findNode(node, searchPath);  | 
428  | 400  |     if (!pNode)  | 
429  | 22  |         return false;  | 
430  |  |  | 
431  | 378  |     const std::string value = getContents(*pNode);  | 
432  |  |  | 
433  |  |     // Prevent repeated memory allocations.  | 
434  | 378  |     static std::string kZero{"0"}; | 
435  | 378  |     static std::string kFalse{"false"}; | 
436  |  |  | 
437  | 378  |     return (value != kZero && value != kFalse);  | 
438  | 400  | }  | 
439  |  |  | 
440  |  | }  // namespace  | 
441  |  |  | 
442  |  | namespace BAG { | 
443  |  |  | 
444  |  | //************************************************************************  | 
445  |  | //! Get the current setting for the BAG_HOME directory.  | 
446  |  | /*!  | 
447  |  | \return  | 
448  |  |     \li If the user has called bagSetHomeFolder(), then that  | 
449  |  |         value is returned, otherwise, getenv("BAG_HOME") is | 
450  |  |         returned.  | 
451  |  | */  | 
452  |  | //************************************************************************  | 
453  |  | std::string bagGetHomeFolder()  | 
454  | 0  | { | 
455  |  |     //If the BAG home folder has been set, then return it.  | 
456  | 0  |     if (!bagHomeFolder.empty())  | 
457  | 0  |         return bagHomeFolder;  | 
458  |  |  | 
459  |  |     //Else we will return the environment variable.  | 
460  | 0  |     const char* bagHome = getenv("BAG_HOME"); | 
461  | 0  |     if (bagHome)  | 
462  | 0  |         return std::string{bagHome}; | 
463  |  |  | 
464  | 0  |     return {}; | 
465  | 0  | }  | 
466  |  |  | 
467  |  | //************************************************************************  | 
468  |  | //! Set the location of the BAG 'home' directory.  | 
469  |  | /*!  | 
470  |  | \param homeFolder  | 
471  |  |     \li The new location for the BAG home directory.  | 
472  |  | */  | 
473  |  | //************************************************************************  | 
474  |  | void bagSetHomeFolder(const char* homeFolder)  | 
475  | 0  | { | 
476  | 0  |     bagHomeFolder = homeFolder;  | 
477  | 0  | }  | 
478  |  |  | 
479  |  | //************************************************************************  | 
480  |  | //! Decode a BagResponsibleParty from the supplied XML node.  | 
481  |  | /*!  | 
482  |  | \param node  | 
483  |  |     \li The XML node containing the responsible party information.  | 
484  |  | \param responsibleParty  | 
485  |  |     \li Modified to contain the responsible party information from \e node.  | 
486  |  | \param schemaVersion  | 
487  |  |     \li The version of the schema stored in \e node.  | 
488  |  | \return  | 
489  |  |     \li True if the information was found and decoded properly, False if  | 
490  |  |         an error occurs.  | 
491  |  | */  | 
492  |  | //************************************************************************  | 
493  |  | bool decodeResponsibleParty(  | 
494  |  |     xmlNode& node,  | 
495  |  |     BagResponsibleParty& responsibleParty,  | 
496  |  |     uint16_t schemaVersion)  | 
497  | 518  | { | 
498  | 518  |     if (schemaVersion == 1)  | 
499  | 0  |     { | 
500  |  |         //smXML:CI_ResponsibleParty/individualName  | 
501  | 0  |         responsibleParty.individualName = getContentsAsCharStar(node,  | 
502  | 0  |             "smXML:CI_ResponsibleParty/individualName");  | 
503  |  |  | 
504  |  |         //smXML:CI_ResponsibleParty/organisationName  | 
505  | 0  |         responsibleParty.organisationName = getContentsAsCharStar(node,  | 
506  | 0  |             "smXML:CI_ResponsibleParty/organisationName");  | 
507  |  |  | 
508  |  |         //smXML:CI_ResponsibleParty/positionName  | 
509  | 0  |         responsibleParty.positionName = getContentsAsCharStar(node,  | 
510  | 0  |             "smXML:CI_ResponsibleParty/positionName");  | 
511  |  |  | 
512  |  |         //smXML:CI_ResponsibleParty/role  | 
513  | 0  |         responsibleParty.role = getContentsAsCharStar(node,  | 
514  | 0  |             "smXML:CI_ResponsibleParty/role");  | 
515  | 0  |     }  | 
516  | 518  |     else if (schemaVersion == 2)  | 
517  | 518  |     { | 
518  |  |         //gmd:CI_ResponsibleParty/gmd:individualName  | 
519  | 518  |         responsibleParty.individualName = getContentsAsCharStar(node,  | 
520  | 518  |             "gmd:CI_ResponsibleParty/gmd:individualName/gco:CharacterString");  | 
521  |  |  | 
522  |  |         //gmd:CI_ResponsibleParty/gmd:organisationName  | 
523  | 518  |         responsibleParty.organisationName = getContentsAsCharStar(node,  | 
524  | 518  |             "gmd:CI_ResponsibleParty/gmd:organisationName/gco:CharacterString");  | 
525  |  |  | 
526  |  |         //gmd:CI_ResponsibleParty/gmd:positionName  | 
527  | 518  |         responsibleParty.positionName = getContentsAsCharStar(node,  | 
528  | 518  |             "gmd:CI_ResponsibleParty/gmd:positionName/gco:CharacterString");  | 
529  |  |  | 
530  |  |         //gmd:CI_ResponsibleParty/gmd:role  | 
531  | 518  |         responsibleParty.role = getContentsAsCharStar(node,  | 
532  | 518  |             "gmd:CI_ResponsibleParty/gmd:role/gmd:CI_RoleCode");  | 
533  | 518  |     }  | 
534  |  |  | 
535  | 518  |     return true;  | 
536  | 518  | }  | 
537  |  |  | 
538  |  | //************************************************************************  | 
539  |  | //! Decode a BagLegalConstraints from the supplied XML node.  | 
540  |  | /*!  | 
541  |  | \param node  | 
542  |  |     \li The XML node containing the legal constraints information.  | 
543  |  | \param legalConstraints  | 
544  |  |     \li Modified to contain the legal constraints information from \e node.  | 
545  |  | \param schemaVersion  | 
546  |  |     \li The version of the schema stored in \e node.  | 
547  |  | \return  | 
548  |  |     \li True if the information was found and decoded properly, False if  | 
549  |  |         an error occurs.  | 
550  |  | */  | 
551  |  | //************************************************************************  | 
552  |  | bool decodeLegalConstraints(  | 
553  |  |     xmlNode& node,  | 
554  |  |     BagLegalConstraints& legalConstraints,  | 
555  |  |     uint16_t schemaVersion)  | 
556  | 200  | { | 
557  | 200  |     if (schemaVersion == 1)  | 
558  | 0  |     { | 
559  |  |         //smXML:MD_LegalConstraints/useConstraints  | 
560  | 0  |         legalConstraints.useConstraints = getContentsAsCharStar(node,  | 
561  | 0  |             "smXML:MD_LegalConstraints/useConstraints");  | 
562  |  |  | 
563  |  |         //smXML:MD_LegalConstraints/otherConstraints  | 
564  | 0  |         legalConstraints.otherConstraints = getContentsAsCharStar(node,  | 
565  | 0  |             "smXML:MD_LegalConstraints/otherConstraints");  | 
566  | 0  |     }  | 
567  | 200  |     else if (schemaVersion == 2)  | 
568  | 200  |     { | 
569  |  |         //gmd:MD_LegalConstraints/gmd:useConstraints  | 
570  | 200  |         legalConstraints.useConstraints = getContentsAsCharStar(node,  | 
571  | 200  |             "gmd:MD_LegalConstraints/gmd:useConstraints/gmd:MD_RestrictionCode");  | 
572  |  |  | 
573  |  |         //gmd:MD_LegalConstraints/gmd:otherConstraints  | 
574  | 200  |         legalConstraints.otherConstraints = getContentsAsCharStar(node,  | 
575  | 200  |             "gmd:MD_LegalConstraints/gmd:otherConstraints/gco:CharacterString");  | 
576  | 200  |     }  | 
577  |  |  | 
578  | 200  |     return true;  | 
579  | 200  | }  | 
580  |  |  | 
581  |  | //************************************************************************  | 
582  |  | //! Decode a BagSecurityConstraints from the supplied XML node.  | 
583  |  | /*!  | 
584  |  | \param node  | 
585  |  |     \li The XML node containing the security constraints information.  | 
586  |  | \param securityConstraints  | 
587  |  |     \li Modified to contain the security constraints information from \e node.  | 
588  |  | \param schemaVersion  | 
589  |  |     \li The version of the schema stored in \e node.  | 
590  |  | \return  | 
591  |  |     \li True if the information was found and decoded properly, False if  | 
592  |  |         an error occurs.  | 
593  |  | */  | 
594  |  | //************************************************************************  | 
595  |  | bool decodeSecurityConstraints(  | 
596  |  |     xmlNode& node,  | 
597  |  |     BagSecurityConstraints& securityConstraints,  | 
598  |  |     uint16_t schemaVersion)  | 
599  | 200  | { | 
600  | 200  |     if (schemaVersion == 1)  | 
601  | 0  |     { | 
602  |  |         //smXML:MD_SecurityConstraints/classification  | 
603  | 0  |         securityConstraints.classification = getContentsAsCharStar(node,  | 
604  | 0  |             "smXML:MD_SecurityConstraints/classification");  | 
605  |  |  | 
606  |  |         //smXML:MD_SecurityConstraints/userNote  | 
607  | 0  |         securityConstraints.userNote = getContentsAsCharStar(node,  | 
608  | 0  |             "smXML:MD_SecurityConstraints/userNote");  | 
609  | 0  |     }  | 
610  | 200  |     else if (schemaVersion == 2)  | 
611  | 200  |     { | 
612  |  |         //gmd:MD_SecurityConstraints/gmd:classification  | 
613  | 200  |         securityConstraints.classification = getContentsAsCharStar(node,  | 
614  | 200  |             "gmd:MD_SecurityConstraints/gmd:classification/gmd:MD_ClassificationCode");  | 
615  |  |  | 
616  |  |         //gmd:MD_SecurityConstraints/gmd:userNote  | 
617  | 200  |         securityConstraints.userNote = getContentsAsCharStar(node,  | 
618  | 200  |             "gmd:MD_SecurityConstraints/gmd:userNote/gco:CharacterString");  | 
619  | 200  |     }  | 
620  |  |  | 
621  | 200  |     return true;  | 
622  | 200  | }  | 
623  |  |  | 
624  |  | //************************************************************************  | 
625  |  | //! Decode a BagSource from the supplied XML node.  | 
626  |  | /*!  | 
627  |  | \param node  | 
628  |  |     \li The XML node containing the source information.  | 
629  |  | \param sourceInfo  | 
630  |  |     \li Modified to contain the source information from \e node.  | 
631  |  | \param schemaVersion  | 
632  |  |     \li The version of the schema stored in \e node.  | 
633  |  | \return  | 
634  |  |     \li True if the information was found and decoded properly, False if  | 
635  |  |         an error occurs.  | 
636  |  | */  | 
637  |  | //************************************************************************  | 
638  |  | bool decodeSourceInfo(  | 
639  |  |     xmlNode& node,  | 
640  |  |     BagSource& sourceInfo,  | 
641  |  |     uint16_t schemaVersion)  | 
642  | 199  | { | 
643  | 199  |     if (schemaVersion == 1)  | 
644  | 0  |     { | 
645  |  |         //smXML:LI_Source/description  | 
646  | 0  |         sourceInfo.description = getContentsAsCharStar(node,  | 
647  | 0  |             "smXML:LI_Source/description");  | 
648  | 0  |     }  | 
649  | 199  |     else if (schemaVersion == 2)  | 
650  | 199  |     { | 
651  |  |         //gmd:LI_Source/gmd:description  | 
652  | 199  |         sourceInfo.description = getContentsAsCharStar(node,  | 
653  | 199  |             "gmd:LI_Source/gmd:description/gco:CharacterString");  | 
654  |  |  | 
655  |  |         //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:title  | 
656  | 199  |         sourceInfo.title = getContentsAsCharStar(node,  | 
657  | 199  |             "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:title/gco:CharacterString");  | 
658  |  |  | 
659  |  |         //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:CI_Date/gmd:date  | 
660  | 199  |         sourceInfo.date = getContentsAsCharStar(node,  | 
661  | 199  |             "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:date/gco:Date");  | 
662  |  |  | 
663  |  |         //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:CI_Date/gmd:dateType  | 
664  | 199  |         sourceInfo.dateType = getContentsAsCharStar(node,  | 
665  | 199  |             "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:dateType/gmd:CI_DateTypeCode");  | 
666  |  |  | 
667  |  |         //gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:citedResponsibleParty  | 
668  | 199  |         const auto partyNodes = findNodes(node,  | 
669  | 199  |             "gmd:LI_Source/gmd:sourceCitation/gmd:CI_Citation/gmd:citedResponsibleParty");  | 
670  | 199  |         if (!partyNodes.empty())  | 
671  | 0  |         { | 
672  | 0  |             sourceInfo.numberOfResponsibleParties =  | 
673  | 0  |                 static_cast<uint32_t>(partyNodes.size());  | 
674  | 0  |             sourceInfo.responsibleParties = new BagResponsibleParty[sourceInfo.numberOfResponsibleParties];  | 
675  |  | 
  | 
676  | 0  |             for (uint32_t i = 0; i < sourceInfo.numberOfResponsibleParties; i++)  | 
677  | 0  |             { | 
678  | 0  |                 initResponsibleParty(sourceInfo.responsibleParties[i]);  | 
679  | 0  |                 if (!decodeResponsibleParty(*partyNodes[i],  | 
680  | 0  |                     sourceInfo.responsibleParties[i], schemaVersion))  | 
681  | 0  |                     return false;  | 
682  | 0  |             }  | 
683  | 0  |         }  | 
684  | 199  |     }  | 
685  |  |  | 
686  | 199  |     return true;  | 
687  | 199  | }  | 
688  |  |  | 
689  |  | //************************************************************************  | 
690  |  | //! Decode a BagProcessStep from the supplied XML node.  | 
691  |  | /*!  | 
692  |  | \param node  | 
693  |  |     \li The XML node containing the process information.  | 
694  |  | \param processStep  | 
695  |  |     \li Modified to contain the process information from \e node.  | 
696  |  | \param schemaVersion  | 
697  |  |     \li The version of the schema stored in \e node.  | 
698  |  | \return  | 
699  |  |     \li True if the information was found and decoded properly, False if  | 
700  |  |         an error occurs.  | 
701  |  | */  | 
702  |  | //************************************************************************  | 
703  |  | bool decodeProcessStep(  | 
704  |  |     xmlNode& node,  | 
705  |  |     BagProcessStep& processStep,  | 
706  |  |     uint16_t schemaVersion)  | 
707  | 199  | { | 
708  | 199  |     if (schemaVersion == 1)  | 
709  | 0  |     { | 
710  |  |         //smXML:BAG_ProcessStep/description  | 
711  | 0  |         processStep.description = getContentsAsCharStar(node,  | 
712  | 0  |             "smXML:BAG_ProcessStep/description");  | 
713  |  |  | 
714  |  |         //smXML:BAG_ProcessStep/dateTime  | 
715  | 0  |         processStep.dateTime = getContentsAsCharStar(node,  | 
716  | 0  |             "smXML:BAG_ProcessStep/dateTime");  | 
717  |  |  | 
718  |  |         //smXML:BAG_ProcessStep/trackingId  | 
719  | 0  |         processStep.trackingId = getContentsAsCharStar(node,  | 
720  | 0  |             "smXML:BAG_ProcessStep/trackingId");  | 
721  |  |  | 
722  |  |         //smXML:BAG_ProcessStep/processor  | 
723  | 0  |         const auto processorNodes = findNodes(node,  | 
724  | 0  |             "smXML:BAG_ProcessStep/processor");  | 
725  | 0  |         if (!processorNodes.empty())  | 
726  | 0  |         { | 
727  | 0  |             processStep.numberOfProcessors =  | 
728  | 0  |                 static_cast<uint32_t>(processorNodes.size());  | 
729  | 0  |             processStep.processors =  | 
730  | 0  |                 new BagResponsibleParty[processStep.numberOfProcessors];  | 
731  |  | 
  | 
732  | 0  |             for (uint32_t i = 0; i < processStep.numberOfProcessors; i++)  | 
733  | 0  |             { | 
734  | 0  |                 initResponsibleParty(processStep.processors[i]);  | 
735  | 0  |                 if (!decodeResponsibleParty(*processorNodes[i],  | 
736  | 0  |                     processStep.processors[i], schemaVersion))  | 
737  | 0  |                     return false;  | 
738  | 0  |             }  | 
739  | 0  |         }  | 
740  |  |  | 
741  |  |         //Sources are stored at the same level as the process step, so go up a level.  | 
742  | 0  |         const auto sourceNodes = findNodes(node,  | 
743  | 0  |             "parent::*/source");  | 
744  | 0  |         if (!sourceNodes.empty())  | 
745  | 0  |         { | 
746  | 0  |             processStep.numberOfSources =  | 
747  | 0  |                 static_cast<uint32_t>(sourceNodes.size());  | 
748  | 0  |             processStep.lineageSources =  | 
749  | 0  |                 new BagSource[processStep.numberOfSources];  | 
750  |  | 
  | 
751  | 0  |             for (uint32_t i = 0; i < processStep.numberOfSources; i++)  | 
752  | 0  |             { | 
753  | 0  |                 initSourceInfo(processStep.lineageSources[i]);  | 
754  | 0  |                 if (!decodeSourceInfo(*sourceNodes[i],  | 
755  | 0  |                     processStep.lineageSources[i], schemaVersion))  | 
756  | 0  |                     return false;  | 
757  | 0  |             }  | 
758  | 0  |         }  | 
759  | 0  |     }  | 
760  | 199  |     else if (schemaVersion == 2)  | 
761  | 199  |     { | 
762  |  |         //bag:BAG_ProcessStep/gmd:description  | 
763  | 199  |         processStep.description = getContentsAsCharStar(node,  | 
764  | 199  |             "//gmd:description/gco:CharacterString");  | 
765  |  |  | 
766  |  |         //bag:BAG_ProcessStep/gmd:dateTime  | 
767  | 199  |         processStep.dateTime = getContentsAsCharStar(node,  | 
768  | 199  |             "//gmd:dateTime/gco:DateTime");  | 
769  |  |  | 
770  |  |         //bag:BAG_ProcessStep/bag:trackingId  | 
771  | 199  |         processStep.trackingId = getContentsAsCharStar(node,  | 
772  | 199  |             "//bag:trackingId/gco:CharacterString");  | 
773  |  |  | 
774  |  |         //bag:BAG_ProcessStep/gmd:processor  | 
775  | 199  |         const auto processorNodes = findNodes(node,  | 
776  | 199  |             "//gmd:processor");  | 
777  | 199  |         if (!processorNodes.empty())  | 
778  | 199  |         { | 
779  | 199  |             processStep.numberOfProcessors =  | 
780  | 199  |                 static_cast<uint32_t>(processorNodes.size());  | 
781  | 199  |             processStep.processors =  | 
782  | 199  |                 new BagResponsibleParty[processStep.numberOfProcessors];  | 
783  |  |  | 
784  | 398  |             for (uint32_t i = 0; i < processStep.numberOfProcessors; i++)  | 
785  | 199  |             { | 
786  | 199  |                 initResponsibleParty(processStep.processors[i]);  | 
787  | 199  |                 if (!decodeResponsibleParty(*processorNodes[i],  | 
788  | 199  |                     processStep.processors[i], schemaVersion))  | 
789  | 0  |                     return false;  | 
790  | 199  |             }  | 
791  | 199  |         }  | 
792  |  |  | 
793  |  |         //bag:BAG_ProcessStep/gmd:source  | 
794  | 199  |         const auto sourceNodes = findNodes(node, "//gmd:source");  | 
795  | 199  |         if (!sourceNodes.empty())  | 
796  | 199  |         { | 
797  | 199  |             processStep.numberOfSources =  | 
798  | 199  |                 static_cast<uint32_t>(sourceNodes.size());  | 
799  | 199  |             processStep.lineageSources =  | 
800  | 199  |                 new BagSource[processStep.numberOfSources];  | 
801  |  |  | 
802  | 398  |             for (uint32_t i = 0; i < processStep.numberOfSources; i++)  | 
803  | 199  |             { | 
804  | 199  |                 initSourceInfo(processStep.lineageSources[i]);  | 
805  | 199  |                 if (!decodeSourceInfo(*sourceNodes[i],  | 
806  | 199  |                     processStep.lineageSources[i], schemaVersion))  | 
807  | 0  |                     return false;  | 
808  | 199  |             }  | 
809  | 199  |         }  | 
810  | 199  |     }  | 
811  |  |  | 
812  | 199  |     return true;  | 
813  | 199  | }  | 
814  |  |  | 
815  |  | //************************************************************************  | 
816  |  | //! Decode a BagDataQuality from the supplied XML node.  | 
817  |  | /*!  | 
818  |  | \param node  | 
819  |  |     \li The XML node containing the data quality information.  | 
820  |  | \param dataQualityInfo  | 
821  |  |     \li Modified to contain the data quality information from \e node.  | 
822  |  | \param schemaVersion  | 
823  |  |     \li The version of the schema stored in \e node.  | 
824  |  | \return  | 
825  |  |     \li True if the information was found and decoded properly, False if  | 
826  |  |         an error occurs.  | 
827  |  | */  | 
828  |  | //************************************************************************  | 
829  |  | bool decodeDataQualityInfo(  | 
830  |  |     xmlNode& node,  | 
831  |  |     BagDataQuality& dataQualityInfo,  | 
832  |  |     uint16_t schemaVersion)  | 
833  | 200  | { | 
834  | 200  |     if (schemaVersion == 1)  | 
835  | 0  |     { | 
836  |  |         //smXML:DQ_DataQuality/scope/smXML:DQ_Scope/level  | 
837  | 0  |         dataQualityInfo.scope = getContentsAsCharStar(node,  | 
838  | 0  |             "smXML:DQ_DataQuality/scope/smXML:DQ_Scope/level");  | 
839  |  |  | 
840  |  |         //smXML:DQ_DataQuality/lineage/smXML:LI_Lineage/processStep  | 
841  | 0  |         const auto stepNodes = findNodes(node,  | 
842  | 0  |             "smXML:DQ_DataQuality/lineage/smXML:LI_Lineage/processStep");  | 
843  | 0  |         if (!stepNodes.empty())  | 
844  | 0  |         { | 
845  | 0  |             dataQualityInfo.numberOfProcessSteps =  | 
846  | 0  |                 static_cast<uint32_t>(stepNodes.size());  | 
847  | 0  |             dataQualityInfo.lineageProcessSteps =  | 
848  | 0  |                 new BagProcessStep[dataQualityInfo.numberOfProcessSteps];  | 
849  |  | 
  | 
850  | 0  |             for (uint32_t i = 0; i < dataQualityInfo.numberOfProcessSteps; i++)  | 
851  | 0  |             { | 
852  | 0  |                 initProcessStep(dataQualityInfo.lineageProcessSteps[i]);  | 
853  | 0  |                 if (!decodeProcessStep(*stepNodes[i],  | 
854  | 0  |                     dataQualityInfo.lineageProcessSteps[i], schemaVersion))  | 
855  | 0  |                     return false;  | 
856  | 0  |             }  | 
857  | 0  |         }  | 
858  | 0  |     }  | 
859  | 200  |     else if (schemaVersion == 2)  | 
860  | 200  |     { | 
861  |  |         //gmd:DQ_DataQuality/gmd:scope/gmd:DQ_Scope/gmd:level  | 
862  | 200  |         delete[] dataQualityInfo.scope;  | 
863  | 200  |         dataQualityInfo.scope = getContentsAsCharStar(node,  | 
864  | 200  |             "gmd:DQ_DataQuality/gmd:scope/gmd:DQ_Scope/gmd:level/gmd:MD_ScopeCode");  | 
865  |  |  | 
866  |  |         //gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:processStep  | 
867  | 200  |         const auto stepNodes = findNodes(node,  | 
868  | 200  |             "gmd:DQ_DataQuality/gmd:lineage/gmd:LI_Lineage/gmd:processStep");  | 
869  | 200  |         if (!stepNodes.empty())  | 
870  | 199  |         { | 
871  | 199  |             dataQualityInfo.numberOfProcessSteps =  | 
872  | 199  |                 static_cast<uint32_t>(stepNodes.size());  | 
873  | 199  |             dataQualityInfo.lineageProcessSteps =  | 
874  | 199  |                 new BagProcessStep[dataQualityInfo.numberOfProcessSteps];  | 
875  |  |  | 
876  | 398  |             for (uint32_t i = 0; i < dataQualityInfo.numberOfProcessSteps; i++)  | 
877  | 199  |             { | 
878  | 199  |                 initProcessStep(dataQualityInfo.lineageProcessSteps[i]);  | 
879  | 199  |                 if (!decodeProcessStep(*stepNodes[i],  | 
880  | 199  |                     dataQualityInfo.lineageProcessSteps[i], schemaVersion))  | 
881  | 0  |                     return false;  | 
882  | 199  |             }  | 
883  | 199  |         }  | 
884  | 200  |     }  | 
885  |  |  | 
886  | 200  |     return true;  | 
887  | 200  | }  | 
888  |  |  | 
889  |  | //************************************************************************  | 
890  |  | //! Decode a BagSpatialRepresentation from the supplied XML node.  | 
891  |  | /*!  | 
892  |  | \param node  | 
893  |  |     \li The XML node containing the spatial representation information.  | 
894  |  | \param spatialRepresentationInfo  | 
895  |  |     \li Modified to contain the spatial representation information from \e node.  | 
896  |  | \param schemaVersion  | 
897  |  |     \li The version of the schema stored in \e node.  | 
898  |  | \return  | 
899  |  |     \li True if the information was found and decoded properly, False if  | 
900  |  |         an error occurs.  | 
901  |  | */  | 
902  |  | //************************************************************************  | 
903  |  | bool decodeSpatialRepresentationInfo(  | 
904  |  |     xmlNode& node,  | 
905  |  |     BagSpatialRepresentation& spatialRepresentationInfo,  | 
906  |  |     uint16_t schemaVersion)  | 
907  | 200  | { | 
908  | 200  |     if (schemaVersion == 1)  | 
909  | 0  |     { | 
910  |  |         //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/dimensionSize  | 
911  | 0  |         spatialRepresentationInfo.numberOfRows = getContentsAsInt(node,  | 
912  | 0  |             "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='row']/dimensionSize");  | 
913  |  |  | 
914  |  |         //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/resolution/smXML:Measure  | 
915  | 0  |         spatialRepresentationInfo.rowResolution = getContentsAsFloat(node,  | 
916  | 0  |             "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='row']/resolution/smXML:Measure/smXML:value");  | 
917  |  |  | 
918  |  |         //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/dimensionSize  | 
919  | 0  |         spatialRepresentationInfo.numberOfColumns = getContentsAsInt(node,  | 
920  | 0  |             "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='column']/dimensionSize");  | 
921  |  |  | 
922  |  |         //smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension/resolution/smXML:Measure  | 
923  | 0  |         spatialRepresentationInfo.columnResolution = getContentsAsFloat(node,  | 
924  | 0  |             "smXML:MD_Georectified/axisDimensionProperties/smXML:MD_Dimension[dimensionName='column']/resolution/smXML:Measure/smXML:value");  | 
925  |  |  | 
926  |  |         //smXML:MD_Georectified/cellGeometry  | 
927  | 0  |         spatialRepresentationInfo.cellGeometry = getContentsAsCharStar(node,  | 
928  | 0  |             "smXML:MD_Georectified/cellGeometry");  | 
929  |  |  | 
930  |  |         //smXML:MD_Georectified/transformationParameterAvailability  | 
931  | 0  |         spatialRepresentationInfo.transformationParameterAvailability =  | 
932  | 0  |             getContentsAsBool(node, "smXML:MD_Georectified/transformationParameterAvailability");  | 
933  |  |  | 
934  |  |         //smXML:MD_Georectified/checkPointAvailability  | 
935  | 0  |         spatialRepresentationInfo.checkPointAvailability = getContentsAsBool(  | 
936  | 0  |             node, "smXML:MD_Georectified/checkPointAvailability");  | 
937  |  |  | 
938  |  |         //smXML:MD_Georectified/cornerPoints/gml:Point  | 
939  | 0  |         { | 
940  | 0  |             const xmlNode* pNode = findNode(node,  | 
941  | 0  |                 "smXML:MD_Georectified/cornerPoints/gml:Point/gml:coordinates");  | 
942  | 0  |             if (!pNode)  | 
943  | 0  |                 return false;  | 
944  |  |  | 
945  |  |             //Get the encoded corner values.  | 
946  | 0  |             const std::string value = getContents(*pNode);  | 
947  |  |  | 
948  |  |             //Decode the extents  | 
949  | 0  |             (void)sscanf(value.c_str(), "%lf,%lf %lf,%lf",  | 
950  | 0  |                 &spatialRepresentationInfo.llCornerX,  | 
951  | 0  |                 &spatialRepresentationInfo.llCornerY,  | 
952  | 0  |                 &spatialRepresentationInfo.urCornerX,  | 
953  | 0  |                 &spatialRepresentationInfo.urCornerY);  | 
954  | 0  |         }  | 
955  |  |  | 
956  |  |         //smXML:MD_Georectified/transformationDimensionDescription  | 
957  | 0  |         spatialRepresentationInfo.transformationDimensionDescription =  | 
958  | 0  |             getContentsAsCharStar(node,  | 
959  | 0  |                 "smXML:MD_Georectified/transformationDimensionDescription");  | 
960  |  |  | 
961  |  |         //smXML:MD_Georectified/transformationDimensionMapping  | 
962  | 0  |         spatialRepresentationInfo.transformationDimensionMapping =  | 
963  | 0  |             getContentsAsCharStar(node,  | 
964  | 0  |                 "smXML:MD_Georectified/transformationDimensionMapping");  | 
965  |  | 
  | 
966  | 0  |     }  | 
967  | 200  |     else if (schemaVersion == 2)  | 
968  | 200  |     { | 
969  |  |         //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionSize  | 
970  | 200  |         spatialRepresentationInfo.numberOfRows = getContentsAsInt(node,  | 
971  | 200  |             "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='row']/parent::*/parent::*/gmd:dimensionSize/gco:Integer");  | 
972  |  |  | 
973  |  |         //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution  | 
974  | 200  |         spatialRepresentationInfo.rowResolution = getContentsAsFloat(node,  | 
975  | 200  |             "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='row']/parent::*/parent::*/gmd:resolution/gco:Measure");  | 
976  |  |  | 
977  |  |         //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionSize  | 
978  | 200  |         spatialRepresentationInfo.numberOfColumns = getContentsAsInt(node,  | 
979  | 200  |             "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:dimensionSize/gco:Integer");  | 
980  |  |  | 
981  |  |         //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution  | 
982  | 200  |         spatialRepresentationInfo.columnResolution = getContentsAsFloat(node,  | 
983  | 200  |             "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:resolution/gco:Measure");  | 
984  |  |  | 
985  |  |         //gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:resolution[@uom]  | 
986  | 200  |         spatialRepresentationInfo.resolutionUnit = getPropertyAsString(node,  | 
987  | 200  |             "gmd:MD_Georectified/gmd:axisDimensionProperties/gmd:MD_Dimension/gmd:dimensionName/gmd:MD_DimensionNameTypeCode[@codeListValue='column']/parent::*/parent::*/gmd:resolution/gco:Measure", "uom");  | 
988  |  |  | 
989  |  |         //gmd:MD_Georectified/gmd:cellGeometry  | 
990  | 200  |         delete[] spatialRepresentationInfo.cellGeometry;  | 
991  | 200  |         spatialRepresentationInfo.cellGeometry = getContentsAsCharStar(node,  | 
992  | 200  |             "gmd:MD_Georectified/gmd:cellGeometry/gmd:MD_CellGeometryCode");  | 
993  |  |  | 
994  |  |         //gmd:MD_Georectified/gmd:transformationParameterAvailability  | 
995  | 200  |         spatialRepresentationInfo.transformationParameterAvailability =  | 
996  | 200  |             getContentsAsBool(node, "gmd:MD_Georectified/gmd:transformationParameterAvailability/gco:Boolean");  | 
997  |  |  | 
998  |  |         //gmd:MD_Georectified/gmd:checkPointAvailability  | 
999  | 200  |         spatialRepresentationInfo.checkPointAvailability = getContentsAsBool(  | 
1000  | 200  |             node, "gmd:MD_Georectified/gmd:checkPointAvailability/gco:Boolean");  | 
1001  |  |  | 
1002  |  |         //gmd:MD_Georectified/gmd:cornerPoints/gml:Point  | 
1003  | 200  |         { | 
1004  | 200  |             const xmlNode *pNode = findNode(node,  | 
1005  | 200  |                 "gmd:MD_Georectified/gmd:cornerPoints/gml:Point/gml:coordinates");  | 
1006  | 200  |             if (!pNode)  | 
1007  | 0  |                 return false;  | 
1008  |  |  | 
1009  |  |             //Get the encoded corner values.  | 
1010  | 200  |             const std::string value = getContents(*pNode);  | 
1011  |  |  | 
1012  |  |             //Decode the extents  | 
1013  | 200  |             (void)sscanf(value.c_str(), "%lf,%lf %lf,%lf",  | 
1014  | 200  |                 &spatialRepresentationInfo.llCornerX,  | 
1015  | 200  |                 &spatialRepresentationInfo.llCornerY,  | 
1016  | 200  |                 &spatialRepresentationInfo.urCornerX,  | 
1017  | 200  |                 &spatialRepresentationInfo.urCornerY);  | 
1018  | 200  |         }  | 
1019  | 200  |     }  | 
1020  |  |  | 
1021  | 200  |     return true;  | 
1022  | 200  | }  | 
1023  |  |  | 
1024  |  | //************************************************************************  | 
1025  |  | //! Decode a BagIdentification from the supplied XML node.  | 
1026  |  | /*!  | 
1027  |  | \param node  | 
1028  |  |     \li The XML node containing the data identification information.  | 
1029  |  | \param dataIdentificationInfo  | 
1030  |  |     \li Modified to contain the data identification information from \e node.  | 
1031  |  | \param schemaVersion  | 
1032  |  |     \li The version of the schema stored in \e node.  | 
1033  |  | \return  | 
1034  |  |     \li True if the information was found and decoded properly, False if  | 
1035  |  |         an error occurs.  | 
1036  |  | */  | 
1037  |  | //************************************************************************  | 
1038  |  | bool decodeDataIdentificationInfo(  | 
1039  |  |     xmlNode& node,  | 
1040  |  |     BagIdentification& dataIdentificationInfo,  | 
1041  |  |     uint16_t schemaVersion)  | 
1042  | 200  | { | 
1043  | 200  |     if (schemaVersion == 1)  | 
1044  | 0  |     { | 
1045  |  |         //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/title  | 
1046  | 0  |         dataIdentificationInfo.title = getContentsAsCharStar(node,  | 
1047  | 0  |             "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/title");  | 
1048  |  |  | 
1049  |  |         //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/date  | 
1050  | 0  |         dataIdentificationInfo.date = getContentsAsCharStar(node,  | 
1051  | 0  |             "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/date");  | 
1052  |  |  | 
1053  |  |         //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/dateType  | 
1054  | 0  |         dataIdentificationInfo.dateType = getContentsAsCharStar(node,  | 
1055  | 0  |             "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/date/smXML:CI_Date/dateType");  | 
1056  |  |  | 
1057  |  |         //smXML:BAG_DataIdentification/citation/smXML:CI_Citation/citedResponsibleParty"  | 
1058  | 0  |         const auto partyNodes = findNodes(node,  | 
1059  | 0  |             "smXML:BAG_DataIdentification/citation/smXML:CI_Citation/citedResponsibleParty");  | 
1060  | 0  |         if (!partyNodes.empty())  | 
1061  | 0  |         { | 
1062  | 0  |             dataIdentificationInfo.numberOfResponsibleParties =  | 
1063  | 0  |                 static_cast<uint32_t>(partyNodes.size());  | 
1064  | 0  |             dataIdentificationInfo.responsibleParties =  | 
1065  | 0  |                 new BagResponsibleParty[dataIdentificationInfo.numberOfResponsibleParties];  | 
1066  |  | 
  | 
1067  | 0  |             for (uint32_t i = 0; i < dataIdentificationInfo.numberOfResponsibleParties; i++)  | 
1068  | 0  |             { | 
1069  | 0  |                 initResponsibleParty(dataIdentificationInfo.responsibleParties[i]);  | 
1070  | 0  |                 if (!decodeResponsibleParty(*partyNodes[i],  | 
1071  | 0  |                     dataIdentificationInfo.responsibleParties[i], schemaVersion))  | 
1072  | 0  |                     return false;  | 
1073  | 0  |             }  | 
1074  | 0  |         }  | 
1075  |  |  | 
1076  |  |         //smXML:BAG_DataIdentification/abstract  | 
1077  | 0  |         dataIdentificationInfo.abstractString = getContentsAsCharStar(node,  | 
1078  | 0  |             "smXML:BAG_DataIdentification/abstract");  | 
1079  |  |  | 
1080  |  |         //smXML:BAG_DataIdentification/status  | 
1081  | 0  |         dataIdentificationInfo.status = getContentsAsCharStar(node,  | 
1082  | 0  |             "smXML:BAG_DataIdentification/status");  | 
1083  |  |  | 
1084  |  |         //smXML:BAG_DataIdentification/spatialRepresentationType  | 
1085  | 0  |         dataIdentificationInfo.spatialRepresentationType = getContentsAsCharStar(  | 
1086  | 0  |             node, "smXML:BAG_DataIdentification/spatialRepresentationType");  | 
1087  |  |  | 
1088  |  |         //smXML:BAG_DataIdentification/language  | 
1089  | 0  |         dataIdentificationInfo.language = getContentsAsCharStar(node,  | 
1090  | 0  |             "smXML:BAG_DataIdentification/language");  | 
1091  |  |  | 
1092  |  |         //Doesn't appear to be set, so always set to utf8  | 
1093  | 0  |         dataIdentificationInfo.characterSet = copyString("utf8"); | 
1094  |  |  | 
1095  |  |         //smXML:BAG_DataIdentification/topicCategory  | 
1096  | 0  |         dataIdentificationInfo.topicCategory = getContentsAsCharStar(node,  | 
1097  | 0  |             "smXML:BAG_DataIdentification/topicCategory");  | 
1098  |  |  | 
1099  |  |         //smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/  | 
1100  | 0  |         dataIdentificationInfo.westBoundingLongitude = getContentsAsFloat(node,  | 
1101  | 0  |             "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/westBoundLongitude");  | 
1102  | 0  |         dataIdentificationInfo.eastBoundingLongitude = getContentsAsFloat(node,  | 
1103  | 0  |             "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/eastBoundLongitude");  | 
1104  | 0  |         dataIdentificationInfo.southBoundingLatitude = getContentsAsFloat(node,  | 
1105  | 0  |             "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/southBoundLatitude");  | 
1106  | 0  |         dataIdentificationInfo.northBoundingLatitude = getContentsAsFloat(node,  | 
1107  | 0  |             "smXML:BAG_DataIdentification/extent/smXML:EX_Extent/geographicElement/smXML:EX_GeographicBoundingBox/northBoundLatitude");  | 
1108  |  |  | 
1109  |  |         //smXML:BAG_DataIdentification/verticalUncertaintyType  | 
1110  | 0  |         dataIdentificationInfo.verticalUncertaintyType = getContentsAsCharStar(  | 
1111  | 0  |             node, "smXML:BAG_DataIdentification/verticalUncertaintyType");  | 
1112  |  |  | 
1113  |  |         //smXML:BAG_DataIdentification/depthCorrectionType  | 
1114  | 0  |         dataIdentificationInfo.depthCorrectionType = getContentsAsCharStar(node,  | 
1115  | 0  |             "smXML:BAG_DataIdentification/depthCorrectionType");  | 
1116  |  |  | 
1117  |  |         //smXML:BAG_DataIdentification/nodeGroupType  | 
1118  | 0  |         dataIdentificationInfo.nodeGroupType = getContentsAsCharStar(node,  | 
1119  | 0  |             "smXML:BAG_DataIdentification/nodeGroupType");  | 
1120  |  |  | 
1121  |  |         //smXML:BAG_DataIdentification/elevationSolutionGroupType  | 
1122  | 0  |         dataIdentificationInfo.elevationSolutionGroupType = getContentsAsCharStar(  | 
1123  | 0  |             node, "smXML:BAG_DataIdentification/elevationSolutionGroupType");  | 
1124  | 0  |     }  | 
1125  | 200  |     else if (schemaVersion == 2)  | 
1126  | 200  |     { | 
1127  |  |         //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:title  | 
1128  | 200  |         dataIdentificationInfo.title = getContentsAsCharStar(node,  | 
1129  | 200  |             "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:title/gco:CharacterString");  | 
1130  |  |  | 
1131  |  |         //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:CI_Date/gmd:date  | 
1132  | 200  |         dataIdentificationInfo.date = getContentsAsCharStar(node,  | 
1133  | 200  |             "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:date/gco:Date");  | 
1134  |  |  | 
1135  |  |         //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:CI_Date/gmd:dateType  | 
1136  | 200  |         dataIdentificationInfo.dateType = getContentsAsCharStar(node,  | 
1137  | 200  |             "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:date/gmd:CI_Date/gmd:dateType/gmd:CI_DateTypeCode");  | 
1138  |  |  | 
1139  |  |         //bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:citedResponsibleParty  | 
1140  | 200  |         const auto partyNodes = findNodes(node,  | 
1141  | 200  |             "bag:BAG_DataIdentification/gmd:citation/gmd:CI_Citation/gmd:citedResponsibleParty");  | 
1142  | 200  |         if (!partyNodes.empty())  | 
1143  | 119  |         { | 
1144  | 119  |             dataIdentificationInfo.numberOfResponsibleParties =  | 
1145  | 119  |                 static_cast<uint32_t>(partyNodes.size());  | 
1146  | 119  |             dataIdentificationInfo.responsibleParties =  | 
1147  | 119  |                 new BagResponsibleParty[dataIdentificationInfo.numberOfResponsibleParties];  | 
1148  |  |  | 
1149  | 238  |             for (uint32_t i = 0; i < dataIdentificationInfo.numberOfResponsibleParties; i++)  | 
1150  | 119  |             { | 
1151  | 119  |                 initResponsibleParty(dataIdentificationInfo.responsibleParties[i]);  | 
1152  | 119  |                 if (!decodeResponsibleParty(*partyNodes[i],  | 
1153  | 119  |                     dataIdentificationInfo.responsibleParties[i], schemaVersion))  | 
1154  | 0  |                     return false;  | 
1155  | 119  |             }  | 
1156  | 119  |         }  | 
1157  |  |  | 
1158  |  |         //bag:BAG_DataIdentification/gmd:abstract  | 
1159  | 200  |         dataIdentificationInfo.abstractString = getContentsAsCharStar(node,  | 
1160  | 200  |             "bag:BAG_DataIdentification/gmd:abstract/gco:CharacterString");  | 
1161  |  |  | 
1162  |  |         //bag:BAG_DataIdentification/gmd:status  | 
1163  | 200  |         dataIdentificationInfo.status = getContentsAsCharStar(node,  | 
1164  | 200  |             "bag:BAG_DataIdentification/gmd:status/gmd:MD_ProgressCode");  | 
1165  |  |  | 
1166  |  |         //bag:BAG_DataIdentification/gmd:spatialRepresentationType  | 
1167  | 200  |         dataIdentificationInfo.spatialRepresentationType = getContentsAsCharStar(  | 
1168  | 200  |             node, "bag:BAG_DataIdentification/gmd:spatialRepresentationType/gmd:MD_SpatialRepresentationTypeCode");  | 
1169  |  |  | 
1170  |  |         //bag:BAG_DataIdentification/gmd:language  | 
1171  | 200  |         dataIdentificationInfo.language = getContentsAsCharStar(node,  | 
1172  | 200  |             "bag:BAG_DataIdentification/gmd:language/gmd:LanguageCode");  | 
1173  |  |  | 
1174  |  |         //bag:BAG_DataIdentification/gmd:characterSet  | 
1175  | 200  |         dataIdentificationInfo.characterSet = getContentsAsCharStar(node,  | 
1176  | 200  |             "bag:BAG_DataIdentification/gmd:characterSet/gmd:MD_CharacterSetCode");  | 
1177  |  |  | 
1178  |  |         //bag:BAG_DataIdentification/gmd:topicCategory  | 
1179  | 200  |         dataIdentificationInfo.topicCategory = getContentsAsCharStar(node,  | 
1180  | 200  |             "bag:BAG_DataIdentification/gmd:topicCategory/gmd:MD_TopicCategoryCode");  | 
1181  |  |  | 
1182  |  |         //bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/  | 
1183  | 200  |         dataIdentificationInfo.westBoundingLongitude = getContentsAsFloat(node,  | 
1184  | 200  |             "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:westBoundLongitude/gco:Decimal");  | 
1185  | 200  |         dataIdentificationInfo.eastBoundingLongitude = getContentsAsFloat(node,  | 
1186  | 200  |             "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:eastBoundLongitude/gco:Decimal");  | 
1187  | 200  |         dataIdentificationInfo.southBoundingLatitude = getContentsAsFloat(node,  | 
1188  | 200  |             "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:southBoundLatitude/gco:Decimal");  | 
1189  | 200  |         dataIdentificationInfo.northBoundingLatitude = getContentsAsFloat(node,  | 
1190  | 200  |             "bag:BAG_DataIdentification/gmd:extent/gmd:EX_Extent/gmd:geographicElement/gmd:EX_GeographicBoundingBox/gmd:northBoundLatitude/gco:Decimal");  | 
1191  |  |  | 
1192  |  |         //bag:BAG_DataIdentification/bag:verticalUncertaintyType  | 
1193  | 200  |         dataIdentificationInfo.verticalUncertaintyType = getContentsAsCharStar(  | 
1194  | 200  |             node, "bag:BAG_DataIdentification/bag:verticalUncertaintyType/bag:BAG_VertUncertCode");  | 
1195  |  |  | 
1196  |  |         //bag:BAG_DataIdentification/bag:depthCorrectionType  | 
1197  | 200  |         dataIdentificationInfo.depthCorrectionType = getContentsAsCharStar(node,  | 
1198  | 200  |             "bag:BAG_DataIdentification/bag:depthCorrectionType/bag:BAG_DepthCorrectCode");  | 
1199  |  |  | 
1200  |  |         //bag:BAG_DataIdentification/bag:nodeGroupType  | 
1201  | 200  |         dataIdentificationInfo.nodeGroupType = getContentsAsCharStar(node,  | 
1202  | 200  |             "bag:BAG_DataIdentification/bag:nodeGroupType/bag:BAG_OptGroupCode");  | 
1203  |  |  | 
1204  |  |         //bag:BAG_DataIdentification/bag:elevationSolutionGroupType  | 
1205  | 200  |         dataIdentificationInfo.elevationSolutionGroupType = getContentsAsCharStar(  | 
1206  | 200  |             node, "bag:BAG_DataIdentification/bag:elevationSolutionGroupType/bag:BAG_OptGroupCode");  | 
1207  | 200  |     }  | 
1208  |  |  | 
1209  | 200  |     return true;  | 
1210  | 200  | }  | 
1211  |  |  | 
1212  |  | //************************************************************************  | 
1213  |  | //! Decode a BagReferenceSystem from a BagSpatialRepresentation, the narrowly defined as the parsing of an EPSG code  | 
1214  |  | //! from the transformationDimensionDescription tag  | 
1215  |  | /*!  | 
1216  |  | \param spatialRepresentationInfo  | 
1217  |  |     \li Spatial representation information input.  | 
1218  |  | \param referenceSystemInfo  | 
1219  |  |     \li Modified to contain the reference system information from \e spatialRepresentationInfo->transformationDimensionDescription.  | 
1220  |  | \param schemaVersion  | 
1221  |  |     \li The version of the schema stored in \e node.  | 
1222  |  | \return  | 
1223  |  |     \li True if the information was found and decoded properly, False if  | 
1224  |  |         the optional tag is not present in the header or an error occurs.  | 
1225  |  | */  | 
1226  |  | //************************************************************************  | 
1227  |  | bool decodeReferenceSystemInfoFromSpatial(  | 
1228  |  |     const BagSpatialRepresentation* spatialRepresentationInfo,  | 
1229  |  |     BagReferenceSystem* referenceSystemInfo,  | 
1230  |  |     uint16_t /*schemaVersion*/)  | 
1231  | 0  | { | 
1232  | 0  |     if ( spatialRepresentationInfo && referenceSystemInfo )  | 
1233  | 0  |     { | 
1234  |  |         // Is the TransformationDimensionDescription parameter present?  | 
1235  | 0  |         if ( spatialRepresentationInfo->transformationDimensionDescription )  | 
1236  | 0  |         { | 
1237  |  |             // Find the assignment operator  | 
1238  | 0  |             auto* equal = strchr(  | 
1239  | 0  |                 spatialRepresentationInfo->transformationDimensionDescription, '=');  | 
1240  | 0  |             if (equal != nullptr)  | 
1241  | 0  |             { | 
1242  | 0  |                 ++equal;  | 
1243  | 0  |                 const auto epsg = atoi(equal);  | 
1244  |  |  | 
1245  |  |                 // Proceed to create a string containing the EPSG authority  | 
1246  |  |                 // code, and set the type to "EPSG".  | 
1247  | 0  |                 if (epsg > 0 && strncmp(  | 
1248  | 0  |                     spatialRepresentationInfo->transformationDimensionDescription, "EPSG", 4) == 0)  | 
1249  | 0  |                 { | 
1250  | 0  |                     char buffer[2048];  | 
1251  |  | 
  | 
1252  | 0  |                     sprintf(buffer, "%d", epsg);  | 
1253  | 0  |                     referenceSystemInfo->definition = copyString(buffer);  | 
1254  | 0  |                     referenceSystemInfo->type = copyString("EPSG"); | 
1255  |  | 
  | 
1256  | 0  |                     return true;  | 
1257  | 0  |                 }  | 
1258  | 0  |             }  | 
1259  | 0  |         }  | 
1260  | 0  |     }  | 
1261  |  |  | 
1262  | 0  |     return false;  | 
1263  | 0  | }  | 
1264  |  |  | 
1265  |  |  | 
1266  |  | //************************************************************************  | 
1267  |  | //! Decode a BagReferenceSystem from the supplied XML node.  | 
1268  |  | /*!  | 
1269  |  | \param node  | 
1270  |  |     \li The XML node containing the reference system information.  | 
1271  |  | \param referenceSystemInfo  | 
1272  |  |     \li Modified to contain the reference system information from \e node.  | 
1273  |  | \param schemaVersion  | 
1274  |  |     \li The version of the schema stored in \e node.  | 
1275  |  | \return  | 
1276  |  |     \li True if the information was found and decoded properly, False if  | 
1277  |  |         an error occurs.  | 
1278  |  | */  | 
1279  |  | //************************************************************************  | 
1280  |  | bool decodeReferenceSystemInfo(  | 
1281  |  |     xmlNode& node,  | 
1282  |  |     BagReferenceSystem& referenceSystemInfo,  | 
1283  |  |     uint16_t schemaVersion)  | 
1284  | 400  | { | 
1285  | 400  |     if (schemaVersion == 1)  | 
1286  | 0  |     { | 
1287  |  |         //If I have an ellipsoid, then this must be horizontal.  | 
1288  | 0  |         auto ellipsoid = getContentsAsString(node, "smXML:MD_CRS/ellipsoid/smXML:RS_Identifier/code");  | 
1289  | 0  |         if (!ellipsoid.empty())  | 
1290  | 0  |         { | 
1291  | 0  |             auto projectionId = getContentsAsString(node, "smXML:MD_CRS/projection/smXML:RS_Identifier/code");  | 
1292  | 0  |             auto datumId = getContentsAsString(node, "smXML:MD_CRS/datum/smXML:RS_Identifier/code");  | 
1293  |  | 
  | 
1294  | 0  |             BagLegacyReferenceSystem v1Def;  | 
1295  | 0  |             memset(&v1Def, 0, sizeof(BagLegacyReferenceSystem));  | 
1296  |  |  | 
1297  |  |             //Store the projection information.  | 
1298  | 0  |             v1Def.coordSys = bagCoordsys(projectionId.c_str());  | 
1299  |  |  | 
1300  |  |             //Store the ellipsoid information.  | 
1301  | 0  |             strncpy(v1Def.geoParameters.ellipsoid, ellipsoid.c_str(), 256);  | 
1302  |  |  | 
1303  |  |             //Store the datum information.  | 
1304  | 0  |             v1Def.geoParameters.datum = bagDatumID(datumId.c_str());  | 
1305  |  | 
  | 
1306  | 0  |             v1Def.geoParameters.zone = getContentsAsInt(node,  | 
1307  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/zone");  | 
1308  | 0  |             v1Def.geoParameters.std_parallel_1 = getContentsAsFloat(node,  | 
1309  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/standardParallel[1]");  | 
1310  | 0  |             v1Def.geoParameters.std_parallel_2 = getContentsAsFloat(node,  | 
1311  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/standardParallel[2]");  | 
1312  | 0  |             v1Def.geoParameters.central_meridian = getContentsAsFloat(node,  | 
1313  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/longitudeOfCentralMeridian");  | 
1314  | 0  |             v1Def.geoParameters.origin_latitude = getContentsAsFloat(node,  | 
1315  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/latitudeOfProjectionOrigin");  | 
1316  | 0  |             v1Def.geoParameters.false_easting = getContentsAsFloat(node,  | 
1317  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/falseEasting");  | 
1318  | 0  |             v1Def.geoParameters.false_northing = getContentsAsFloat(node,  | 
1319  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/falseNorthing");  | 
1320  | 0  |             const double scaleFactAtEq = getContentsAsFloat(node,  | 
1321  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/scaleFactorAtEquator");  | 
1322  | 0  |             v1Def.geoParameters.longitude_of_centre = getContentsAsFloat(node,  | 
1323  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/longitudeOfProjectionCenter");  | 
1324  | 0  |             v1Def.geoParameters.latitude_of_centre = getContentsAsFloat(node,  | 
1325  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/latitudeOfProjectionCenter");  | 
1326  | 0  |             v1Def.geoParameters.longitude_down_from_pole = getContentsAsFloat(  | 
1327  | 0  |                 node, "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/straightVerticalLongitudeFromPole");  | 
1328  | 0  |             const double scaleAtProjOrigin = getContentsAsFloat(node,  | 
1329  | 0  |                 "smXML:MD_CRS/projectionParameters/smXML:MD_ProjectionParameters/scaleFactorAtProjectionOrigin");  | 
1330  |  |  | 
1331  |  |             /* dhf */  | 
1332  |  |             /* scaleFactAtEq - for mercator */  | 
1333  |  |             /* scaleAtCenterLine - for oblique mercator (not supported) */  | 
1334  |  |             /* scaleAtProjOrigin - for polar stereographic & transverse mercator */  | 
1335  | 0  |             if (v1Def.coordSys == CoordinateType::Mercator)  | 
1336  | 0  |               v1Def.geoParameters.scale_factor = scaleFactAtEq;  | 
1337  | 0  |             if (v1Def.coordSys == CoordinateType::Transverse_Mercator ||  | 
1338  | 0  |                 v1Def.coordSys == CoordinateType::Polar_Stereo)  | 
1339  | 0  |               v1Def.geoParameters.scale_factor = scaleAtProjOrigin;  | 
1340  |  | 
  | 
1341  | 0  |             char buffer[2048];  | 
1342  | 0  |             const BagError error = bagLegacyToWkt(v1Def, buffer, sizeof(buffer),  | 
1343  | 0  |                 nullptr, 0);  | 
1344  | 0  |             if (error)  | 
1345  | 0  |                 return false;  | 
1346  |  |  | 
1347  | 0  |             referenceSystemInfo.definition = copyString(buffer);  | 
1348  | 0  |             referenceSystemInfo.type = copyString("WKT"); | 
1349  | 0  |         }  | 
1350  |  |         //Else it must be vertical.  | 
1351  | 0  |         else  | 
1352  | 0  |         { | 
1353  | 0  |             auto datum = getContentsAsString(node, "smXML:MD_CRS/datum/smXML:RS_Identifier/code");  | 
1354  |  | 
  | 
1355  | 0  |             BagLegacyReferenceSystem system;  | 
1356  | 0  |             strncpy(system.geoParameters.vertical_datum, datum.c_str(), 256);  | 
1357  |  | 
  | 
1358  | 0  |             char buffer[1024];  | 
1359  | 0  |             const BagError error = bagLegacyToWkt(system, nullptr, 0, buffer,  | 
1360  | 0  |                 sizeof(buffer));  | 
1361  | 0  |             if (error)  | 
1362  | 0  |                 return false;  | 
1363  |  |  | 
1364  | 0  |             referenceSystemInfo.definition = copyString(buffer);  | 
1365  | 0  |             referenceSystemInfo.type = copyString("WKT"); | 
1366  | 0  |         }  | 
1367  | 0  |     }  | 
1368  | 400  |     else if (schemaVersion == 2)  | 
1369  | 400  |     { | 
1370  |  |         //gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code  | 
1371  | 400  |         referenceSystemInfo.definition = getContentsAsCharStar(node,  | 
1372  | 400  |             "gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:code/gco:CharacterString");  | 
1373  |  |  | 
1374  |  |         //gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:codeSpace  | 
1375  | 400  |         referenceSystemInfo.type = getContentsAsCharStar(node,  | 
1376  | 400  |             "gmd:MD_ReferenceSystem/gmd:referenceSystemIdentifier/gmd:RS_Identifier/gmd:codeSpace/gco:CharacterString");  | 
1377  | 400  |     }  | 
1378  |  |  | 
1379  | 400  |     return true;  | 
1380  | 400  | }  | 
1381  |  |  | 
1382  |  | //************************************************************************  | 
1383  |  | //! Validate an XML document against the current BAG metadata schema.  | 
1384  |  | /*!  | 
1385  |  | \param metadataDocument  | 
1386  |  |     \li The document to be validated.  | 
1387  |  | \return  | 
1388  |  |     \li BAG_SUCCESS if the document passes schema validation, a BAG error  | 
1389  |  |         code if an error occurs.  | 
1390  |  | */  | 
1391  |  | //************************************************************************  | 
1392  |  | BagError validateSchema(xmlDoc& metadataDocument)  | 
1393  | 0  | { | 
1394  |  |     //Get the location of the BAG home directory.  | 
1395  | 0  |     const std::string bagHome = bagGetHomeFolder();  | 
1396  |  | 
  | 
1397  | 0  |     if (bagHome.empty())  | 
1398  | 0  |         return BAG_METADTA_NO_HOME;  | 
1399  |  |  | 
1400  |  |     //Build the full path to the schema location.  | 
1401  | 0  |     std::string schemaFile(bagHome);  | 
1402  | 0  |     schemaFile += "/";  | 
1403  | 0  |     schemaFile += ons_schema_location;  | 
1404  |  |  | 
1405  |  |     // make sure the main schema file exists.  | 
1406  | 0  |     struct stat fStat;  | 
1407  | 0  |     if (stat(schemaFile.c_str(), &fStat))  | 
1408  | 0  |         return BAG_METADTA_SCHEMA_FILE_MISSING;  | 
1409  |  |  | 
1410  |  |     // Open the schema.  | 
1411  | 0  |     xmlDoc *pSchemaDoc = xmlParseFile(schemaFile.c_str());  | 
1412  | 0  |     if (!pSchemaDoc)  | 
1413  | 0  |         return BAG_METADTA_PARSE_FAILED;  | 
1414  |  |  | 
1415  |  |     // Parse the schema.  | 
1416  | 0  |     xmlSchemaParserCtxt *pContext = xmlSchemaNewDocParserCtxt(pSchemaDoc);  | 
1417  | 0  |     if (!pContext)  | 
1418  | 0  |     { | 
1419  | 0  |         xmlFreeDoc(pSchemaDoc);  | 
1420  |  | 
  | 
1421  | 0  |         return BAG_METADTA_SCHEMA_SETUP_FAILED;  | 
1422  | 0  |     }  | 
1423  |  |  | 
1424  |  |     // Initialize the schema object.  | 
1425  | 0  |     xmlSchema *pSchema = xmlSchemaParse(pContext);  | 
1426  | 0  |     if (!pSchema)  | 
1427  | 0  |     { | 
1428  | 0  |         xmlSchemaFreeParserCtxt(pContext);  | 
1429  | 0  |         xmlFreeDoc(pSchemaDoc);  | 
1430  |  | 
  | 
1431  | 0  |         return BAG_METADTA_SCHEMA_SETUP_FAILED;  | 
1432  | 0  |     }  | 
1433  |  |  | 
1434  |  |     // Create the validation object.  | 
1435  | 0  |     xmlSchemaValidCtxt *pValidationContext = xmlSchemaNewValidCtxt(pSchema);  | 
1436  | 0  |     if (!pValidationContext)  | 
1437  | 0  |     { | 
1438  | 0  |         xmlSchemaFree(pSchema);  | 
1439  | 0  |         xmlSchemaFreeParserCtxt(pContext);  | 
1440  | 0  |         xmlFreeDoc(pSchemaDoc);  | 
1441  |  | 
  | 
1442  | 0  |         return BAG_METADTA_SCHEMA_VALIDATION_SETUP_FAILED;  | 
1443  | 0  |     }  | 
1444  |  |  | 
1445  |  |     // Validate the document.  | 
1446  | 0  |     const int result = xmlSchemaValidateDoc(pValidationContext, &metadataDocument);  | 
1447  |  | 
  | 
1448  | 0  |     xmlSchemaFreeValidCtxt(pValidationContext);  | 
1449  | 0  |     xmlSchemaFree(pSchema);  | 
1450  | 0  |     xmlSchemaFreeParserCtxt(pContext);  | 
1451  | 0  |     xmlFreeDoc(pSchemaDoc);  | 
1452  |  | 
  | 
1453  | 0  |     return (result == 0) ? BAG_SUCCESS : BAG_METADTA_VALIDATE_FAILED;  | 
1454  | 0  | }  | 
1455  |  |  | 
1456  |  | //************************************************************************  | 
1457  |  | //! Import the BAG_METADATA from a version 1 schema.  | 
1458  |  | /*!  | 
1459  |  |     Imports the metadata from a 'version 1' BAG schema.  Version 1 schemas  | 
1460  |  |     were used in BAG versions 1.0 - 1.4.  Version 2 schemas are used in  | 
1461  |  |     BAG version 1.5 and newer.  | 
1462  |  |  | 
1463  |  | \param document  | 
1464  |  |     \li The XML document containing the 'version 1' schema.  | 
1465  |  | \param metadata  | 
1466  |  |     \li Modified to contain the BAG metadata information from \e document.  | 
1467  |  |         Input should not be NULL.  | 
1468  |  | \return  | 
1469  |  |     \li BAG_SUCCESS if the information is successfully extracted from \e document,  | 
1470  |  |         an error code otherwise.  | 
1471  |  | */  | 
1472  |  | //************************************************************************  | 
1473  |  | BagError bagImportMetadataFromXmlV1(  | 
1474  |  |     const xmlDoc& document,  | 
1475  |  |     BagMetadata& metadata)  | 
1476  | 0  | { | 
1477  | 0  |     xmlNode* pRoot = xmlDocGetRootElement(&document);  | 
1478  | 0  |     if (!pRoot)  | 
1479  | 0  |         return BAG_METADTA_NOT_INITIALIZED;  | 
1480  |  |  | 
1481  |  |     //gmd:language  | 
1482  | 0  |     metadata.language = getContentsAsCharStar(*pRoot, "/smXML:MD_Metadata/language");  | 
1483  |  |  | 
1484  |  |     //gmd:characterSet  | 
1485  | 0  |     metadata.characterSet = copyString("eng"); | 
1486  |  |  | 
1487  |  |     //gmd:hierarchyLevel  | 
1488  | 0  |     metadata.hierarchyLevel = copyString("dataset"); | 
1489  |  |  | 
1490  |  |     //gmd:contact  | 
1491  | 0  |     { | 
1492  | 0  |         auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/contact");  | 
1493  | 0  |         if (!pNode)  | 
1494  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1495  |  |  | 
1496  | 0  |         if (!decodeResponsibleParty(*pNode, *metadata.contact, 1))  | 
1497  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1498  | 0  |     }  | 
1499  |  |  | 
1500  |  |     //gmd:dateStamp  | 
1501  | 0  |     metadata.dateStamp = getContentsAsCharStar(*pRoot,  | 
1502  | 0  |         "/smXML:MD_Metadata/dateStamp");  | 
1503  |  |  | 
1504  |  |     //gmd:metadataStandardName  | 
1505  | 0  |     metadata.metadataStandardName = getContentsAsCharStar(*pRoot,  | 
1506  | 0  |         "/smXML:MD_Metadata/metadataStandardName");  | 
1507  |  |  | 
1508  |  |     //gmd:metadataStandardVersion  | 
1509  | 0  |     metadata.metadataStandardVersion = getContentsAsCharStar(*pRoot,  | 
1510  | 0  |         "/smXML:MD_Metadata/metadataStandardVersion");  | 
1511  |  |  | 
1512  |  |     //gmd:spatialRepresentationInfo  | 
1513  | 0  |     { | 
1514  | 0  |         auto* pNode = findNode(*pRoot,  | 
1515  | 0  |             "/smXML:MD_Metadata/spatialRepresentationInfo");  | 
1516  | 0  |         if (!pNode)  | 
1517  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1518  |  |  | 
1519  | 0  |         if (!decodeSpatialRepresentationInfo(*pNode,  | 
1520  | 0  |             *metadata.spatialRepresentationInfo, 1))  | 
1521  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1522  | 0  |     }  | 
1523  |  |  | 
1524  |  |     //gmd:referenceSystemInfo (horizontal)  | 
1525  | 0  |     { | 
1526  | 0  |         auto* pNode = findNode(*pRoot,  | 
1527  | 0  |             "/smXML:MD_Metadata/referenceSystemInfo[1]");  | 
1528  | 0  |         if (!pNode)  | 
1529  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1530  |  |  | 
1531  | 0  |         if (!decodeReferenceSystemInfo(*pNode, *metadata.horizontalReferenceSystem, 1))  | 
1532  | 0  |         { | 
1533  |  |             // If the reference system could not be identified from this block  | 
1534  |  |             // of code look for an EPSG code in the spatial reference system  | 
1535  | 0  |             if (!decodeReferenceSystemInfoFromSpatial(  | 
1536  | 0  |                 metadata.spatialRepresentationInfo,  | 
1537  | 0  |                 metadata.horizontalReferenceSystem, 1))  | 
1538  | 0  |                 return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1539  | 0  |         }  | 
1540  | 0  |     }  | 
1541  |  |  | 
1542  |  |     //gmd:referenceSystemInfo (vertical)  | 
1543  | 0  |     { | 
1544  | 0  |         auto* pNode = findNode(*pRoot,  | 
1545  | 0  |             "/smXML:MD_Metadata/referenceSystemInfo[2]");  | 
1546  | 0  |         if (!pNode)  | 
1547  | 0  |         { | 
1548  |  |             //If we could not find the vertical coordinate system node, then  | 
1549  |  |             //lets look in the other location.  | 
1550  | 0  |             auto* pNode2 = findNode(*pRoot,  | 
1551  | 0  |                 "/smXML:MD_Metadata/referenceSystemInfo[1]//verticalDatum");  | 
1552  | 0  |             if (!pNode2)  | 
1553  | 0  |                 return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1554  |  |  | 
1555  | 0  |             const auto datum = getContentsAsString(*pNode2,  | 
1556  | 0  |                 "smXML:RS_Identifier/code");  | 
1557  | 0  |             if (datum.empty())  | 
1558  | 0  |                 return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1559  |  |  | 
1560  | 0  |             BagLegacyReferenceSystem system;  | 
1561  | 0  |             strncpy(system.geoParameters.vertical_datum, datum.c_str(), 256);  | 
1562  |  | 
  | 
1563  | 0  |             char buffer[1024];  | 
1564  | 0  |             BagError error = bagLegacyToWkt(system, nullptr, 0, buffer,  | 
1565  | 0  |                 sizeof(buffer));  | 
1566  | 0  |             if (error)  | 
1567  | 0  |                 return error;  | 
1568  |  |  | 
1569  | 0  |             metadata.verticalReferenceSystem->definition = copyString(buffer);  | 
1570  | 0  |             metadata.verticalReferenceSystem->type = copyString("WKT"); | 
1571  | 0  |         }  | 
1572  | 0  |         else if (!decodeReferenceSystemInfo(*pNode,  | 
1573  | 0  |             *metadata.verticalReferenceSystem, 1))  | 
1574  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1575  | 0  |     }  | 
1576  |  |  | 
1577  |  |     //Because the previous metadata profile did not store the unit of measure  | 
1578  |  |     //for the spatial representation element, we will use the spatial reference  | 
1579  |  |     //system to figure it out.  | 
1580  | 0  |     { | 
1581  |  |         //Get the WKT horizontal reference system string.  | 
1582  | 0  |         const std::string horizontalWKT{ | 
1583  | 0  |             metadata.horizontalReferenceSystem->definition};  | 
1584  |  |  | 
1585  |  |         //If we have a projection, then it must be metres (its all we supported in the past)  | 
1586  | 0  |         if (horizontalWKT.find("PROJCS[") >= 0) | 
1587  | 0  |             metadata.spatialRepresentationInfo->resolutionUnit = copyString("Metre"); | 
1588  |  |         //Else it must be geographic  | 
1589  | 0  |         else  | 
1590  | 0  |             metadata.spatialRepresentationInfo->resolutionUnit = copyString("Degree"); | 
1591  | 0  |     }  | 
1592  |  |  | 
1593  |  |     //gmd:identificationInfo  | 
1594  | 0  |     { | 
1595  | 0  |         auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/identificationInfo");  | 
1596  | 0  |         if (!pNode)  | 
1597  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1598  |  |  | 
1599  | 0  |         if (!decodeDataIdentificationInfo(*pNode, *metadata.identificationInfo, 1))  | 
1600  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1601  | 0  |     }  | 
1602  |  |  | 
1603  |  |     //gmd:dataQualityInfo  | 
1604  | 0  |     { | 
1605  | 0  |         auto* pNode = findNode(*pRoot, "/smXML:MD_Metadata/dataQualityInfo");  | 
1606  | 0  |         if (!pNode)  | 
1607  | 0  |         { | 
1608  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1609  | 0  |         }  | 
1610  |  |  | 
1611  | 0  |         if (!decodeDataQualityInfo(*pNode, *metadata.dataQualityInfo, 1))  | 
1612  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1613  | 0  |     }  | 
1614  |  |  | 
1615  |  |     //gmd:metadataConstraints (legal)  | 
1616  | 0  |     { | 
1617  | 0  |         auto* pNode = findNode(*pRoot,  | 
1618  | 0  |             "/smXML:MD_Metadata/metadataConstraints/smXML:MD_LegalConstraints/parent::*");  | 
1619  | 0  |         if (!pNode)  | 
1620  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1621  |  |  | 
1622  | 0  |         if (!decodeLegalConstraints(*pNode, *metadata.legalConstraints, 1))  | 
1623  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1624  | 0  |     }  | 
1625  |  |  | 
1626  |  |     //gmd:metadataConstraints (security)  | 
1627  | 0  |     { | 
1628  | 0  |         auto* pNode = findNode(*pRoot,  | 
1629  | 0  |             "/smXML:MD_Metadata/metadataConstraints/smXML:MD_SecurityConstraints/parent::*");  | 
1630  | 0  |         if (!pNode)  | 
1631  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1632  |  |  | 
1633  | 0  |         if (!decodeSecurityConstraints(*pNode, *metadata.securityConstraints, 1))  | 
1634  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1635  | 0  |     }  | 
1636  |  |  | 
1637  | 0  |     return BAG_SUCCESS;  | 
1638  | 0  | }  | 
1639  |  |  | 
1640  |  | //************************************************************************  | 
1641  |  | //! Import the BAG_METADATA from a version 2 schema.  | 
1642  |  | /*!  | 
1643  |  |     Imports the metadata from a 'version 2' BAG schema.  Version 2 schemas  | 
1644  |  |     are used in BAG version 1.5 and newer.  | 
1645  |  |  | 
1646  |  | \param document  | 
1647  |  |     \li The XML document containing the 'version 2' schema.  | 
1648  |  | \param metadata  | 
1649  |  |     \li Modified to contain the BAG metadata information from \e document.  | 
1650  |  |         Input should not be NULL.  | 
1651  |  | \return  | 
1652  |  |     \li BAG_SUCCESS if the information is successfully extracted from \e document,  | 
1653  |  |         an error code otherwise.  | 
1654  |  | */  | 
1655  |  | //************************************************************************  | 
1656  |  | BagError bagImportMetadataFromXmlV2(  | 
1657  |  |     const xmlDoc& document,  | 
1658  |  |     BagMetadata& metadata)  | 
1659  | 200  | { | 
1660  | 200  |     auto* pRoot = xmlDocGetRootElement(&document);  | 
1661  | 200  |     if (!pRoot)  | 
1662  | 0  |         return BAG_METADTA_NOT_INITIALIZED;  | 
1663  |  |  | 
1664  |  |     //gmd:fileIdentifier  | 
1665  | 200  |     delete[] metadata.fileIdentifier;  | 
1666  | 200  |     metadata.fileIdentifier = getContentsAsCharStar(*pRoot,  | 
1667  | 200  |         "/gmi:MI_Metadata/gmd:fileIdentifier/gco:CharacterString");  | 
1668  |  |  | 
1669  |  |     //gmd:language  | 
1670  | 200  |     delete[] metadata.language;  | 
1671  | 200  |     metadata.language = getContentsAsCharStar(*pRoot,  | 
1672  | 200  |         "/gmi:MI_Metadata/gmd:language/gmd:LanguageCode");  | 
1673  |  |  | 
1674  |  |     //gmd:characterSet  | 
1675  | 200  |     delete[] metadata.characterSet;  | 
1676  | 200  |     metadata.characterSet = getContentsAsCharStar(*pRoot,  | 
1677  | 200  |         "/gmi:MI_Metadata/gmd:characterSet/gmd:MD_CharacterSetCode");  | 
1678  |  |  | 
1679  |  |     //gmd:hierarchyLevel  | 
1680  | 200  |     delete[] metadata.hierarchyLevel;  | 
1681  | 200  |     metadata.hierarchyLevel = getContentsAsCharStar(*pRoot,  | 
1682  | 200  |         "/gmi:MI_Metadata/gmd:hierarchyLevel/gmd:MD_ScopeCode");  | 
1683  |  |  | 
1684  |  |     //gmd:contact  | 
1685  | 200  |     { | 
1686  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:contact");  | 
1687  | 200  |         if (!pNode)  | 
1688  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1689  |  |  | 
1690  | 200  |         if (!decodeResponsibleParty(*pNode, *metadata.contact, 2))  | 
1691  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1692  | 200  |     }  | 
1693  |  |  | 
1694  |  |     //gmd:dateStamp  | 
1695  | 200  |     delete[] metadata.dateStamp;  | 
1696  | 200  |     metadata.dateStamp = getContentsAsCharStar(*pRoot,  | 
1697  | 200  |         "/gmi:MI_Metadata/gmd:dateStamp/gco:Date");  | 
1698  |  |  | 
1699  |  |     //gmd:metadataStandardName  | 
1700  | 200  |     delete[] metadata.metadataStandardName;  | 
1701  | 200  |     metadata.metadataStandardName = getContentsAsCharStar(*pRoot,  | 
1702  | 200  |         "/gmi:MI_Metadata/gmd:metadataStandardName/gco:CharacterString");  | 
1703  |  |  | 
1704  |  |     //gmd:metadataStandardVersion  | 
1705  | 200  |     delete[] metadata.metadataStandardVersion;  | 
1706  | 200  |     metadata.metadataStandardVersion = getContentsAsCharStar(*pRoot,  | 
1707  | 200  |         "/gmi:MI_Metadata/gmd:metadataStandardVersion/gco:CharacterString");  | 
1708  |  |  | 
1709  |  |     //gmd:spatialRepresentationInfo  | 
1710  | 200  |     { | 
1711  | 200  |         auto* pNode = findNode(*pRoot,  | 
1712  | 200  |             "/gmi:MI_Metadata/gmd:spatialRepresentationInfo/gmd:MD_Georectified/parent::*");  | 
1713  | 200  |         if (!pNode)  | 
1714  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1715  |  |  | 
1716  | 200  |         if (!decodeSpatialRepresentationInfo(*pNode, *metadata.spatialRepresentationInfo, 2))  | 
1717  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1718  | 200  |     }  | 
1719  |  |  | 
1720  |  |     //gmd:referenceSystemInfo (horizontal)  | 
1721  | 200  |     { | 
1722  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:referenceSystemInfo[1]");  | 
1723  | 200  |         if (!pNode)  | 
1724  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1725  |  |  | 
1726  | 200  |         if (!decodeReferenceSystemInfo(*pNode, *metadata.horizontalReferenceSystem, 2))  | 
1727  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1728  | 200  |     }  | 
1729  |  |  | 
1730  |  |     //gmd:referenceSystemInfo (vertical)  | 
1731  | 200  |     { | 
1732  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:referenceSystemInfo[2]");  | 
1733  | 200  |         if (!pNode)  | 
1734  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1735  |  |  | 
1736  | 200  |         if (!decodeReferenceSystemInfo(*pNode, *metadata.verticalReferenceSystem, 2))  | 
1737  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1738  | 200  |     }  | 
1739  |  |  | 
1740  |  |     //gmd:identificationInfo  | 
1741  | 200  |     { | 
1742  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:identificationInfo");  | 
1743  | 200  |         if (!pNode)  | 
1744  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1745  |  |  | 
1746  | 200  |         if (!decodeDataIdentificationInfo(*pNode, *metadata.identificationInfo, 2))  | 
1747  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1748  | 200  |     }  | 
1749  |  |  | 
1750  |  |     //gmd:dataQualityInfo  | 
1751  | 200  |     { | 
1752  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:dataQualityInfo");  | 
1753  | 200  |         if (!pNode)  | 
1754  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1755  |  |  | 
1756  | 200  |         if (!decodeDataQualityInfo(*pNode, *metadata.dataQualityInfo, 2))  | 
1757  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1758  | 200  |     }  | 
1759  |  |  | 
1760  |  |     //gmd:metadataConstraints (legal)  | 
1761  | 200  |     { | 
1762  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:metadataConstraints/gmd:MD_LegalConstraints/parent::*");  | 
1763  | 200  |         if (!pNode)  | 
1764  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1765  |  |  | 
1766  | 200  |         if (!decodeLegalConstraints(*pNode, *metadata.legalConstraints, 2))  | 
1767  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1768  | 200  |     }  | 
1769  |  |  | 
1770  |  |     //gmd:metadataConstraints (security)  | 
1771  | 200  |     { | 
1772  | 200  |         auto* pNode = findNode(*pRoot, "/gmi:MI_Metadata/gmd:metadataConstraints/gmd:MD_SecurityConstraints/parent::*");  | 
1773  | 200  |         if (!pNode)  | 
1774  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1775  |  |  | 
1776  | 200  |         if (!decodeSecurityConstraints(*pNode, *metadata.securityConstraints, 2))  | 
1777  | 0  |             return BAG_METADTA_MISSING_MANDATORY_ITEM;  | 
1778  | 200  |     }  | 
1779  |  |  | 
1780  | 200  |     return BAG_SUCCESS;  | 
1781  | 200  | }  | 
1782  |  |  | 
1783  |  | //************************************************************************  | 
1784  |  | //! Import the BAG_METADATA from an XML document.  | 
1785  |  | /*!  | 
1786  |  |     Imports the BAG metadata information from any supported schema version.  | 
1787  |  |  | 
1788  |  | \param document  | 
1789  |  |     \li The XML document containing the 'version 2' schema.  | 
1790  |  | \param metadata  | 
1791  |  |     \li Modified to contain the BAG metadata information from \e document.  | 
1792  |  |         Input should not be NULL.  | 
1793  |  | \param doValidation  | 
1794  |  |     \li True to perform the schema validation (conformance test).  False  | 
1795  |  |         to simply extract the data.  | 
1796  |  | \return  | 
1797  |  |     \li BAG_SUCCESS on success.  A BAG error code is returned if there  | 
1798  |  |         is an error, or if schema validation fails (only if \e doValidation  | 
1799  |  |         is True).  | 
1800  |  | */  | 
1801  |  | //************************************************************************  | 
1802  |  | BagError bagImportMetadataFromXml(  | 
1803  |  |     xmlDoc& document,  | 
1804  |  |     BagMetadata& metadata,  | 
1805  |  |     bool doValidation)  | 
1806  | 200  | { | 
1807  | 200  |     const xmlNode* pRoot = xmlDocGetRootElement(&document);  | 
1808  | 200  |     if (!pRoot)  | 
1809  | 0  |         return BAG_METADTA_EMPTY_DOCUMENT;  | 
1810  |  |  | 
1811  | 200  |     if (doValidation)  | 
1812  | 0  |     { | 
1813  | 0  |         const BagError ret = validateSchema(document);  | 
1814  | 0  |         if (ret)  | 
1815  | 0  |             return ret;  | 
1816  | 0  |     }  | 
1817  |  |  | 
1818  |  |     //Get the name of the root node.  | 
1819  | 200  |     const std::string rootName = getNodeName(*pRoot);  | 
1820  |  |  | 
1821  |  |     //We will use the root node's name to figure out what version of the schema we are working with.  | 
1822  | 200  |     const uint16_t schemaVersion = (rootName == "smXML:MD_Metadata") ? 1 : 2;  | 
1823  |  |  | 
1824  | 200  |     return (schemaVersion == 1) ?  | 
1825  | 0  |         bagImportMetadataFromXmlV1(document, metadata) :  | 
1826  | 200  |         bagImportMetadataFromXmlV2(document, metadata);  | 
1827  | 200  | }  | 
1828  |  |  | 
1829  |  | //************************************************************************  | 
1830  |  | //! Import the BAG_METADATA from an XML document stored in a character buffer.  | 
1831  |  | /*!  | 
1832  |  |     Imports the BAG metadata information from any supported schema version.  | 
1833  |  |  | 
1834  |  | \param xmlBuffer  | 
1835  |  |     \li The character buffer containing the XML document to be used for  | 
1836  |  |         import.  Input should not be NULL.  | 
1837  |  | \param bufferSize  | 
1838  |  |     \li The size in bytes of the \e xmlBuffer.  | 
1839  |  | \param metadata  | 
1840  |  |     \li Modified to contain the BAG metadata information from \e xmlBuffer.  | 
1841  |  |         Input should not be NULL.  | 
1842  |  | \param doValidation  | 
1843  |  |     \li True to perform the schema validation (conformance test).  False  | 
1844  |  |         to simply extract the data.  | 
1845  |  | \return  | 
1846  |  |     \li BAG_SUCCESS if the information is successfully extracted from \e xmlBuffer,  | 
1847  |  |         an error code otherwise.  If \e doValidation is True, an error will be returned  | 
1848  |  |         if the validation fails.  | 
1849  |  | */  | 
1850  |  | //************************************************************************  | 
1851  |  | BagError bagImportMetadataFromXmlBuffer(  | 
1852  |  |     const char* xmlBuffer,  | 
1853  |  |     int bufferSize,  | 
1854  |  |     BagMetadata& metadata,  | 
1855  |  |     bool doValidation)  | 
1856  | 200  | { | 
1857  | 200  |     xmlDoc* pDocument = xmlParseMemory(xmlBuffer, bufferSize);  | 
1858  | 200  |     if (!pDocument)  | 
1859  | 0  |         return BAG_METADTA_NOT_INITIALIZED;  | 
1860  |  |  | 
1861  | 200  |     const BagError err = bagImportMetadataFromXml(*pDocument, metadata, doValidation);  | 
1862  | 200  |     xmlFreeDoc(pDocument);  | 
1863  | 200  |     return err;  | 
1864  | 200  | }  | 
1865  |  |  | 
1866  |  | //************************************************************************  | 
1867  |  | //! Import the BAG_METADATA from an XML file.  | 
1868  |  | /*!  | 
1869  |  |     Imports the BAG metadata information from any supported schema version.  | 
1870  |  |  | 
1871  |  | \param fileName  | 
1872  |  |     \li The fully qualified name of the XML file to be read.  | 
1873  |  | \param metadata  | 
1874  |  |     \li Modified to contain the BAG metadata information from \e fileName.  | 
1875  |  |         Input should not be NULL.  | 
1876  |  | \param doValidation  | 
1877  |  |     \li True to perform the schema validation (conformance test).  False  | 
1878  |  |         to simply extract the data.  | 
1879  |  | \return  | 
1880  |  |     \li BAG_SUCCESS if the information is successfully extracted from \e xmlBuffer,  | 
1881  |  |         an error code otherwise.  If \e doValidation is True, an error will be returned  | 
1882  |  |         if the validation fails.  | 
1883  |  | */  | 
1884  |  | //************************************************************************  | 
1885  |  | BagError bagImportMetadataFromXmlFile(  | 
1886  |  |     const char* fileName,  | 
1887  |  |     BagMetadata& metadata,  | 
1888  |  |     bool doValidation)  | 
1889  | 0  | { | 
1890  | 0  |     xmlDoc* pDocument = xmlParseFile(fileName);  | 
1891  | 0  |     if (!pDocument)  | 
1892  | 0  |         return BAG_METADTA_NOT_INITIALIZED;  | 
1893  |  |  | 
1894  | 0  |     const BagError err = bagImportMetadataFromXml(*pDocument, metadata, doValidation);  | 
1895  | 0  |     xmlFreeDoc(pDocument);  | 
1896  | 0  |     return err;  | 
1897  | 0  | }  | 
1898  |  |  | 
1899  |  | }  // namespace BAG  | 
1900  |  |  |