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