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