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 246 : GMLExpatHandler::GMLExpatHandler( GMLReader *poReader, XML_Parser oParser ) : GMLHandler(poReader)
253 :
254 : {
255 246 : m_oParser = oParser;
256 246 : m_bStopParsing = FALSE;
257 246 : m_nDataHandlerCounter = 0;
258 246 : }
259 :
260 : /************************************************************************/
261 : /* startElementCbk() */
262 : /************************************************************************/
263 :
264 52926 : void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszName,
265 : const char **ppszAttr)
266 :
267 : {
268 52926 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
269 52926 : if (pThis->m_bStopParsing)
270 0 : return;
271 :
272 52926 : const char* pszIter = pszName;
273 : char ch;
274 712922 : while((ch = *pszIter) != '\0')
275 : {
276 607070 : if (ch == ':')
277 36674 : pszName = pszIter + 1;
278 607070 : pszIter ++;
279 : }
280 :
281 52926 : 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 52862 : void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, const char* pszName )
294 :
295 : {
296 52862 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
297 52862 : if (pThis->m_bStopParsing)
298 0 : return;
299 :
300 52862 : 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 157126 : void XMLCALL GMLExpatHandler::dataHandlerCbk(void *pUserData, const char *data, int nLen)
313 :
314 : {
315 157126 : GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
316 157126 : if (pThis->m_bStopParsing)
317 0 : return;
318 :
319 157126 : 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 157126 : 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 157126 : 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 2826 : const char* GMLExpatHandler::GetFID(void* attr)
349 : {
350 2826 : const char** papszIter = (const char** )attr;
351 5756 : while(*papszIter)
352 : {
353 1084 : if (strcmp(*papszIter, "fid") == 0 ||
354 : strcmp(*papszIter, "gml:id") == 0)
355 : {
356 980 : return papszIter[1];
357 : }
358 104 : papszIter += 2;
359 : }
360 1846 : return NULL;
361 : }
362 :
363 : /************************************************************************/
364 : /* AddAttributes() */
365 : /************************************************************************/
366 :
367 33642 : CPLXMLNode* GMLExpatHandler::AddAttributes(CPLXMLNode* psNode, void* attr)
368 : {
369 33642 : const char** papszIter = (const char** )attr;
370 :
371 33642 : CPLXMLNode* psLastChild = NULL;
372 :
373 84852 : while(*papszIter)
374 : {
375 17568 : CPLXMLNode* psChild = CPLCreateXMLNode(NULL, CXT_Attribute, papszIter[0]);
376 17568 : CPLCreateXMLNode(psChild, CXT_Text, papszIter[1]);
377 :
378 17568 : if (psLastChild == NULL)
379 16502 : psNode->psChild = psChild;
380 : else
381 1066 : psLastChild->psNext = psChild;
382 17568 : psLastChild = psChild;
383 :
384 17568 : papszIter += 2;
385 : }
386 :
387 33642 : return psLastChild;
388 : }
389 :
390 : /************************************************************************/
391 : /* GetAttributeValue() */
392 : /************************************************************************/
393 :
394 18840 : char* GMLExpatHandler::GetAttributeValue(void* attr, const char* pszAttributeName)
395 : {
396 18840 : const char** papszIter = (const char** )attr;
397 37704 : while(*papszIter)
398 : {
399 204 : if (strcmp(*papszIter, pszAttributeName) == 0)
400 : {
401 180 : return CPLStrdup(papszIter[1]);
402 : }
403 24 : papszIter += 2;
404 : }
405 18660 : 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 12054 : static int GMLHandlerSortGeometryElements(const void *_pA, const void *_pB)
445 : {
446 12054 : GeometryNamesStruct* pA = (GeometryNamesStruct*)_pA;
447 12054 : GeometryNamesStruct* pB = (GeometryNamesStruct*)_pB;
448 12054 : CPLAssert(pA->nHash != pB->nHash);
449 12054 : if (pA->nHash < pB->nHash)
450 6150 : return -1;
451 : else
452 5904 : return 1;
453 : }
454 :
455 : /************************************************************************/
456 : /* GMLHandler() */
457 : /************************************************************************/
458 :
459 246 : GMLHandler::GMLHandler( GMLReader *poReader )
460 :
461 : {
462 246 : m_poReader = poReader;
463 246 : m_bInCurField = FALSE;
464 246 : m_nCurFieldAlloc = 0;
465 246 : m_nCurFieldLen = 0;
466 246 : m_pszCurField = NULL;
467 246 : m_nAttributeIndex = -1;
468 246 : m_nAttributeDepth = 0;
469 :
470 246 : m_pszGeometry = NULL;
471 246 : m_nGeomAlloc = 0;
472 246 : m_nGeomLen = 0;
473 246 : m_nGeometryDepth = 0;
474 :
475 246 : m_nDepthFeature = m_nDepth = 0;
476 246 : m_inBoundedByDepth = 0;
477 246 : m_pszCityGMLGenericAttrName = NULL;
478 246 : m_inCityGMLGenericAttrDepth = 0;
479 246 : m_bIsCityGML = FALSE;
480 246 : m_bIsAIXM = FALSE;
481 246 : m_bReportHref = FALSE;
482 246 : m_pszHref = NULL;
483 246 : m_pszUom = NULL;
484 246 : m_pszValue = NULL;
485 :
486 : pasGeometryNames = (GeometryNamesStruct*)CPLMalloc(
487 246 : GML_GEOMETRY_TYPE_COUNT * sizeof(GeometryNamesStruct));
488 4428 : for(int i=0; i<GML_GEOMETRY_TYPE_COUNT; i++)
489 : {
490 4182 : pasGeometryNames[i].pszName = apszGMLGeometryElements[i];
491 4182 : pasGeometryNames[i].nHash =
492 4182 : CPLHashSetHashStr(pasGeometryNames[i].pszName);
493 : }
494 : qsort(pasGeometryNames, GML_GEOMETRY_TYPE_COUNT,
495 : sizeof(GeometryNamesStruct),
496 246 : GMLHandlerSortGeometryElements);
497 :
498 246 : nStackDepth = 0;
499 246 : stateStack[0] = STATE_TOP;
500 246 : }
501 :
502 : /************************************************************************/
503 : /* ~GMLHandler() */
504 : /************************************************************************/
505 :
506 246 : GMLHandler::~GMLHandler()
507 :
508 : {
509 246 : if (apsXMLNode.size() >= 2 && apsXMLNode[1].psNode != NULL)
510 6 : CPLDestroyXMLNode(apsXMLNode[1].psNode);
511 :
512 246 : CPLFree( m_pszCurField );
513 246 : CPLFree( m_pszGeometry );
514 246 : CPLFree( m_pszCityGMLGenericAttrName );
515 246 : CPLFree( m_pszHref );
516 246 : CPLFree( m_pszUom );
517 246 : CPLFree( m_pszValue );
518 246 : CPLFree( pasGeometryNames );
519 246 : }
520 :
521 :
522 : /************************************************************************/
523 : /* startElement() */
524 : /************************************************************************/
525 :
526 52926 : OGRErr GMLHandler::startElement(const char *pszName, int nLenName, void* attr)
527 : {
528 : OGRErr eRet;
529 52926 : switch(stateStack[nStackDepth])
530 : {
531 246 : case STATE_TOP: eRet = startElementTop(pszName, nLenName, attr); break;
532 4712 : case STATE_DEFAULT: eRet = startElementDefault(pszName, nLenName, attr); break;
533 12512 : case STATE_FEATURE: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
534 1498 : case STATE_PROPERTY: eRet = startElementFeatureAttribute(pszName, nLenName, attr); break;
535 30848 : case STATE_GEOMETRY: eRet = startElementGeometry(pszName, nLenName, attr); break;
536 128 : case STATE_IGNORED_FEATURE: eRet = OGRERR_NONE; break;
537 2970 : case STATE_BOUNDED_BY: eRet = startElementBoundedBy(pszName, nLenName, attr); break;
538 12 : case STATE_CITYGML_ATTRIBUTE: eRet = startElementCityGMLGenericAttr(pszName, nLenName, attr); break;
539 0 : default: eRet = OGRERR_NONE; break;
540 : }
541 52926 : m_nDepth++;
542 52926 : return eRet;
543 : }
544 :
545 : /************************************************************************/
546 : /* endElement() */
547 : /************************************************************************/
548 :
549 52862 : OGRErr GMLHandler::endElement()
550 : {
551 52862 : m_nDepth--;
552 52862 : switch(stateStack[nStackDepth])
553 : {
554 0 : case STATE_TOP: return OGRERR_NONE; break;
555 1912 : case STATE_DEFAULT: return endElementDefault(); break;
556 3902 : case STATE_FEATURE: return endElementFeature(); break;
557 9348 : case STATE_PROPERTY: return endElementAttribute(); break;
558 33600 : case STATE_GEOMETRY: return endElementGeometry(); break;
559 152 : case STATE_IGNORED_FEATURE: return endElementIgnoredFeature(); break;
560 3924 : case STATE_BOUNDED_BY: return endElementBoundedBy(); break;
561 24 : case STATE_CITYGML_ATTRIBUTE: return endElementCityGMLGenericAttr(); break;
562 0 : default: return OGRERR_NONE; break;
563 : }
564 : }
565 :
566 : /************************************************************************/
567 : /* dataHandler() */
568 : /************************************************************************/
569 :
570 157126 : OGRErr GMLHandler::dataHandler(const char *data, int nLen)
571 : {
572 157126 : switch(stateStack[nStackDepth])
573 : {
574 0 : case STATE_TOP: return OGRERR_NONE; break;
575 10100 : case STATE_DEFAULT: return OGRERR_NONE; break;
576 22924 : case STATE_FEATURE: return OGRERR_NONE; break;
577 13600 : case STATE_PROPERTY: return dataHandlerAttribute(data, nLen); break;
578 103360 : case STATE_GEOMETRY: return dataHandlerGeometry(data, nLen); break;
579 280 : case STATE_IGNORED_FEATURE: return OGRERR_NONE; break;
580 6802 : case STATE_BOUNDED_BY: return OGRERR_NONE; break;
581 60 : 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 2970 : OGRErr GMLHandler::startElementBoundedBy(const char *pszName, int nLenName, void* attr )
594 : {
595 2970 : if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
596 : {
597 116 : char* pszGlobalSRSName = GetAttributeValue(attr, "srsName");
598 116 : m_poReader->SetGlobalSRSName(pszGlobalSRSName);
599 116 : CPLFree(pszGlobalSRSName);
600 : }
601 :
602 2970 : return OGRERR_NONE;
603 : }
604 :
605 : /************************************************************************/
606 : /* startElementGeometry() */
607 : /************************************************************************/
608 :
609 33642 : OGRErr GMLHandler::startElementGeometry(const char *pszName, int nLenName, void* attr )
610 : {
611 33642 : 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 33642 : CPLXMLNode* psCurNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
622 33642 : psCurNode->eType = CXT_Element;
623 33642 : psCurNode->pszValue = (char*) CPLMalloc( nLenName+1 );
624 33642 : memcpy(psCurNode->pszValue, pszName, nLenName+1);
625 :
626 : /* Attach element as the last child of its parent */
627 33642 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
628 33642 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
629 :
630 33642 : if (psLastChildParent == NULL)
631 : {
632 15796 : CPLXMLNode* psParent = sNodeLastChild.psNode;
633 15796 : if (psParent)
634 13002 : psParent->psChild = psCurNode;
635 : }
636 : else
637 : {
638 17846 : psLastChildParent->psNext = psCurNode;
639 : }
640 33642 : sNodeLastChild.psLastChild = psCurNode;
641 :
642 : /* Add attributes to the element */
643 33642 : 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 33642 : 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 33642 : sNewNodeLastChild.psNode = psCurNode;
665 33642 : sNewNodeLastChild.psLastChild = psLastChildCurNode;
666 33642 : apsXMLNode.push_back(sNewNodeLastChild);
667 :
668 33642 : 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 33642 : return OGRERR_NONE;
677 : }
678 :
679 : /************************************************************************/
680 : /* startElementCityGMLGenericAttr() */
681 : /************************************************************************/
682 :
683 12 : OGRErr GMLHandler::startElementCityGMLGenericAttr(const char *pszName, int nLenName, void* attr )
684 : {
685 12 : if( strcmp(pszName, "value") == 0 )
686 : {
687 12 : if(m_pszCurField)
688 : {
689 0 : CPLFree(m_pszCurField);
690 0 : m_pszCurField = NULL;
691 0 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
692 : }
693 12 : m_bInCurField = TRUE;
694 : }
695 :
696 12 : return OGRERR_NONE;
697 : }
698 : /************************************************************************/
699 : /* startElementFeatureAttribute() */
700 : /************************************************************************/
701 :
702 14010 : OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenName, void* attr )
703 : {
704 : /* Reset flag */
705 14010 : m_bInCurField = FALSE;
706 :
707 14010 : 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 14010 : 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 2798 : const char* pszGeometryElement = poState->m_poFeature->GetClass()->GetGeometryElement();
720 2798 : if (pszGeometryElement != NULL)
721 706 : 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 2092 : if (m_bIsAIXM &&
727 : strcmp(poState->m_poFeature->GetClass()->GetName(), "RouteSegment") == 0)
728 0 : bReadGeometry = strcmp( pszName, "Curve") == 0;
729 : else
730 2092 : bReadGeometry = TRUE;
731 : }
732 2798 : if (bReadGeometry)
733 : {
734 2794 : m_nGeometryDepth = m_nDepth;
735 :
736 2794 : CPLAssert(apsXMLNode.size() == 0);
737 :
738 : NodeLastChild sNodeLastChild;
739 2794 : sNodeLastChild.psNode = NULL;
740 2794 : sNodeLastChild.psLastChild = NULL;
741 2794 : apsXMLNode.push_back(sNodeLastChild);
742 :
743 2794 : PUSH_STATE(STATE_GEOMETRY);
744 :
745 2794 : return startElementGeometry(pszName, nLenName, attr);
746 : }
747 : }
748 :
749 :
750 11212 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
751 : {
752 770 : m_inBoundedByDepth = m_nDepth;
753 :
754 770 : PUSH_STATE(STATE_BOUNDED_BY);
755 :
756 770 : return OGRERR_NONE;
757 : }
758 :
759 : /* -------------------------------------------------------------------- */
760 : /* Is it a CityGML generic attribute ? */
761 : /* -------------------------------------------------------------------- */
762 10442 : else if( m_bIsCityGML &&
763 : m_poReader->IsCityGMLGenericAttributeElement( pszName, attr ) )
764 : {
765 12 : CPLFree(m_pszCityGMLGenericAttrName);
766 12 : m_pszCityGMLGenericAttrName = GetAttributeValue(attr, "name");
767 12 : m_inCityGMLGenericAttrDepth = m_nDepth;
768 :
769 12 : PUSH_STATE(STATE_CITYGML_ATTRIBUTE);
770 :
771 12 : 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 10430 : else if( (m_nAttributeIndex =
779 : m_poReader->GetAttributeElementIndex( pszName, nLenName )) != -1 )
780 : {
781 9350 : if(m_pszCurField)
782 : {
783 1188 : CPLFree(m_pszCurField);
784 1188 : m_pszCurField = NULL;
785 1188 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
786 : }
787 9350 : m_bInCurField = TRUE;
788 9350 : if (m_bReportHref)
789 : {
790 0 : CPLFree(m_pszHref);
791 0 : m_pszHref = GetAttributeValue(attr, "xlink:href");
792 : }
793 9350 : CPLFree(m_pszUom);
794 9350 : m_pszUom = GetAttributeValue(attr, "uom");
795 9350 : CPLFree(m_pszValue);
796 9350 : m_pszValue = GetAttributeValue(attr, "value");
797 :
798 9350 : if (stateStack[nStackDepth] != STATE_PROPERTY)
799 : {
800 9294 : m_nAttributeDepth = m_nDepth;
801 9294 : PUSH_STATE(STATE_PROPERTY);
802 : }
803 :
804 : }
805 1080 : 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 10434 : poState->PushPath( pszName, nLenName );
827 :
828 10434 : return OGRERR_NONE;
829 : }
830 :
831 : /************************************************************************/
832 : /* startElementTop() */
833 : /************************************************************************/
834 :
835 246 : OGRErr GMLHandler::startElementTop(const char *pszName, int nLenName, void* attr )
836 :
837 : {
838 246 : if (strcmp(pszName, "CityModel") == 0 )
839 : {
840 4 : m_bIsCityGML = TRUE;
841 : }
842 242 : else if (strcmp(pszName, "AIXMBasicMessage") == 0)
843 : {
844 0 : m_bIsAIXM = m_bReportHref = TRUE;
845 : }
846 :
847 246 : stateStack[0] = STATE_DEFAULT;
848 :
849 246 : return OGRERR_NONE;
850 : }
851 :
852 : /************************************************************************/
853 : /* startElementDefault() */
854 : /************************************************************************/
855 :
856 4712 : 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 4712 : if( (nClassIndex = m_poReader->GetFeatureElementIndex( pszName, nLenName )) != -1 )
864 : {
865 2850 : const char* pszFilteredClassName = m_poReader->GetFilteredClassName();
866 2850 : if ( pszFilteredClassName != NULL &&
867 : strcmp(pszName, pszFilteredClassName) != 0 )
868 : {
869 24 : m_nDepthFeature = m_nDepth;
870 :
871 24 : PUSH_STATE(STATE_IGNORED_FEATURE);
872 :
873 24 : return OGRERR_NONE;
874 : }
875 : else
876 : {
877 2826 : m_poReader->PushFeature( pszName, GetFID(attr), nClassIndex );
878 :
879 2826 : m_nDepthFeature = m_nDepth;
880 :
881 2826 : PUSH_STATE(STATE_FEATURE);
882 :
883 2826 : return OGRERR_NONE;
884 : }
885 : }
886 :
887 1862 : else if( nLenName == 9 && strcmp(pszName, "boundedBy") == 0 )
888 : {
889 184 : m_inBoundedByDepth = m_nDepth;
890 :
891 184 : PUSH_STATE(STATE_BOUNDED_BY);
892 :
893 184 : return OGRERR_NONE;
894 : }
895 :
896 : /* -------------------------------------------------------------------- */
897 : /* Push the element onto the current state's path. */
898 : /* -------------------------------------------------------------------- */
899 1678 : m_poReader->GetState()->PushPath( pszName, nLenName );
900 :
901 1678 : return OGRERR_NONE;
902 : }
903 :
904 : /************************************************************************/
905 : /* endElementIgnoredFeature() */
906 : /************************************************************************/
907 :
908 152 : OGRErr GMLHandler::endElementIgnoredFeature()
909 :
910 : {
911 152 : if (m_nDepth == m_nDepthFeature)
912 : {
913 24 : POP_STATE();
914 : }
915 152 : return OGRERR_NONE;
916 : }
917 :
918 : /************************************************************************/
919 : /* endElementBoundedBy() */
920 : /************************************************************************/
921 3924 : OGRErr GMLHandler::endElementBoundedBy()
922 :
923 : {
924 3924 : if( m_inBoundedByDepth == m_nDepth)
925 : {
926 954 : POP_STATE();
927 : }
928 :
929 3924 : 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 33600 : OGRErr GMLHandler::endElementGeometry()
1003 :
1004 : {
1005 33600 : if (m_nGeomLen)
1006 : {
1007 4696 : CPLXMLNode* psNode = (CPLXMLNode *) CPLCalloc(sizeof(CPLXMLNode),1);
1008 4696 : psNode->eType = CXT_Text;
1009 4696 : psNode->pszValue = m_pszGeometry;
1010 :
1011 4696 : NodeLastChild& sNodeLastChild = apsXMLNode[apsXMLNode.size()-1];
1012 4696 : CPLXMLNode* psLastChildParent = sNodeLastChild.psLastChild;
1013 4696 : if (psLastChildParent == NULL)
1014 : {
1015 1636 : CPLXMLNode* psParent = sNodeLastChild.psNode;
1016 1636 : if (psParent)
1017 1636 : psParent->psChild = psNode;
1018 : }
1019 : else
1020 3060 : psLastChildParent->psNext = psNode;
1021 4696 : sNodeLastChild.psLastChild = psNode;
1022 :
1023 4696 : m_pszGeometry = NULL;
1024 4696 : m_nGeomAlloc = 0;
1025 4696 : m_nGeomLen = 0;
1026 : }
1027 :
1028 33600 : if( m_nDepth == m_nGeometryDepth )
1029 : {
1030 2788 : CPLXMLNode* psInterestNode = apsXMLNode[apsXMLNode.size()-1].psNode;
1031 :
1032 : /*char* pszXML = CPLSerializeXMLTree(psInterestNode);
1033 : CPLDebug("GML", "geometry = %s", pszXML);
1034 : CPLFree(pszXML);*/
1035 :
1036 2788 : 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 2788 : if ( m_bIsAIXM && psInterestNode != NULL &&
1043 : strcmp(psInterestNode->pszValue, "ElevatedPoint") == 0 )
1044 : {
1045 0 : psInterestNode = ParseAIXMElevationPoint(psInterestNode);
1046 : }
1047 :
1048 2788 : if (m_poReader->FetchAllGeometries())
1049 0 : m_poReader->GetState()->m_poFeature->AddGeometry(psInterestNode);
1050 : else
1051 2788 : m_poReader->GetState()->m_poFeature->SetGeometryDirectly(psInterestNode);
1052 :
1053 2788 : POP_STATE();
1054 : }
1055 :
1056 33600 : apsXMLNode.pop_back();
1057 :
1058 33600 : return OGRERR_NONE;
1059 : }
1060 :
1061 : /************************************************************************/
1062 : /* endElementCityGMLGenericAttr() */
1063 : /************************************************************************/
1064 24 : OGRErr GMLHandler::endElementCityGMLGenericAttr()
1065 :
1066 : {
1067 24 : if( m_pszCityGMLGenericAttrName != NULL && m_bInCurField )
1068 : {
1069 : m_poReader->SetFeaturePropertyDirectly( m_pszCityGMLGenericAttrName,
1070 12 : m_pszCurField, -1 );
1071 12 : m_pszCurField = NULL;
1072 12 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1073 12 : m_bInCurField = FALSE;
1074 12 : CPLFree(m_pszCityGMLGenericAttrName);
1075 12 : m_pszCityGMLGenericAttrName = NULL;
1076 : }
1077 :
1078 24 : if( m_inCityGMLGenericAttrDepth == m_nDepth )
1079 : {
1080 12 : POP_STATE();
1081 : }
1082 :
1083 24 : return OGRERR_NONE;
1084 : }
1085 :
1086 : /************************************************************************/
1087 : /* endElementAttribute() */
1088 : /************************************************************************/
1089 9348 : OGRErr GMLHandler::endElementAttribute()
1090 :
1091 : {
1092 9348 : GMLReadState *poState = m_poReader->GetState();
1093 :
1094 9348 : if (m_bInCurField)
1095 : {
1096 7890 : if (m_pszCurField == NULL)
1097 : {
1098 84 : if (m_pszValue != NULL)
1099 : {
1100 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1101 20 : m_pszValue, -1 );
1102 20 : m_pszValue = NULL;
1103 : }
1104 : }
1105 : else
1106 : {
1107 : m_poReader->SetFeaturePropertyDirectly( poState->osPath.c_str(),
1108 : m_pszCurField,
1109 7806 : m_nAttributeIndex );
1110 7806 : m_pszCurField = NULL;
1111 : }
1112 :
1113 7890 : 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 7890 : if (m_pszUom != NULL)
1121 : {
1122 20 : CPLString osPropNameUom = poState->osPath + "_uom";
1123 20 : m_poReader->SetFeaturePropertyDirectly( osPropNameUom, m_pszUom, -1 );
1124 20 : m_pszUom = NULL;
1125 : }
1126 :
1127 7890 : m_nCurFieldLen = m_nCurFieldAlloc = 0;
1128 7890 : m_bInCurField = FALSE;
1129 7890 : m_nAttributeIndex = -1;
1130 :
1131 7890 : CPLFree( m_pszValue );
1132 7890 : m_pszValue = NULL;
1133 : }
1134 :
1135 9348 : poState->PopPath();
1136 :
1137 9348 : if( m_nAttributeDepth == m_nDepth )
1138 : {
1139 9292 : POP_STATE();
1140 : }
1141 :
1142 9348 : return OGRERR_NONE;
1143 : }
1144 :
1145 : /************************************************************************/
1146 : /* endElementFeature() */
1147 : /************************************************************************/
1148 3902 : 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 3902 : if( m_nDepth == m_nDepthFeature )
1157 : {
1158 2820 : m_poReader->PopState();
1159 :
1160 2820 : 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 1082 : m_poReader->GetState()->PopPath();
1170 : }
1171 :
1172 3902 : return OGRERR_NONE;
1173 : }
1174 :
1175 : /************************************************************************/
1176 : /* endElementDefault() */
1177 : /************************************************************************/
1178 1912 : OGRErr GMLHandler::endElementDefault()
1179 :
1180 : {
1181 1912 : if (m_nDepth > 0)
1182 1672 : m_poReader->GetState()->PopPath();
1183 :
1184 1912 : return OGRERR_NONE;
1185 : }
1186 :
1187 : /************************************************************************/
1188 : /* dataHandlerAttribute() */
1189 : /************************************************************************/
1190 :
1191 13660 : OGRErr GMLHandler::dataHandlerAttribute(const char *data, int nLen)
1192 :
1193 : {
1194 13660 : int nIter = 0;
1195 :
1196 13660 : if( m_bInCurField )
1197 : {
1198 : // Ignore white space
1199 10814 : if (m_nCurFieldLen == 0)
1200 : {
1201 33100 : while (nIter < nLen)
1202 : {
1203 19298 : char ch = data[nIter];
1204 19298 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1205 7818 : break;
1206 11480 : nIter ++;
1207 : }
1208 : }
1209 :
1210 10814 : int nCharsLen = nLen - nIter;
1211 :
1212 10814 : if (m_nCurFieldLen + nCharsLen + 1 > m_nCurFieldAlloc)
1213 : {
1214 9052 : m_nCurFieldAlloc = m_nCurFieldAlloc * 4 / 3 + nCharsLen + 1;
1215 : char *pszNewCurField = (char *)
1216 9052 : VSIRealloc( m_pszCurField, m_nCurFieldAlloc );
1217 9052 : if (pszNewCurField == NULL)
1218 : {
1219 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1220 : }
1221 9052 : m_pszCurField = pszNewCurField;
1222 : }
1223 10814 : memcpy( m_pszCurField + m_nCurFieldLen, data + nIter, nCharsLen);
1224 10814 : m_nCurFieldLen += nCharsLen;
1225 10814 : m_pszCurField[m_nCurFieldLen] = '\0';
1226 : }
1227 :
1228 13660 : return OGRERR_NONE;
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* dataHandlerGeometry() */
1233 : /************************************************************************/
1234 :
1235 103360 : OGRErr GMLHandler::dataHandlerGeometry(const char *data, int nLen)
1236 :
1237 : {
1238 103360 : int nIter = 0;
1239 :
1240 : // Ignore white space
1241 103360 : if (m_nGeomLen == 0)
1242 : {
1243 890472 : while (nIter < nLen)
1244 : {
1245 689008 : char ch = data[nIter];
1246 689008 : if( !(ch == ' ' || ch == 10 || ch == 13 || ch == '\t') )
1247 4696 : break;
1248 684312 : nIter ++;
1249 : }
1250 : }
1251 :
1252 103360 : int nCharsLen = nLen - nIter;
1253 103360 : if (nCharsLen)
1254 : {
1255 4976 : if( m_nGeomLen + nCharsLen + 1 > m_nGeomAlloc )
1256 : {
1257 4894 : m_nGeomAlloc = m_nGeomAlloc * 4 / 3 + nCharsLen + 1;
1258 : char* pszNewGeometry = (char *)
1259 4894 : VSIRealloc( m_pszGeometry, m_nGeomAlloc);
1260 4894 : if (pszNewGeometry == NULL)
1261 : {
1262 0 : return OGRERR_NOT_ENOUGH_MEMORY;
1263 : }
1264 4894 : m_pszGeometry = pszNewGeometry;
1265 : }
1266 4976 : memcpy( m_pszGeometry+m_nGeomLen, data + nIter, nCharsLen);
1267 4976 : m_nGeomLen += nCharsLen;
1268 4976 : m_pszGeometry[m_nGeomLen] = '\0';
1269 : }
1270 :
1271 103360 : return OGRERR_NONE;
1272 : }
1273 :
1274 :
1275 : /************************************************************************/
1276 : /* IsGeometryElement() */
1277 : /************************************************************************/
1278 :
1279 14010 : int GMLHandler::IsGeometryElement( const char *pszElement )
1280 :
1281 : {
1282 14010 : int nFirst = 0;
1283 14010 : int nLast = GML_GEOMETRY_TYPE_COUNT- 1;
1284 14010 : unsigned long nHash = CPLHashSetHashStr(pszElement);
1285 53250 : do
1286 : {
1287 56048 : int nMiddle = (nFirst + nLast) / 2;
1288 56048 : if (nHash == pasGeometryNames[nMiddle].nHash)
1289 2798 : return strcmp(pszElement, pasGeometryNames[nMiddle].pszName) == 0;
1290 53250 : if (nHash < pasGeometryNames[nMiddle].nHash)
1291 32180 : nLast = nMiddle - 1;
1292 : else
1293 21070 : nFirst = nMiddle + 1;
1294 : } while(nFirst <= nLast);
1295 :
1296 11212 : if (m_bIsAIXM && strcmp( pszElement, "ElevatedPoint") == 0)
1297 0 : return TRUE;
1298 :
1299 11212 : return FALSE;
1300 : }
|