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