Line data Source code
1 : /**********************************************************************
2 : *
3 : * Project: NAS Reader
4 : * Purpose: Implementation of NASHandler class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam
9 : * Copyright (c) 2010-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include <ctype.h>
15 : #include "nasreaderp.h"
16 : #include "cpl_conv.h"
17 : #include "cpl_string.h"
18 : #include "ogr_xerces.h"
19 :
20 : #define NASDebug(fmt, ...) \
21 : CPLDebugOnly("NAS", "%s:%d %s " fmt, __FILE__, __LINE__, __FUNCTION__, \
22 : __VA_ARGS__)
23 :
24 : /*
25 : Update modes:
26 :
27 : GID<7
28 : <wfs:Transaction version="1.0.0" service="WFS">
29 : <wfs:Delete typeName="AX_BesondereFlurstuecksgrenze">
30 : <ogc:Filter>
31 : <ogc:FeatureId fid="DENW18AL0000nANA20120117T130819Z" />
32 : </ogc:Filter>
33 : </wfs:Delete>
34 : <wfsext:Replace vendorId="AdV" safeToIgnore="false">
35 : <AP_PTO gml:id="DENW18AL0000pewY20131011T071138Z">
36 : [...]
37 : </AP_PTO>
38 : <ogc:Filter>
39 : <ogc:FeatureId fid="DENW18AL0000pewY20120117T143330Z" />
40 : </ogc:Filter>
41 : </wfsext:Replace>
42 : <wfs:Update typeName="AX_KommunalesGebiet">
43 : <wfs:Property>
44 : <wfs:Name>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:Name>
45 : <wfs:Value>2012-08-14T12:32:30Z</wfs:Value>
46 : </wfs:Property>
47 : <wfs:Property>
48 : <wfs:Name>adv:anlass</wfs:Name>
49 : <wfs:Value>000000</wfs:Value>
50 : </wfs:Property>
51 : <wfs:Property>
52 : <wfs:Name>adv:anlass</wfs:Name>
53 : <wfs:Value>010102</wfs:Value>
54 : </wfs:Property>
55 : <ogc:Filter>
56 : <ogc:FeatureId fid="DENW11AL000062WD20111016T122010Z" />
57 : </ogc:Filter>
58 : </wfs:Update>
59 : </wfs:Transaction>
60 :
61 : GID>=7
62 : <wfs:Transaction>
63 : <wfs:Insert>
64 : <AX_Flurstueck gml:id="DEBY0000F0000001">
65 : …
66 : </AX_Flurstueck>
67 : <AX_Gebaeude gml:id="DEBY0000G0000001">
68 : …
69 : </AX_Gebaeude>
70 : </wfs:Insert>
71 : <wfs:Replace>
72 : <AX_Flurstueck gml:id="DEBY0000F0000002">
73 : …
74 : </AX_Flurstueck>
75 : <fes:Filter>
76 : <fes:ResourceId rid="DEBY0000F000000220010101T000000Z"/>
77 : </fes:Filter>
78 : </wfs:Replace>
79 : <wfs:Delete typeNames=“AX_Buchungsstelle”>
80 : <fes:Filter>
81 : <fes:ResourceId rid="DEBY0000B000000320010101T000000Z"/>
82 : <fes:ResourceId rid="DEBY0000B000000420010101T000000Z"/>
83 : …
84 : </fes:Filter>
85 : </wfs:Delete>
86 : <wfs:Update typeNames="adv:AX_Flurstueck">
87 : <wfs:Property>
88 : <wfs:ValueReference>adv:lebenszeitintervall/adv:AA_Lebenszeitintervall/adv:endet</wfs:ValueReference>
89 : <wfs:Value>2007-11-13T12:00:00Z</wfs:Value>
90 : </wfs:Property>
91 : <wfs:Property>
92 : <wfs:ValueReference>adv:anlass</wfs:ValueReference>
93 : <wfs:Value>000000</wfs:Value>
94 : </wfs:Property>
95 : <wfs:Property>
96 : <wfs:ValueReference>adv:anlass</wfs:ValueReference>
97 : <wfs:Value>010102</wfs:Value>
98 : </wfs:Property>
99 : <wfs:Filter>
100 : <fes:ResourceId rid="DEBY123412345678"/>
101 : </wfs:Filter>
102 : </wfs:Update>
103 : </wfs:Transaction>
104 : */
105 :
106 : /************************************************************************/
107 : /* NASHandler() */
108 : /************************************************************************/
109 :
110 8 : NASHandler::NASHandler(NASReader *poReader)
111 : : m_poReader(poReader), m_pszCurField(nullptr), m_pszGeometry(nullptr),
112 : m_nGeomAlloc(0), m_nGeomLen(0), m_nGeometryDepth(0),
113 : m_nGeometryPropertyIndex(-1), m_nDepth(0), m_nDepthFeature(0),
114 8 : m_bIgnoreFeature(false), m_Locator(nullptr)
115 : {
116 8 : }
117 :
118 : /************************************************************************/
119 : /* ~NASHandler() */
120 : /************************************************************************/
121 :
122 16 : NASHandler::~NASHandler()
123 :
124 : {
125 8 : CPLFree(m_pszCurField);
126 8 : CPLFree(m_pszGeometry);
127 16 : }
128 :
129 : /************************************************************************/
130 : /* GetAttributes() */
131 : /************************************************************************/
132 :
133 120 : CPLString NASHandler::GetAttributes(const Attributes *attrs)
134 : {
135 120 : CPLString osRes;
136 :
137 144 : for (unsigned int i = 0; i < attrs->getLength(); i++)
138 : {
139 24 : osRes += " ";
140 24 : osRes += transcode(attrs->getQName(i));
141 24 : osRes += "=\"";
142 24 : osRes += transcode(attrs->getValue(i));
143 24 : osRes += "\"";
144 : }
145 120 : return osRes;
146 : }
147 :
148 : /************************************************************************/
149 : /* setDocumentLocator() */
150 : /************************************************************************/
151 :
152 8 : void NASHandler::setDocumentLocator(const Locator *locator)
153 : {
154 8 : m_Locator = locator;
155 8 : return DefaultHandler::setDocumentLocator(locator);
156 : }
157 :
158 : /************************************************************************/
159 : /* startElement() */
160 : /************************************************************************/
161 :
162 571 : void NASHandler::startElement(const XMLCh *const /* uri */,
163 : const XMLCh *const localname,
164 : const XMLCh *const /* qname */,
165 : const Attributes &attrs)
166 :
167 : {
168 571 : m_nEntityCounter = 0;
169 :
170 571 : GMLReadState *poState = m_poReader->GetState();
171 :
172 571 : transcode(localname, m_osElementName);
173 :
174 571 : NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
175 : m_osElementName.c_str(), poState ? "(state)" : "(no state)",
176 : m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
177 :
178 571 : m_nDepth++;
179 571 : if (m_bIgnoreFeature && m_nDepth > m_nDepthFeature)
180 93 : return;
181 :
182 478 : if (m_nDepthFeature == 0)
183 : {
184 199 : if (m_osElementName == "Replace")
185 : {
186 4 : const XMLCh achSafeToIgnore[] = {'s', 'a', 'f', 'e', 'T', 'o', 'I',
187 : 'g', 'n', 'o', 'r', 'e', 0};
188 4 : int nIndex = attrs.getIndex(achSafeToIgnore);
189 4 : if (nIndex != -1)
190 4 : transcode(attrs.getValue(nIndex), m_osSafeToIgnore);
191 : else
192 0 : m_osSafeToIgnore = "true";
193 4 : m_osReplacingFID = "";
194 :
195 4 : CPLAssert(m_osDeleteContext == "");
196 4 : m_osDeleteContext = m_osElementName;
197 : }
198 195 : else if (m_osElementName == "Update" || m_osElementName == "Delete")
199 : {
200 4 : const XMLCh achTypeNames[] = {'t', 'y', 'p', 'e', 'N',
201 : 'a', 'm', 'e', 's', 0};
202 4 : const XMLCh achTypeName[] = {'t', 'y', 'p', 'e', 'N',
203 : 'a', 'm', 'e', 0};
204 4 : int nIndex = attrs.getIndex(achTypeNames);
205 4 : if (nIndex == -1)
206 4 : nIndex = attrs.getIndex(achTypeName);
207 :
208 4 : if (nIndex == -1)
209 : {
210 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
211 : "NAS: expected type name missing at %s:%d:%d",
212 0 : m_poReader->GetSourceFileName(),
213 0 : static_cast<int>(m_Locator->getLineNumber()),
214 0 : static_cast<int>(m_Locator->getColumnNumber()));
215 0 : return;
216 : }
217 :
218 4 : transcode(attrs.getValue(nIndex), m_osTypeName);
219 :
220 4 : const char *pszTypeName = strchr(m_osTypeName.c_str(), ':');
221 4 : pszTypeName = pszTypeName ? pszTypeName + 1 : m_osTypeName.c_str();
222 4 : m_osTypeName = pszTypeName;
223 :
224 4 : CPLAssert(m_osDeleteContext == "");
225 4 : m_osDeleteContext = m_osElementName;
226 : }
227 191 : else if (m_osDeleteContext == "Update" &&
228 0 : (m_osElementName == "Name" ||
229 0 : m_osElementName == "ValueReference" ||
230 0 : m_osElementName == "Value"))
231 : {
232 : // fetch value
233 0 : CPLFree(m_pszCurField);
234 0 : m_pszCurField = CPLStrdup("");
235 : }
236 209 : else if (m_osDeleteContext != "" && (m_osElementName == "ResourceId" ||
237 18 : m_osElementName == "FeatureId"))
238 : {
239 : const char *pszFilteredClassName =
240 7 : m_poReader->GetFilteredClassName();
241 7 : if (!pszFilteredClassName || EQUAL(pszFilteredClassName, "Delete"))
242 : {
243 7 : const XMLCh achRid[] = {'r', 'i', 'd', 0};
244 7 : const XMLCh achFid[] = {'f', 'i', 'd', 0};
245 7 : if (m_osTypeName == "")
246 : {
247 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
248 : "NAS: type name(s) missing at %s:%d:%d",
249 0 : m_poReader->GetSourceFileName(),
250 0 : static_cast<int>(m_Locator->getLineNumber()),
251 0 : static_cast<int>(m_Locator->getColumnNumber()));
252 0 : return;
253 : }
254 :
255 7 : int nIndex = attrs.getIndex(
256 7 : m_osElementName == "ResourceId" ? achRid : achFid);
257 7 : if (nIndex == -1)
258 : {
259 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
260 : "NAS: expected feature id missing at %s,%d:%d",
261 0 : m_poReader->GetSourceFileName(),
262 0 : static_cast<int>(m_Locator->getLineNumber()),
263 0 : static_cast<int>(m_Locator->getColumnNumber()));
264 0 : return;
265 : }
266 :
267 14 : CPLString osFeatureId;
268 7 : transcode(attrs.getValue(nIndex), osFeatureId);
269 :
270 7 : m_poReader->PushFeature("Delete", attrs);
271 7 : m_poReader->SetFeaturePropertyDirectly("typeName",
272 : CPLStrdup(m_osTypeName));
273 7 : m_poReader->SetFeaturePropertyDirectly(
274 : "context", CPLStrdup(m_osDeleteContext));
275 7 : m_poReader->SetFeaturePropertyDirectly("FeatureId",
276 : CPLStrdup(osFeatureId));
277 :
278 7 : if (m_osDeleteContext == "Replace")
279 : {
280 3 : if (m_osReplacingFID == "")
281 : {
282 0 : CPLError(
283 : CE_Failure, CPLE_AssertionFailed,
284 : "NAS: replacing feature id not set at %s:%d:%d",
285 0 : m_poReader->GetSourceFileName(),
286 0 : static_cast<int>(m_Locator->getLineNumber()),
287 0 : static_cast<int>(m_Locator->getColumnNumber()));
288 0 : return;
289 : }
290 :
291 3 : m_poReader->SetFeaturePropertyDirectly(
292 : "replacedBy", CPLStrdup(m_osReplacingFID));
293 3 : m_poReader->SetFeaturePropertyDirectly(
294 : "safeToIgnore", CPLStrdup(m_osSafeToIgnore));
295 3 : m_osReplacingFID = "";
296 3 : m_osSafeToIgnore = "";
297 : }
298 4 : else if (m_osDeleteContext == "Update")
299 : {
300 0 : m_poReader->SetFeaturePropertyDirectly(
301 : "endet", CPLStrdup(m_osUpdateEnds));
302 0 : for (std::list<CPLString>::iterator it =
303 0 : m_UpdateOccasions.begin();
304 0 : it != m_UpdateOccasions.end(); ++it)
305 : {
306 0 : m_poReader->SetFeaturePropertyDirectly("anlass",
307 0 : CPLStrdup(*it));
308 : }
309 :
310 0 : m_osUpdateEnds = "";
311 0 : m_UpdateOccasions.clear();
312 : }
313 :
314 7 : return;
315 : }
316 : else
317 : {
318 : // we don't issue Delete features
319 0 : m_osDeleteContext = "";
320 : }
321 : }
322 184 : else if (m_poReader->IsFeatureElement(m_osElementName))
323 : {
324 4 : m_nDepthFeature = m_nDepth - 1;
325 :
326 : // record id of replacing feature
327 4 : if (m_osDeleteContext == "Replace")
328 : {
329 4 : const XMLCh achGmlId[] = {'g', 'm', 'l', ':', 'i', 'd', 0};
330 4 : int nIndex = attrs.getIndex(achGmlId);
331 4 : if (nIndex == -1)
332 : {
333 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
334 : "NAS: id of replacing feature not set at %s:%d:%d",
335 0 : m_poReader->GetSourceFileName(),
336 0 : static_cast<int>(m_Locator->getLineNumber()),
337 0 : static_cast<int>(m_Locator->getColumnNumber()));
338 0 : m_bIgnoreFeature = true;
339 0 : return;
340 : }
341 :
342 4 : CPLAssert(m_osReplacingFID == "");
343 4 : transcode(attrs.getValue(nIndex), m_osReplacingFID);
344 : }
345 :
346 4 : m_osTypeName = m_osElementName;
347 :
348 : const char *pszFilteredClassName =
349 4 : m_poReader->GetFilteredClassName();
350 6 : m_bIgnoreFeature = pszFilteredClassName &&
351 2 : !EQUAL(m_osElementName, pszFilteredClassName);
352 :
353 4 : if (!m_bIgnoreFeature)
354 3 : m_poReader->PushFeature(m_osElementName, attrs);
355 :
356 4 : return;
357 : }
358 : }
359 279 : else if (m_pszGeometry != nullptr || IsGeometryElement(m_osElementName))
360 : {
361 240 : if (m_nGeometryPropertyIndex == -1 && poState->m_poFeature &&
362 120 : poState->m_poFeature->GetClass())
363 : {
364 120 : GMLFeatureClass *poClass = poState->m_poFeature->GetClass();
365 120 : m_nGeometryPropertyIndex =
366 120 : poClass->GetGeometryPropertyIndexBySrcElement(
367 : poState->osPath.c_str());
368 : }
369 :
370 120 : const int nLNLen = static_cast<int>(m_osElementName.size());
371 120 : CPLString osAttributes = GetAttributes(&attrs);
372 :
373 : /* should save attributes too! */
374 :
375 120 : if (m_pszGeometry == nullptr)
376 3 : m_nGeometryDepth = poState->m_nPathLength;
377 :
378 237 : if (m_pszGeometry == nullptr ||
379 117 : m_nGeomLen + nLNLen + 4 + (int)osAttributes.size() > m_nGeomAlloc)
380 : {
381 3 : m_nGeomAlloc =
382 3 : (int)(m_nGeomAlloc * 1.3 + nLNLen + osAttributes.size() + 1000);
383 3 : m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
384 : }
385 :
386 120 : strcpy(m_pszGeometry + m_nGeomLen, "<");
387 120 : strcpy(m_pszGeometry + m_nGeomLen + 1, m_osElementName);
388 :
389 120 : if (!osAttributes.empty())
390 : {
391 24 : strcat(m_pszGeometry + m_nGeomLen, " ");
392 24 : strcat(m_pszGeometry + m_nGeomLen, osAttributes);
393 : }
394 :
395 120 : strcat(m_pszGeometry + m_nGeomLen, ">");
396 120 : m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
397 : }
398 159 : else if (m_poReader->IsAttributeElement(m_osElementName, attrs))
399 : {
400 159 : m_poReader->DealWithAttributes(
401 159 : m_osElementName, static_cast<int>(m_osElementName.length()), attrs);
402 159 : CPLFree(m_pszCurField);
403 159 : m_pszCurField = CPLStrdup("");
404 : }
405 :
406 467 : poState->PushPath(m_osElementName);
407 :
408 467 : if (poState->osPath.size() > 512)
409 : {
410 0 : CPLError(CE_Failure, CPLE_AssertionFailed,
411 : "NAS: Too long path. Stop parsing at %s:%d:%d",
412 0 : m_poReader->GetSourceFileName(),
413 0 : static_cast<int>(m_Locator->getLineNumber()),
414 0 : static_cast<int>(m_Locator->getColumnNumber()));
415 0 : m_poReader->StopParsing();
416 : }
417 : }
418 :
419 : /************************************************************************/
420 : /* endElement() */
421 : /************************************************************************/
422 555 : void NASHandler::endElement(const XMLCh *const /* uri */,
423 : const XMLCh *const localname,
424 : const XMLCh *const /* qname */)
425 :
426 : {
427 555 : m_nEntityCounter = 0;
428 :
429 555 : GMLReadState *poState = m_poReader->GetState();
430 :
431 555 : transcode(localname, m_osElementName);
432 :
433 555 : NASDebug("element=%s poState=%s m_nDepth=%d m_nDepthFeature=%d context=%s",
434 : m_osElementName.c_str(), poState ? "(state)" : "(no state)",
435 : m_nDepth, m_nDepthFeature, m_osDeleteContext.c_str());
436 :
437 555 : m_nDepth--;
438 555 : if (m_bIgnoreFeature && m_nDepth >= m_nDepthFeature)
439 : {
440 94 : if (m_nDepth == m_nDepthFeature)
441 : {
442 1 : m_bIgnoreFeature = false;
443 1 : m_nDepthFeature = 0;
444 : }
445 94 : return;
446 : }
447 :
448 461 : if (m_osDeleteContext == "Update")
449 : {
450 0 : if (m_osElementName == "Name" || m_osElementName == "ValueReference")
451 : {
452 : const char *pszName;
453 0 : pszName = strrchr(m_pszCurField, '/');
454 0 : pszName = pszName ? pszName + 1 : m_pszCurField;
455 0 : pszName = strrchr(pszName, ':');
456 0 : pszName = pszName ? pszName + 1 : m_pszCurField;
457 :
458 0 : CPLAssert(m_osUpdatePropertyName == "");
459 0 : m_osUpdatePropertyName = pszName;
460 0 : CPLFree(m_pszCurField);
461 0 : m_pszCurField = nullptr;
462 :
463 0 : if (m_osUpdatePropertyName != "endet" &&
464 0 : m_osUpdatePropertyName != "anlass")
465 : {
466 0 : CPLError(CE_Failure, CPLE_AppDefined,
467 : "NAS: Unexpected property name %s at %s:%d:%d",
468 : m_osUpdatePropertyName.c_str(),
469 0 : m_poReader->GetSourceFileName(),
470 0 : static_cast<int>(m_Locator->getLineNumber()),
471 0 : static_cast<int>(m_Locator->getColumnNumber()));
472 0 : m_osUpdatePropertyName = "";
473 : }
474 : }
475 0 : else if (m_osElementName == "Value")
476 : {
477 0 : CPLAssert(m_osUpdatePropertyName != "");
478 0 : if (m_osUpdatePropertyName == "endet")
479 0 : m_osUpdateEnds = m_pszCurField;
480 0 : else if (m_osUpdatePropertyName == "anlass")
481 0 : m_UpdateOccasions.push_back(m_pszCurField);
482 0 : m_osUpdatePropertyName = "";
483 0 : CPLFree(m_pszCurField);
484 0 : m_pszCurField = nullptr;
485 : }
486 : }
487 461 : else if (m_pszCurField != nullptr && poState->m_poFeature != nullptr)
488 : {
489 87 : m_poReader->SetFeaturePropertyDirectly(poState->osPath.c_str(),
490 : m_pszCurField);
491 87 : m_pszCurField = nullptr;
492 : }
493 :
494 : /* -------------------------------------------------------------------- */
495 : /* If we are collecting Geometry than store it, and consider if */
496 : /* this is the end of the geometry. */
497 : /* -------------------------------------------------------------------- */
498 461 : if (m_pszGeometry != nullptr)
499 : {
500 120 : int nLNLen = static_cast<int>(m_osElementName.size());
501 :
502 : /* should save attributes too! */
503 :
504 120 : if (m_nGeomLen + nLNLen + 4 > m_nGeomAlloc)
505 : {
506 0 : m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nLNLen + 1000);
507 0 : m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
508 : }
509 :
510 120 : strcat(m_pszGeometry + m_nGeomLen, "</");
511 120 : strcpy(m_pszGeometry + m_nGeomLen + 2, m_osElementName);
512 120 : strcat(m_pszGeometry + m_nGeomLen + nLNLen + 2, ">");
513 120 : m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
514 :
515 120 : if (poState->m_nPathLength == m_nGeometryDepth + 1)
516 : {
517 3 : if (poState->m_poFeature != nullptr)
518 : {
519 3 : CPLXMLNode *psNode = CPLParseXMLString(m_pszGeometry);
520 3 : if (psNode)
521 : {
522 : /* workaround for common malformed gml:pos with just a
523 : * elevation value instead of a full 3D coordinate:
524 : *
525 : * <gml:Point gml:id="BII2H">
526 : * <gml:pos
527 : * srsName="urn:adv:crs:ETRS89_h">41.394</gml:pos>
528 : * </gml:Point>
529 : *
530 : */
531 : const char *pszPos =
532 3 : CPLGetXMLValue(psNode, "=Point.pos", nullptr);
533 3 : if (pszPos != nullptr && strstr(pszPos, " ") == nullptr)
534 : {
535 0 : CPLSetXMLValue(psNode, "pos",
536 : CPLSPrintf("0 0 %s", pszPos));
537 : }
538 :
539 0 : if (m_nGeometryPropertyIndex >= 0 &&
540 0 : m_nGeometryPropertyIndex <
541 3 : poState->m_poFeature->GetGeometryCount() &&
542 0 : poState->m_poFeature
543 0 : ->GetGeometryList()[m_nGeometryPropertyIndex])
544 : {
545 : int iId =
546 0 : poState->m_poFeature->GetClass()->GetPropertyIndex(
547 : "gml_id");
548 : const GMLProperty *poIdProp =
549 0 : poState->m_poFeature->GetProperty(iId);
550 : #ifdef DEBUG_VERBOSE
551 : char *pszOldGeom = CPLSerializeXMLTree(
552 : poState->m_poFeature
553 : ->GetGeometryList()[m_nGeometryPropertyIndex]);
554 :
555 : NASDebug(
556 : "Overwriting other geometry (%s; replace:%s; "
557 : "with:%s) at %s:%d:%d",
558 : poIdProp && poIdProp->nSubProperties > 0 &&
559 : poIdProp->papszSubProperties[0]
560 : ? poIdProp->papszSubProperties[0]
561 : : "(null)",
562 : m_pszGeometry, pszOldGeom,
563 : m_poReader->GetSourceFileName(),
564 : static_cast<int>(m_Locator->getLineNumber()),
565 : static_cast<int>(m_Locator->getColumnNumber()));
566 :
567 : CPLFree(pszOldGeom);
568 : #else
569 0 : CPLError(
570 : CE_Warning, CPLE_AppDefined,
571 : "NAS: Overwriting other geometry (%s) at %s:%d:%d",
572 0 : poIdProp && poIdProp->nSubProperties > 0 &&
573 0 : poIdProp->papszSubProperties[0]
574 0 : ? poIdProp->papszSubProperties[0]
575 : : "(null)",
576 0 : m_poReader->GetSourceFileName(),
577 0 : static_cast<int>(m_Locator->getLineNumber()),
578 0 : static_cast<int>(m_Locator->getColumnNumber()));
579 : #endif
580 : }
581 :
582 3 : if (m_nGeometryPropertyIndex >= 0)
583 0 : poState->m_poFeature->SetGeometryDirectly(
584 : m_nGeometryPropertyIndex, psNode);
585 :
586 : // no geometry property or property without element path
587 6 : else if (poState->m_poFeature->GetClass()
588 5 : ->GetGeometryPropertyCount() == 0 ||
589 1 : (poState->m_poFeature->GetClass()
590 2 : ->GetGeometryPropertyCount() == 1 &&
591 1 : poState->m_poFeature->GetClass()
592 : ->GetGeometryProperty(0)
593 1 : ->GetSrcElement() &&
594 1 : *poState->m_poFeature->GetClass()
595 : ->GetGeometryProperty(0)
596 1 : ->GetSrcElement() == 0))
597 3 : poState->m_poFeature->SetGeometryDirectly(psNode);
598 :
599 : else
600 : {
601 0 : CPLError(
602 : CE_Warning, CPLE_AssertionFailed,
603 : "NAS: Unexpected geometry skipped (class:%s "
604 : "path:%s geom:%s) at %s:%d:%d",
605 0 : poState->m_poFeature->GetClass()->GetName(),
606 : poState->osPath.c_str(), m_pszGeometry,
607 0 : m_poReader->GetSourceFileName(),
608 0 : static_cast<int>(m_Locator->getLineNumber()),
609 0 : static_cast<int>(m_Locator->getColumnNumber()));
610 0 : CPLDestroyXMLNode(psNode);
611 : }
612 : }
613 : else
614 0 : CPLError(CE_Warning, CPLE_AppDefined,
615 : "NAS: Invalid geometry skipped at %s:%d:%d",
616 0 : m_poReader->GetSourceFileName(),
617 0 : static_cast<int>(m_Locator->getLineNumber()),
618 0 : static_cast<int>(m_Locator->getColumnNumber()));
619 : }
620 : else
621 0 : CPLError(CE_Warning, CPLE_AppDefined,
622 : "NAS: Skipping geometry without feature at %s:%d:%d",
623 0 : m_poReader->GetSourceFileName(),
624 0 : static_cast<int>(m_Locator->getLineNumber()),
625 0 : static_cast<int>(m_Locator->getColumnNumber()));
626 :
627 3 : CPLFree(m_pszGeometry);
628 3 : m_pszGeometry = nullptr;
629 3 : m_nGeomAlloc = m_nGeomLen = 0;
630 3 : m_nGeometryPropertyIndex = -1;
631 : }
632 : }
633 :
634 : // Finished actual feature or ResourceId/FeatureId of Delete/Replace/Update operation
635 7 : if ((m_nDepth == m_nDepthFeature && poState->m_poFeature != nullptr &&
636 3 : EQUAL(m_osElementName,
637 1218 : poState->m_poFeature->GetClass()->GetElementName())) ||
638 754 : (m_osDeleteContext != "" &&
639 592 : (m_osElementName == "ResourceId" || m_osElementName == "FeatureId")))
640 : {
641 10 : m_nDepthFeature = 0;
642 10 : m_poReader->PopState();
643 : }
644 : else
645 451 : poState->PopPath();
646 :
647 461 : if (m_osDeleteContext == m_osElementName)
648 : {
649 5 : m_osDeleteContext = "";
650 : }
651 : }
652 :
653 : /************************************************************************/
654 : /* startEntity() */
655 : /************************************************************************/
656 :
657 1001 : void NASHandler::startEntity(const XMLCh *const /* name */)
658 : {
659 1001 : m_nEntityCounter++;
660 1001 : if (m_nEntityCounter > 1000 && !m_poReader->HasStoppedParsing())
661 : {
662 : throw SAXNotSupportedException(
663 1 : "File probably corrupted (million laugh pattern)");
664 : }
665 1000 : }
666 :
667 : /************************************************************************/
668 : /* characters() */
669 : /************************************************************************/
670 :
671 2056 : void NASHandler::characters(const XMLCh *const chars, const XMLSize_t length)
672 : {
673 2056 : if (m_pszCurField != nullptr)
674 : {
675 180 : const int nCurFieldLength = static_cast<int>(strlen(m_pszCurField));
676 :
677 180 : int nSkipped = 0;
678 180 : if (nCurFieldLength == 0)
679 : {
680 : // Ignore white space
681 1101 : while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
682 2100 : chars[nSkipped] == 13 || chars[nSkipped] == '\t')
683 921 : nSkipped++;
684 : }
685 :
686 180 : transcode(chars + nSkipped, m_osCharacters,
687 180 : static_cast<int>(length) - nSkipped);
688 :
689 360 : m_pszCurField = static_cast<char *>(CPLRealloc(
690 180 : m_pszCurField, nCurFieldLength + m_osCharacters.size() + 1));
691 180 : memcpy(m_pszCurField + nCurFieldLength, m_osCharacters.c_str(),
692 180 : m_osCharacters.size() + 1);
693 : }
694 :
695 2056 : if (m_pszGeometry != nullptr)
696 : {
697 237 : int nSkipped = 0;
698 237 : if (m_nGeomLen == 0)
699 : {
700 : // Ignore white space
701 0 : while (chars[nSkipped] == ' ' || chars[nSkipped] == 10 ||
702 0 : chars[nSkipped] == 13 || chars[nSkipped] == '\t')
703 0 : nSkipped++;
704 : }
705 :
706 237 : transcode(chars + nSkipped, m_osCharacters,
707 237 : static_cast<int>(length) - nSkipped);
708 :
709 237 : const int nCharsLen = static_cast<int>(m_osCharacters.size());
710 :
711 237 : if (m_nGeomLen + nCharsLen * 4 + 4 > m_nGeomAlloc)
712 : {
713 3 : m_nGeomAlloc = (int)(m_nGeomAlloc * 1.3 + nCharsLen * 4 + 1000);
714 3 : m_pszGeometry = (char *)CPLRealloc(m_pszGeometry, m_nGeomAlloc);
715 : }
716 :
717 237 : memcpy(m_pszGeometry + m_nGeomLen, m_osCharacters.c_str(),
718 237 : m_osCharacters.size() + 1);
719 237 : m_nGeomLen += static_cast<int>(strlen(m_pszGeometry + m_nGeomLen));
720 : }
721 2056 : }
722 :
723 : /************************************************************************/
724 : /* fatalError() */
725 : /************************************************************************/
726 :
727 0 : void NASHandler::fatalError(const SAXParseException &exception)
728 :
729 : {
730 0 : CPLString osErrMsg;
731 0 : transcode(exception.getMessage(), osErrMsg);
732 0 : CPLError(CE_Failure, CPLE_AppDefined,
733 : "NAS: XML Parsing Error: %s at line %d, column %d\n",
734 0 : osErrMsg.c_str(), static_cast<int>(exception.getLineNumber()),
735 0 : static_cast<int>(exception.getColumnNumber()));
736 0 : }
737 :
738 : /************************************************************************/
739 : /* IsGeometryElement() */
740 : /************************************************************************/
741 :
742 162 : bool NASHandler::IsGeometryElement(const char *pszElement)
743 :
744 : {
745 324 : return strcmp(pszElement, "Polygon") == 0 ||
746 162 : strcmp(pszElement, "MultiPolygon") == 0 ||
747 162 : strcmp(pszElement, "MultiPoint") == 0 ||
748 162 : strcmp(pszElement, "MultiLineString") == 0 ||
749 162 : strcmp(pszElement, "MultiSurface") == 0 ||
750 162 : strcmp(pszElement, "GeometryCollection") == 0 ||
751 162 : strcmp(pszElement, "Point") == 0 ||
752 162 : strcmp(pszElement, "Curve") == 0 ||
753 162 : strcmp(pszElement, "MultiCurve") == 0 ||
754 162 : strcmp(pszElement, "CompositeCurve") == 0 ||
755 162 : strcmp(pszElement, "Surface") == 0 ||
756 483 : strcmp(pszElement, "PolygonPatch") == 0 ||
757 321 : strcmp(pszElement, "LineString") == 0;
758 : }
759 :
760 : // vim: set sw=4 expandtab ai :
|