1 : /**********************************************************************
2 : * $Id: gmlhandler.cpp 23566 2011-12-13 20:51:04Z 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\n",
139 0 : pszErrorMessage );
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 111 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
253 :
254 : {
255 111 : m_oParser = oParser;
256 111 : m_bStopParsing = FALSE;
257 111 : m_nDataHandlerCounter = 0;
258 111 : }
259 :
260 : /************************************************************************/
261 : /* startElementCbk() */
262 : /************************************************************************/
263 :
264 14797 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
265 : const char **ppszAttr)
266 :
267 : {
268 14797 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
269 14797 : if (pThis->m_bStopParsing)
270 0 : return;
271 :
272 14797 : const char* pszIter = pszName;
273 : char ch;
274 201287 : while((ch = *pszIter) != '\0')
275 : {
276 171693 : if (ch == ':')
277 10864 : pszName = pszIter + 1;
278 171693 : pszIter ++;
279 : }
280 :
281 14797 : 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 14790 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
294 :
295 : {
296 14790 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
297 14790 : if (pThis->m_bStopParsing)
298 0 : return;
299 :
300 14790 : 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 39489 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
313 :
314 : {
315 39489 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
316 39489 : if (pThis->m_bStopParsing)
317 0 : return;
318 :
319 39489 : 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 39489 : 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 39489 : 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 960 : const char* GMLExpatHandler::GetFID(void* attr)
349 : {
350 960 : const char** papszIter = (const char** )attr;
351 1942 : while(*papszIter)
352 : {
353 465 : if (strcmp(*papszIter, "fid") == 0 ||
354 : strcmp(*papszIter, "gml:id") == 0)
355 : {
356 443 : return papszIter[1];
357 : }
358 22 : papszIter += 2;
359 : }
360 517 : return NULL;
361 : }
362 :
363 : /************************************************************************/
364 : /* AddAttributes() */
365 : /************************************************************************/
366 :
367 7604 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
368 : {
369 7604 : const char** papszIter = (const char** )attr;
370 :
371 7604 : CPLXMLNode* psLastChild = NULL;
372 :
373 19581 : while(*papszIter)
374 : {
375 4373 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
376 4373 : CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
377 :
378 4373 : if (psLastChild == NULL)
379 3934 : psNode->psChild = psChild;
380 : else
381 439 : psLastChild->psNext = psChild;
382 4373 : psLastChild = psChild;
383 :
384 4373 : papszIter += 2;
385 : }
386 :
387 7604 : return psLastChild;
388 : }
389 :
390 : /************************************************************************/
391 : /* GetAttributeValue() */
392 : /************************************************************************/
393 :
394 5873 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
395 : {
396 5873 : const char** papszIter = (const char** )attr;
397 11761 : while(*papszIter)
398 : {
399 98 : if (strcmp(*papszIter, pszAttributeName) == 0)
400 : {
401 83 : return CPLStrdup(papszIter[1]);
402 : }
403 15 : papszIter += 2;
404 : }
405 5790 : return NULL;
406 : }
407 :
408 : #endif
409 :
410 :
411 : static const char* const apszGMLGeometryElements[] =
412 : {
413 : "CompositeSurface",
414 : "Curve",
415 : "GeometryCollection", /* OGR < 1.8.0 bug... */
416 : "LineString",
417 : "MultiCurve",
418 : "MultiGeometry",
419 : "MultiLineString",
420 : "MultiPoint",
421 : "MultiPolygon",
422 : "MultiSurface",
423 : "Point",
424 : "Polygon",
425 : "PolygonPatch",
426 : "Solid",
427 : "Surface",
428 : "TopoCurve",
429 : "TopoSurface"
430 : };
431 :
432 : #define GML_GEOMETRY_TYPE_COUNT \
433 : (int)(sizeof(apszGMLGeometryElements) / sizeof(apszGMLGeometryElements[0]))
434 :
435 : struct _GeometryNamesStruct {
436 : unsigned long nHash;
437 : const char *pszName;
438 : } ;
439 :
440 : /************************************************************************/
441 : /* GMLHandlerSortGeometryElements() */
442 : /************************************************************************/
443 :
444 5439 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
445 : {
446 5439 : GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
447 5439 : GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
448 5439 : CPLAssert(pA->nHash != pB->nHash);
449 5439 : if (pA->nHash < pB->nHash)
450 2775 : return -1;
451 : else
452 2664 : return 1;
453 : }
454 :
455 : /************************************************************************/
456 : /* GMLHandler() */
457 : /************************************************************************/
458 :
459 111 : GMLHandler::GMLHandler( GMLReader *poReader )
460 :
461 : {
462 111 : m_poReader = poReader;
463 111 : m_bInCurField = FALSE;
464 111 : m_nCurFieldAlloc = 0;
465 111 : m_nCurFieldLen = 0;
466 111 : m_pszCurField = NULL;
467 111 : m_nAttributeIndex = -1;
468 111 : m_nAttributeDepth = 0;
469 :
470 111 : m_pszGeometry = NULL;
471 111 : m_nGeomAlloc = 0;
472 111 : m_nGeomLen = 0;
473 111 : m_nGeometryDepth = 0;
474 :
475 111 : m_nDepthFeature = m_nDepth = 0;
476 111 : m_inBoundedByDepth = 0;
477 111 : m_pszCityGMLGenericAttrName = NULL;
478 111 : m_inCityGMLGenericAttrDepth = 0;
479 111 : m_bIsCityGML = FALSE;
480 111 : m_bIsAIXM = FALSE;
481 111 : m_bReportHref = FALSE;
482 111 : m_pszHref = NULL;
483 111 : m_pszUom = NULL;
484 111 : m_pszValue = NULL;
485 :
486 : pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
487 111 : GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
488 1998 : for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
489 : {
490 1887 : pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
491 1887 : pasGeometryNames[i].nHash =
492 1887 : CPLHashSetHashStr(pasGeometryNames[i].pszName);
493 : }
494 : qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
495 : sizeof(GeometryNamesStruct),
496 111 : GMLHandlerSortGeometryElements);
497 :
498 111 : nStackDepth = 0;
499 111 : stateStack[0] = STATE_TOP;
500 111 : }
501 :
502 : /************************************************************************/
503 : /* ~GMLHandler() */
504 : /************************************************************************/
505 :
506 111 : GMLHandler::~GMLHandler()
507 :
508 : {
509 111 : if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
510 1 : CPLDestroyXMLNode(apsXMLNode[1].psNode);
511 :
512 111 : CPLFree( m_pszCurField );
513 111 : CPLFree( m_pszGeometry );
514 111 : CPLFree( m_pszCityGMLGenericAttrName );
515 111 : CPLFree( m_pszHref );
516 111 : CPLFree( m_pszUom );
517 111 : CPLFree( m_pszValue );
518 111 : CPLFree( pasGeometryNames );
519 111 : }
520 :
521 :
522 : /************************************************************************/
523 : /* startElement() */
524 : /************************************************************************/
525 :
526 14797 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
527 : {
528 : OGRErr eRet;
529 14797 : switch(stateStack[nStackDepth])
530 : {
531 111 : case STATE_TOP: eRet = startElementTop(pszName, nLenName, attr); break;
532 1836 : case STATE_DEFAULT: eRet = startElementDefault(pszName, nLenName, attr); break;
533 4218 : case STATE_FEATURE: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
534 495 : case STATE_PROPERTY: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
535 6658 : case STATE_GEOMETRY: eRet = startElementGeometry(pszName, nLenName, attr); break;
536 64 : case STATE_IGNORED_FEATURE: eRet = OGRERR_NONE; break;
537 1409 : case STATE_BOUNDED_BY: eRet = startElementBoundedBy(pszName, nLenName, attr); break;
538 6 : case STATE_CITYGML_ATTRIBUTE: eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
539 0 : default: eRet = OGRERR_NONE; break;
540 : }
541 14797 : m_nDepth++;
542 14797 : return eRet;
543 : }
544 :
545 : /************************************************************************/
546 : /* endElement() */
547 : /************************************************************************/
548 :
549 14790 : OGRErr GMLHandler::endElement()
550 : {
551 14790 : m_nDepth--;
552 14790 : switch(stateStack[nStackDepth])
553 : {
554 0 : case STATE_TOP: return OGRERR_NONE; break;
555 886 : case STATE_DEFAULT: return endElementDefault(); break;
556 1447 : case STATE_FEATURE: return endElementFeature(); break;
557 2905 : case STATE_PROPERTY: return endElementAttribute(); break;
558 7601 : case STATE_GEOMETRY: return endElementGeometry(); break;
559 76 : case STATE_IGNORED_FEATURE: return endElementIgnoredFeature(); break;
560 1863 : case STATE_BOUNDED_BY: return endElementBoundedBy(); break;
561 12 : case STATE_CITYGML_ATTRIBUTE: return endElementCityGMLGenericAttr(); break;
562 0 : default: return OGRERR_NONE; break;
563 : }
564 : }
565 :
566 : /************************************************************************/
567 : /* dataHandler() */
568 : /************************************************************************/
569 :
570 39489 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
571 : {
572 39489 : switch(stateStack[nStackDepth])
573 : {
574 0 : case STATE_TOP: return OGRERR_NONE; break;
575 3968 : case STATE_DEFAULT: return OGRERR_NONE; break;
576 7370 : case STATE_FEATURE: return OGRERR_NONE; break;
577 4077 : case STATE_PROPERTY: return dataHandlerAttribute(data, nLen); break;
578 20618 : case STATE_GEOMETRY: return dataHandlerGeometry(data, nLen); break;
579 140 : case STATE_IGNORED_FEATURE: return OGRERR_NONE; break;
580 3286 : case STATE_BOUNDED_BY: return OGRERR_NONE; break;
581 30 : case STATE_CITYGML_ATTRIBUTE: return dataHandlerAttribute(data, nLen); break;
582 0 : default: return OGRERR_NONE; break;
583 : }
584 : }
585 :
586 : #define PUSH_STATE(val) do { nStackDepth ++; CPLAssert(nStackDepth < STACK_SIZE); stateStack[nStackDepth] = val; } while(0)
587 : #define POP_STATE() nStackDepth --
588 :
589 : /************************************************************************/
590 : /* startElementBoundedBy() */
591 : /************************************************************************/
592 :
593 1409 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
594 : {
595 1409 : if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
596 : {
597 51 : char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
598 51 : m_poReader->SetGlobalSRSName(pszGlobalSRSName);
599 51 : CPLFree(pszGlobalSRSName);
600 : }
601 :
602 1409 : return OGRERR_NONE;
603 : }
604 :
605 : /************************************************************************/
606 : /* startElementGeometry() */
607 : /************************************************************************/
608 :
609 7604 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
610 : {
611 7604 : if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
612 : {
613 0 : m_inBoundedByDepth = m_nDepth;
614 :
615 0 : PUSH_STATE(STATE_BOUNDED_BY);
616 :
617 0 : return OGRERR_NONE;
618 : }
619 :
620 : /* Create new XML Element */
621 7604 : CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
622 7604 : psCurNode->eType = CXT_Element;
623 7604 : psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
624 7604 : memcpy(psCurNode->pszValue, pszName, nLenName+1);
625 :
626 : /* Attach element as the last child of its parent */
627 7604 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
628 7604 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
629 :
630 7604 : if (psLastChildParent == NULL)
631 : {
632 3494 : CPLXMLNode* psParent = sNodeLastChild.psNode;
633 3494 : if (psParent)
634 2548 : psParent->psChild = psCurNode;
635 : }
636 : else
637 : {
638 4110 : psLastChildParent->psNext = psCurNode;
639 : }
640 7604 : sNodeLastChild.psLastChild = psCurNode;
641 :
642 : /* Add attributes to the element */
643 7604 : CPLXMLNode* psLastChildCurNode = AddAttributes(psCurNode, attr);
644 :
645 : /* Some CityGML lack a srsDimension="3" in posList, such as in */
646 : /* http://www.citygml.org/fileadmin/count.php?f=fileadmin%2Fcitygml%2Fdocs%2FFrankfurt_Street_Setting_LOD3.zip */
647 : /* So we have to add it manually */
648 7604 : if (m_bIsCityGML && nLenName == 7 &&
649 : strcmp(pszName, "posList") == 0 &&
650 : CPLGetXMLValue(psCurNode, "srsDimension", NULL) == NULL)
651 : {
652 0 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, "srsDimension");
653 0 : CPLCreateXMLNode(psChild, CXT_Text, "3");
654 :
655 0 : if (psLastChildCurNode == NULL)
656 0 : psCurNode->psChild = psChild;
657 : else
658 0 : psLastChildCurNode->psNext = psChild;
659 0 : psLastChildCurNode = psChild;
660 : }
661 :
662 : /* Push the element on the stack */
663 : NodeLastChild sNewNodeLastChild;
664 7604 : sNewNodeLastChild.psNode = psCurNode;
665 7604 : sNewNodeLastChild.psLastChild = psLastChildCurNode;
666 7604 : apsXMLNode.push_back(sNewNodeLastChild);
667 :
668 7604 : if (m_pszGeometry)
669 : {
670 0 : CPLFree(m_pszGeometry);
671 0 : m_pszGeometry = NULL;
672 0 : m_nGeomAlloc = 0;
673 0 : m_nGeomLen = 0;
674 : }
675 :
676 7604 : return OGRERR_NONE;
677 : }
678 :
679 : /************************************************************************/
680 : /* startElementCityGMLGenericAttr() */
681 : /************************************************************************/
682 :
683 6 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
684 : {
685 6 : if( strcmp(pszName, "value") == 0 )
686 : {
687 6 : if(m_pszCurField)
688 : {
689 0 : CPLFree(m_pszCurField);
690 0 : m_pszCurField = NULL;
691 0 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
692 : }
693 6 : m_bInCurField = TRUE;
694 : }
695 :
696 6 : return OGRERR_NONE;
697 : }
698 : /************************************************************************/
699 : /* startElementFeatureAttribute() */
700 : /************************************************************************/
701 :
702 4713 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
703 : {
704 : /* Reset flag */
705 4713 : m_bInCurField = FALSE;
706 :
707 4713 : GMLReadState *poState = m_poReader->GetState();
708 :
709 : /* -------------------------------------------------------------------- */
710 : /* If we are collecting geometry, or if we determine this is a */
711 : /* geometry element then append to the geometry info. */
712 : /* -------------------------------------------------------------------- */
713 4713 : if( IsGeometryElement( pszName ) )
714 : {
715 : int bReadGeometry;
716 :
717 : /* If the <GeometryElementPath> is defined in the .gfs, use it */
718 : /* to read the appropriate geometry element */
719 948 : const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
720 948 : if (pszGeometryElement != NULL)
721 336 : bReadGeometry = strcmp(poState->osPath.c_str(), pszGeometryElement) == 0;
722 : else
723 : {
724 : /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
725 : /* not 'start' and 'end' geometries */
726 612 : if (m_bIsAIXM &&
727 : strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
728 0 : bReadGeometry = strcmp( pszName, "Curve") == 0;
729 : else
730 612 : bReadGeometry = TRUE;
731 : }
732 948 : if (bReadGeometry)
733 : {
734 946 : m_nGeometryDepth = m_nDepth;
735 :
736 946 : CPLAssert(apsXMLNode.size() == 0);
737 :
738 : NodeLastChild sNodeLastChild;
739 946 : sNodeLastChild.psNode = NULL;
740 946 : sNodeLastChild.psLastChild = NULL;
741 946 : apsXMLNode.push_back(sNodeLastChild);
742 :
743 946 : PUSH_STATE(STATE_GEOMETRY);
744 :
745 946 : return startElementGeometry(pszName, nLenName, attr);
746 : }
747 : }
748 :
749 :
750 3765 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
751 : {
752 367 : m_inBoundedByDepth = m_nDepth;
753 :
754 367 : PUSH_STATE(STATE_BOUNDED_BY);
755 :
756 367 : return OGRERR_NONE;
757 : }
758 :
759 : /* -------------------------------------------------------------------- */
760 : /* Is it a CityGML generic attribute ? */
761 : /* -------------------------------------------------------------------- */
762 3398 : else if( m_bIsCityGML &&
763 : m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
764 : {
765 6 : CPLFree(m_pszCityGMLGenericAttrName);
766 6 : m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
767 6 : m_inCityGMLGenericAttrDepth = m_nDepth;
768 :
769 6 : PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
770 :
771 6 : return OGRERR_NONE;
772 : }
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* If it is (or at least potentially is) a simple attribute, */
776 : /* then start collecting it. */
777 : /* -------------------------------------------------------------------- */
778 3392 : else if( (m_nAttributeIndex =
779 : m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
780 : {
781 2905 : if(m_pszCurField)
782 : {
783 347 : CPLFree(m_pszCurField);
784 347 : m_pszCurField = NULL;
785 347 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
786 : }
787 2905 : m_bInCurField = TRUE;
788 2905 : if (m_bReportHref)
789 : {
790 0 : CPLFree(m_pszHref);
791 0 : m_pszHref = GetAttributeValue(attr, "xlink:href");
792 : }
793 2905 : CPLFree(m_pszUom);
794 2905 : m_pszUom = GetAttributeValue(attr, "uom");
795 2905 : CPLFree(m_pszValue);
796 2905 : m_pszValue = GetAttributeValue(attr, "value");
797 :
798 2905 : if (stateStack[nStackDepth] != STATE_PROPERTY)
799 : {
800 2877 : m_nAttributeDepth = m_nDepth;
801 2877 : PUSH_STATE(STATE_PROPERTY);
802 : }
803 :
804 : }
805 487 : else if( m_bReportHref && (m_nAttributeIndex =
806 : m_poReader->GetAttributeElementIndex( CPLSPrintf("%s_href", pszName ),
807 : nLenName + 5 )) != -1 )
808 : {
809 0 : if(m_pszCurField)
810 : {
811 0 : CPLFree(m_pszCurField);
812 0 : m_pszCurField = NULL;
813 0 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
814 : }
815 0 : m_bInCurField = TRUE;
816 0 : CPLFree(m_pszHref);
817 0 : m_pszHref = GetAttributeValue(attr, "xlink:href");
818 :
819 0 : if (stateStack[nStackDepth] != STATE_PROPERTY)
820 : {
821 0 : m_nAttributeDepth = m_nDepth;
822 0 : PUSH_STATE(STATE_PROPERTY);
823 : }
824 : }
825 :
826 3394 : poState->PushPath( pszName, nLenName );
827 :
828 3394 : return OGRERR_NONE;
829 : }
830 :
831 : /************************************************************************/
832 : /* startElementTop() */
833 : /************************************************************************/
834 :
835 111 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
836 :
837 : {
838 111 : if (strcmp(pszName, "CityModel") == 0 )
839 : {
840 2 : m_bIsCityGML = TRUE;
841 : }
842 109 : else if (strcmp(pszName, "AIXMBasicMessage") == 0)
843 : {
844 0 : m_bIsAIXM = m_bReportHref = TRUE;
845 : }
846 :
847 111 : stateStack[0] = STATE_DEFAULT;
848 :
849 111 : return OGRERR_NONE;
850 : }
851 :
852 : /************************************************************************/
853 : /* startElementDefault() */
854 : /************************************************************************/
855 :
856 1836 : OGRErr GMLHandler::startElementDefault(const char *pszName, int nLenName, void* attr )
857 :
858 : {
859 : /* -------------------------------------------------------------------- */
860 : /* Is it a feature? If so push a whole new state, and return. */
861 : /* -------------------------------------------------------------------- */
862 : int nClassIndex;
863 1836 : if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
864 : {
865 972 : const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
866 972 : if ( pszFilteredClassName != NULL &&
867 : strcmp(pszName, pszFilteredClassName) != 0 )
868 : {
869 12 : m_nDepthFeature = m_nDepth;
870 :
871 12 : PUSH_STATE(STATE_IGNORED_FEATURE);
872 :
873 12 : return OGRERR_NONE;
874 : }
875 : else
876 : {
877 960 : m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
878 :
879 960 : m_nDepthFeature = m_nDepth;
880 :
881 960 : PUSH_STATE(STATE_FEATURE);
882 :
883 960 : return OGRERR_NONE;
884 : }
885 : }
886 :
887 864 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
888 : {
889 87 : m_inBoundedByDepth = m_nDepth;
890 :
891 87 : PUSH_STATE(STATE_BOUNDED_BY);
892 :
893 87 : return OGRERR_NONE;
894 : }
895 :
896 : /* -------------------------------------------------------------------- */
897 : /* Push the element onto the current state's path. */
898 : /* -------------------------------------------------------------------- */
899 777 : m_poReader->GetState()->PushPath( pszName, nLenName );
900 :
901 777 : return OGRERR_NONE;
902 : }
903 :
904 : /************************************************************************/
905 : /* endElementIgnoredFeature() */
906 : /************************************************************************/
907 :
908 76 : OGRErr GMLHandler::endElementIgnoredFeature()
909 :
910 : {
911 76 : if (m_nDepth == m_nDepthFeature)
912 : {
913 12 : POP_STATE();
914 : }
915 76 : return OGRERR_NONE;
916 : }
917 :
918 : /************************************************************************/
919 : /* endElementBoundedBy() */
920 : /************************************************************************/
921 1863 : OGRErr GMLHandler::endElementBoundedBy()
922 :
923 : {
924 1863 : if( m_inBoundedByDepth == m_nDepth)
925 : {
926 454 : POP_STATE();
927 : }
928 :
929 1863 : return OGRERR_NONE;
930 : }
931 :
932 : /************************************************************************/
933 : /* ParseAIXMElevationPoint() */
934 : /************************************************************************/
935 :
936 0 : CPLXMLNode* GMLHandler::ParseAIXMElevationPoint(CPLXMLNode *psGML)
937 : {
938 : const char* pszElevation =
939 0 : CPLGetXMLValue( psGML, "elevation", NULL );
940 0 : if (pszElevation)
941 : {
942 : m_poReader->SetFeaturePropertyDirectly( "elevation",
943 0 : CPLStrdup(pszElevation), -1 );
944 : const char* pszElevationUnit =
945 0 : CPLGetXMLValue( psGML, "elevation.uom", NULL );
946 0 : if (pszElevationUnit)
947 : {
948 : m_poReader->SetFeaturePropertyDirectly( "elevation_uom",
949 0 : CPLStrdup(pszElevationUnit), -1 );
950 : }
951 : }
952 :
953 : const char* pszGeoidUndulation =
954 0 : CPLGetXMLValue( psGML, "geoidUndulation", NULL );
955 0 : if (pszGeoidUndulation)
956 : {
957 : m_poReader->SetFeaturePropertyDirectly( "geoidUndulation",
958 0 : CPLStrdup(pszGeoidUndulation), -1 );
959 : const char* pszGeoidUndulationUnit =
960 0 : CPLGetXMLValue( psGML, "geoidUndulation.uom", NULL );
961 0 : if (pszGeoidUndulationUnit)
962 : {
963 : m_poReader->SetFeaturePropertyDirectly( "geoidUndulation_uom",
964 0 : CPLStrdup(pszGeoidUndulationUnit), -1 );
965 : }
966 : }
967 :
968 : const char* pszPos =
969 0 : CPLGetXMLValue( psGML, "pos", NULL );
970 : const char* pszCoordinates =
971 0 : CPLGetXMLValue( psGML, "coordinates", NULL );
972 0 : if (pszPos != NULL)
973 : {
974 : char* pszGeometry = CPLStrdup(CPLSPrintf(
975 : "<gml:Point><gml:pos>%s</gml:pos></gml:Point>",
976 0 : pszPos));
977 0 : CPLDestroyXMLNode(psGML);
978 0 : psGML = CPLParseXMLString(pszGeometry);
979 0 : CPLFree(pszGeometry);
980 : }
981 0 : else if (pszCoordinates != NULL)
982 : {
983 : char* pszGeometry = CPLStrdup(CPLSPrintf(
984 : "<gml:Point><gml:coordinates>%s</gml:coordinates></gml:Point>",
985 0 : pszCoordinates));
986 0 : CPLDestroyXMLNode(psGML);
987 0 : psGML = CPLParseXMLString(pszGeometry);
988 0 : CPLFree(pszGeometry);
989 : }
990 : else
991 : {
992 0 : CPLDestroyXMLNode(psGML);
993 0 : psGML = NULL;
994 : }
995 :
996 0 : return psGML;
997 : }
998 :
999 : /************************************************************************/
1000 : /* endElementGeometry() */
1001 : /************************************************************************/
1002 7601 : OGRErr GMLHandler::endElementGeometry()
1003 :
1004 : {
1005 7601 : if (m_nGeomLen)
1006 : {
1007 1408 : CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
1008 1408 : psNode->eType = CXT_Text;
1009 1408 : psNode->pszValue = m_pszGeometry;
1010 :
1011 1408 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
1012 1408 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
1013 1408 : if (psLastChildParent == NULL)
1014 : {
1015 677 : CPLXMLNode* psParent = sNodeLastChild.psNode;
1016 677 : if (psParent)
1017 677 : psParent->psChild = psNode;
1018 : }
1019 : else
1020 731 : psLastChildParent->psNext = psNode;
1021 1408 : sNodeLastChild.psLastChild = psNode;
1022 :
1023 1408 : m_pszGeometry = NULL;
1024 1408 : m_nGeomAlloc = 0;
1025 1408 : m_nGeomLen = 0;
1026 : }
1027 :
1028 7601 : if( m_nDepth == m_nGeometryDepth )
1029 : {
1030 945 : CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
1031 :
1032 : /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
1033 : CPLDebug("GML", "geometry = %s", pszXML);
1034 : CPLFree(pszXML);*/
1035 :
1036 945 : apsXMLNode.pop_back();
1037 :
1038 : /* AIXM ElevatedPoint. We want to parse this */
1039 : /* a bit specially because ElevatedPoint is aixm: stuff and */
1040 : /* the srsDimension of the <gml:pos> can be set to TRUE although */
1041 : /* they are only 2 coordinates in practice */
1042 945 : if ( m_bIsAIXM && psInterestNode != NULL &&
1043 : strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
1044 : {
1045 0 : psInterestNode = ParseAIXMElevationPoint(psInterestNode);
1046 : }
1047 :
1048 945 : if (m_poReader->FetchAllGeometries())
1049 0 : m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
1050 : else
1051 945 : m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
1052 :
1053 945 : POP_STATE();
1054 : }
1055 :
1056 7601 : apsXMLNode.pop_back();
1057 :
1058 7601 : return OGRERR_NONE;
1059 : }
1060 :
1061 : /************************************************************************/
1062 : /* endElementCityGMLGenericAttr() */
1063 : /************************************************************************/
1064 12 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
1065 :
1066 : {
1067 12 : if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
1068 : {
1069 : m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
1070 6 : m_pszCurField, -1 );
1071 6 : m_pszCurField = NULL;
1072 6 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1073 6 : m_bInCurField = FALSE;
1074 6 : CPLFree(m_pszCityGMLGenericAttrName);
1075 6 : m_pszCityGMLGenericAttrName = NULL;
1076 : }
1077 :
1078 12 : if( m_inCityGMLGenericAttrDepth == m_nDepth )
1079 : {
1080 6 : POP_STATE();
1081 : }
1082 :
1083 12 : return OGRERR_NONE;
1084 : }
1085 :
1086 : /************************************************************************/
1087 : /* endElementAttribute() */
1088 : /************************************************************************/
1089 2905 : OGRErr GMLHandler::endElementAttribute()
1090 :
1091 : {
1092 2905 : GMLReadState *poState = m_poReader->GetState();
1093 :
1094 2905 : if (m_bInCurField)
1095 : {
1096 2429 : if (m_pszCurField == NULL)
1097 : {
1098 12 : if (m_pszValue != NULL)
1099 : {
1100 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1101 10 : m_pszValue, -1 );
1102 10 : m_pszValue = NULL;
1103 : }
1104 : }
1105 : else
1106 : {
1107 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1108 : m_pszCurField,
1109 2417 : m_nAttributeIndex );
1110 2417 : m_pszCurField = NULL;
1111 : }
1112 :
1113 2429 : if (m_pszHref != NULL)
1114 : {
1115 0 : CPLString osPropNameHref = poState->osPath + "_href";
1116 0 : m_poReader->SetFeaturePropertyDirectly( osPropNameHref, m_pszHref, -1 );
1117 0 : m_pszHref = NULL;
1118 : }
1119 :
1120 2429 : if (m_pszUom != NULL)
1121 : {
1122 10 : CPLString osPropNameUom = poState->osPath + "_uom";
1123 10 : m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
1124 10 : m_pszUom = NULL;
1125 : }
1126 :
1127 2429 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1128 2429 : m_bInCurField = FALSE;
1129 2429 : m_nAttributeIndex = -1;
1130 :
1131 2429 : CPLFree( m_pszValue );
1132 2429 : m_pszValue = NULL;
1133 : }
1134 :
1135 2905 : poState->PopPath();
1136 :
1137 2905 : if( m_nAttributeDepth == m_nDepth )
1138 : {
1139 2877 : POP_STATE();
1140 : }
1141 :
1142 2905 : return OGRERR_NONE;
1143 : }
1144 :
1145 : /************************************************************************/
1146 : /* endElementFeature() */
1147 : /************************************************************************/
1148 1447 : OGRErr GMLHandler::endElementFeature()
1149 :
1150 : {
1151 : /* -------------------------------------------------------------------- */
1152 : /* If we are collecting a feature, and this element tag matches */
1153 : /* element name for the class, then we have finished the */
1154 : /* feature, and we pop the feature read state. */
1155 : /* -------------------------------------------------------------------- */
1156 1447 : if( m_nDepth == m_nDepthFeature )
1157 : {
1158 959 : m_poReader->PopState();
1159 :
1160 959 : POP_STATE();
1161 : }
1162 :
1163 : /* -------------------------------------------------------------------- */
1164 : /* Otherwise, we just pop the element off the local read states */
1165 : /* element stack. */
1166 : /* -------------------------------------------------------------------- */
1167 : else
1168 : {
1169 488 : m_poReader->GetState()->PopPath();
1170 : }
1171 :
1172 1447 : return OGRERR_NONE;
1173 : }
1174 :
1175 : /************************************************************************/
1176 : /* endElementDefault() */
1177 : /************************************************************************/
1178 886 : OGRErr GMLHandler::endElementDefault()
1179 :
1180 : {
1181 886 : if (m_nDepth > 0)
1182 776 : m_poReader->GetState()->PopPath();
1183 :
1184 886 : return OGRERR_NONE;
1185 : }
1186 :
1187 : /************************************************************************/
1188 : /* dataHandlerAttribute() */
1189 : /************************************************************************/
1190 :
1191 4107 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
1192 :
1193 : {
1194 4107 : int nIter = 0;
1195 :
1196 4107 : if( m_bInCurField )
1197 : {
1198 : // Ignore white space
1199 3261 : if (m_nCurFieldLen == 0)
1200 : {
1201 9820 : while (nIter < nLen)
1202 : {
1203 5725 : char ch = data[nIter];
1204 5725 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1205 2423 : break;
1206 3302 : nIter ++;
1207 : }
1208 : }
1209 :
1210 3261 : int nCharsLen = nLen - nIter;
1211 :
1212 3261 : if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
1213 : {
1214 2786 : m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
1215 : char *pszNewCurField = (char *)
1216 2786 : VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
1217 2786 : if (pszNewCurField == NULL)
1218 : {
1219 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1220 : }
1221 2786 : m_pszCurField = pszNewCurField;
1222 : }
1223 3261 : memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
1224 3261 : m_nCurFieldLen += nCharsLen;
1225 3261 : m_pszCurField[m_nCurFieldLen] = '\0';
1226 : }
1227 :
1228 4107 : return OGRERR_NONE;
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* dataHandlerGeometry() */
1233 : /************************************************************************/
1234 :
1235 20618 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
1236 :
1237 : {
1238 20618 : int nIter = 0;
1239 :
1240 : // Ignore white space
1241 20618 : if (m_nGeomLen == 0)
1242 : {
1243 163426 : while (nIter < nLen)
1244 : {
1245 123878 : char ch = data[nIter];
1246 123878 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1247 1408 : break;
1248 122470 : nIter ++;
1249 : }
1250 : }
1251 :
1252 20618 : int nCharsLen = nLen - nIter;
1253 20618 : if (nCharsLen)
1254 : {
1255 1548 : if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
1256 : {
1257 1507 : m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
1258 : char* pszNewGeometry = (char *)
1259 1507 : VSIRealloc( m_pszGeometry, m_nGeomAlloc);
1260 1507 : if (pszNewGeometry == NULL)
1261 : {
1262 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1263 : }
1264 1507 : m_pszGeometry = pszNewGeometry;
1265 : }
1266 1548 : memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
1267 1548 : m_nGeomLen += nCharsLen;
1268 1548 : m_pszGeometry[m_nGeomLen] = '\0';
1269 : }
1270 :
1271 20618 : return OGRERR_NONE;
1272 : }
1273 :
1274 :
1275 : /************************************************************************/
1276 : /* IsGeometryElement() */
1277 : /************************************************************************/
1278 :
1279 4713 : int GMLHandler::IsGeometryElement( const char *pszElement )
1280 :
1281 : {
1282 4713 : int nFirst = 0;
1283 4713 : int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
1284 4713 : unsigned long nHash = CPLHashSetHashStr(pszElement);
1285 17576 : do
1286 : {
1287 18524 : int nMiddle = (nFirst + nLast) / 2;
1288 18524 : if (nHash == pasGeometryNames[nMiddle].nHash)
1289 948 : return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
1290 17576 : if (nHash < pasGeometryNames[nMiddle].nHash)
1291 11000 : nLast = nMiddle - 1;
1292 : else
1293 6576 : nFirst = nMiddle + 1;
1294 : } while(nFirst <= nLast);
1295 :
1296 3765 : if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
1297 0 : return TRUE;
1298 :
1299 3765 : return FALSE;
1300 : }
|