1 : /**********************************************************************
2 : * $Id: gmlhandler.cpp 25183 2012-10-27 18:09:53Z rouault $
3 : *
4 : * Project: GML Reader
5 : * Purpose: Implementation of GMLHandler 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 <ctype.h>
31 : #include "gmlreaderp.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 : #include "cpl_hash_set.h"
35 :
36 : #ifdef HAVE_XERCES
37 :
38 : /* Must be a multiple of 4 */
39 : #define MAX_TOKEN_SIZE 1000
40 :
41 : /************************************************************************/
42 : /* GMLXercesHandler() */
43 : /************************************************************************/
44 :
45 0 : GMLXercesHandler::GMLXercesHandler( GMLReader *poReader ) : GMLHandler(poReader)
46 : {
47 0 : m_nEntityCounter = 0;
48 0 : }
49 :
50 : /************************************************************************/
51 : /* startElement() */
52 : /************************************************************************/
53 :
54 0 : void GMLXercesHandler::startElement(const XMLCh* const uri,
55 : const XMLCh* const localname,
56 : const XMLCh* const qname,
57 : const Attributes& attrs )
58 :
59 : {
60 : char szElementName[MAX_TOKEN_SIZE];
61 :
62 0 : m_nEntityCounter = 0;
63 :
64 : /* A XMLCh character can expand to 4 bytes in UTF-8 */
65 0 : if (4 * tr_strlen( localname ) >= MAX_TOKEN_SIZE)
66 : {
67 : static int bWarnOnce = FALSE;
68 0 : XMLCh* tempBuffer = (XMLCh*) CPLMalloc(sizeof(XMLCh) * (MAX_TOKEN_SIZE / 4 + 1));
69 0 : memcpy(tempBuffer, localname, sizeof(XMLCh) * (MAX_TOKEN_SIZE / 4));
70 0 : tempBuffer[MAX_TOKEN_SIZE / 4] = 0;
71 0 : tr_strcpy( szElementName, tempBuffer );
72 0 : CPLFree(tempBuffer);
73 0 : if (!bWarnOnce)
74 : {
75 0 : bWarnOnce = TRUE;
76 0 : CPLError(CE_Warning, CPLE_AppDefined, "A too big element name has been truncated");
77 : }
78 : }
79 : else
80 0 : tr_strcpy( szElementName, localname );
81 :
82 0 : if (GMLHandler::startElement(szElementName, strlen(szElementName), (void*) &attrs) == OGRERR_NOT_ENOUGH_MEMORY)
83 : {
84 0 : throw SAXNotSupportedException("Out of memory");
85 : }
86 0 : }
87 :
88 : /************************************************************************/
89 : /* endElement() */
90 : /************************************************************************/
91 0 : void GMLXercesHandler::endElement(const XMLCh* const uri,
92 : const XMLCh* const localname,
93 : const XMLCh* const qname )
94 :
95 : {
96 0 : m_nEntityCounter = 0;
97 :
98 0 : if (GMLHandler::endElement() == OGRERR_NOT_ENOUGH_MEMORY)
99 : {
100 0 : throw SAXNotSupportedException("Out of memory");
101 : }
102 0 : }
103 :
104 : /************************************************************************/
105 : /* characters() */
106 : /************************************************************************/
107 :
108 0 : void GMLXercesHandler::characters(const XMLCh* const chars_in,
109 : #if XERCES_VERSION_MAJOR >= 3
110 : const XMLSize_t length
111 : #else
112 : const unsigned int length
113 : #endif
114 : )
115 :
116 : {
117 0 : char* utf8String = tr_strdup(chars_in);
118 0 : int nLen = strlen(utf8String);
119 0 : OGRErr eErr = GMLHandler::dataHandler(utf8String, nLen);
120 0 : CPLFree(utf8String);
121 0 : if (eErr == OGRERR_NOT_ENOUGH_MEMORY)
122 : {
123 0 : throw SAXNotSupportedException("Out of memory");
124 : }
125 0 : }
126 :
127 : /************************************************************************/
128 : /* fatalError() */
129 : /************************************************************************/
130 :
131 0 : void GMLXercesHandler::fatalError( const SAXParseException &exception)
132 :
133 : {
134 : char *pszErrorMessage;
135 :
136 0 : pszErrorMessage = tr_strdup( exception.getMessage() );
137 : CPLError( CE_Failure, CPLE_AppDefined,
138 : "XML Parsing Error: %s at line %d, column %d\n",
139 0 : pszErrorMessage, (int)exception.getLineNumber(), (int)exception.getColumnNumber() );
140 :
141 0 : CPLFree( pszErrorMessage );
142 0 : }
143 :
144 : /************************************************************************/
145 : /* startEntity() */
146 : /************************************************************************/
147 :
148 0 : void GMLXercesHandler::startEntity (const XMLCh *const name)
149 : {
150 0 : m_nEntityCounter ++;
151 0 : if (m_nEntityCounter > 1000 && !m_poReader->HasStoppedParsing())
152 : {
153 0 : throw SAXNotSupportedException("File probably corrupted (million laugh pattern)");
154 : }
155 0 : }
156 :
157 : /************************************************************************/
158 : /* GetFID() */
159 : /************************************************************************/
160 :
161 0 : const char* GMLXercesHandler::GetFID(void* attr)
162 : {
163 0 : const Attributes* attrs = (const Attributes*) attr;
164 : int nFIDIndex;
165 : XMLCh anFID[100];
166 :
167 0 : tr_strcpy( anFID, "fid" );
168 0 : nFIDIndex = attrs->getIndex( anFID );
169 0 : if( nFIDIndex != -1 )
170 : {
171 0 : char* pszValue = tr_strdup( attrs->getValue( nFIDIndex ) );
172 0 : osFID.assign(pszValue);
173 0 : CPLFree(pszValue);
174 0 : return osFID.c_str();
175 : }
176 : else
177 : {
178 0 : tr_strcpy( anFID, "gml:id" );
179 0 : nFIDIndex = attrs->getIndex( anFID );
180 0 : if( nFIDIndex != -1 )
181 : {
182 0 : char* pszValue = tr_strdup( attrs->getValue( nFIDIndex ) );
183 0 : osFID.assign(pszValue);
184 0 : CPLFree(pszValue);
185 0 : return osFID.c_str();
186 : }
187 : }
188 :
189 0 : osFID.resize(0);
190 0 : return NULL;
191 : }
192 :
193 : /************************************************************************/
194 : /* AddAttributes() */
195 : /************************************************************************/
196 :
197 0 : CPLXMLNode* GMLXercesHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
198 : {
199 0 : const Attributes* attrs = (const Attributes*) attr;
200 :
201 0 : CPLXMLNode* psLastChild = NULL;
202 :
203 0 : for(unsigned int i=0; i < attrs->getLength(); i++)
204 : {
205 0 : char* pszName = tr_strdup(attrs->getQName(i));
206 0 : char* pszValue = tr_strdup(attrs->getValue(i));
207 :
208 0 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, pszName);
209 0 : CPLCreateXMLNode(psChild, CXT_Text, pszValue);
210 :
211 0 : CPLFree(pszName);
212 0 : CPLFree(pszValue);
213 :
214 0 : if (psLastChild == NULL)
215 0 : psNode->psChild = psChild;
216 : else
217 0 : psLastChild->psNext = psChild;
218 0 : psLastChild = psChild;
219 : }
220 :
221 0 : return psLastChild;
222 : }
223 :
224 : /************************************************************************/
225 : /* GetAttributeValue() */
226 : /************************************************************************/
227 :
228 0 : char* GMLXercesHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
229 : {
230 0 : const Attributes* attrs = (const Attributes*) attr;
231 0 : for(unsigned int i=0; i < attrs->getLength(); i++)
232 : {
233 0 : char* pszString = tr_strdup(attrs->getQName(i));
234 0 : if (strcmp(pszString, pszAttributeName) == 0)
235 : {
236 0 : CPLFree(pszString);
237 0 : return tr_strdup(attrs->getValue(i));
238 : }
239 0 : CPLFree(pszString);
240 : }
241 0 : return NULL;
242 : }
243 :
244 : #endif
245 :
246 : #ifdef HAVE_EXPAT
247 :
248 : /************************************************************************/
249 : /* GMLExpatHandler() */
250 : /************************************************************************/
251 :
252 200 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
253 :
254 : {
255 200 : m_oParser = oParser;
256 200 : m_bStopParsing = FALSE;
257 200 : m_nDataHandlerCounter = 0;
258 200 : }
259 :
260 : /************************************************************************/
261 : /* startElementCbk() */
262 : /************************************************************************/
263 :
264 52227 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
265 : const char **ppszAttr)
266 :
267 : {
268 52227 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
269 52227 : if (pThis->m_bStopParsing)
270 0 : return;
271 :
272 52227 : const char* pszIter = pszName;
273 : char ch;
274 730670 : while((ch = *pszIter) != '\0')
275 : {
276 626216 : if (ch == ':')
277 43968 : pszName = pszIter + 1;
278 626216 : pszIter ++;
279 : }
280 :
281 52227 : if (pThis->GMLHandler::startElement(pszName, (int)(pszIter - pszName), ppszAttr) == OGRERR_NOT_ENOUGH_MEMORY)
282 : {
283 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
284 0 : pThis->m_bStopParsing = TRUE;
285 0 : XML_StopParser(pThis->m_oParser, XML_FALSE);
286 : }
287 :
288 : }
289 :
290 : /************************************************************************/
291 : /* endElementCbk() */
292 : /************************************************************************/
293 52173 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
294 :
295 : {
296 52173 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
297 52173 : if (pThis->m_bStopParsing)
298 0 : return;
299 :
300 52173 : if (pThis->GMLHandler::endElement() == OGRERR_NOT_ENOUGH_MEMORY)
301 : {
302 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
303 0 : pThis->m_bStopParsing = TRUE;
304 0 : XML_StopParser(pThis->m_oParser, XML_FALSE);
305 : }
306 : }
307 :
308 : /************************************************************************/
309 : /* dataHandlerCbk() */
310 : /************************************************************************/
311 :
312 151474 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
313 :
314 : {
315 151474 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
316 151474 : if (pThis->m_bStopParsing)
317 0 : return;
318 :
319 151474 : pThis->m_nDataHandlerCounter ++;
320 : /* The size of the buffer that is fetched and that Expat parses is */
321 : /* PARSER_BUF_SIZE bytes. If the dataHandlerCbk() callback is called */
322 : /* more than PARSER_BUF_SIZE times, this means that one byte in the */
323 : /* file expands to more XML text fragments, which is the sign of a */
324 : /* likely abuse of <!ENTITY> */
325 : /* Note: the counter is zeroed by ResetDataHandlerCounter() before each */
326 : /* new XML parsing. */
327 151474 : if (pThis->m_nDataHandlerCounter >= PARSER_BUF_SIZE)
328 : {
329 0 : CPLError(CE_Failure, CPLE_AppDefined, "File probably corrupted (million laugh pattern)");
330 0 : pThis->m_bStopParsing = TRUE;
331 0 : XML_StopParser(pThis->m_oParser, XML_FALSE);
332 0 : return;
333 : }
334 :
335 151474 : if (pThis->GMLHandler::dataHandler(data, nLen) == OGRERR_NOT_ENOUGH_MEMORY)
336 : {
337 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
338 0 : pThis->m_bStopParsing = TRUE;
339 0 : XML_StopParser(pThis->m_oParser, XML_FALSE);
340 0 : return;
341 : }
342 : }
343 :
344 : /************************************************************************/
345 : /* GetFID() */
346 : /************************************************************************/
347 :
348 2508 : const char* GMLExpatHandler::GetFID(void* attr)
349 : {
350 2508 : const char** papszIter = (const char** )attr;
351 6478 : while(*papszIter)
352 : {
353 3053 : if (strcmp(*papszIter, "fid") == 0 ||
354 : strcmp(*papszIter, "gml:id") == 0)
355 : {
356 1591 : return papszIter[1];
357 : }
358 1462 : papszIter += 2;
359 : }
360 917 : return NULL;
361 : }
362 :
363 : /************************************************************************/
364 : /* AddAttributes() */
365 : /************************************************************************/
366 :
367 23174 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
368 : {
369 23174 : const char** papszIter = (const char** )attr;
370 :
371 23174 : CPLXMLNode* psLastChild = NULL;
372 :
373 58703 : while(*papszIter)
374 : {
375 12355 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
376 12355 : CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
377 :
378 12355 : if (psLastChild == NULL)
379 10065 : psNode->psChild = psChild;
380 : else
381 2290 : psLastChild->psNext = psChild;
382 12355 : psLastChild = psChild;
383 :
384 12355 : papszIter += 2;
385 : }
386 :
387 23174 : return psLastChild;
388 : }
389 :
390 : /************************************************************************/
391 : /* GetAttributeValue() */
392 : /************************************************************************/
393 :
394 33307 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
395 : {
396 33307 : const char** papszIter = (const char** )attr;
397 66628 : while(*papszIter)
398 : {
399 149 : if (strcmp(*papszIter, pszAttributeName) == 0)
400 : {
401 135 : return CPLStrdup(papszIter[1]);
402 : }
403 14 : papszIter += 2;
404 : }
405 33172 : return NULL;
406 : }
407 :
408 : #endif
409 :
410 :
411 : static const char* const apszGMLGeometryElements[] =
412 : {
413 : "CompositeCurve",
414 : "CompositeSurface",
415 : "Curve",
416 : "GeometryCollection", /* OGR < 1.8.0 bug... */
417 : "LineString",
418 : "MultiCurve",
419 : "MultiGeometry",
420 : "MultiLineString",
421 : "MultiPoint",
422 : "MultiPolygon",
423 : "MultiSurface",
424 : "Point",
425 : "Polygon",
426 : "PolygonPatch",
427 : "SimplePolygon", /* GML 3.3 compact encoding */
428 : "SimpleRectangle", /* GML 3.3 compact encoding */
429 : "SimpleTriangle", /* GML 3.3 compact encoding */
430 : "SimpleMultiPoint", /* GML 3.3 compact encoding */
431 : "Solid",
432 : "Surface",
433 : "TopoCurve",
434 : "TopoSurface"
435 : };
436 :
437 : #define GML_GEOMETRY_TYPE_COUNT \
438 : (int)(sizeof(apszGMLGeometryElements) / sizeof(apszGMLGeometryElements[0]))
439 :
440 : struct _GeometryNamesStruct {
441 : unsigned long nHash;
442 : const char *pszName;
443 : } ;
444 :
445 : /************************************************************************/
446 : /* GMLHandlerSortGeometryElements() */
447 : /************************************************************************/
448 :
449 14800 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
450 : {
451 14800 : GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
452 14800 : GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
453 14800 : CPLAssert(pA->nHash != pB->nHash);
454 14800 : if (pA->nHash < pB->nHash)
455 6800 : return -1;
456 : else
457 8000 : return 1;
458 : }
459 :
460 : /************************************************************************/
461 : /* GMLHandler() */
462 : /************************************************************************/
463 :
464 200 : GMLHandler::GMLHandler( GMLReader *poReader )
465 :
466 : {
467 200 : m_poReader = poReader;
468 200 : m_bInCurField = FALSE;
469 200 : m_nCurFieldAlloc = 0;
470 200 : m_nCurFieldLen = 0;
471 200 : m_pszCurField = NULL;
472 200 : m_nAttributeIndex = -1;
473 200 : m_nAttributeDepth = 0;
474 :
475 200 : m_pszGeometry = NULL;
476 200 : m_nGeomAlloc = 0;
477 200 : m_nGeomLen = 0;
478 200 : m_nGeometryDepth = 0;
479 200 : m_bAlreadyFoundGeometry = FALSE;
480 :
481 200 : m_nDepthFeature = m_nDepth = 0;
482 200 : m_inBoundedByDepth = 0;
483 200 : m_pszCityGMLGenericAttrName = NULL;
484 200 : m_inCityGMLGenericAttrDepth = 0;
485 200 : m_bIsCityGML = FALSE;
486 200 : m_bIsAIXM = FALSE;
487 200 : m_bReportHref = FALSE;
488 200 : m_pszHref = NULL;
489 200 : m_pszUom = NULL;
490 200 : m_pszValue = NULL;
491 :
492 : pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
493 200 : GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
494 4600 : for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
495 : {
496 4400 : pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
497 4400 : pasGeometryNames[i].nHash =
498 4400 : CPLHashSetHashStr(pasGeometryNames[i].pszName);
499 : }
500 : qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
501 : sizeof(GeometryNamesStruct),
502 200 : GMLHandlerSortGeometryElements);
503 :
504 200 : nStackDepth = 0;
505 200 : stateStack[0] = STATE_TOP;
506 200 : }
507 :
508 : /************************************************************************/
509 : /* ~GMLHandler() */
510 : /************************************************************************/
511 :
512 200 : GMLHandler::~GMLHandler()
513 :
514 : {
515 200 : if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
516 6 : CPLDestroyXMLNode(apsXMLNode[1].psNode);
517 :
518 200 : CPLFree( m_pszCurField );
519 200 : CPLFree( m_pszGeometry );
520 200 : CPLFree( m_pszCityGMLGenericAttrName );
521 200 : CPLFree( m_pszHref );
522 200 : CPLFree( m_pszUom );
523 200 : CPLFree( m_pszValue );
524 200 : CPLFree( pasGeometryNames );
525 200 : }
526 :
527 :
528 : /************************************************************************/
529 : /* startElement() */
530 : /************************************************************************/
531 :
532 52227 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
533 : {
534 : OGRErr eRet;
535 52227 : switch(stateStack[nStackDepth])
536 : {
537 200 : case STATE_TOP: eRet = startElementTop(pszName, nLenName, attr); break;
538 6905 : case STATE_DEFAULT: eRet = startElementDefault(pszName, nLenName, attr); break;
539 20917 : case STATE_FEATURE: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
540 727 : case STATE_PROPERTY: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
541 20686 : case STATE_GEOMETRY: eRet = startElementGeometry(pszName, nLenName, attr); break;
542 0 : case STATE_IGNORED_FEATURE: eRet = OGRERR_NONE; break;
543 2786 : case STATE_BOUNDED_BY: eRet = startElementBoundedBy(pszName, nLenName, attr); break;
544 6 : case STATE_CITYGML_ATTRIBUTE: eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
545 0 : default: eRet = OGRERR_NONE; break;
546 : }
547 52227 : m_nDepth++;
548 52227 : return eRet;
549 : }
550 :
551 : /************************************************************************/
552 : /* endElement() */
553 : /************************************************************************/
554 :
555 52173 : OGRErr GMLHandler::endElement()
556 : {
557 52173 : m_nDepth--;
558 52173 : switch(stateStack[nStackDepth])
559 : {
560 0 : case STATE_TOP: return OGRERR_NONE; break;
561 4422 : case STATE_DEFAULT: return endElementDefault(); break;
562 4311 : case STATE_FEATURE: return endElementFeature(); break;
563 16595 : case STATE_PROPERTY: return endElementAttribute(); break;
564 23143 : case STATE_GEOMETRY: return endElementGeometry(); break;
565 0 : case STATE_IGNORED_FEATURE: return endElementIgnoredFeature(); break;
566 3690 : case STATE_BOUNDED_BY: return endElementBoundedBy(); break;
567 12 : case STATE_CITYGML_ATTRIBUTE: return endElementCityGMLGenericAttr(); break;
568 0 : default: return OGRERR_NONE; break;
569 : }
570 : }
571 :
572 : /************************************************************************/
573 : /* dataHandler() */
574 : /************************************************************************/
575 :
576 151474 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
577 : {
578 151474 : switch(stateStack[nStackDepth])
579 : {
580 0 : case STATE_TOP: return OGRERR_NONE; break;
581 17714 : case STATE_DEFAULT: return OGRERR_NONE; break;
582 39750 : case STATE_FEATURE: return OGRERR_NONE; break;
583 18130 : case STATE_PROPERTY: return dataHandlerAttribute(data, nLen); break;
584 71696 : case STATE_GEOMETRY: return dataHandlerGeometry(data, nLen); break;
585 0 : case STATE_IGNORED_FEATURE: return OGRERR_NONE; break;
586 4154 : case STATE_BOUNDED_BY: return OGRERR_NONE; break;
587 30 : case STATE_CITYGML_ATTRIBUTE: return dataHandlerAttribute(data, nLen); break;
588 0 : default: return OGRERR_NONE; break;
589 : }
590 : }
591 :
592 : #define PUSH_STATE(val) do { nStackDepth ++; CPLAssert(nStackDepth < STACK_SIZE); stateStack[nStackDepth] = val; } while(0)
593 : #define POP_STATE() nStackDepth --
594 :
595 : /************************************************************************/
596 : /* startElementBoundedBy() */
597 : /************************************************************************/
598 :
599 2786 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
600 : {
601 2786 : if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
602 : {
603 107 : char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
604 107 : m_poReader->SetGlobalSRSName(pszGlobalSRSName);
605 107 : CPLFree(pszGlobalSRSName);
606 : }
607 :
608 2786 : return OGRERR_NONE;
609 : }
610 :
611 : /************************************************************************/
612 : /* startElementGeometry() */
613 : /************************************************************************/
614 :
615 23174 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
616 : {
617 23174 : if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
618 : {
619 0 : m_inBoundedByDepth = m_nDepth;
620 :
621 0 : PUSH_STATE(STATE_BOUNDED_BY);
622 :
623 0 : return OGRERR_NONE;
624 : }
625 :
626 : /* Create new XML Element */
627 23174 : CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
628 23174 : psCurNode->eType = CXT_Element;
629 23174 : psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
630 23174 : memcpy(psCurNode->pszValue, pszName, nLenName+1);
631 :
632 : /* Attach element as the last child of its parent */
633 23174 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
634 23174 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
635 :
636 23174 : if (psLastChildParent == NULL)
637 : {
638 12030 : CPLXMLNode* psParent = sNodeLastChild.psNode;
639 12030 : if (psParent)
640 9542 : psParent->psChild = psCurNode;
641 : }
642 : else
643 : {
644 11144 : psLastChildParent->psNext = psCurNode;
645 : }
646 23174 : sNodeLastChild.psLastChild = psCurNode;
647 :
648 : /* Add attributes to the element */
649 23174 : CPLXMLNode* psLastChildCurNode = AddAttributes(psCurNode, attr);
650 :
651 : /* Some CityGML lack a srsDimension="3" in posList, such as in */
652 : /* http://www.citygml.org/fileadmin/count.php?f=fileadmin%2Fcitygml%2Fdocs%2FFrankfurt_Street_Setting_LOD3.zip */
653 : /* So we have to add it manually */
654 23174 : if (m_bIsCityGML && nLenName == 7 &&
655 : strcmp(pszName, "posList") == 0 &&
656 : CPLGetXMLValue(psCurNode, "srsDimension", NULL) == NULL)
657 : {
658 0 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, "srsDimension");
659 0 : CPLCreateXMLNode(psChild, CXT_Text, "3");
660 :
661 0 : if (psLastChildCurNode == NULL)
662 0 : psCurNode->psChild = psChild;
663 : else
664 0 : psLastChildCurNode->psNext = psChild;
665 0 : psLastChildCurNode = psChild;
666 : }
667 :
668 : /* Push the element on the stack */
669 : NodeLastChild sNewNodeLastChild;
670 23174 : sNewNodeLastChild.psNode = psCurNode;
671 23174 : sNewNodeLastChild.psLastChild = psLastChildCurNode;
672 23174 : apsXMLNode.push_back(sNewNodeLastChild);
673 :
674 23174 : if (m_pszGeometry)
675 : {
676 0 : CPLFree(m_pszGeometry);
677 0 : m_pszGeometry = NULL;
678 0 : m_nGeomAlloc = 0;
679 0 : m_nGeomLen = 0;
680 : }
681 :
682 23174 : return OGRERR_NONE;
683 : }
684 :
685 : /************************************************************************/
686 : /* startElementCityGMLGenericAttr() */
687 : /************************************************************************/
688 :
689 6 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
690 : {
691 6 : if( strcmp(pszName, "value") == 0 )
692 : {
693 6 : if(m_pszCurField)
694 : {
695 0 : CPLFree(m_pszCurField);
696 0 : m_pszCurField = NULL;
697 0 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
698 : }
699 6 : m_bInCurField = TRUE;
700 : }
701 :
702 6 : return OGRERR_NONE;
703 : }
704 : /************************************************************************/
705 : /* startElementFeatureAttribute() */
706 : /************************************************************************/
707 :
708 21644 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
709 : {
710 : /* Reset flag */
711 21644 : m_bInCurField = FALSE;
712 :
713 21644 : GMLReadState *poState = m_poReader->GetState();
714 :
715 : /* -------------------------------------------------------------------- */
716 : /* If we are collecting geometry, or if we determine this is a */
717 : /* geometry element then append to the geometry info. */
718 : /* -------------------------------------------------------------------- */
719 21644 : if( IsGeometryElement( pszName ) )
720 : {
721 : int bReadGeometry;
722 :
723 : /* If the <GeometryElementPath> is defined in the .gfs, use it */
724 : /* to read the appropriate geometry element */
725 2492 : const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
726 2492 : if (pszGeometryElement != NULL)
727 1454 : bReadGeometry = strcmp(poState->osPath.c_str(), pszGeometryElement) == 0;
728 1038 : else if( m_poReader->FetchAllGeometries() )
729 : {
730 0 : bReadGeometry = TRUE;
731 : }
732 : else
733 : {
734 : /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
735 : /* not 'start' and 'end' geometries */
736 1038 : if (m_bIsAIXM &&
737 : strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
738 0 : bReadGeometry = strcmp( pszName, "Curve") == 0;
739 :
740 : /* For Inspire objects : the "main" geometry is in a <geometry> element */
741 1038 : else if (m_bAlreadyFoundGeometry)
742 2 : bReadGeometry = FALSE;
743 1036 : else if (strcmp( poState->osPath.c_str(), "geometry") == 0)
744 : {
745 8 : m_bAlreadyFoundGeometry = TRUE;
746 8 : bReadGeometry = TRUE;
747 : }
748 :
749 : else
750 1028 : bReadGeometry = TRUE;
751 : }
752 2492 : if (bReadGeometry)
753 : {
754 2488 : m_nGeometryDepth = m_nDepth;
755 :
756 2488 : CPLAssert(apsXMLNode.size() == 0);
757 :
758 : NodeLastChild sNodeLastChild;
759 2488 : sNodeLastChild.psNode = NULL;
760 2488 : sNodeLastChild.psLastChild = NULL;
761 2488 : apsXMLNode.push_back(sNodeLastChild);
762 :
763 2488 : PUSH_STATE(STATE_GEOMETRY);
764 :
765 2488 : return startElementGeometry(pszName, nLenName, attr);
766 : }
767 : }
768 :
769 :
770 19152 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
771 : {
772 741 : m_inBoundedByDepth = m_nDepth;
773 :
774 741 : PUSH_STATE(STATE_BOUNDED_BY);
775 :
776 741 : return OGRERR_NONE;
777 : }
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* Is it a CityGML generic attribute ? */
781 : /* -------------------------------------------------------------------- */
782 18411 : else if( m_bIsCityGML &&
783 : m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
784 : {
785 6 : CPLFree(m_pszCityGMLGenericAttrName);
786 6 : m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
787 6 : m_inCityGMLGenericAttrDepth = m_nDepth;
788 :
789 6 : PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
790 :
791 6 : return OGRERR_NONE;
792 : }
793 :
794 : /* -------------------------------------------------------------------- */
795 : /* If it is (or at least potentially is) a simple attribute, */
796 : /* then start collecting it. */
797 : /* -------------------------------------------------------------------- */
798 18405 : else if( (m_nAttributeIndex =
799 : m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
800 : {
801 16594 : if(m_pszCurField)
802 : {
803 568 : CPLFree(m_pszCurField);
804 568 : m_pszCurField = NULL;
805 568 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
806 : }
807 16594 : m_bInCurField = TRUE;
808 16594 : if (m_bReportHref)
809 : {
810 0 : CPLFree(m_pszHref);
811 0 : m_pszHref = GetAttributeValue(attr, "xlink:href");
812 : }
813 16594 : CPLFree(m_pszUom);
814 16594 : m_pszUom = GetAttributeValue(attr, "uom");
815 16594 : CPLFree(m_pszValue);
816 16594 : m_pszValue = GetAttributeValue(attr, "value");
817 :
818 16594 : if (stateStack[nStackDepth] != STATE_PROPERTY)
819 : {
820 16564 : m_nAttributeDepth = m_nDepth;
821 16564 : PUSH_STATE(STATE_PROPERTY);
822 : }
823 :
824 : }
825 1811 : else if( m_bReportHref && (m_nAttributeIndex =
826 : m_poReader->GetAttributeElementIndex( CPLSPrintf("%s_href", pszName ),
827 : nLenName + 5 )) != -1 )
828 : {
829 0 : if(m_pszCurField)
830 : {
831 0 : CPLFree(m_pszCurField);
832 0 : m_pszCurField = NULL;
833 0 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
834 : }
835 0 : m_bInCurField = TRUE;
836 0 : CPLFree(m_pszHref);
837 0 : m_pszHref = GetAttributeValue(attr, "xlink:href");
838 :
839 0 : if (stateStack[nStackDepth] != STATE_PROPERTY)
840 : {
841 0 : m_nAttributeDepth = m_nDepth;
842 0 : PUSH_STATE(STATE_PROPERTY);
843 : }
844 : }
845 :
846 18409 : poState->PushPath( pszName, nLenName );
847 :
848 18409 : return OGRERR_NONE;
849 : }
850 :
851 : /************************************************************************/
852 : /* startElementTop() */
853 : /************************************************************************/
854 :
855 200 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
856 :
857 : {
858 200 : if (strcmp(pszName, "CityModel") == 0 )
859 : {
860 2 : m_bIsCityGML = TRUE;
861 : }
862 198 : else if (strcmp(pszName, "AIXMBasicMessage") == 0)
863 : {
864 0 : m_bIsAIXM = m_bReportHref = TRUE;
865 : }
866 :
867 200 : stateStack[0] = STATE_DEFAULT;
868 :
869 200 : return OGRERR_NONE;
870 : }
871 :
872 : /************************************************************************/
873 : /* startElementDefault() */
874 : /************************************************************************/
875 :
876 6905 : OGRErr GMLHandler::startElementDefault(const char *pszName, int nLenName, void* attr )
877 :
878 : {
879 : /* -------------------------------------------------------------------- */
880 : /* Is it a feature? If so push a whole new state, and return. */
881 : /* -------------------------------------------------------------------- */
882 : int nClassIndex;
883 6905 : if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
884 : {
885 2508 : m_bAlreadyFoundGeometry = FALSE;
886 :
887 2508 : const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
888 2508 : if ( pszFilteredClassName != NULL &&
889 : strcmp(pszName, pszFilteredClassName) != 0 )
890 : {
891 0 : m_nDepthFeature = m_nDepth;
892 :
893 0 : PUSH_STATE(STATE_IGNORED_FEATURE);
894 :
895 0 : return OGRERR_NONE;
896 : }
897 : else
898 : {
899 2508 : m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
900 :
901 2508 : m_nDepthFeature = m_nDepth;
902 :
903 2508 : PUSH_STATE(STATE_FEATURE);
904 :
905 2508 : return OGRERR_NONE;
906 : }
907 : }
908 :
909 4397 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
910 : {
911 163 : m_inBoundedByDepth = m_nDepth;
912 :
913 163 : PUSH_STATE(STATE_BOUNDED_BY);
914 :
915 163 : return OGRERR_NONE;
916 : }
917 :
918 : /* -------------------------------------------------------------------- */
919 : /* Push the element onto the current state's path. */
920 : /* -------------------------------------------------------------------- */
921 4234 : m_poReader->GetState()->PushPath( pszName, nLenName );
922 :
923 4234 : return OGRERR_NONE;
924 : }
925 :
926 : /************************************************************************/
927 : /* endElementIgnoredFeature() */
928 : /************************************************************************/
929 :
930 0 : OGRErr GMLHandler::endElementIgnoredFeature()
931 :
932 : {
933 0 : if (m_nDepth == m_nDepthFeature)
934 : {
935 0 : POP_STATE();
936 : }
937 0 : return OGRERR_NONE;
938 : }
939 :
940 : /************************************************************************/
941 : /* endElementBoundedBy() */
942 : /************************************************************************/
943 3690 : OGRErr GMLHandler::endElementBoundedBy()
944 :
945 : {
946 3690 : if( m_inBoundedByDepth == m_nDepth)
947 : {
948 904 : POP_STATE();
949 : }
950 :
951 3690 : return OGRERR_NONE;
952 : }
953 :
954 : /************************************************************************/
955 : /* ParseAIXMElevationPoint() */
956 : /************************************************************************/
957 :
958 0 : CPLXMLNode* GMLHandler::ParseAIXMElevationPoint(CPLXMLNode *psGML)
959 : {
960 : const char* pszElevation =
961 0 : CPLGetXMLValue( psGML, "elevation", NULL );
962 0 : if (pszElevation)
963 : {
964 : m_poReader->SetFeaturePropertyDirectly( "elevation",
965 0 : CPLStrdup(pszElevation), -1 );
966 : const char* pszElevationUnit =
967 0 : CPLGetXMLValue( psGML, "elevation.uom", NULL );
968 0 : if (pszElevationUnit)
969 : {
970 : m_poReader->SetFeaturePropertyDirectly( "elevation_uom",
971 0 : CPLStrdup(pszElevationUnit), -1 );
972 : }
973 : }
974 :
975 : const char* pszGeoidUndulation =
976 0 : CPLGetXMLValue( psGML, "geoidUndulation", NULL );
977 0 : if (pszGeoidUndulation)
978 : {
979 : m_poReader->SetFeaturePropertyDirectly( "geoidUndulation",
980 0 : CPLStrdup(pszGeoidUndulation), -1 );
981 : const char* pszGeoidUndulationUnit =
982 0 : CPLGetXMLValue( psGML, "geoidUndulation.uom", NULL );
983 0 : if (pszGeoidUndulationUnit)
984 : {
985 : m_poReader->SetFeaturePropertyDirectly( "geoidUndulation_uom",
986 0 : CPLStrdup(pszGeoidUndulationUnit), -1 );
987 : }
988 : }
989 :
990 : const char* pszPos =
991 0 : CPLGetXMLValue( psGML, "pos", NULL );
992 : const char* pszCoordinates =
993 0 : CPLGetXMLValue( psGML, "coordinates", NULL );
994 0 : if (pszPos != NULL)
995 : {
996 : char* pszGeometry = CPLStrdup(CPLSPrintf(
997 : "<gml:Point><gml:pos>%s</gml:pos></gml:Point>",
998 0 : pszPos));
999 0 : CPLDestroyXMLNode(psGML);
1000 0 : psGML = CPLParseXMLString(pszGeometry);
1001 0 : CPLFree(pszGeometry);
1002 : }
1003 0 : else if (pszCoordinates != NULL)
1004 : {
1005 : char* pszGeometry = CPLStrdup(CPLSPrintf(
1006 : "<gml:Point><gml:coordinates>%s</gml:coordinates></gml:Point>",
1007 0 : pszCoordinates));
1008 0 : CPLDestroyXMLNode(psGML);
1009 0 : psGML = CPLParseXMLString(pszGeometry);
1010 0 : CPLFree(pszGeometry);
1011 : }
1012 : else
1013 : {
1014 0 : CPLDestroyXMLNode(psGML);
1015 0 : psGML = NULL;
1016 : }
1017 :
1018 0 : return psGML;
1019 : }
1020 :
1021 : /************************************************************************/
1022 : /* endElementGeometry() */
1023 : /************************************************************************/
1024 23143 : OGRErr GMLHandler::endElementGeometry()
1025 :
1026 : {
1027 23143 : if (m_nGeomLen)
1028 : {
1029 3825 : CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
1030 3825 : psNode->eType = CXT_Text;
1031 3825 : psNode->pszValue = m_pszGeometry;
1032 :
1033 3825 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
1034 3825 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
1035 3825 : if (psLastChildParent == NULL)
1036 : {
1037 2314 : CPLXMLNode* psParent = sNodeLastChild.psNode;
1038 2314 : if (psParent)
1039 2314 : psParent->psChild = psNode;
1040 : }
1041 : else
1042 1511 : psLastChildParent->psNext = psNode;
1043 3825 : sNodeLastChild.psLastChild = psNode;
1044 :
1045 3825 : m_pszGeometry = NULL;
1046 3825 : m_nGeomAlloc = 0;
1047 3825 : m_nGeomLen = 0;
1048 : }
1049 :
1050 23143 : if( m_nDepth == m_nGeometryDepth )
1051 : {
1052 2482 : CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
1053 :
1054 : /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
1055 : CPLDebug("GML", "geometry = %s", pszXML);
1056 : CPLFree(pszXML);*/
1057 :
1058 2482 : apsXMLNode.pop_back();
1059 :
1060 : /* AIXM ElevatedPoint. We want to parse this */
1061 : /* a bit specially because ElevatedPoint is aixm: stuff and */
1062 : /* the srsDimension of the <gml:pos> can be set to TRUE although */
1063 : /* they are only 2 coordinates in practice */
1064 2482 : if ( m_bIsAIXM && psInterestNode != NULL &&
1065 : strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
1066 : {
1067 0 : psInterestNode = ParseAIXMElevationPoint(psInterestNode);
1068 : }
1069 :
1070 2482 : if (m_poReader->FetchAllGeometries())
1071 0 : m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
1072 : else
1073 2482 : m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
1074 :
1075 2482 : POP_STATE();
1076 : }
1077 :
1078 23143 : apsXMLNode.pop_back();
1079 :
1080 23143 : return OGRERR_NONE;
1081 : }
1082 :
1083 : /************************************************************************/
1084 : /* endElementCityGMLGenericAttr() */
1085 : /************************************************************************/
1086 12 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
1087 :
1088 : {
1089 12 : if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
1090 : {
1091 : m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
1092 6 : m_pszCurField, -1 );
1093 6 : m_pszCurField = NULL;
1094 6 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1095 6 : m_bInCurField = FALSE;
1096 6 : CPLFree(m_pszCityGMLGenericAttrName);
1097 6 : m_pszCityGMLGenericAttrName = NULL;
1098 : }
1099 :
1100 12 : if( m_inCityGMLGenericAttrDepth == m_nDepth )
1101 : {
1102 6 : POP_STATE();
1103 : }
1104 :
1105 12 : return OGRERR_NONE;
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* endElementAttribute() */
1110 : /************************************************************************/
1111 16595 : OGRErr GMLHandler::endElementAttribute()
1112 :
1113 : {
1114 16595 : GMLReadState *poState = m_poReader->GetState();
1115 :
1116 16595 : if (m_bInCurField)
1117 : {
1118 15888 : if (m_pszCurField == NULL)
1119 : {
1120 543 : if (m_pszValue != NULL)
1121 : {
1122 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1123 10 : m_pszValue, -1 );
1124 10 : m_pszValue = NULL;
1125 : }
1126 : }
1127 : else
1128 : {
1129 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1130 : m_pszCurField,
1131 15345 : m_nAttributeIndex );
1132 15345 : m_pszCurField = NULL;
1133 : }
1134 :
1135 15888 : if (m_pszHref != NULL)
1136 : {
1137 0 : CPLString osPropNameHref = poState->osPath + "_href";
1138 0 : m_poReader->SetFeaturePropertyDirectly( osPropNameHref, m_pszHref, -1 );
1139 0 : m_pszHref = NULL;
1140 : }
1141 :
1142 15888 : if (m_pszUom != NULL)
1143 : {
1144 10 : CPLString osPropNameUom = poState->osPath + "_uom";
1145 10 : m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
1146 10 : m_pszUom = NULL;
1147 : }
1148 :
1149 15888 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1150 15888 : m_bInCurField = FALSE;
1151 15888 : m_nAttributeIndex = -1;
1152 :
1153 15888 : CPLFree( m_pszValue );
1154 15888 : m_pszValue = NULL;
1155 : }
1156 :
1157 16595 : poState->PopPath();
1158 :
1159 16595 : if( m_nAttributeDepth == m_nDepth )
1160 : {
1161 16563 : POP_STATE();
1162 : }
1163 :
1164 16595 : return OGRERR_NONE;
1165 : }
1166 :
1167 : /************************************************************************/
1168 : /* endElementFeature() */
1169 : /************************************************************************/
1170 4311 : OGRErr GMLHandler::endElementFeature()
1171 :
1172 : {
1173 : /* -------------------------------------------------------------------- */
1174 : /* If we are collecting a feature, and this element tag matches */
1175 : /* element name for the class, then we have finished the */
1176 : /* feature, and we pop the feature read state. */
1177 : /* -------------------------------------------------------------------- */
1178 4311 : if( m_nDepth == m_nDepthFeature )
1179 : {
1180 2502 : m_poReader->PopState();
1181 :
1182 2502 : POP_STATE();
1183 : }
1184 :
1185 : /* -------------------------------------------------------------------- */
1186 : /* Otherwise, we just pop the element off the local read states */
1187 : /* element stack. */
1188 : /* -------------------------------------------------------------------- */
1189 : else
1190 : {
1191 1809 : m_poReader->GetState()->PopPath();
1192 : }
1193 :
1194 4311 : return OGRERR_NONE;
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* endElementDefault() */
1199 : /************************************************************************/
1200 4422 : OGRErr GMLHandler::endElementDefault()
1201 :
1202 : {
1203 4422 : if (m_nDepth > 0)
1204 4228 : m_poReader->GetState()->PopPath();
1205 :
1206 4422 : return OGRERR_NONE;
1207 : }
1208 :
1209 : /************************************************************************/
1210 : /* dataHandlerAttribute() */
1211 : /************************************************************************/
1212 :
1213 18160 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
1214 :
1215 : {
1216 18160 : int nIter = 0;
1217 :
1218 18160 : if( m_bInCurField )
1219 : {
1220 : // Ignore white space
1221 16793 : if (m_nCurFieldLen == 0)
1222 : {
1223 39078 : while (nIter < nLen)
1224 : {
1225 20847 : char ch = data[nIter];
1226 20847 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1227 15351 : break;
1228 5496 : nIter ++;
1229 : }
1230 : }
1231 :
1232 16793 : int nCharsLen = nLen - nIter;
1233 :
1234 16793 : if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
1235 : {
1236 15940 : m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
1237 : char *pszNewCurField = (char *)
1238 15940 : VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
1239 15940 : if (pszNewCurField == NULL)
1240 : {
1241 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1242 : }
1243 15940 : m_pszCurField = pszNewCurField;
1244 : }
1245 16793 : memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
1246 16793 : m_nCurFieldLen += nCharsLen;
1247 16793 : m_pszCurField[m_nCurFieldLen] = '\0';
1248 : }
1249 :
1250 18160 : return OGRERR_NONE;
1251 : }
1252 :
1253 : /************************************************************************/
1254 : /* dataHandlerGeometry() */
1255 : /************************************************************************/
1256 :
1257 71696 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
1258 :
1259 : {
1260 71696 : int nIter = 0;
1261 :
1262 : // Ignore white space
1263 71696 : if (m_nGeomLen == 0)
1264 : {
1265 617504 : while (nIter < nLen)
1266 : {
1267 478258 : char ch = data[nIter];
1268 478258 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1269 3826 : break;
1270 474432 : nIter ++;
1271 : }
1272 : }
1273 :
1274 71696 : int nCharsLen = nLen - nIter;
1275 71696 : if (nCharsLen)
1276 : {
1277 3986 : if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
1278 : {
1279 3950 : m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
1280 : char* pszNewGeometry = (char *)
1281 3950 : VSIRealloc( m_pszGeometry, m_nGeomAlloc);
1282 3950 : if (pszNewGeometry == NULL)
1283 : {
1284 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1285 : }
1286 3950 : m_pszGeometry = pszNewGeometry;
1287 : }
1288 3986 : memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
1289 3986 : m_nGeomLen += nCharsLen;
1290 3986 : m_pszGeometry[m_nGeomLen] = '\0';
1291 : }
1292 :
1293 71696 : return OGRERR_NONE;
1294 : }
1295 :
1296 :
1297 : /************************************************************************/
1298 : /* IsGeometryElement() */
1299 : /************************************************************************/
1300 :
1301 21644 : int GMLHandler::IsGeometryElement( const char *pszElement )
1302 :
1303 : {
1304 21644 : int nFirst = 0;
1305 21644 : int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
1306 21644 : unsigned long nHash = CPLHashSetHashStr(pszElement);
1307 96551 : do
1308 : {
1309 99043 : int nMiddle = (nFirst + nLast) / 2;
1310 99043 : if (nHash == pasGeometryNames[nMiddle].nHash)
1311 2492 : return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
1312 96551 : if (nHash < pasGeometryNames[nMiddle].nHash)
1313 51772 : nLast = nMiddle - 1;
1314 : else
1315 44779 : nFirst = nMiddle + 1;
1316 : } while(nFirst <= nLast);
1317 :
1318 19152 : if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
1319 0 : return TRUE;
1320 :
1321 19152 : return FALSE;
1322 : }
|