1 : /******************************************************************************
2 : * $Id: gmlreader.cpp 23566 2011-12-13 20:51:04Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLReader class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam
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 : #include "cpl_string.h"
33 : #include "gmlutils.h"
34 : #include "gmlreaderp.h"
35 : #include "cpl_conv.h"
36 : #include <map>
37 :
38 : #define SUPPORT_GEOMETRY
39 :
40 : #ifdef SUPPORT_GEOMETRY
41 : # include "ogr_geometry.h"
42 : #endif
43 :
44 : /************************************************************************/
45 : /* ~IGMLReader() */
46 : /************************************************************************/
47 :
48 72 : IGMLReader::~IGMLReader()
49 :
50 : {
51 72 : }
52 :
53 : /************************************************************************/
54 : /* ==================================================================== */
55 : /* No XERCES or EXPAT Library */
56 : /* ==================================================================== */
57 : /************************************************************************/
58 : #if !defined(HAVE_XERCES) && !defined(HAVE_EXPAT)
59 :
60 : /************************************************************************/
61 : /* CreateGMLReader() */
62 : /************************************************************************/
63 :
64 : IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
65 : int bInvertAxisOrderIfLatLong,
66 : int bConsiderEPSGAsURN,
67 : int bGetSecondaryGeometryOption)
68 :
69 : {
70 : CPLError( CE_Failure, CPLE_AppDefined,
71 : "Unable to create Xerces C++ or Expat based GML reader, Xerces or Expat support\n"
72 : "not configured into GDAL/OGR." );
73 : return NULL;
74 : }
75 :
76 : /************************************************************************/
77 : /* ==================================================================== */
78 : /* With XERCES or EXPAT Library */
79 : /* ==================================================================== */
80 : /************************************************************************/
81 : #else /* defined(HAVE_XERCES) || defined(HAVE_EXPAT) */
82 :
83 : /************************************************************************/
84 : /* CreateGMLReader() */
85 : /************************************************************************/
86 :
87 67 : IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
88 : int bInvertAxisOrderIfLatLong,
89 : int bConsiderEPSGAsURN,
90 : int bGetSecondaryGeometryOption)
91 :
92 : {
93 : return new GMLReader(bUseExpatParserPreferably,
94 : bInvertAxisOrderIfLatLong,
95 : bConsiderEPSGAsURN,
96 67 : bGetSecondaryGeometryOption);
97 : }
98 :
99 : #endif
100 :
101 : int GMLReader::m_bXercesInitialized = FALSE;
102 : int GMLReader::m_nInstanceCount = 0;
103 :
104 : /************************************************************************/
105 : /* GMLReader() */
106 : /************************************************************************/
107 :
108 67 : GMLReader::GMLReader(int bUseExpatParserPreferably,
109 : int bInvertAxisOrderIfLatLong,
110 : int bConsiderEPSGAsURN,
111 67 : int bGetSecondaryGeometryOption)
112 :
113 : {
114 : #ifndef HAVE_XERCES
115 : bUseExpatReader = TRUE;
116 : #else
117 67 : bUseExpatReader = FALSE;
118 : #ifdef HAVE_EXPAT
119 67 : if(bUseExpatParserPreferably)
120 67 : bUseExpatReader = TRUE;
121 : #endif
122 : #endif
123 :
124 : #if defined(HAVE_EXPAT) && defined(HAVE_XERCES)
125 67 : if (bUseExpatReader)
126 67 : CPLDebug("GML", "Using Expat reader");
127 : else
128 0 : CPLDebug("GML", "Using Xerces reader");
129 : #endif
130 :
131 67 : m_nInstanceCount++;
132 67 : m_nClassCount = 0;
133 67 : m_papoClass = NULL;
134 :
135 67 : m_bClassListLocked = FALSE;
136 :
137 67 : m_poGMLHandler = NULL;
138 : #ifdef HAVE_XERCES
139 67 : m_poSAXReader = NULL;
140 67 : m_poCompleteFeature = NULL;
141 67 : m_GMLInputSource = NULL;
142 67 : m_bEOF = FALSE;
143 : #endif
144 : #ifdef HAVE_EXPAT
145 67 : oParser = NULL;
146 67 : ppoFeatureTab = NULL;
147 67 : nFeatureTabIndex = 0;
148 67 : nFeatureTabLength = 0;
149 67 : nFeatureTabAlloc = 0;
150 67 : pabyBuf = NULL;
151 : #endif
152 67 : fpGML = NULL;
153 67 : m_bReadStarted = FALSE;
154 :
155 67 : m_poState = NULL;
156 67 : m_poRecycledState = NULL;
157 :
158 67 : m_pszFilename = NULL;
159 :
160 67 : m_bStopParsing = FALSE;
161 :
162 : /* A bit experimental. Not publicly advertized. See commented doc in drv_gml.html */
163 67 : m_bFetchAllGeometries = CSLTestBoolean(CPLGetConfigOption("GML_FETCH_ALL_GEOMETRIES", "NO"));
164 :
165 67 : m_bInvertAxisOrderIfLatLong = bInvertAxisOrderIfLatLong;
166 67 : m_bConsiderEPSGAsURN = bConsiderEPSGAsURN;
167 67 : m_bGetSecondaryGeometryOption = bGetSecondaryGeometryOption;
168 :
169 67 : m_pszGlobalSRSName = NULL;
170 67 : m_bCanUseGlobalSRSName = FALSE;
171 :
172 67 : m_pszFilteredClassName = NULL;
173 :
174 67 : m_bSequentialLayers = -1;
175 67 : }
176 :
177 : /************************************************************************/
178 : /* ~GMLReader() */
179 : /************************************************************************/
180 :
181 67 : GMLReader::~GMLReader()
182 :
183 : {
184 67 : ClearClasses();
185 :
186 67 : CPLFree( m_pszFilename );
187 :
188 67 : CleanupParser();
189 :
190 67 : delete m_poRecycledState;
191 :
192 67 : --m_nInstanceCount;
193 : #ifdef HAVE_XERCES
194 67 : if( m_nInstanceCount == 0 && m_bXercesInitialized )
195 : {
196 0 : XMLPlatformUtils::Terminate();
197 0 : m_bXercesInitialized = FALSE;
198 : }
199 : #endif
200 : #ifdef HAVE_EXPAT
201 67 : CPLFree(pabyBuf);
202 : #endif
203 :
204 67 : if (fpGML)
205 57 : VSIFCloseL(fpGML);
206 67 : fpGML = NULL;
207 :
208 67 : CPLFree(m_pszGlobalSRSName);
209 :
210 67 : CPLFree(m_pszFilteredClassName);
211 67 : }
212 :
213 : /************************************************************************/
214 : /* SetSourceFile() */
215 : /************************************************************************/
216 :
217 69 : void GMLReader::SetSourceFile( const char *pszFilename )
218 :
219 : {
220 69 : CPLFree( m_pszFilename );
221 69 : m_pszFilename = CPLStrdup( pszFilename );
222 69 : }
223 :
224 : /************************************************************************/
225 : /* GetSourceFileName() */
226 : /************************************************************************/
227 :
228 0 : const char* GMLReader::GetSourceFileName()
229 :
230 : {
231 0 : return m_pszFilename;
232 : }
233 :
234 : /************************************************************************/
235 : /* SetupParser() */
236 : /************************************************************************/
237 :
238 111 : int GMLReader::SetupParser()
239 :
240 : {
241 111 : if (fpGML == NULL)
242 58 : fpGML = VSIFOpenL(m_pszFilename, "rt");
243 111 : if (fpGML != NULL)
244 111 : VSIFSeekL( fpGML, 0, SEEK_SET );
245 :
246 111 : int bRet = -1;
247 : #ifdef HAVE_EXPAT
248 111 : if (bUseExpatReader)
249 111 : bRet = SetupParserExpat();
250 : #endif
251 :
252 : #ifdef HAVE_XERCES
253 111 : if (!bUseExpatReader)
254 0 : bRet = SetupParserXerces();
255 : #endif
256 111 : if (bRet < 0)
257 : {
258 0 : CPLError(CE_Failure, CPLE_AppDefined, "SetupParser(): shouldn't happen");
259 0 : return FALSE;
260 : }
261 :
262 111 : if (!bRet)
263 0 : return FALSE;
264 :
265 111 : m_bReadStarted = FALSE;
266 :
267 : // Push an empty state.
268 111 : PushState( m_poRecycledState ? m_poRecycledState : new GMLReadState() );
269 111 : m_poRecycledState = NULL;
270 :
271 111 : return TRUE;
272 : }
273 :
274 : #ifdef HAVE_XERCES
275 : /************************************************************************/
276 : /* SetupParserXerces() */
277 : /************************************************************************/
278 :
279 0 : int GMLReader::SetupParserXerces()
280 : {
281 0 : if( !m_bXercesInitialized )
282 : {
283 : try
284 : {
285 0 : XMLPlatformUtils::Initialize();
286 : }
287 :
288 0 : catch (const XMLException& toCatch)
289 : {
290 : CPLError( CE_Warning, CPLE_AppDefined,
291 : "Exception initializing Xerces based GML reader.\n%s",
292 0 : tr_strdup(toCatch.getMessage()) );
293 0 : return FALSE;
294 : }
295 0 : m_bXercesInitialized = TRUE;
296 : }
297 :
298 : // Cleanup any old parser.
299 0 : if( m_poSAXReader != NULL )
300 0 : CleanupParser();
301 :
302 : // Create and initialize parser.
303 0 : XMLCh* xmlUriValid = NULL;
304 0 : XMLCh* xmlUriNS = NULL;
305 :
306 : try{
307 0 : m_poSAXReader = XMLReaderFactory::createXMLReader();
308 :
309 0 : GMLXercesHandler* poXercesHandler = new GMLXercesHandler( this );
310 0 : m_poGMLHandler = poXercesHandler;
311 :
312 0 : m_poSAXReader->setContentHandler( poXercesHandler );
313 0 : m_poSAXReader->setErrorHandler( poXercesHandler );
314 0 : m_poSAXReader->setLexicalHandler( poXercesHandler );
315 0 : m_poSAXReader->setEntityResolver( poXercesHandler );
316 0 : m_poSAXReader->setDTDHandler( poXercesHandler );
317 :
318 0 : xmlUriValid = XMLString::transcode("http://xml.org/sax/features/validation");
319 0 : xmlUriNS = XMLString::transcode("http://xml.org/sax/features/namespaces");
320 :
321 : #if (OGR_GML_VALIDATION)
322 : m_poSAXReader->setFeature( xmlUriValid, true);
323 : m_poSAXReader->setFeature( xmlUriNS, true);
324 :
325 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, true );
326 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, true );
327 :
328 : // m_poSAXReader->setDoSchema(true);
329 : // m_poSAXReader->setValidationSchemaFullChecking(true);
330 : #else
331 0 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreValidation, false);
332 :
333 : #if XERCES_VERSION_MAJOR >= 3
334 0 : m_poSAXReader->setFeature( XMLUni::fgXercesSchema, false);
335 : #else
336 : m_poSAXReader->setFeature( XMLUni::fgSAX2CoreNameSpaces, false);
337 : #endif
338 :
339 : #endif
340 0 : XMLString::release( &xmlUriValid );
341 0 : XMLString::release( &xmlUriNS );
342 : }
343 0 : catch (...)
344 : {
345 0 : XMLString::release( &xmlUriValid );
346 0 : XMLString::release( &xmlUriNS );
347 :
348 : CPLError( CE_Warning, CPLE_AppDefined,
349 0 : "Exception initializing Xerces based GML reader.\n" );
350 0 : return FALSE;
351 : }
352 :
353 0 : if (m_GMLInputSource == NULL && fpGML != NULL)
354 0 : m_GMLInputSource = new GMLInputSource(fpGML);
355 :
356 0 : return TRUE;
357 : }
358 : #endif
359 :
360 : /************************************************************************/
361 : /* SetupParserExpat() */
362 : /************************************************************************/
363 :
364 : #ifdef HAVE_EXPAT
365 111 : int GMLReader::SetupParserExpat()
366 : {
367 : // Cleanup any old parser.
368 111 : if( oParser != NULL )
369 1 : CleanupParser();
370 :
371 111 : oParser = OGRCreateExpatXMLParser();
372 111 : m_poGMLHandler = new GMLExpatHandler( this, oParser );
373 :
374 111 : XML_SetElementHandler(oParser, GMLExpatHandler::startElementCbk, GMLExpatHandler::endElementCbk);
375 111 : XML_SetCharacterDataHandler(oParser, GMLExpatHandler::dataHandlerCbk);
376 111 : XML_SetUserData(oParser, m_poGMLHandler);
377 :
378 111 : if (pabyBuf == NULL)
379 57 : pabyBuf = (char*)VSIMalloc(PARSER_BUF_SIZE);
380 111 : if (pabyBuf == NULL)
381 0 : return FALSE;
382 :
383 111 : return TRUE;
384 : }
385 : #endif
386 :
387 : /************************************************************************/
388 : /* CleanupParser() */
389 : /************************************************************************/
390 :
391 246 : void GMLReader::CleanupParser()
392 :
393 : {
394 : #ifdef HAVE_XERCES
395 246 : if( !bUseExpatReader && m_poSAXReader == NULL )
396 0 : return;
397 : #endif
398 :
399 : #ifdef HAVE_EXPAT
400 246 : if ( bUseExpatReader && oParser == NULL )
401 135 : return;
402 : #endif
403 :
404 334 : while( m_poState )
405 112 : PopState();
406 :
407 : #ifdef HAVE_XERCES
408 111 : delete m_poSAXReader;
409 111 : m_poSAXReader = NULL;
410 111 : delete m_GMLInputSource;
411 111 : m_GMLInputSource = NULL;
412 111 : delete m_poCompleteFeature;
413 111 : m_poCompleteFeature = NULL;
414 111 : m_bEOF = FALSE;
415 : #endif
416 :
417 : #ifdef HAVE_EXPAT
418 111 : if (oParser)
419 111 : XML_ParserFree(oParser);
420 111 : oParser = NULL;
421 :
422 : int i;
423 295 : for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
424 184 : delete ppoFeatureTab[i];
425 111 : CPLFree(ppoFeatureTab);
426 111 : nFeatureTabIndex = 0;
427 111 : nFeatureTabLength = 0;
428 111 : nFeatureTabAlloc = 0;
429 111 : ppoFeatureTab = NULL;
430 :
431 : #endif
432 :
433 111 : delete m_poGMLHandler;
434 111 : m_poGMLHandler = NULL;
435 :
436 111 : m_bReadStarted = FALSE;
437 : }
438 :
439 : #ifdef HAVE_XERCES
440 :
441 0 : GMLBinInputStream::GMLBinInputStream(VSILFILE* fp)
442 : {
443 0 : this->fp = fp;
444 0 : emptyString = 0;
445 0 : }
446 :
447 0 : GMLBinInputStream::~ GMLBinInputStream()
448 : {
449 0 : }
450 :
451 : #if XERCES_VERSION_MAJOR >= 3
452 0 : XMLFilePos GMLBinInputStream::curPos() const
453 : {
454 0 : return (XMLFilePos)VSIFTellL(fp);
455 : }
456 :
457 0 : XMLSize_t GMLBinInputStream::readBytes(XMLByte* const toFill, const XMLSize_t maxToRead)
458 : {
459 0 : return (XMLSize_t)VSIFReadL(toFill, 1, maxToRead, fp);
460 : }
461 :
462 0 : const XMLCh* GMLBinInputStream::getContentType() const
463 : {
464 0 : return &emptyString;
465 : }
466 : #else
467 : unsigned int GMLBinInputStream::curPos() const
468 : {
469 : return (unsigned int)VSIFTellL(fp);
470 : }
471 :
472 : unsigned int GMLBinInputStream::readBytes(XMLByte* const toFill, const unsigned int maxToRead)
473 : {
474 : return (unsigned int)VSIFReadL(toFill, 1, maxToRead, fp);
475 : }
476 : #endif
477 :
478 0 : GMLInputSource::GMLInputSource(VSILFILE* fp, MemoryManager* const manager) : InputSource(manager)
479 : {
480 0 : binInputStream = new GMLBinInputStream(fp);
481 0 : }
482 :
483 0 : GMLInputSource::~GMLInputSource()
484 : {
485 0 : }
486 :
487 0 : BinInputStream* GMLInputSource::makeStream() const
488 : {
489 0 : return binInputStream;
490 : }
491 :
492 : #endif // HAVE_XERCES
493 :
494 : /************************************************************************/
495 : /* NextFeatureXerces() */
496 : /************************************************************************/
497 :
498 : #ifdef HAVE_XERCES
499 0 : GMLFeature *GMLReader::NextFeatureXerces()
500 :
501 : {
502 0 : GMLFeature *poReturn = NULL;
503 :
504 0 : if (m_bEOF)
505 0 : return NULL;
506 :
507 : try
508 : {
509 0 : if( !m_bReadStarted )
510 : {
511 0 : if( m_poSAXReader == NULL )
512 0 : SetupParser();
513 :
514 0 : m_bReadStarted = TRUE;
515 :
516 0 : if (m_GMLInputSource == NULL)
517 0 : return NULL;
518 :
519 0 : if( !m_poSAXReader->parseFirst( *m_GMLInputSource, m_oToFill ) )
520 0 : return NULL;
521 : }
522 :
523 0 : while( m_poCompleteFeature == NULL
524 : && !m_bStopParsing
525 0 : && m_poSAXReader->parseNext( m_oToFill ) ) {}
526 :
527 0 : if (m_poCompleteFeature == NULL)
528 0 : m_bEOF = TRUE;
529 :
530 0 : poReturn = m_poCompleteFeature;
531 0 : m_poCompleteFeature = NULL;
532 :
533 : }
534 0 : catch (const XMLException& toCatch)
535 : {
536 0 : char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
537 : CPLDebug( "GML",
538 : "Error during NextFeature()! Message:\n%s",
539 0 : pszErrorMessage );
540 0 : CPLFree(pszErrorMessage);
541 0 : m_bStopParsing = TRUE;
542 : }
543 0 : catch (const SAXException& toCatch)
544 : {
545 0 : char *pszErrorMessage = tr_strdup( toCatch.getMessage() );
546 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMessage);
547 0 : CPLFree(pszErrorMessage);
548 0 : m_bStopParsing = TRUE;
549 : }
550 :
551 0 : return poReturn;
552 : }
553 : #endif
554 :
555 : #ifdef HAVE_EXPAT
556 840 : GMLFeature *GMLReader::NextFeatureExpat()
557 :
558 : {
559 840 : if (!m_bReadStarted)
560 : {
561 111 : if (oParser == NULL)
562 88 : SetupParser();
563 :
564 111 : m_bReadStarted = TRUE;
565 : }
566 :
567 840 : if (fpGML == NULL || m_bStopParsing)
568 0 : return NULL;
569 :
570 840 : if (nFeatureTabIndex < nFeatureTabLength)
571 : {
572 665 : return ppoFeatureTab[nFeatureTabIndex++];
573 : }
574 :
575 175 : if (VSIFEofL(fpGML))
576 63 : return NULL;
577 :
578 112 : nFeatureTabLength = 0;
579 112 : nFeatureTabIndex = 0;
580 :
581 : int nDone;
582 112 : do
583 : {
584 : /* Reset counter that is used to detect billion laugh attacks */
585 112 : ((GMLExpatHandler*)m_poGMLHandler)->ResetDataHandlerCounter();
586 :
587 : unsigned int nLen =
588 112 : (unsigned int)VSIFReadL( pabyBuf, 1, PARSER_BUF_SIZE, fpGML );
589 112 : nDone = VSIFEofL(fpGML);
590 112 : if (XML_Parse(oParser, pabyBuf, nLen, nDone) == XML_STATUS_ERROR)
591 : {
592 : CPLError(CE_Failure, CPLE_AppDefined,
593 : "XML parsing of GML file failed : %s "
594 : "at line %d, column %d",
595 : XML_ErrorString(XML_GetErrorCode(oParser)),
596 : (int)XML_GetCurrentLineNumber(oParser),
597 0 : (int)XML_GetCurrentColumnNumber(oParser));
598 0 : m_bStopParsing = TRUE;
599 : }
600 112 : if (!m_bStopParsing)
601 112 : m_bStopParsing = ((GMLExpatHandler*)m_poGMLHandler)->HasStoppedParsing();
602 :
603 : } while (!nDone && !m_bStopParsing && nFeatureTabLength == 0);
604 :
605 112 : return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
606 : }
607 : #endif
608 :
609 840 : GMLFeature *GMLReader::NextFeature()
610 : {
611 : #ifdef HAVE_EXPAT
612 840 : if (bUseExpatReader)
613 840 : return NextFeatureExpat();
614 : #endif
615 :
616 : #ifdef HAVE_XERCES
617 0 : if (!bUseExpatReader)
618 0 : return NextFeatureXerces();
619 : #endif
620 :
621 0 : CPLError(CE_Failure, CPLE_AppDefined, "NextFeature(): Should not happen");
622 0 : return NULL;
623 : }
624 :
625 : /************************************************************************/
626 : /* PushFeature() */
627 : /* */
628 : /* Create a feature based on the named element. If the */
629 : /* corresponding feature class doesn't exist yet, then create */
630 : /* it now. A new GMLReadState will be created for the feature, */
631 : /* and it will be placed within that state. The state is */
632 : /* pushed onto the readstate stack. */
633 : /************************************************************************/
634 :
635 960 : void GMLReader::PushFeature( const char *pszElement,
636 : const char *pszFID,
637 : int nClassIndex )
638 :
639 : {
640 : int iClass;
641 :
642 960 : if( nClassIndex != INT_MAX )
643 : {
644 482 : iClass = nClassIndex;
645 : }
646 : else
647 : {
648 : /* -------------------------------------------------------------------- */
649 : /* Find the class of this element. */
650 : /* -------------------------------------------------------------------- */
651 625 : for( iClass = 0; iClass < m_nClassCount; iClass++ )
652 : {
653 595 : if( EQUAL(pszElement,m_papoClass[iClass]->GetElementName()) )
654 448 : break;
655 : }
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Create a new feature class for this element, if there is no */
659 : /* existing class for it. */
660 : /* -------------------------------------------------------------------- */
661 478 : if( iClass == m_nClassCount )
662 : {
663 30 : CPLAssert( !m_bClassListLocked );
664 :
665 30 : GMLFeatureClass *poNewClass = new GMLFeatureClass( pszElement );
666 :
667 30 : AddClass( poNewClass );
668 : }
669 : }
670 :
671 : /* -------------------------------------------------------------------- */
672 : /* Create a feature of this feature class. Try to set the fid */
673 : /* if available. */
674 : /* -------------------------------------------------------------------- */
675 960 : GMLFeature *poFeature = new GMLFeature( m_papoClass[iClass] );
676 960 : if( pszFID != NULL )
677 : {
678 443 : poFeature->SetFID( pszFID );
679 : }
680 :
681 : /* -------------------------------------------------------------------- */
682 : /* Create and push a new read state. */
683 : /* -------------------------------------------------------------------- */
684 : GMLReadState *poState;
685 :
686 960 : poState = m_poRecycledState ? m_poRecycledState : new GMLReadState();
687 960 : m_poRecycledState = NULL;
688 960 : poState->m_poFeature = poFeature;
689 960 : PushState( poState );
690 960 : }
691 :
692 : /************************************************************************/
693 : /* IsFeatureElement() */
694 : /* */
695 : /* Based on context and the element name, is this element a new */
696 : /* GML feature element? */
697 : /************************************************************************/
698 :
699 1836 : int GMLReader::GetFeatureElementIndex( const char *pszElement, int nElementLength )
700 :
701 : {
702 1836 : const char *pszLast = m_poState->GetLastComponent();
703 1836 : size_t nLenLast = m_poState->GetLastComponentLen();
704 :
705 1836 : if( nLenLast >= 6 && (EQUAL(pszLast+nLenLast-6,"member") ||
706 : EQUAL(pszLast+nLenLast-7,"members")) )
707 : {
708 : /* Default feature name */
709 : }
710 : else
711 : {
712 875 : if (nLenLast == 4 && strcmp(pszLast, "dane") == 0)
713 : {
714 : /* Polish TBD GML */
715 : }
716 :
717 : /* Begin of OpenLS */
718 875 : else if (nLenLast == 19 && nElementLength == 15 &&
719 : strcmp(pszLast, "GeocodeResponseList") == 0 &&
720 : strcmp(pszElement, "GeocodedAddress") == 0)
721 : {
722 : }
723 877 : else if (nLenLast == 22 &&
724 : strcmp(pszLast, "DetermineRouteResponse") == 0)
725 : {
726 : /* We don't want the children of RouteInstructionsList */
727 : /* to be a single feature. We want each RouteInstruction */
728 : /* to be a feature */
729 3 : if (strcmp(pszElement, "RouteInstructionsList") == 0)
730 1 : return -1;
731 : }
732 872 : else if (nElementLength == 16 && nLenLast == 21 &&
733 : strcmp(pszElement, "RouteInstruction") == 0 &&
734 : strcmp(pszLast, "RouteInstructionsList") == 0)
735 : {
736 : }
737 : /* End of OpenLS */
738 :
739 863 : else if (nLenLast > 6 && strcmp(pszLast + nLenLast - 6, "_layer") == 0 &&
740 : nElementLength > 8 && strcmp(pszElement + nElementLength - 8, "_feature") == 0)
741 : {
742 : /* GML answer of MapServer WMS GetFeatureInfo request */
743 : }
744 : else
745 863 : return -1;
746 : }
747 :
748 : // If the class list isn't locked, any element that is a featureMember
749 : // will do.
750 972 : if( !m_bClassListLocked )
751 478 : return INT_MAX;
752 :
753 : // otherwise, find a class with the desired element name.
754 598 : for( int i = 0; i < m_nClassCount; i++ )
755 : {
756 1146 : if( nElementLength == (int)m_papoClass[i]->GetElementNameLen() &&
757 548 : memcmp(pszElement,m_papoClass[i]->GetElementName(), nElementLength) == 0 )
758 494 : return i;
759 : }
760 :
761 0 : return -1;
762 : }
763 :
764 : /************************************************************************/
765 : /* IsCityGMLGenericAttributeElement() */
766 : /************************************************************************/
767 :
768 12 : int GMLReader::IsCityGMLGenericAttributeElement( const char *pszElement, void* attr )
769 :
770 : {
771 12 : if( strcmp(pszElement, "stringAttribute") != 0 &&
772 : strcmp(pszElement, "intAttribute") != 0 &&
773 : strcmp(pszElement, "doubleAttribute") != 0 )
774 6 : return FALSE;
775 :
776 6 : char* pszVal = m_poGMLHandler->GetAttributeValue(attr, "name");
777 6 : if (pszVal == NULL)
778 0 : return FALSE;
779 :
780 6 : GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
781 :
782 : // If the schema is not yet locked, then any simple element
783 : // is potentially an attribute.
784 6 : if( !poClass->IsSchemaLocked() )
785 : {
786 6 : CPLFree(pszVal);
787 6 : return TRUE;
788 : }
789 :
790 0 : for( int i = 0; i < poClass->GetPropertyCount(); i++ )
791 : {
792 0 : if( strcmp(poClass->GetProperty(i)->GetSrcElement(),pszVal) == 0 )
793 : {
794 0 : CPLFree(pszVal);
795 0 : return TRUE;
796 : }
797 : }
798 :
799 0 : CPLFree(pszVal);
800 0 : return FALSE;
801 : }
802 :
803 : /************************************************************************/
804 : /* GetAttributeElementIndex() */
805 : /************************************************************************/
806 :
807 3392 : int GMLReader::GetAttributeElementIndex( const char *pszElement, int nLen )
808 :
809 : {
810 3392 : GMLFeatureClass *poClass = m_poState->m_poFeature->GetClass();
811 :
812 : // If the schema is not yet locked, then any simple element
813 : // is potentially an attribute.
814 3392 : if( !poClass->IsSchemaLocked() )
815 1758 : return INT_MAX;
816 :
817 : // Otherwise build the path to this element into a single string
818 : // and compare against known attributes.
819 1634 : if( m_poState->m_nPathLength == 0 )
820 1622 : return poClass->GetPropertyIndexBySrcElement(pszElement, nLen);
821 : else
822 : {
823 12 : int nFullLen = nLen + m_poState->osPath.size() + 1;
824 12 : osElemPath.reserve(nFullLen);
825 12 : osElemPath.assign(m_poState->osPath);
826 12 : osElemPath.append(1, '|');
827 12 : osElemPath.append(pszElement, nLen);
828 12 : return poClass->GetPropertyIndexBySrcElement(osElemPath.c_str(), nFullLen);
829 : }
830 : }
831 :
832 : /************************************************************************/
833 : /* PopState() */
834 : /************************************************************************/
835 :
836 1071 : void GMLReader::PopState()
837 :
838 : {
839 1071 : if( m_poState != NULL )
840 : {
841 : #ifdef HAVE_XERCES
842 1071 : if( !bUseExpatReader && m_poState->m_poFeature != NULL &&
843 : m_poCompleteFeature == NULL )
844 : {
845 0 : m_poCompleteFeature = m_poState->m_poFeature;
846 0 : m_poState->m_poFeature = NULL;
847 : }
848 : #endif
849 :
850 : #ifdef HAVE_EXPAT
851 1071 : if ( bUseExpatReader && m_poState->m_poFeature != NULL )
852 : {
853 960 : if (nFeatureTabLength >= nFeatureTabAlloc)
854 : {
855 129 : nFeatureTabAlloc = nFeatureTabLength * 4 / 3 + 16;
856 : ppoFeatureTab = (GMLFeature**)
857 : CPLRealloc(ppoFeatureTab,
858 129 : sizeof(GMLFeature*) * (nFeatureTabAlloc));
859 : }
860 960 : ppoFeatureTab[nFeatureTabLength] = m_poState->m_poFeature;
861 960 : nFeatureTabLength++;
862 :
863 960 : m_poState->m_poFeature = NULL;
864 : }
865 : #endif
866 :
867 : GMLReadState *poParent;
868 :
869 1071 : poParent = m_poState->m_poParentState;
870 :
871 1071 : delete m_poRecycledState;
872 1071 : m_poRecycledState = m_poState;
873 1071 : m_poRecycledState->Reset();
874 1071 : m_poState = poParent;
875 : }
876 1071 : }
877 :
878 : /************************************************************************/
879 : /* PushState() */
880 : /************************************************************************/
881 :
882 1071 : void GMLReader::PushState( GMLReadState *poState )
883 :
884 : {
885 1071 : poState->m_poParentState = m_poState;
886 1071 : m_poState = poState;
887 1071 : }
888 :
889 : /************************************************************************/
890 : /* GetClass() */
891 : /************************************************************************/
892 :
893 358 : GMLFeatureClass *GMLReader::GetClass( int iClass ) const
894 :
895 : {
896 358 : if( iClass < 0 || iClass >= m_nClassCount )
897 0 : return NULL;
898 : else
899 358 : return m_papoClass[iClass];
900 : }
901 :
902 : /************************************************************************/
903 : /* GetClass() */
904 : /************************************************************************/
905 :
906 185 : GMLFeatureClass *GMLReader::GetClass( const char *pszName ) const
907 :
908 : {
909 256 : for( int iClass = 0; iClass < m_nClassCount; iClass++ )
910 : {
911 162 : if( EQUAL(GetClass(iClass)->GetName(),pszName) )
912 91 : return GetClass(iClass);
913 : }
914 :
915 94 : return NULL;
916 : }
917 :
918 : /************************************************************************/
919 : /* AddClass() */
920 : /************************************************************************/
921 :
922 93 : int GMLReader::AddClass( GMLFeatureClass *poNewClass )
923 :
924 : {
925 93 : CPLAssert( GetClass( poNewClass->GetName() ) == NULL );
926 :
927 93 : m_nClassCount++;
928 : m_papoClass = (GMLFeatureClass **)
929 93 : CPLRealloc( m_papoClass, sizeof(void*) * m_nClassCount );
930 93 : m_papoClass[m_nClassCount-1] = poNewClass;
931 :
932 93 : return m_nClassCount-1;
933 : }
934 :
935 : /************************************************************************/
936 : /* ClearClasses() */
937 : /************************************************************************/
938 :
939 88 : void GMLReader::ClearClasses()
940 :
941 : {
942 179 : for( int i = 0; i < m_nClassCount; i++ )
943 91 : delete m_papoClass[i];
944 88 : CPLFree( m_papoClass );
945 :
946 88 : m_nClassCount = 0;
947 88 : m_papoClass = NULL;
948 88 : }
949 :
950 : /************************************************************************/
951 : /* SetFeaturePropertyDirectly() */
952 : /* */
953 : /* Set the property value on the current feature, adding the */
954 : /* property name to the GMLFeatureClass if required. */
955 : /* The pszValue ownership is passed to this function. */
956 : /************************************************************************/
957 :
958 2443 : void GMLReader::SetFeaturePropertyDirectly( const char *pszElement,
959 : char *pszValue,
960 : int iPropertyIn )
961 :
962 : {
963 2443 : GMLFeature *poFeature = GetState()->m_poFeature;
964 :
965 2443 : CPLAssert( poFeature != NULL );
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Does this property exist in the feature class? If not, add */
969 : /* it. */
970 : /* -------------------------------------------------------------------- */
971 2443 : GMLFeatureClass *poClass = poFeature->GetClass();
972 : int iProperty;
973 :
974 2443 : int nPropertyCount = poClass->GetPropertyCount();
975 3588 : if (iPropertyIn >= 0 && iPropertyIn < nPropertyCount)
976 : {
977 1145 : iProperty = iPropertyIn;
978 : }
979 : else
980 : {
981 2797 : for( iProperty=0; iProperty < nPropertyCount; iProperty++ )
982 : {
983 2723 : if( strcmp(poClass->GetProperty( iProperty )->GetSrcElement(),
984 : pszElement ) == 0 )
985 1224 : break;
986 : }
987 :
988 1298 : if( iProperty == nPropertyCount )
989 : {
990 74 : if( poClass->IsSchemaLocked() )
991 : {
992 0 : CPLDebug("GML","Encountered property missing from class schema.");
993 0 : CPLFree(pszValue);
994 0 : return;
995 : }
996 :
997 74 : CPLString osFieldName;
998 :
999 74 : if( strchr(pszElement,'|') == NULL )
1000 69 : osFieldName = pszElement;
1001 : else
1002 : {
1003 5 : osFieldName = strrchr(pszElement,'|') + 1;
1004 5 : if( poClass->GetPropertyIndex(osFieldName) != -1 )
1005 0 : osFieldName = pszElement;
1006 : }
1007 :
1008 : // Does this conflict with an existing property name?
1009 149 : while( poClass->GetProperty(osFieldName) != NULL )
1010 : {
1011 1 : osFieldName += "_";
1012 : }
1013 :
1014 74 : GMLPropertyDefn *poPDefn = new GMLPropertyDefn(osFieldName,pszElement);
1015 :
1016 148 : if( EQUAL(CPLGetConfigOption( "GML_FIELDTYPES", ""), "ALWAYS_STRING") )
1017 0 : poPDefn->SetType( GMLPT_String );
1018 :
1019 74 : if (poClass->AddProperty( poPDefn ) < 0)
1020 : {
1021 0 : delete poPDefn;
1022 0 : CPLFree(pszValue);
1023 : return;
1024 0 : }
1025 : }
1026 : }
1027 :
1028 : /* -------------------------------------------------------------------- */
1029 : /* Set the property */
1030 : /* -------------------------------------------------------------------- */
1031 2443 : poFeature->SetPropertyDirectly( iProperty, pszValue );
1032 :
1033 : /* -------------------------------------------------------------------- */
1034 : /* Do we need to update the property type? */
1035 : /* -------------------------------------------------------------------- */
1036 2443 : if( !poClass->IsSchemaLocked() )
1037 : {
1038 : poClass->GetProperty(iProperty)->AnalysePropertyValue(
1039 1298 : poFeature->GetProperty(iProperty));
1040 : }
1041 : }
1042 :
1043 : /************************************************************************/
1044 : /* LoadClasses() */
1045 : /************************************************************************/
1046 :
1047 15 : int GMLReader::LoadClasses( const char *pszFile )
1048 :
1049 : {
1050 : // Add logic later to determine reasonable default schema file.
1051 15 : if( pszFile == NULL )
1052 0 : return FALSE;
1053 :
1054 : /* -------------------------------------------------------------------- */
1055 : /* Load the raw XML file. */
1056 : /* -------------------------------------------------------------------- */
1057 : VSILFILE *fp;
1058 : int nLength;
1059 : char *pszWholeText;
1060 :
1061 15 : fp = VSIFOpenL( pszFile, "rb" );
1062 :
1063 15 : if( fp == NULL )
1064 : {
1065 : CPLError( CE_Failure, CPLE_OpenFailed,
1066 0 : "Failed to open file %s.", pszFile );
1067 0 : return FALSE;
1068 : }
1069 :
1070 15 : VSIFSeekL( fp, 0, SEEK_END );
1071 15 : nLength = (int) VSIFTellL( fp );
1072 15 : VSIFSeekL( fp, 0, SEEK_SET );
1073 :
1074 15 : pszWholeText = (char *) VSIMalloc(nLength+1);
1075 15 : if( pszWholeText == NULL )
1076 : {
1077 : CPLError( CE_Failure, CPLE_AppDefined,
1078 : "Failed to allocate %d byte buffer for %s,\n"
1079 : "is this really a GMLFeatureClassList file?",
1080 0 : nLength, pszFile );
1081 0 : VSIFCloseL( fp );
1082 0 : return FALSE;
1083 : }
1084 :
1085 15 : if( VSIFReadL( pszWholeText, nLength, 1, fp ) != 1 )
1086 : {
1087 0 : VSIFree( pszWholeText );
1088 0 : VSIFCloseL( fp );
1089 : CPLError( CE_Failure, CPLE_AppDefined,
1090 0 : "Read failed on %s.", pszFile );
1091 0 : return FALSE;
1092 : }
1093 15 : pszWholeText[nLength] = '\0';
1094 :
1095 15 : VSIFCloseL( fp );
1096 :
1097 15 : if( strstr( pszWholeText, "<GMLFeatureClassList>" ) == NULL )
1098 : {
1099 0 : VSIFree( pszWholeText );
1100 : CPLError( CE_Failure, CPLE_AppDefined,
1101 : "File %s does not contain a GMLFeatureClassList tree.",
1102 0 : pszFile );
1103 0 : return FALSE;
1104 : }
1105 :
1106 : /* -------------------------------------------------------------------- */
1107 : /* Convert to XML parse tree. */
1108 : /* -------------------------------------------------------------------- */
1109 : CPLXMLNode *psRoot;
1110 :
1111 15 : psRoot = CPLParseXMLString( pszWholeText );
1112 15 : VSIFree( pszWholeText );
1113 :
1114 : // We assume parser will report errors via CPL.
1115 15 : if( psRoot == NULL )
1116 0 : return FALSE;
1117 :
1118 15 : if( psRoot->eType != CXT_Element
1119 : || !EQUAL(psRoot->pszValue,"GMLFeatureClassList") )
1120 : {
1121 0 : CPLDestroyXMLNode(psRoot);
1122 : CPLError( CE_Failure, CPLE_AppDefined,
1123 : "File %s is not a GMLFeatureClassList document.",
1124 0 : pszFile );
1125 0 : return FALSE;
1126 : }
1127 :
1128 15 : const char* pszSequentialLayers = CPLGetXMLValue(psRoot, "SequentialLayers", NULL);
1129 15 : if (pszSequentialLayers)
1130 3 : m_bSequentialLayers = CSLTestBoolean(pszSequentialLayers);
1131 :
1132 : /* -------------------------------------------------------------------- */
1133 : /* Extract feature classes for all definitions found. */
1134 : /* -------------------------------------------------------------------- */
1135 : CPLXMLNode *psThis;
1136 :
1137 42 : for( psThis = psRoot->psChild; psThis != NULL; psThis = psThis->psNext )
1138 : {
1139 27 : if( psThis->eType == CXT_Element
1140 : && EQUAL(psThis->pszValue,"GMLFeatureClass") )
1141 : {
1142 : GMLFeatureClass *poClass;
1143 :
1144 24 : poClass = new GMLFeatureClass();
1145 :
1146 24 : if( !poClass->InitializeFromXML( psThis ) )
1147 : {
1148 0 : delete poClass;
1149 0 : CPLDestroyXMLNode( psRoot );
1150 0 : return FALSE;
1151 : }
1152 :
1153 24 : poClass->SetSchemaLocked( TRUE );
1154 :
1155 24 : AddClass( poClass );
1156 : }
1157 : }
1158 :
1159 15 : CPLDestroyXMLNode( psRoot );
1160 :
1161 15 : SetClassListLocked( TRUE );
1162 :
1163 15 : return TRUE;
1164 : }
1165 :
1166 : /************************************************************************/
1167 : /* SaveClasses() */
1168 : /************************************************************************/
1169 :
1170 20 : int GMLReader::SaveClasses( const char *pszFile )
1171 :
1172 : {
1173 : // Add logic later to determine reasonable default schema file.
1174 20 : if( pszFile == NULL )
1175 0 : return FALSE;
1176 :
1177 : /* -------------------------------------------------------------------- */
1178 : /* Create in memory schema tree. */
1179 : /* -------------------------------------------------------------------- */
1180 : CPLXMLNode *psRoot;
1181 :
1182 20 : psRoot = CPLCreateXMLNode( NULL, CXT_Element, "GMLFeatureClassList" );
1183 :
1184 20 : if (m_bSequentialLayers != -1 && m_nClassCount > 1)
1185 : {
1186 : CPLCreateXMLElementAndValue( psRoot, "SequentialLayers",
1187 5 : m_bSequentialLayers ? "true" : "false" );
1188 : }
1189 :
1190 48 : for( int iClass = 0; iClass < m_nClassCount; iClass++ )
1191 : {
1192 28 : CPLAddXMLChild( psRoot, m_papoClass[iClass]->SerializeToXML() );
1193 : }
1194 :
1195 : /* -------------------------------------------------------------------- */
1196 : /* Serialize to disk. */
1197 : /* -------------------------------------------------------------------- */
1198 : VSILFILE *fp;
1199 20 : int bSuccess = TRUE;
1200 20 : char *pszWholeText = CPLSerializeXMLTree( psRoot );
1201 :
1202 20 : CPLDestroyXMLNode( psRoot );
1203 :
1204 20 : fp = VSIFOpenL( pszFile, "wb" );
1205 :
1206 20 : if( fp == NULL )
1207 0 : bSuccess = FALSE;
1208 20 : else if( VSIFWriteL( pszWholeText, strlen(pszWholeText), 1, fp ) != 1 )
1209 0 : bSuccess = FALSE;
1210 : else
1211 20 : VSIFCloseL( fp );
1212 :
1213 20 : CPLFree( pszWholeText );
1214 :
1215 20 : return bSuccess;
1216 : }
1217 :
1218 : /************************************************************************/
1219 : /* PrescanForSchema() */
1220 : /* */
1221 : /* For now we use a pretty dumb approach of just doing a normal */
1222 : /* scan of the whole file, building up the schema information. */
1223 : /* Eventually we hope to do a more efficient scan when just */
1224 : /* looking for schema information. */
1225 : /************************************************************************/
1226 :
1227 21 : int GMLReader::PrescanForSchema( int bGetExtents )
1228 :
1229 : {
1230 : GMLFeature *poFeature;
1231 :
1232 21 : if( m_pszFilename == NULL )
1233 0 : return FALSE;
1234 :
1235 21 : SetClassListLocked( FALSE );
1236 :
1237 21 : ClearClasses();
1238 21 : if( !SetupParser() )
1239 0 : return FALSE;
1240 :
1241 21 : m_bCanUseGlobalSRSName = TRUE;
1242 :
1243 21 : std::map<GMLFeatureClass*, int> osMapCountFeatureWithoutGeometry;
1244 21 : GMLFeatureClass *poLastClass = NULL;
1245 :
1246 21 : m_bSequentialLayers = TRUE;
1247 :
1248 21 : void* hCacheSRS = GML_BuildOGRGeometryFromList_CreateCache();
1249 :
1250 21 : std::string osWork;
1251 :
1252 254 : while( (poFeature = NextFeature()) != NULL )
1253 : {
1254 212 : GMLFeatureClass *poClass = poFeature->GetClass();
1255 :
1256 212 : if (poLastClass != NULL && poClass != poLastClass &&
1257 : poClass->GetFeatureCount() != -1)
1258 0 : m_bSequentialLayers = FALSE;
1259 212 : poLastClass = poClass;
1260 :
1261 212 : if( poClass->GetFeatureCount() == -1 )
1262 28 : poClass->SetFeatureCount( 1 );
1263 : else
1264 184 : poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
1265 :
1266 212 : const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
1267 212 : if (papsGeometry[0] == NULL)
1268 : {
1269 : std::map<GMLFeatureClass*, int>::iterator oIter =
1270 8 : osMapCountFeatureWithoutGeometry.find(poClass);
1271 8 : if (oIter == osMapCountFeatureWithoutGeometry.end())
1272 2 : osMapCountFeatureWithoutGeometry[poClass] = 1;
1273 : else
1274 6 : oIter->second ++;
1275 : }
1276 :
1277 :
1278 : #ifdef SUPPORT_GEOMETRY
1279 212 : if( bGetExtents )
1280 : {
1281 : OGRGeometry *poGeometry = GML_BuildOGRGeometryFromList(
1282 : papsGeometry, TRUE, m_bInvertAxisOrderIfLatLong,
1283 212 : NULL, m_bConsiderEPSGAsURN, m_bGetSecondaryGeometryOption, hCacheSRS);
1284 :
1285 212 : if( poGeometry != NULL )
1286 : {
1287 : double dfXMin, dfXMax, dfYMin, dfYMax;
1288 204 : OGREnvelope sEnvelope;
1289 : OGRwkbGeometryType eGType = (OGRwkbGeometryType)
1290 204 : poClass->GetGeometryType();
1291 :
1292 : const char* pszSRSName = GML_ExtractSrsNameFromGeometry(papsGeometry,
1293 : osWork,
1294 204 : m_bConsiderEPSGAsURN);
1295 204 : if (pszSRSName != NULL)
1296 107 : m_bCanUseGlobalSRSName = FALSE;
1297 204 : poClass->MergeSRSName(pszSRSName);
1298 :
1299 : // Merge geometry type into layer.
1300 204 : if( poClass->GetFeatureCount() == 1 && eGType == wkbUnknown )
1301 26 : eGType = wkbNone;
1302 :
1303 : poClass->SetGeometryType(
1304 : (int) OGRMergeGeometryTypes(
1305 204 : eGType, poGeometry->getGeometryType() ) );
1306 :
1307 : // merge extents.
1308 204 : if (!poGeometry->IsEmpty())
1309 : {
1310 204 : poGeometry->getEnvelope( &sEnvelope );
1311 204 : if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
1312 : {
1313 178 : dfXMin = MIN(dfXMin,sEnvelope.MinX);
1314 178 : dfXMax = MAX(dfXMax,sEnvelope.MaxX);
1315 178 : dfYMin = MIN(dfYMin,sEnvelope.MinY);
1316 178 : dfYMax = MAX(dfYMax,sEnvelope.MaxY);
1317 : }
1318 : else
1319 : {
1320 26 : dfXMin = sEnvelope.MinX;
1321 26 : dfXMax = sEnvelope.MaxX;
1322 26 : dfYMin = sEnvelope.MinY;
1323 26 : dfYMax = sEnvelope.MaxY;
1324 : }
1325 :
1326 204 : poClass->SetExtents( dfXMin, dfXMax, dfYMin, dfYMax );
1327 : }
1328 204 : delete poGeometry;
1329 :
1330 : }
1331 : #endif /* def SUPPORT_GEOMETRY */
1332 : }
1333 :
1334 212 : delete poFeature;
1335 : }
1336 :
1337 21 : GML_BuildOGRGeometryFromList_DestroyCache(hCacheSRS);
1338 :
1339 49 : for( int i = 0; i < m_nClassCount; i++ )
1340 : {
1341 28 : GMLFeatureClass *poClass = m_papoClass[i];
1342 28 : const char* pszSRSName = poClass->GetSRSName();
1343 :
1344 28 : if (m_bCanUseGlobalSRSName)
1345 13 : pszSRSName = m_pszGlobalSRSName;
1346 :
1347 28 : if (m_bInvertAxisOrderIfLatLong && GML_IsSRSLatLongOrder(pszSRSName))
1348 : {
1349 6 : OGRSpatialReference oSRS;
1350 6 : if (oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE)
1351 : {
1352 6 : OGR_SRSNode *poGEOGCS = oSRS.GetAttrNode( "GEOGCS" );
1353 6 : if( poGEOGCS != NULL )
1354 : {
1355 6 : poGEOGCS->StripNodes( "AXIS" );
1356 :
1357 6 : char* pszWKT = NULL;
1358 6 : if (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE)
1359 6 : poClass->SetSRSName(pszWKT);
1360 6 : CPLFree(pszWKT);
1361 :
1362 : /* So when we have computed the extent, we didn't know yet */
1363 : /* the SRS to use. Now we know it, we have to fix the extent */
1364 : /* order */
1365 6 : if (m_bCanUseGlobalSRSName)
1366 : {
1367 : double dfXMin, dfXMax, dfYMin, dfYMax;
1368 1 : if( poClass->GetExtents(&dfXMin, &dfXMax, &dfYMin, &dfYMax) )
1369 1 : poClass->SetExtents( dfYMin, dfYMax, dfXMin, dfXMax );
1370 : }
1371 : }
1372 6 : }
1373 : }
1374 :
1375 : std::map<GMLFeatureClass*, int>::iterator oIter =
1376 28 : osMapCountFeatureWithoutGeometry.find(poClass);
1377 28 : if (oIter != osMapCountFeatureWithoutGeometry.end() &&
1378 : oIter->second == poClass->GetFeatureCount())
1379 : {
1380 2 : poClass->SetGeometryType(wkbNone);
1381 : }
1382 : }
1383 :
1384 21 : CleanupParser();
1385 :
1386 21 : return m_nClassCount > 0;
1387 : }
1388 :
1389 : /************************************************************************/
1390 : /* ResetReading() */
1391 : /************************************************************************/
1392 :
1393 156 : void GMLReader::ResetReading()
1394 :
1395 : {
1396 156 : CleanupParser();
1397 156 : SetFilteredClassName(NULL);
1398 156 : }
1399 :
1400 : /************************************************************************/
1401 : /* SetGlobalSRSName() */
1402 : /************************************************************************/
1403 :
1404 51 : void GMLReader::SetGlobalSRSName( const char* pszGlobalSRSName )
1405 : {
1406 51 : if (m_pszGlobalSRSName == NULL && pszGlobalSRSName != NULL)
1407 : {
1408 31 : if (strncmp(pszGlobalSRSName, "EPSG:", 5) == 0 &&
1409 : m_bConsiderEPSGAsURN)
1410 : {
1411 : m_pszGlobalSRSName = CPLStrdup(CPLSPrintf("urn:ogc:def:crs:EPSG::%s",
1412 5 : pszGlobalSRSName+5));
1413 : }
1414 : else
1415 : {
1416 21 : m_pszGlobalSRSName = CPLStrdup(pszGlobalSRSName);
1417 : }
1418 : }
1419 51 : }
1420 :
1421 : /************************************************************************/
1422 : /* SetFilteredClassName() */
1423 : /************************************************************************/
1424 :
1425 159 : int GMLReader::SetFilteredClassName(const char* pszClassName)
1426 : {
1427 159 : CPLFree(m_pszFilteredClassName);
1428 159 : m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
1429 159 : return TRUE;
1430 : }
|