1 : /******************************************************************************
2 : * $Id: resolvexlinks.cpp 22205 2011-04-18 21:17:30Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLReader::ResolveXlinks() method.
6 : * Author: Chaitanya kumar CH, chaitanya@osgeo.in
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Chaitanya kumar CH
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 "gmlreader.h"
31 : #include "cpl_error.h"
32 :
33 : CPL_CVSID("$Id: resolvexlinks.cpp 22205 2011-04-18 21:17:30Z rouault $");
34 :
35 : #include "gmlreaderp.h"
36 : #include "cpl_conv.h"
37 : #include "cpl_string.h"
38 : #include "cpl_http.h"
39 :
40 : #include <stack>
41 :
42 : /************************************************************************/
43 : /* GetID() */
44 : /* */
45 : /* Returns the reference to the gml:id of psNode. NULL if not */
46 : /* found. */
47 : /************************************************************************/
48 :
49 863246 : static const char* GetID( CPLXMLNode * psNode )
50 :
51 : {
52 863246 : if( psNode == NULL )
53 0 : return NULL;
54 :
55 : CPLXMLNode *psChild;
56 2236863 : for( psChild = psNode->psChild; psChild != NULL; psChild = psChild->psNext )
57 : {
58 1470253 : if( psChild->eType == CXT_Attribute
59 : && EQUAL(psChild->pszValue, "gml:id") )
60 : {
61 96636 : return psChild->psChild->pszValue;
62 : }
63 : }
64 766610 : return NULL;
65 : }
66 :
67 : /************************************************************************/
68 : /* CompareNodeIDs() */
69 : /* */
70 : /* Compares two nodes by their IDs */
71 : /************************************************************************/
72 :
73 : /*static int CompareNodeIDs( CPLXMLNode * psNode1, CPLXMLNode * psNode2 )
74 :
75 : {
76 : if( psNode2 == NULL )
77 : return TRUE;
78 :
79 : if( psNode1 == NULL )
80 : return FALSE;
81 :
82 : return ( strcmp( GetID(psNode2), GetID(psNode1) ) > 0 );
83 : }*/
84 :
85 : /************************************************************************/
86 : /* BuildIDIndex() */
87 : /* */
88 : /* Returns an array of nodes sorted by their gml:id strings */
89 : /* XXX: This method can be used to build an array of pointers to */
90 : /* nodes sorted by their id values. */
91 : /************************************************************************/
92 : /*
93 : static std::vector<CPLXMLNode*> BuildIDIndex( CPLXMLNode* psNode,
94 : std::vector<CPLXMLNode*> &apsNode )
95 :
96 : {
97 : CPLXMLNode *psSibling;
98 : for( psSibling = psNode; psSibling != NULL; psSibling = psSibling->psNext )
99 : {
100 : if( GetID( psSibling ) != NULL )
101 : apsNode.push_back( psSibling );
102 : BuildIDIndex( psNode->psChild, apsNode );
103 : }
104 : return NULL;
105 : }*/
106 :
107 : /************************************************************************/
108 : /* FindElementByID() */
109 : /* */
110 : /* Find a node with the indicated "gml:id" in the node tree and */
111 : /* it's siblings. */
112 : /************************************************************************/
113 :
114 820274 : static CPLXMLNode *FindElementByID( CPLXMLNode * psRoot,
115 : const char *pszID )
116 :
117 : {
118 820274 : if( psRoot == NULL )
119 26638 : return NULL;
120 :
121 793636 : CPLXMLNode *psSibling, *psReturn = NULL;
122 :
123 : // check for id attribute
124 2231140 : for( psSibling = psRoot; psSibling != NULL; psSibling = psSibling->psNext)
125 : {
126 1438291 : if( psSibling->eType == CXT_Element )
127 : {
128 : // check that sibling for id value
129 863246 : const char* pszIDOfSibling = GetID( psSibling );
130 863246 : if( pszIDOfSibling != NULL && EQUAL( pszIDOfSibling, pszID) )
131 787 : return psSibling;
132 : }
133 : }
134 :
135 : // search the child elements of all the psRoot's siblings
136 2181833 : for( psSibling = psRoot; psSibling != NULL; psSibling = psSibling->psNext)
137 : {
138 1394291 : if( psSibling->eType == CXT_Element )
139 : {
140 819411 : psReturn = FindElementByID( psSibling->psChild, pszID );
141 819411 : if( psReturn != NULL )
142 5307 : return psReturn;
143 : }
144 : }
145 787542 : return NULL;
146 : }
147 :
148 : /************************************************************************/
149 : /* RemoveIDs() */
150 : /* */
151 : /* Remove all the gml:id nodes. Doesn't check psRoot's siblings */
152 : /************************************************************************/
153 :
154 3902 : static void RemoveIDs( CPLXMLNode * psRoot )
155 :
156 : {
157 3902 : if( psRoot == NULL )
158 0 : return;
159 :
160 3902 : CPLXMLNode *psChild = psRoot->psChild;
161 :
162 : // check for id attribute
163 11646 : while( psChild != NULL && !( psChild->eType == CXT_Attribute && EQUAL(psChild->pszValue, "gml:id")))
164 3842 : psChild = psChild->psNext;
165 3902 : CPLRemoveXMLChild( psRoot, psChild );
166 3902 : CPLDestroyXMLNode( psChild );
167 :
168 : // search the child elements of psRoot
169 9133 : for( psChild = psRoot->psChild; psChild != NULL; psChild = psChild->psNext)
170 5231 : if( psChild->eType == CXT_Element )
171 3115 : RemoveIDs( psChild );
172 : }
173 :
174 : /************************************************************************/
175 : /* TrimTree() */
176 : /* */
177 : /* Remove all nodes without a gml:id node in the descendents. */
178 : /* Returns TRUE if there is a gml:id node in the descendents. */
179 : /************************************************************************/
180 :
181 9170 : static int TrimTree( CPLXMLNode * psRoot )
182 :
183 : {
184 9170 : if( psRoot == NULL )
185 0 : return FALSE;
186 :
187 9170 : CPLXMLNode *psChild = psRoot->psChild;
188 :
189 : // check for id attribute
190 32930 : while( psChild != NULL && !( psChild->eType == CXT_Attribute && EQUAL(psChild->pszValue, "gml:id")))
191 14590 : psChild = psChild->psNext;
192 :
193 9170 : if( psChild != NULL )
194 845 : return TRUE;
195 :
196 : // search the child elements of psRoot
197 8325 : int bReturn = FALSE, bRemove;
198 31240 : for( psChild = psRoot->psChild; psChild != NULL;)
199 : {
200 14590 : CPLXMLNode* psNextChild = psChild->psNext;
201 14590 : if( psChild->eType == CXT_Element )
202 : {
203 9160 : bRemove = TrimTree( psChild );
204 9160 : if( bRemove )
205 : {
206 3855 : bReturn = bRemove;
207 : }
208 : else
209 : {
210 : //remove this child
211 5305 : CPLRemoveXMLChild( psRoot, psChild );
212 5305 : CPLDestroyXMLNode( psChild );
213 : }
214 : }
215 :
216 14590 : psChild = psNextChild;
217 : }
218 8325 : return bReturn;
219 : }
220 :
221 : /************************************************************************/
222 : /* CorrectURLs() */
223 : /* */
224 : /* Processes the node and all it's children recursively. Siblings of */
225 : /* psRoot are ignored. */
226 : /* - Replaces all every URL in URL#id pairs with pszURL. */
227 : /* - Leaves it alone if the paths are same or the URL is not relative. */
228 : /* - If it is relative, the path from pszURL is prepended. */
229 : /************************************************************************/
230 :
231 11334 : static void CorrectURLs( CPLXMLNode * psRoot, const char *pszURL )
232 :
233 : {
234 11334 : if( psRoot == NULL || pszURL == NULL )
235 0 : return;
236 11334 : if( pszURL[0] == '\0' )
237 0 : return;
238 :
239 11334 : CPLXMLNode *psChild = psRoot->psChild;
240 :
241 : // check for xlink:href attribute
242 39778 : while( psChild != NULL && !( ( psChild->eType == CXT_Attribute ) &&
243 : ( EQUAL(psChild->pszValue, "xlink:href") )) )
244 17110 : psChild = psChild->psNext;
245 :
246 11424 : if( psChild != NULL &&
247 : !( strstr( psChild->psChild->pszValue, pszURL ) == psChild->psChild->pszValue
248 90 : && psChild->psChild->pszValue[strlen(pszURL)] == '#' ) )
249 : {
250 : //href has a different url
251 : size_t nLen;
252 : char *pszNew;
253 1097 : if( psChild->psChild->pszValue[0] == '#' )
254 : {
255 : //empty URL: prepend the given URL
256 : nLen = CPLStrnlen( pszURL, 1024 ) +
257 871 : CPLStrnlen( psChild->psChild->pszValue, 1024 ) + 1;
258 871 : pszNew = (char *)CPLMalloc( nLen * sizeof(char));
259 871 : CPLStrlcpy( pszNew, pszURL, nLen );
260 871 : CPLStrlcat( pszNew, psChild->psChild->pszValue, nLen );
261 871 : CPLSetXMLValue( psRoot, "#xlink:href", pszNew );
262 871 : CPLFree( pszNew );
263 : }
264 : else
265 : {
266 : size_t nPathLen;
267 4972 : for( nPathLen = strlen(pszURL);
268 2486 : nPathLen > 0 && pszURL[nPathLen - 1] != '/'
269 2260 : && pszURL[nPathLen - 1] != '\\';
270 : nPathLen--);
271 :
272 226 : if( strncmp( pszURL, psChild->psChild->pszValue, nPathLen ) != 0 )
273 : {
274 : //different path
275 : int nURLLen = strchr( psChild->psChild->pszValue, '#' ) -
276 218 : psChild->psChild->pszValue;
277 218 : char *pszURLWithoutID = (char *)CPLMalloc( (nURLLen+1) * sizeof(char));
278 218 : strncpy( pszURLWithoutID, psChild->psChild->pszValue, nURLLen );
279 218 : pszURLWithoutID[nURLLen] = '\0';
280 :
281 218 : if( CPLIsFilenameRelative( pszURLWithoutID ) &&
282 : strstr( pszURLWithoutID, ":" ) == NULL )
283 : {
284 : //relative URL: prepend the path of pszURL
285 : nLen = nPathLen +
286 134 : CPLStrnlen( psChild->psChild->pszValue, 1024 ) + 1;
287 134 : pszNew = (char *)CPLMalloc( nLen * sizeof(char));
288 : size_t i;
289 2914 : for( i = 0; i < nPathLen; i++ )
290 2780 : pszNew[i] = pszURL[i];
291 134 : pszNew[nPathLen] = '\0';
292 134 : CPLStrlcat( pszNew, psChild->psChild->pszValue, nLen );
293 134 : CPLSetXMLValue( psRoot, "#xlink:href", pszNew );
294 134 : CPLFree( pszNew );
295 : }
296 218 : CPLFree( pszURLWithoutID );
297 : }
298 : }
299 : }
300 :
301 : // search the child elements of psRoot
302 30140 : for( psChild = psRoot->psChild; psChild != NULL; psChild = psChild->psNext)
303 18806 : if( psChild->eType == CXT_Element )
304 10537 : CorrectURLs( psChild, pszURL );
305 : }
306 :
307 : /************************************************************************/
308 : /* FindTreeByURL() */
309 : /* */
310 : /* Find a doc tree that is located at pszURL. */
311 : /* If not present in ppapsRoot, it updates it and ppapszResourceHREF. */
312 : /************************************************************************/
313 :
314 863 : static CPLXMLNode *FindTreeByURL( CPLXMLNode *** ppapsRoot,
315 : char *** ppapszResourceHREF,
316 : const char *pszURL )
317 :
318 : {
319 863 : if( *ppapsRoot == NULL || ppapszResourceHREF == NULL )
320 0 : return NULL;
321 :
322 : //if found in ppapszResourceHREF
323 : int i, nItems;
324 : char *pszLocation;
325 863 : if( ( i = CSLFindString( *ppapszResourceHREF, pszURL )) >= 0 )
326 : {
327 : //return corresponding psRoot
328 858 : return (*ppapsRoot)[i];
329 : }
330 : else
331 : {
332 5 : CPLXMLNode *psSrcTree = NULL, *psSibling;
333 5 : pszLocation = CPLStrdup( pszURL );
334 : //if it is part of filesystem
335 5 : if( CPLCheckForFile( pszLocation, NULL) )
336 : {//filesystem
337 2 : psSrcTree = CPLParseXMLFile( pszURL );
338 : }
339 3 : else if( CPLHTTPEnabled() )
340 : {//web resource
341 3 : CPLErrorReset();
342 3 : CPLHTTPResult *psResult = CPLHTTPFetch( pszURL, NULL );
343 3 : if( psResult != NULL )
344 : {
345 3 : if( psResult->nDataLen > 0 && CPLGetLastErrorNo() == 0)
346 3 : psSrcTree = CPLParseXMLString( (const char*)psResult->pabyData );
347 3 : CPLHTTPDestroyResult( psResult );
348 : }
349 : }
350 :
351 : //report error in case the resource cannot be retrieved.
352 5 : if( psSrcTree == NULL )
353 : CPLError( CE_Failure, CPLE_NotSupported,
354 0 : "Could not access %s", pszLocation );
355 :
356 5 : CPLFree( pszLocation );
357 :
358 : /************************************************************************/
359 : /* In the external GML resource we will only need elements */
360 : /* identified by a "gml:id". So trim them. */
361 : /************************************************************************/
362 5 : psSibling = psSrcTree;
363 20 : while( psSibling != NULL )
364 : {
365 10 : TrimTree( psSibling );
366 10 : psSibling = psSibling->psNext;
367 : }
368 :
369 : //update to lists
370 5 : nItems = CSLCount(*ppapszResourceHREF);
371 5 : *ppapszResourceHREF = CSLAddString( *ppapszResourceHREF, pszURL );
372 : *ppapsRoot = (CPLXMLNode**)CPLRealloc(*ppapsRoot,
373 5 : (nItems+2)*sizeof(CPLXMLNode*));
374 5 : (*ppapsRoot)[nItems] = psSrcTree;
375 5 : (*ppapsRoot)[nItems+1] = NULL;
376 :
377 : //return the tree
378 5 : return (*ppapsRoot)[nItems];
379 : }
380 : }
381 :
382 : /************************************************************************/
383 : /* ResolveTree() */
384 : /* Resolves the xlinks in a node and it's siblings */
385 : /* If any error is encountered or any element is skipped(papszSkip): */
386 : /* If bStrict is TRUE, process is stopped and CE_Error is returned */
387 : /* If bStrict is FALSE, the process is continued but CE_Warning is */
388 : /* returned at the end. */
389 : /* If everything goes fine, CE_None is returned. */
390 : /************************************************************************/
391 :
392 11015 : static CPLErr Resolve( CPLXMLNode * psNode,
393 : CPLXMLNode *** ppapsRoot,
394 : char *** ppapszResourceHREF,
395 : char ** papszSkip,
396 : const int bStrict )
397 :
398 : {
399 : //for each sibling
400 11015 : CPLXMLNode *psSibling = NULL;
401 11015 : CPLXMLNode *psResource = NULL;
402 11015 : CPLXMLNode *psTarget = NULL;
403 11015 : CPLErr eReturn = CE_None, eReturned;
404 :
405 29365 : for( psSibling = psNode; psSibling != NULL; psSibling = psSibling->psNext )
406 : {
407 18350 : if( psSibling->eType != CXT_Element )
408 7016 : continue;
409 :
410 11334 : CPLXMLNode *psChild = psSibling->psChild;
411 39778 : while( psChild != NULL &&
412 : !( psChild->eType == CXT_Attribute &&
413 : EQUAL( psChild->pszValue, "xlink:href" ) ) )
414 17110 : psChild = psChild->psNext;
415 :
416 : //if a child has a "xlink:href" attribute
417 11334 : if( psChild != NULL && psChild->psChild != NULL )
418 : {
419 1187 : if( CSLFindString( papszSkip, psSibling->pszValue ) >= 0 )
420 : {//Skipping a specified element
421 324 : eReturn = CE_Warning;
422 324 : continue;
423 : }
424 :
425 : static int i = 0;
426 863 : if( i-- == 0 )
427 : {//a way to track progress
428 4 : i = 256;
429 : CPLDebug( "GML",
430 : "Resolving xlinks... (currently %s)",
431 4 : psChild->psChild->pszValue );
432 : }
433 :
434 : char **papszTokens;
435 : papszTokens = CSLTokenizeString2( psChild->psChild->pszValue, "#",
436 : CSLT_ALLOWEMPTYTOKENS |
437 : CSLT_STRIPLEADSPACES |
438 863 : CSLT_STRIPENDSPACES );
439 863 : if( CSLCount( papszTokens ) != 2 || strlen(papszTokens[1]) <= 0 )
440 : {
441 : CPLError( bStrict ? CE_Failure : CE_Warning,
442 : CPLE_NotSupported,
443 : "Error parsing the href %s.%s",
444 : psChild->psChild->pszValue,
445 0 : bStrict ? "" : " Skipping..." );
446 0 : CSLDestroy( papszTokens );
447 0 : if( bStrict )
448 0 : return CE_Failure;
449 0 : eReturn = CE_Warning;
450 0 : continue;
451 : }
452 :
453 : //look for the resource with that URL
454 : psResource = FindTreeByURL( ppapsRoot,
455 : ppapszResourceHREF,
456 863 : papszTokens[0] );
457 863 : if( psResource == NULL )
458 : {
459 0 : CSLDestroy( papszTokens );
460 0 : if( bStrict )
461 0 : return CE_Failure;
462 0 : eReturn = CE_Warning;
463 0 : continue;
464 : }
465 :
466 : //look for the element with the ID
467 863 : psTarget = FindElementByID( psResource, papszTokens[1] );
468 863 : if( psTarget != NULL )
469 : {
470 : //remove the xlink:href attribute
471 787 : CPLRemoveXMLChild( psSibling, psChild );
472 787 : CPLDestroyXMLNode( psChild );
473 :
474 : //make a copy of psTarget
475 : CPLXMLNode *psCopy = CPLCreateXMLNode( NULL,
476 : CXT_Element,
477 787 : psTarget->pszValue );
478 787 : psCopy->psChild = CPLCloneXMLTree( psTarget->psChild );
479 787 : RemoveIDs( psCopy );
480 : //correct empty URLs in URL#id pairs
481 787 : if( CPLStrnlen( papszTokens[0], 1 ) > 0 )
482 : {
483 787 : CorrectURLs( psCopy, papszTokens[0] );
484 : }
485 787 : CPLAddXMLChild( psSibling, psCopy );
486 787 : CSLDestroy( papszTokens );
487 : }
488 : else
489 : {
490 : //element not found
491 76 : CSLDestroy( papszTokens );
492 : CPLError( bStrict ? CE_Failure : CE_Warning,
493 : CPLE_ObjectNull,
494 : "Couldn't find the element with id %s.",
495 76 : psChild->psChild->pszValue );
496 76 : if( bStrict )
497 0 : return CE_Failure;
498 76 : eReturn = CE_Warning;
499 : }
500 : }
501 :
502 : //Recurse with the first child
503 : eReturned=Resolve( psSibling->psChild,
504 : ppapsRoot,
505 : ppapszResourceHREF,
506 : papszSkip,
507 11010 : bStrict );
508 :
509 11010 : if( eReturned == CE_Failure )
510 0 : return CE_Failure;
511 :
512 11010 : if( eReturned == CE_Warning )
513 1139 : eReturn = CE_Warning;
514 : }
515 11015 : return eReturn;
516 : }
517 :
518 : /************************************************************************/
519 : /* ResolveXlinks() */
520 : /* Returns TRUE for success */
521 : /* - Returns CE_None for success, */
522 : /* CE_Warning if the resolved file is saved to a different file or */
523 : /* CE_Failure if it could not be saved at all. */
524 : /* - m_pszFilename will be set to the file the resolved file was */
525 : /* saved to. */
526 : /************************************************************************/
527 :
528 5 : int GMLReader::ResolveXlinks( const char *pszFile,
529 : int* pbOutIsTempFile,
530 : char **papszSkip,
531 : const int bStrict)
532 :
533 : {
534 5 : *pbOutIsTempFile = FALSE;
535 :
536 : // Check if the original source file is set.
537 5 : if( m_pszFilename == NULL )
538 : {
539 : CPLError( CE_Failure, CPLE_NotSupported,
540 : "GML source file needs to be set first with "
541 0 : "GMLReader::SetSourceFile()." );
542 0 : return FALSE;
543 : }
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Load the raw XML file into a XML Node tree. */
547 : /* -------------------------------------------------------------------- */
548 : CPLXMLNode **papsSrcTree;
549 5 : papsSrcTree = (CPLXMLNode **)CPLCalloc( 2, sizeof(CPLXMLNode *));
550 5 : papsSrcTree[0] = CPLParseXMLFile( m_pszFilename );
551 :
552 5 : if( papsSrcTree[0] == NULL )
553 : {
554 0 : CPLFree(papsSrcTree);
555 0 : return FALSE;
556 : }
557 :
558 : //make all the URLs absolute
559 5 : CPLXMLNode *psSibling = NULL;
560 15 : for( psSibling = papsSrcTree[0]; psSibling != NULL; psSibling = psSibling->psNext )
561 10 : CorrectURLs( psSibling, m_pszFilename );
562 :
563 : //setup resource data structure
564 5 : char **papszResourceHREF = NULL;
565 : // "" is the href of the original source file
566 5 : papszResourceHREF = CSLAddString( papszResourceHREF, m_pszFilename );
567 :
568 : //call resolver
569 5 : CPLErr eReturned = CE_None;
570 5 : eReturned = Resolve( papsSrcTree[0], &papsSrcTree, &papszResourceHREF, papszSkip, bStrict );
571 :
572 5 : int bReturn = TRUE;
573 5 : if( eReturned != CE_Failure )
574 : {
575 5 : char *pszTmpName = NULL;
576 5 : int bTryWithTempFile = FALSE;
577 5 : if( EQUALN(pszFile, "/vsitar/", strlen("/vsitar/")) ||
578 : EQUALN(pszFile, "/vsigzip/", strlen("/vsigzip/")) ||
579 : EQUALN(pszFile, "/vsizip/", strlen("/vsizip/")) )
580 : {
581 0 : bTryWithTempFile = TRUE;
582 : }
583 5 : else if( !CPLSerializeXMLTreeToFile( papsSrcTree[0], pszFile ) )
584 : {
585 : CPLError( CE_Failure, CPLE_FileIO,
586 : "Cannot serialize resolved file %s to %s.",
587 0 : m_pszFilename, pszFile );
588 0 : bTryWithTempFile = TRUE;
589 : }
590 :
591 5 : if (bTryWithTempFile)
592 : {
593 0 : pszTmpName = CPLStrdup( CPLGenerateTempFilename( "ResolvedGML" ) );
594 0 : if( !CPLSerializeXMLTreeToFile( papsSrcTree[0], pszTmpName ) )
595 : {
596 : CPLError( CE_Failure, CPLE_FileIO,
597 : "Cannot serialize resolved file %s to %s either.",
598 0 : m_pszFilename, pszTmpName );
599 0 : CPLFree( pszTmpName );
600 0 : bReturn = FALSE;
601 : }
602 : else
603 : {
604 : //set the source file to the resolved file
605 0 : CPLFree( m_pszFilename );
606 0 : m_pszFilename = pszTmpName;
607 0 : *pbOutIsTempFile = TRUE;
608 : }
609 : }
610 : else
611 : {
612 : //set the source file to the resolved file
613 5 : CPLFree( m_pszFilename );
614 5 : m_pszFilename = CPLStrdup( pszFile );
615 : }
616 : }
617 : else
618 : {
619 0 : bReturn = FALSE;
620 : }
621 :
622 5 : int nItems = CSLCount( papszResourceHREF );
623 5 : CSLDestroy( papszResourceHREF );
624 20 : while( nItems > 0 )
625 10 : CPLDestroyXMLNode( papsSrcTree[--nItems] );
626 5 : CPLFree( papsSrcTree );
627 :
628 5 : return bReturn;
629 : }
|