Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GML Reader
4 : * Purpose: Implementation of GMLReader::ResolveXlinks() method.
5 : * Author: Chaitanya kumar CH, chaitanya@osgeo.in
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Chaitanya kumar CH
9 : * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "gmlreader.h"
32 : #include "gmlreaderp.h"
33 :
34 : #include <cstddef>
35 : #include <cstring>
36 :
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_http.h"
40 : #include "cpl_minixml.h"
41 : #include "cpl_string.h"
42 :
43 : /************************************************************************/
44 : /* GetID() */
45 : /* */
46 : /* Returns the reference to the gml:id of psNode. NULL if not */
47 : /* found. */
48 : /************************************************************************/
49 :
50 107255 : static const char *GetID(CPLXMLNode *psNode)
51 :
52 : {
53 107255 : if (psNode == nullptr)
54 0 : return nullptr;
55 :
56 261530 : for (CPLXMLNode *psChild = psNode->psChild; psChild != nullptr;
57 154275 : psChild = psChild->psNext)
58 : {
59 165003 : if (psChild->eType == CXT_Attribute &&
60 35151 : EQUAL(psChild->pszValue, "gml:id"))
61 : {
62 10728 : return psChild->psChild->pszValue;
63 : }
64 : }
65 96527 : return nullptr;
66 : }
67 :
68 : /************************************************************************/
69 : /* CompareNodeIDs() */
70 : /* */
71 : /* Compares two nodes by their IDs */
72 : /************************************************************************/
73 :
74 : /*static int CompareNodeIDs( CPLXMLNode * psNode1, CPLXMLNode * psNode2 )
75 :
76 : {
77 : if( psNode2 == NULL )
78 : return TRUE;
79 :
80 : if( psNode1 == NULL )
81 : return FALSE;
82 :
83 : return strcmp( GetID(psNode2), GetID(psNode1) ) > 0;
84 : }*/
85 :
86 : /************************************************************************/
87 : /* BuildIDIndex() */
88 : /* */
89 : /* Returns an array of nodes sorted by their gml:id strings */
90 : /* XXX: This method can be used to build an array of pointers to */
91 : /* nodes sorted by their id values. */
92 : /************************************************************************/
93 : /*
94 : static std::vector<CPLXMLNode*> BuildIDIndex( CPLXMLNode* psNode,
95 : std::vector<CPLXMLNode*> &apsNode )
96 :
97 : {
98 : for( CPLXMLNode *psSibling = psNode;
99 : psSibling != NULL;
100 : psSibling = psSibling->psNext )
101 : {
102 : if( GetID( psSibling ) != NULL )
103 : apsNode.push_back( psSibling );
104 : BuildIDIndex( psNode->psChild, apsNode );
105 : }
106 : return NULL;
107 : }*/
108 :
109 : /************************************************************************/
110 : /* FindElementByID() */
111 : /* */
112 : /* Find a node with the indicated "gml:id" in the node tree and */
113 : /* its siblings. */
114 : /************************************************************************/
115 :
116 100770 : static CPLXMLNode *FindElementByID(CPLXMLNode *psRoot, const char *pszID)
117 :
118 : {
119 100770 : if (psRoot == nullptr)
120 9109 : return nullptr;
121 :
122 : // Check for id attribute.
123 253761 : for (CPLXMLNode *psSibling = psRoot; psSibling != nullptr;
124 162100 : psSibling = psSibling->psNext)
125 : {
126 162413 : if (psSibling->eType == CXT_Element)
127 : {
128 : // check that sibling for id value
129 107255 : const char *pszIDOfSibling = GetID(psSibling);
130 107255 : if (pszIDOfSibling != nullptr && EQUAL(pszIDOfSibling, pszID))
131 313 : return psSibling;
132 : }
133 : }
134 :
135 : // Search the child elements of all the psRoot's siblings.
136 244818 : for (CPLXMLNode *psSibling = psRoot; psSibling != nullptr;
137 153470 : psSibling = psSibling->psNext)
138 : {
139 155557 : if (psSibling->eType == CXT_Element)
140 : {
141 100457 : CPLXMLNode *psReturn = FindElementByID(psSibling->psChild, pszID);
142 100457 : if (psReturn != nullptr)
143 2087 : return psReturn;
144 : }
145 : }
146 89261 : return nullptr;
147 : }
148 :
149 : /************************************************************************/
150 : /* RemoveIDs() */
151 : /* */
152 : /* Remove all the gml:id nodes. Doesn't check psRoot's siblings */
153 : /************************************************************************/
154 :
155 1690 : static void RemoveIDs(CPLXMLNode *psRoot)
156 :
157 : {
158 1690 : if (psRoot == nullptr)
159 0 : return;
160 :
161 1690 : CPLXMLNode *psChild = psRoot->psChild;
162 :
163 : // Check for id attribute.
164 3244 : while (psChild != nullptr && !(psChild->eType == CXT_Attribute &&
165 987 : EQUAL(psChild->pszValue, "gml:id")))
166 1554 : psChild = psChild->psNext;
167 1690 : CPLRemoveXMLChild(psRoot, psChild);
168 1690 : CPLDestroyXMLNode(psChild);
169 :
170 : // Search the child elements of psRoot.
171 3775 : for (psChild = psRoot->psChild; psChild != nullptr;
172 2085 : psChild = psChild->psNext)
173 2085 : if (psChild->eType == CXT_Element)
174 1377 : RemoveIDs(psChild);
175 : }
176 :
177 : /************************************************************************/
178 : /* TrimTree() */
179 : /* */
180 : /* Remove all nodes without a gml:id node in the descendants. */
181 : /* Returns TRUE if there is a gml:id node in the descendants. */
182 : /************************************************************************/
183 :
184 0 : static bool TrimTree(CPLXMLNode *psRoot)
185 :
186 : {
187 0 : if (psRoot == nullptr)
188 0 : return false;
189 :
190 0 : CPLXMLNode *psChild = psRoot->psChild;
191 :
192 : // Check for id attribute.
193 0 : while (psChild != nullptr && !(psChild->eType == CXT_Attribute &&
194 0 : EQUAL(psChild->pszValue, "gml:id")))
195 0 : psChild = psChild->psNext;
196 :
197 0 : if (psChild != nullptr)
198 0 : return true;
199 :
200 : // Search the child elements of psRoot.
201 0 : bool bReturn = false;
202 0 : for (psChild = psRoot->psChild; psChild != nullptr;)
203 : {
204 0 : CPLXMLNode *psNextChild = psChild->psNext;
205 0 : if (psChild->eType == CXT_Element)
206 : {
207 0 : const bool bRemove = TrimTree(psChild);
208 0 : if (bRemove)
209 : {
210 0 : bReturn = bRemove;
211 : }
212 : else
213 : {
214 : // Remove this child.
215 0 : CPLRemoveXMLChild(psRoot, psChild);
216 0 : CPLDestroyXMLNode(psChild);
217 : }
218 : }
219 :
220 0 : psChild = psNextChild;
221 : }
222 0 : return bReturn;
223 : }
224 :
225 : /************************************************************************/
226 : /* CorrectURLs() */
227 : /* */
228 : /* Processes the node and all its children recursively. Siblings of */
229 : /* psRoot are ignored. */
230 : /* - Replaces all every URL in URL#id pairs with pszURL. */
231 : /* - Leaves it alone if the paths are same or the URL is not relative. */
232 : /* - If it is relative, the path from pszURL is prepended. */
233 : /************************************************************************/
234 :
235 3490 : static void CorrectURLs(CPLXMLNode *psRoot, const char *pszURL)
236 :
237 : {
238 3490 : if (psRoot == nullptr || pszURL == nullptr)
239 0 : return;
240 3490 : if (pszURL[0] == '\0')
241 0 : return;
242 :
243 3490 : CPLXMLNode *psChild = psRoot->psChild;
244 :
245 : // Check for xlink:href attribute.
246 8449 : while (psChild != nullptr && !((psChild->eType == CXT_Attribute) &&
247 1552 : (EQUAL(psChild->pszValue, "xlink:href"))))
248 4959 : psChild = psChild->psNext;
249 :
250 3490 : if (psChild != nullptr &&
251 313 : !(strstr(psChild->psChild->pszValue, pszURL) ==
252 313 : psChild->psChild->pszValue &&
253 0 : psChild->psChild->pszValue[strlen(pszURL)] == '#'))
254 : {
255 : // href has a different url.
256 313 : if (psChild->psChild->pszValue[0] == '#')
257 : {
258 : // Empty URL: prepend the given URL.
259 313 : const size_t nLen = CPLStrnlen(pszURL, 1024) +
260 313 : CPLStrnlen(psChild->psChild->pszValue, 1024) +
261 313 : 1;
262 313 : char *pszNew = static_cast<char *>(CPLMalloc(nLen * sizeof(char)));
263 313 : CPLStrlcpy(pszNew, pszURL, nLen);
264 313 : CPLStrlcat(pszNew, psChild->psChild->pszValue, nLen);
265 313 : CPLSetXMLValue(psRoot, "#xlink:href", pszNew);
266 313 : CPLFree(pszNew);
267 : }
268 : else
269 : {
270 0 : size_t nPathLen = strlen(pszURL); // Used after for.
271 0 : for (; nPathLen > 0 && pszURL[nPathLen - 1] != '/' &&
272 0 : pszURL[nPathLen - 1] != '\\';
273 : nPathLen--)
274 : {
275 : }
276 :
277 0 : const char *pszDash = strchr(psChild->psChild->pszValue, '#');
278 0 : if (pszDash != nullptr &&
279 0 : strncmp(pszURL, psChild->psChild->pszValue, nPathLen) != 0)
280 : {
281 : // Different path.
282 0 : const int nURLLen =
283 0 : static_cast<int>(pszDash - psChild->psChild->pszValue);
284 : char *pszURLWithoutID = static_cast<char *>(
285 0 : CPLMalloc((nURLLen + 1) * sizeof(char)));
286 0 : strncpy(pszURLWithoutID, psChild->psChild->pszValue, nURLLen);
287 0 : pszURLWithoutID[nURLLen] = '\0';
288 :
289 0 : if (CPLIsFilenameRelative(pszURLWithoutID) &&
290 0 : strstr(pszURLWithoutID, ":") == nullptr)
291 : {
292 : // Relative URL: prepend the path of pszURL.
293 : const size_t nLen =
294 0 : nPathLen +
295 0 : CPLStrnlen(psChild->psChild->pszValue, 1024) + 1;
296 : char *pszNew =
297 0 : static_cast<char *>(CPLMalloc(nLen * sizeof(char)));
298 0 : for (size_t i = 0; i < nPathLen; i++)
299 0 : pszNew[i] = pszURL[i];
300 0 : pszNew[nPathLen] = '\0';
301 0 : CPLStrlcat(pszNew, psChild->psChild->pszValue, nLen);
302 0 : CPLSetXMLValue(psRoot, "#xlink:href", pszNew);
303 0 : CPLFree(pszNew);
304 : }
305 0 : CPLFree(pszURLWithoutID);
306 : }
307 : }
308 : }
309 :
310 : // Search the child elements of psRoot.
311 8762 : for (psChild = psRoot->psChild; psChild != nullptr;
312 5272 : psChild = psChild->psNext)
313 5272 : if (psChild->eType == CXT_Element)
314 3171 : CorrectURLs(psChild, pszURL);
315 : }
316 :
317 : /************************************************************************/
318 : /* FindTreeByURL() */
319 : /* */
320 : /* Find a doc tree that is located at pszURL. */
321 : /* If not present in ppapsRoot, it updates it and ppapszResourceHREF. */
322 : /************************************************************************/
323 :
324 313 : static CPLXMLNode *FindTreeByURL(CPLXMLNode ***ppapsRoot,
325 : char ***ppapszResourceHREF, const char *pszURL)
326 :
327 : {
328 313 : if (*ppapsRoot == nullptr || ppapszResourceHREF == nullptr)
329 0 : return nullptr;
330 :
331 : // If found in ppapszResourceHREF.
332 313 : const int i = CSLFindString(*ppapszResourceHREF, pszURL);
333 313 : if (i >= 0)
334 : {
335 : // Return corresponding psRoot.
336 313 : return (*ppapsRoot)[i];
337 : }
338 :
339 0 : CPLXMLNode *psSrcTree = nullptr;
340 0 : char *pszLocation = CPLStrdup(pszURL);
341 : // If it is part of filesystem.
342 0 : if (CPLCheckForFile(pszLocation, nullptr))
343 : {
344 : // Filesystem.
345 0 : psSrcTree = CPLParseXMLFile(pszURL);
346 : }
347 0 : else if (CPLHTTPEnabled())
348 : {
349 : // Web resource.
350 0 : CPLErrorReset();
351 0 : CPLHTTPResult *psResult = CPLHTTPFetch(pszURL, nullptr);
352 0 : if (psResult != nullptr)
353 : {
354 0 : if (psResult->nDataLen > 0 && CPLGetLastErrorNo() == 0)
355 0 : psSrcTree = CPLParseXMLString(
356 0 : reinterpret_cast<const char *>(psResult->pabyData));
357 0 : CPLHTTPDestroyResult(psResult);
358 : }
359 : }
360 :
361 : // Report error in case the resource cannot be retrieved.
362 0 : if (psSrcTree == nullptr)
363 0 : CPLError(CE_Failure, CPLE_NotSupported, "Could not access %s",
364 : pszLocation);
365 :
366 0 : CPLFree(pszLocation);
367 :
368 : /************************************************************************/
369 : /* In the external GML resource we will only need elements */
370 : /* identified by a "gml:id". So trim them. */
371 : /************************************************************************/
372 0 : CPLXMLNode *psSibling = psSrcTree;
373 0 : while (psSibling != nullptr)
374 : {
375 0 : TrimTree(psSibling);
376 0 : psSibling = psSibling->psNext;
377 : }
378 :
379 : // Update to lists.
380 0 : int nItems = CSLCount(*ppapszResourceHREF);
381 0 : *ppapszResourceHREF = CSLAddString(*ppapszResourceHREF, pszURL);
382 0 : *ppapsRoot = static_cast<CPLXMLNode **>(
383 0 : CPLRealloc(*ppapsRoot, (nItems + 2) * sizeof(CPLXMLNode *)));
384 0 : (*ppapsRoot)[nItems] = psSrcTree;
385 0 : (*ppapsRoot)[nItems + 1] = nullptr;
386 :
387 : // Return the tree.
388 0 : return (*ppapsRoot)[nItems];
389 : }
390 :
391 : /************************************************************************/
392 : /* ResolveTree() */
393 : /* Resolves the xlinks in a node and its siblings */
394 : /* If any error is encountered or any element is skipped(papszSkip): */
395 : /* If bStrict is TRUE, process is stopped and CE_Error is returned */
396 : /* If bStrict is FALSE, the process is continued but CE_Warning is */
397 : /* returned at the end. */
398 : /* If everything goes fine, CE_None is returned. */
399 : /************************************************************************/
400 :
401 3493 : static CPLErr Resolve(CPLXMLNode *psNode, CPLXMLNode ***ppapsRoot,
402 : char ***ppapszResourceHREF, char **papszSkip,
403 : const int bStrict, int nDepth)
404 :
405 : {
406 : // For each sibling.
407 3493 : CPLXMLNode *psSibling = nullptr;
408 3493 : CPLXMLNode *psResource = nullptr;
409 3493 : CPLXMLNode *psTarget = nullptr;
410 3493 : CPLErr eReturn = CE_None, eReturned;
411 :
412 8771 : for (psSibling = psNode; psSibling != nullptr;
413 5278 : psSibling = psSibling->psNext)
414 : {
415 5278 : if (psSibling->eType != CXT_Element)
416 1788 : continue;
417 :
418 3490 : CPLXMLNode *psChild = psSibling->psChild;
419 8449 : while (psChild != nullptr && !(psChild->eType == CXT_Attribute &&
420 1552 : EQUAL(psChild->pszValue, "xlink:href")))
421 4959 : psChild = psChild->psNext;
422 :
423 : // If a child has a "xlink:href" attribute.
424 3490 : if (psChild != nullptr && psChild->psChild != nullptr)
425 : {
426 313 : if (CSLFindString(papszSkip, psSibling->pszValue) >= 0)
427 : {
428 : // Skipping a specified element.
429 0 : eReturn = CE_Warning;
430 0 : continue;
431 : }
432 :
433 313 : const int nDepthCheck = 256;
434 313 : if (nDepth % nDepthCheck == 0)
435 : {
436 : // A way to track progress.
437 0 : CPLDebug("GML", "Resolving xlinks... (currently %s)",
438 0 : psChild->psChild->pszValue);
439 : }
440 :
441 626 : char **papszTokens = CSLTokenizeString2(
442 313 : psChild->psChild->pszValue, "#",
443 : CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES |
444 : CSLT_STRIPENDSPACES);
445 313 : if (CSLCount(papszTokens) != 2 || papszTokens[1][0] == '\0')
446 : {
447 0 : CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_NotSupported,
448 : "Error parsing the href %s.%s",
449 0 : psChild->psChild->pszValue,
450 : bStrict ? "" : " Skipping...");
451 0 : CSLDestroy(papszTokens);
452 0 : if (bStrict)
453 0 : return CE_Failure;
454 0 : eReturn = CE_Warning;
455 0 : continue;
456 : }
457 :
458 : // Look for the resource with that URL.
459 : psResource =
460 313 : FindTreeByURL(ppapsRoot, ppapszResourceHREF, papszTokens[0]);
461 313 : if (psResource == nullptr)
462 : {
463 0 : CSLDestroy(papszTokens);
464 0 : if (bStrict)
465 0 : return CE_Failure;
466 0 : eReturn = CE_Warning;
467 0 : continue;
468 : }
469 :
470 : // Look for the element with the ID.
471 313 : psTarget = FindElementByID(psResource, papszTokens[1]);
472 313 : if (psTarget != nullptr)
473 : {
474 : // Remove the xlink:href attribute.
475 313 : CPLRemoveXMLChild(psSibling, psChild);
476 313 : CPLDestroyXMLNode(psChild);
477 :
478 : // Make a copy of psTarget.
479 : CPLXMLNode *psCopy =
480 313 : CPLCreateXMLNode(nullptr, CXT_Element, psTarget->pszValue);
481 313 : psCopy->psChild = CPLCloneXMLTree(psTarget->psChild);
482 313 : RemoveIDs(psCopy);
483 : // Correct empty URLs in URL#id pairs.
484 313 : if (CPLStrnlen(papszTokens[0], 1) > 0)
485 : {
486 313 : CorrectURLs(psCopy, papszTokens[0]);
487 : }
488 313 : CPLAddXMLChild(psSibling, psCopy);
489 313 : CSLDestroy(papszTokens);
490 : }
491 : else
492 : {
493 : // Element not found.
494 0 : CSLDestroy(papszTokens);
495 0 : CPLError(bStrict ? CE_Failure : CE_Warning, CPLE_ObjectNull,
496 : "Couldn't find the element with id %s.",
497 0 : psChild->psChild->pszValue);
498 0 : if (bStrict)
499 0 : return CE_Failure;
500 0 : eReturn = CE_Warning;
501 : }
502 : }
503 :
504 : // Recurse with the first child.
505 3490 : eReturned = Resolve(psSibling->psChild, ppapsRoot, ppapszResourceHREF,
506 : papszSkip, bStrict, nDepth + 1);
507 :
508 3490 : if (eReturned == CE_Failure)
509 0 : return CE_Failure;
510 :
511 3490 : if (eReturned == CE_Warning)
512 0 : eReturn = CE_Warning;
513 : }
514 3493 : return eReturn;
515 : }
516 :
517 : /************************************************************************/
518 : /* ResolveXlinks() */
519 : /* Returns TRUE for success */
520 : /* - Returns CE_None for success, */
521 : /* CE_Warning if the resolved file is saved to a different file or */
522 : /* CE_Failure if it could not be saved at all. */
523 : /* - m_pszFilename will be set to the file the resolved file was */
524 : /* saved to. */
525 : /************************************************************************/
526 :
527 3 : bool GMLReader::ResolveXlinks(const char *pszFile, bool *pbOutIsTempFile,
528 : char **papszSkip, const bool bStrict)
529 :
530 : {
531 3 : *pbOutIsTempFile = false;
532 :
533 : // Check if the original source file is set.
534 3 : if (m_pszFilename == nullptr)
535 : {
536 0 : CPLError(CE_Failure, CPLE_NotSupported,
537 : "GML source file needs to be set first with "
538 : "GMLReader::SetSourceFile().");
539 0 : return false;
540 : }
541 :
542 : /* -------------------------------------------------------------------- */
543 : /* Load the raw XML file into a XML Node tree. */
544 : /* -------------------------------------------------------------------- */
545 : CPLXMLNode **papsSrcTree =
546 3 : static_cast<CPLXMLNode **>(CPLCalloc(2, sizeof(CPLXMLNode *)));
547 3 : papsSrcTree[0] = CPLParseXMLFile(m_pszFilename);
548 :
549 3 : if (papsSrcTree[0] == nullptr)
550 : {
551 0 : CPLFree(papsSrcTree);
552 0 : return false;
553 : }
554 :
555 : // Make all the URLs absolute.
556 3 : CPLXMLNode *psSibling = nullptr;
557 9 : for (psSibling = papsSrcTree[0]; psSibling != nullptr;
558 6 : psSibling = psSibling->psNext)
559 6 : CorrectURLs(psSibling, m_pszFilename);
560 :
561 : // Setup resource data structure.
562 3 : char **papszResourceHREF = nullptr;
563 : // "" is the href of the original source file.
564 3 : papszResourceHREF = CSLAddString(papszResourceHREF, m_pszFilename);
565 :
566 : // Call resolver.
567 3 : const CPLErr eReturned = Resolve(papsSrcTree[0], &papsSrcTree,
568 : &papszResourceHREF, papszSkip, bStrict, 0);
569 :
570 3 : bool bReturn = true;
571 3 : if (eReturned != CE_Failure)
572 : {
573 3 : char *pszTmpName = nullptr;
574 3 : bool bTryWithTempFile = false;
575 3 : if (STARTS_WITH_CI(pszFile, "/vsitar/") ||
576 3 : STARTS_WITH_CI(pszFile, "/vsigzip/") ||
577 3 : STARTS_WITH_CI(pszFile, "/vsizip/") ||
578 3 : STARTS_WITH_CI(pszFile, "/vsicurl"))
579 : {
580 0 : bTryWithTempFile = true;
581 : }
582 3 : else if (!CPLSerializeXMLTreeToFile(papsSrcTree[0], pszFile))
583 : {
584 0 : CPLError(CE_Failure, CPLE_FileIO,
585 : "Cannot serialize resolved file %s to %s.", m_pszFilename,
586 : pszFile);
587 0 : bTryWithTempFile = true;
588 : }
589 :
590 3 : if (bTryWithTempFile)
591 : {
592 0 : pszTmpName = CPLStrdup(CPLGenerateTempFilename("ResolvedGML"));
593 0 : if (!CPLSerializeXMLTreeToFile(papsSrcTree[0], pszTmpName))
594 : {
595 0 : CPLError(CE_Failure, CPLE_FileIO,
596 : "Cannot serialize resolved file %s to %s either.",
597 : m_pszFilename, pszTmpName);
598 0 : CPLFree(pszTmpName);
599 0 : bReturn = false;
600 : }
601 : else
602 : {
603 : // Set the source file to the resolved file.
604 0 : CPLFree(m_pszFilename);
605 0 : m_pszFilename = pszTmpName;
606 0 : *pbOutIsTempFile = true;
607 : }
608 : }
609 : else
610 : {
611 : // Set the source file to the resolved file.
612 3 : CPLFree(m_pszFilename);
613 3 : m_pszFilename = CPLStrdup(pszFile);
614 : }
615 : }
616 : else
617 : {
618 0 : bReturn = false;
619 : }
620 :
621 3 : const int nItems = CSLCount(papszResourceHREF);
622 3 : CSLDestroy(papszResourceHREF);
623 6 : for (int i = 0; i < nItems; i++)
624 3 : CPLDestroyXMLNode(papsSrcTree[i]);
625 3 : CPLFree(papsSrcTree);
626 :
627 3 : return bReturn;
628 : }
|