Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: LV BAG Translator
4 : * Purpose: Implements OGRLVBAGLayer.
5 : * Author: Laixer B.V., info at laixer dot com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2020, Laixer B.V. <info at laixer dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_conv.h"
14 : #include "ogr_geos.h"
15 : #include "ogr_lvbag.h"
16 : #include "ogr_p.h"
17 :
18 : constexpr const char *pszSpecificationUrn = "urn:ogc:def:crs:EPSG::28992";
19 : constexpr const size_t nDefaultIdentifierSize = 16;
20 :
21 : /************************************************************************/
22 : /* OGRLVBAGLayer() */
23 : /* */
24 : /* Note that the OGRLVBAGLayer assumes ownership of the passed */
25 : /* file pointer. */
26 : /************************************************************************/
27 :
28 29 : OGRLVBAGLayer::OGRLVBAGLayer(const char *pszFilename, OGRLayerPool *poPoolIn,
29 29 : char **papszOpenOptions)
30 29 : : OGRAbstractProxiedLayer{poPoolIn}, poFeatureDefn{new OGRFeatureDefn{}},
31 : fp{nullptr}, osFilename{pszFilename}, eFileDescriptorsState{FD_CLOSED},
32 : oParser{nullptr}, bSchemaOnly{false}, bHasReadSchema{false},
33 : bFixInvalidData{
34 58 : CPLFetchBool(papszOpenOptions, "AUTOCORRECT_INVALID_DATA", false)},
35 58 : bLegacyId{CPLFetchBool(papszOpenOptions, "LEGACY_ID", false)},
36 : nNextFID{0}, nCurrentDepth{0}, nGeometryElementDepth{0},
37 : nFeatureCollectionDepth{0}, nFeatureElementDepth{0},
38 : nAttributeElementDepth{0},
39 : eAddressRefState{AddressRefState::ADDRESS_PRIMARY}, osElementString{},
40 58 : osAttributeString{}, bCollectData{false}
41 : {
42 29 : SetDescription(CPLGetBasenameSafe(pszFilename).c_str());
43 :
44 29 : poFeatureDefn->Reference();
45 29 : }
46 :
47 : /************************************************************************/
48 : /* ~OGRLVBAGLayer() */
49 : /************************************************************************/
50 :
51 58 : OGRLVBAGLayer::~OGRLVBAGLayer()
52 : {
53 29 : delete m_poFeature;
54 29 : poFeatureDefn->Release();
55 29 : OGRLVBAGLayer::CloseUnderlyingLayer();
56 58 : }
57 :
58 : /************************************************************************/
59 : /* ResetReading() */
60 : /************************************************************************/
61 :
62 558 : void OGRLVBAGLayer::ResetReading()
63 : {
64 558 : if (!TouchLayer())
65 : {
66 0 : return;
67 : }
68 :
69 558 : VSIRewindL(fp);
70 :
71 558 : nNextFID = 0;
72 558 : nCurrentDepth = 0;
73 558 : nGeometryElementDepth = 0;
74 558 : nFeatureCollectionDepth = 0;
75 558 : nFeatureElementDepth = 0;
76 558 : nAttributeElementDepth = 0;
77 558 : eAddressRefState = AddressRefState::ADDRESS_PRIMARY;
78 558 : bCollectData = false;
79 : }
80 :
81 : /************************************************************************/
82 : /* GetLayerDefn() */
83 : /************************************************************************/
84 :
85 2094 : const OGRFeatureDefn *OGRLVBAGLayer::GetLayerDefn() const
86 : {
87 2094 : if (!bHasReadSchema)
88 : {
89 26 : if (!const_cast<OGRLVBAGLayer *>(this)->TouchLayer())
90 : {
91 0 : return nullptr;
92 : }
93 :
94 26 : bSchemaOnly = true;
95 :
96 26 : const_cast<OGRLVBAGLayer *>(this)->ConfigureParser();
97 26 : const_cast<OGRLVBAGLayer *>(this)->ParseDocument();
98 : }
99 :
100 2094 : return poFeatureDefn;
101 : }
102 :
103 : /************************************************************************/
104 : /* XMLTagSplit() */
105 : /************************************************************************/
106 :
107 8076 : static inline const char *XMLTagSplit(const char *pszName)
108 : {
109 8076 : const char *pszTag = pszName;
110 8076 : const char *pszSep = strchr(pszTag, ':');
111 8076 : if (pszSep)
112 : {
113 8076 : pszTag = pszSep + 1;
114 : }
115 :
116 8076 : return pszTag;
117 : }
118 :
119 : /************************************************************************/
120 : /* AddSpatialRef() */
121 : /************************************************************************/
122 :
123 21 : void OGRLVBAGLayer::AddSpatialRef(OGRwkbGeometryType eTypeIn)
124 : {
125 21 : OGRGeomFieldDefn *poGeomField = poFeatureDefn->GetGeomFieldDefn(0);
126 21 : OGRSpatialReference *poSRS = new OGRSpatialReference();
127 21 : poSRS->importFromURN(pszSpecificationUrn);
128 21 : poGeomField->SetSpatialRef(poSRS);
129 21 : poGeomField->SetType(eTypeIn);
130 21 : poSRS->Release();
131 21 : }
132 :
133 : /************************************************************************/
134 : /* AddIdentifierFieldDefn() */
135 : /************************************************************************/
136 :
137 24 : void OGRLVBAGLayer::AddIdentifierFieldDefn()
138 : {
139 48 : OGRFieldDefn oField0("identificatie", OFTString);
140 :
141 24 : poFeatureDefn->AddFieldDefn(&oField0);
142 24 : }
143 :
144 : /************************************************************************/
145 : /* AddDocumentFieldDefn() */
146 : /************************************************************************/
147 :
148 24 : void OGRLVBAGLayer::AddDocumentFieldDefn()
149 : {
150 48 : OGRFieldDefn oField0("status", OFTString);
151 48 : OGRFieldDefn oField1("geconstateerd", OFTInteger);
152 24 : oField1.SetSubType(OFSTBoolean);
153 48 : OGRFieldDefn oField2("documentDatum", OFTDate);
154 48 : OGRFieldDefn oField3("documentNummer", OFTString);
155 :
156 24 : poFeatureDefn->AddFieldDefn(&oField0);
157 24 : poFeatureDefn->AddFieldDefn(&oField1);
158 24 : poFeatureDefn->AddFieldDefn(&oField2);
159 24 : poFeatureDefn->AddFieldDefn(&oField3);
160 24 : }
161 :
162 : /************************************************************************/
163 : /* AddOccurrenceFieldDefn() */
164 : /************************************************************************/
165 :
166 24 : void OGRLVBAGLayer::AddOccurrenceFieldDefn()
167 : {
168 48 : OGRFieldDefn oField0("voorkomenIdentificatie", OFTInteger);
169 48 : OGRFieldDefn oField1("beginGeldigheid", OFTDate);
170 48 : OGRFieldDefn oField2("eindGeldigheid", OFTDate);
171 48 : OGRFieldDefn oField3("tijdstipRegistratie", OFTDateTime);
172 48 : OGRFieldDefn oField4("eindRegistratie", OFTDateTime);
173 48 : OGRFieldDefn oField5("tijdstipInactief", OFTDateTime);
174 48 : OGRFieldDefn oField6("tijdstipRegistratieLV", OFTDateTime);
175 48 : OGRFieldDefn oField7("tijdstipEindRegistratieLV", OFTDateTime);
176 48 : OGRFieldDefn oField8("tijdstipInactiefLV", OFTDateTime);
177 48 : OGRFieldDefn oField9("tijdstipNietBagLV", OFTDateTime);
178 :
179 24 : poFeatureDefn->AddFieldDefn(&oField0);
180 24 : poFeatureDefn->AddFieldDefn(&oField1);
181 24 : poFeatureDefn->AddFieldDefn(&oField2);
182 24 : poFeatureDefn->AddFieldDefn(&oField3);
183 24 : poFeatureDefn->AddFieldDefn(&oField4);
184 24 : poFeatureDefn->AddFieldDefn(&oField5);
185 24 : poFeatureDefn->AddFieldDefn(&oField6);
186 24 : poFeatureDefn->AddFieldDefn(&oField7);
187 24 : poFeatureDefn->AddFieldDefn(&oField8);
188 24 : poFeatureDefn->AddFieldDefn(&oField9);
189 24 : }
190 :
191 : /************************************************************************/
192 : /* CreateFeatureDefn() */
193 : /************************************************************************/
194 :
195 24 : void OGRLVBAGLayer::CreateFeatureDefn(const char *pszDataset)
196 : {
197 24 : if (EQUAL("pnd", pszDataset))
198 : {
199 20 : OGRFieldDefn oField0("oorspronkelijkBouwjaar", OFTInteger);
200 :
201 10 : poFeatureDefn->AddFieldDefn(&oField0);
202 :
203 10 : AddIdentifierFieldDefn();
204 10 : AddDocumentFieldDefn();
205 10 : AddOccurrenceFieldDefn();
206 :
207 10 : poFeatureDefn->SetName("Pand");
208 10 : SetDescription(poFeatureDefn->GetName());
209 :
210 10 : AddSpatialRef(wkbPolygon);
211 : }
212 14 : else if (EQUAL("num", pszDataset))
213 : {
214 4 : OGRFieldDefn oField0("huisnummer", OFTInteger);
215 4 : OGRFieldDefn oField1("huisletter", OFTString);
216 4 : OGRFieldDefn oField2("huisnummerToevoeging", OFTString);
217 4 : OGRFieldDefn oField3("postcode", OFTString);
218 4 : OGRFieldDefn oField4("typeAdresseerbaarObject", OFTString);
219 4 : OGRFieldDefn oField5("openbareruimteRef", OFTString);
220 4 : OGRFieldDefn oField6("woonplaatsRef", OFTString);
221 :
222 2 : poFeatureDefn->AddFieldDefn(&oField0);
223 2 : poFeatureDefn->AddFieldDefn(&oField1);
224 2 : poFeatureDefn->AddFieldDefn(&oField2);
225 2 : poFeatureDefn->AddFieldDefn(&oField3);
226 2 : poFeatureDefn->AddFieldDefn(&oField4);
227 2 : poFeatureDefn->AddFieldDefn(&oField5);
228 2 : poFeatureDefn->AddFieldDefn(&oField6);
229 :
230 2 : AddIdentifierFieldDefn();
231 2 : AddDocumentFieldDefn();
232 2 : AddOccurrenceFieldDefn();
233 :
234 2 : poFeatureDefn->SetName("Nummeraanduiding");
235 2 : SetDescription(poFeatureDefn->GetName());
236 : }
237 12 : else if (EQUAL("lig", pszDataset))
238 : {
239 2 : OGRFieldDefn oField0("hoofdadresNummeraanduidingRef", OFTString);
240 2 : OGRFieldDefn oField1("nevenadresNummeraanduidingRef", OFTStringList);
241 :
242 1 : poFeatureDefn->AddFieldDefn(&oField0);
243 1 : poFeatureDefn->AddFieldDefn(&oField1);
244 :
245 1 : AddIdentifierFieldDefn();
246 1 : AddDocumentFieldDefn();
247 1 : AddOccurrenceFieldDefn();
248 :
249 1 : poFeatureDefn->SetName("Ligplaats");
250 1 : SetDescription(poFeatureDefn->GetName());
251 :
252 1 : AddSpatialRef(wkbPolygon);
253 : }
254 11 : else if (EQUAL("sta", pszDataset))
255 : {
256 4 : OGRFieldDefn oField0("hoofdadresNummeraanduidingRef", OFTString);
257 4 : OGRFieldDefn oField1("nevenadresNummeraanduidingRef", OFTStringList);
258 :
259 2 : poFeatureDefn->AddFieldDefn(&oField0);
260 2 : poFeatureDefn->AddFieldDefn(&oField1);
261 :
262 2 : AddIdentifierFieldDefn();
263 2 : AddDocumentFieldDefn();
264 2 : AddOccurrenceFieldDefn();
265 :
266 2 : poFeatureDefn->SetName("Standplaats");
267 2 : SetDescription(poFeatureDefn->GetName());
268 :
269 2 : AddSpatialRef(wkbPolygon);
270 : }
271 9 : else if (EQUAL("opr", pszDataset))
272 : {
273 2 : OGRFieldDefn oField0("naam", OFTString);
274 2 : OGRFieldDefn oField1("type", OFTString);
275 2 : OGRFieldDefn oField2("woonplaatsRef", OFTString);
276 2 : OGRFieldDefn oField3("verkorteNaam", OFTString);
277 :
278 1 : poFeatureDefn->AddFieldDefn(&oField0);
279 1 : poFeatureDefn->AddFieldDefn(&oField1);
280 1 : poFeatureDefn->AddFieldDefn(&oField2);
281 1 : poFeatureDefn->AddFieldDefn(&oField3);
282 :
283 1 : AddIdentifierFieldDefn();
284 1 : AddDocumentFieldDefn();
285 1 : AddOccurrenceFieldDefn();
286 :
287 1 : poFeatureDefn->SetName("Openbareruimte");
288 1 : SetDescription(poFeatureDefn->GetName());
289 : }
290 8 : else if (EQUAL("vbo", pszDataset))
291 : {
292 10 : OGRFieldDefn oField0("gebruiksdoel", OFTStringList);
293 10 : OGRFieldDefn oField1("oppervlakte", OFTInteger);
294 10 : OGRFieldDefn oField2("hoofdadresNummeraanduidingRef", OFTString);
295 10 : OGRFieldDefn oField3("nevenadresNummeraanduidingRef", OFTStringList);
296 10 : OGRFieldDefn oField4("pandRef", OFTStringList);
297 :
298 5 : poFeatureDefn->AddFieldDefn(&oField0);
299 5 : poFeatureDefn->AddFieldDefn(&oField1);
300 5 : poFeatureDefn->AddFieldDefn(&oField2);
301 5 : poFeatureDefn->AddFieldDefn(&oField3);
302 5 : poFeatureDefn->AddFieldDefn(&oField4);
303 :
304 5 : AddIdentifierFieldDefn();
305 5 : AddDocumentFieldDefn();
306 5 : AddOccurrenceFieldDefn();
307 :
308 5 : poFeatureDefn->SetName("Verblijfsobject");
309 5 : SetDescription(poFeatureDefn->GetName());
310 :
311 5 : AddSpatialRef(wkbPoint);
312 : }
313 3 : else if (EQUAL("wpl", pszDataset))
314 : {
315 6 : OGRFieldDefn oField0("naam", OFTString);
316 :
317 3 : poFeatureDefn->AddFieldDefn(&oField0);
318 :
319 3 : AddIdentifierFieldDefn();
320 3 : AddDocumentFieldDefn();
321 3 : AddOccurrenceFieldDefn();
322 :
323 3 : poFeatureDefn->SetName("Woonplaats");
324 3 : SetDescription(poFeatureDefn->GetName());
325 :
326 3 : AddSpatialRef(wkbMultiPolygon);
327 : }
328 : else
329 : {
330 0 : CPLError(CE_Failure, CPLE_AppDefined,
331 : "Parsing LV BAG extract failed : invalid layer definition");
332 : }
333 24 : }
334 :
335 : /************************************************************************/
336 : /* StartDataCollect() */
337 : /************************************************************************/
338 :
339 8685 : void OGRLVBAGLayer::StartDataCollect()
340 : {
341 8685 : osElementString.Clear();
342 8685 : osAttributeString.Clear();
343 8685 : bCollectData = true;
344 8685 : }
345 :
346 : /************************************************************************/
347 : /* StopDataCollect() */
348 : /************************************************************************/
349 :
350 8528 : void OGRLVBAGLayer::StopDataCollect()
351 : {
352 8528 : bCollectData = false;
353 8528 : osElementString.Trim();
354 8528 : osAttributeString.Trim();
355 8528 : }
356 :
357 : /************************************************************************/
358 : /* DataHandlerCbk() */
359 : /************************************************************************/
360 :
361 48281 : void OGRLVBAGLayer::DataHandlerCbk(const char *data, int nLen)
362 : {
363 48281 : if (nLen && bCollectData)
364 : {
365 19725 : osElementString.append(data, nLen);
366 : }
367 48281 : }
368 :
369 : /************************************************************************/
370 : /* TouchLayer() */
371 : /************************************************************************/
372 :
373 1182 : bool OGRLVBAGLayer::TouchLayer()
374 : {
375 1182 : poPool->SetLastUsedLayer(this);
376 :
377 1182 : switch (eFileDescriptorsState)
378 : {
379 1153 : case FD_OPENED:
380 1153 : return true;
381 0 : case FD_CANNOT_REOPEN:
382 0 : return false;
383 29 : case FD_CLOSED:
384 29 : break;
385 : }
386 :
387 29 : fp = VSIFOpenExL(osFilename, "rb", true);
388 29 : if (!fp)
389 : {
390 0 : CPLError(CE_Warning, CPLE_AppDefined,
391 : "Opening LV BAG extract failed : %s", osFilename.c_str());
392 0 : eFileDescriptorsState = FD_CANNOT_REOPEN;
393 0 : return false;
394 : }
395 :
396 29 : eFileDescriptorsState = FD_OPENED;
397 :
398 29 : return true;
399 : }
400 :
401 : /************************************************************************/
402 : /* CloseUnderlyingLayer() */
403 : /************************************************************************/
404 :
405 29 : void OGRLVBAGLayer::CloseUnderlyingLayer()
406 : {
407 29 : if (fp)
408 : {
409 29 : VSIFCloseL(fp);
410 : }
411 29 : fp = nullptr;
412 :
413 29 : eFileDescriptorsState = FD_CLOSED;
414 29 : }
415 :
416 : /************************************************************************/
417 : /* startElementCbk() */
418 : /************************************************************************/
419 :
420 14546 : void OGRLVBAGLayer::StartElementCbk(const char *pszName, const char **ppszAttr)
421 : {
422 14546 : if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
423 10202 : nGeometryElementDepth == 0 && EQUAL("objecten:geometrie", pszName))
424 : {
425 428 : nGeometryElementDepth = nCurrentDepth;
426 428 : StartDataCollect();
427 : }
428 14118 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
429 9774 : nGeometryElementDepth + 1 == nCurrentDepth &&
430 534 : !STARTS_WITH_CI(pszName, "gml"))
431 : {
432 106 : nGeometryElementDepth = nCurrentDepth;
433 106 : StartDataCollect();
434 : }
435 14012 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
436 541 : nGeometryElementDepth == 0 && STARTS_WITH_CI(pszName, "objecten"))
437 541 : nAttributeElementDepth = nCurrentDepth;
438 13471 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
439 9668 : nGeometryElementDepth == 0 &&
440 7970 : (EQUAL("objecten:identificatie", pszName) ||
441 7429 : STARTS_WITH_CI(pszName, "objecten-ref")))
442 : {
443 718 : StartDataCollect();
444 718 : const char **papszIter = ppszAttr;
445 718 : while (papszIter && *papszIter != nullptr)
446 : {
447 718 : if (EQUAL("domein", papszIter[0]))
448 : {
449 718 : osAttributeString = papszIter[1];
450 718 : break;
451 : }
452 0 : papszIter += 2;
453 718 : }
454 : }
455 12753 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
456 8950 : nGeometryElementDepth == 0 &&
457 7252 : EQUAL("objecten:heeftalshoofdadres", pszName))
458 21 : eAddressRefState = AddressRefState::ADDRESS_PRIMARY;
459 12732 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
460 8929 : nGeometryElementDepth == 0 &&
461 7231 : EQUAL("objecten:heeftalsnevenadres", pszName))
462 1 : eAddressRefState = AddressRefState::ADDRESS_SECONDARY;
463 12731 : else if (nFeatureElementDepth > 0 && nAttributeElementDepth > 0 &&
464 8928 : nGeometryElementDepth == 0)
465 7230 : StartDataCollect();
466 5501 : else if (nGeometryElementDepth > 0 && STARTS_WITH_CI(pszName, "gml"))
467 : {
468 1698 : osElementString += "<";
469 1698 : osElementString += pszName;
470 :
471 1698 : const char **papszIter = ppszAttr;
472 3395 : while (papszIter && *papszIter != nullptr)
473 : {
474 1697 : OGRGeomFieldDefn *poGeomField = poFeatureDefn->GetGeomFieldDefn(0);
475 2125 : if (EQUAL("srsname", papszIter[0]) &&
476 428 : poGeomField->GetSpatialRef() == nullptr)
477 : {
478 0 : OGRSpatialReference *poSRS = new OGRSpatialReference();
479 0 : poSRS->importFromURN(papszIter[1]);
480 0 : poGeomField->SetSpatialRef(poSRS);
481 0 : poSRS->Release();
482 : }
483 :
484 1697 : osElementString += " ";
485 1697 : osElementString += papszIter[0];
486 1697 : osElementString += "=\"";
487 1697 : osElementString += papszIter[1];
488 1697 : osElementString += "\"";
489 1697 : papszIter += 2;
490 : }
491 :
492 1698 : osElementString += ">";
493 : }
494 3803 : else if (nFeatureCollectionDepth > 0 && nFeatureElementDepth == 0 &&
495 2368 : EQUAL("sl-bag-extract:bagObject", pszName) && bHasReadSchema)
496 : {
497 541 : nFeatureElementDepth = nCurrentDepth;
498 541 : m_poFeature = new OGRFeature(poFeatureDefn);
499 541 : m_poFeature->SetFID(nNextFID++);
500 : }
501 3262 : else if (nFeatureCollectionDepth == 0 && EQUAL("sl:standBestand", pszName))
502 205 : nFeatureCollectionDepth = nCurrentDepth;
503 3057 : else if (nFeatureCollectionDepth > 0 && EQUAL("sl:objectType", pszName))
504 203 : StartDataCollect();
505 :
506 14546 : nCurrentDepth++;
507 14546 : }
508 :
509 : /************************************************************************/
510 : /* endElementCbk() */
511 : /************************************************************************/
512 :
513 14278 : void OGRLVBAGLayer::EndElementCbk(const char *pszName)
514 : {
515 14278 : nCurrentDepth--;
516 :
517 14278 : if (nCurrentDepth > nAttributeElementDepth && nAttributeElementDepth > 0 &&
518 10202 : nGeometryElementDepth == 0)
519 : {
520 8076 : const char *pszTag = XMLTagSplit(pszName);
521 :
522 8076 : StopDataCollect();
523 8076 : if (!osElementString.empty())
524 : {
525 6170 : int iFieldIndex = poFeatureDefn->GetFieldIndex(pszTag);
526 :
527 6170 : if (EQUAL("nummeraanduidingref", pszTag))
528 : {
529 24 : switch (eAddressRefState)
530 : {
531 3 : case AddressRefState::ADDRESS_SECONDARY:
532 6 : iFieldIndex = poFeatureDefn->GetFieldIndex(
533 3 : "nevenadresnummeraanduidingref");
534 3 : break;
535 :
536 21 : default:
537 42 : iFieldIndex = poFeatureDefn->GetFieldIndex(
538 21 : "hoofdadresnummeraanduidingref");
539 21 : break;
540 : }
541 : }
542 :
543 6170 : if (EQUAL("identificatie", pszTag) ||
544 5629 : STARTS_WITH_CI(pszName, "objecten-ref"))
545 : {
546 718 : bool bIsIdInvalid = false;
547 718 : if (osElementString.size() == nDefaultIdentifierSize - 1)
548 : {
549 2 : osElementString = '0' + osElementString;
550 : }
551 716 : else if (osElementString.size() > nDefaultIdentifierSize)
552 : {
553 0 : bIsIdInvalid = true;
554 0 : m_poFeature->SetFieldNull(iFieldIndex);
555 0 : CPLError(CE_Warning, CPLE_AppDefined,
556 : "Invalid identificatie : %s, value set to null",
557 : osElementString.c_str());
558 : }
559 718 : if (!bIsIdInvalid)
560 : {
561 718 : if (!bLegacyId && !osAttributeString.empty())
562 : {
563 : osElementString =
564 718 : osAttributeString + '.' + osElementString;
565 : }
566 : }
567 : }
568 :
569 6170 : if (iFieldIndex > -1)
570 : {
571 : const OGRFieldDefn *poFieldDefn =
572 6170 : poFeatureDefn->GetFieldDefn(iFieldIndex);
573 6170 : if (poFieldDefn->GetType() == OFTStringList)
574 : {
575 20 : if (m_poFeature->IsFieldSetAndNotNull(iFieldIndex))
576 : {
577 10 : CPLStringList aoList;
578 : char **papszIter =
579 5 : m_poFeature->GetFieldAsStringList(iFieldIndex);
580 11 : while (papszIter != nullptr && *papszIter != nullptr)
581 : {
582 6 : aoList.AddString(*papszIter);
583 6 : papszIter++;
584 : }
585 :
586 5 : aoList.AddString(osElementString.c_str());
587 5 : m_poFeature->UnsetField(iFieldIndex);
588 5 : m_poFeature->SetField(iFieldIndex, aoList.List());
589 : }
590 : else
591 15 : m_poFeature->SetField(iFieldIndex,
592 : osElementString.c_str());
593 : }
594 6150 : else if (poFieldDefn->GetSubType() ==
595 : OGRFieldSubType::OFSTBoolean)
596 : {
597 541 : if (EQUAL("n", osElementString.c_str()))
598 541 : m_poFeature->SetField(iFieldIndex, 0);
599 0 : else if (EQUAL("j", osElementString.c_str()))
600 0 : m_poFeature->SetField(iFieldIndex, 1);
601 : else
602 : {
603 0 : CPLError(CE_Failure, CPLE_AppDefined,
604 : "Parsing boolean failed");
605 0 : XML_StopParser(oParser.get(), XML_FALSE);
606 : }
607 : }
608 : else
609 5609 : m_poFeature->SetField(iFieldIndex, osElementString.c_str());
610 :
611 6248 : if (bFixInvalidData && (poFieldDefn->GetType() == OFTDate ||
612 78 : poFieldDefn->GetType() == OFTDateTime))
613 : {
614 : int nYear;
615 53 : m_poFeature->GetFieldAsDateTime(
616 : iFieldIndex, &nYear, nullptr, nullptr, nullptr, nullptr,
617 : static_cast<float *>(nullptr), nullptr);
618 53 : if (nYear > 2100)
619 : {
620 0 : m_poFeature->SetFieldNull(iFieldIndex);
621 0 : CPLError(CE_Warning, CPLE_AppDefined,
622 : "Invalid date : %s, value set to null",
623 : osElementString.c_str());
624 : }
625 : }
626 : }
627 6170 : osElementString.Clear();
628 8076 : }
629 : }
630 6202 : else if (nAttributeElementDepth == nCurrentDepth)
631 668 : nAttributeElementDepth = 0;
632 5534 : else if (nGeometryElementDepth > 0 && nCurrentDepth > nGeometryElementDepth)
633 : {
634 1698 : osElementString += "</";
635 1698 : osElementString += pszName;
636 1698 : osElementString += ">";
637 : }
638 3836 : else if (nGeometryElementDepth == nCurrentDepth)
639 : {
640 428 : StopDataCollect();
641 428 : if (!osElementString.empty())
642 : {
643 : std::unique_ptr<OGRGeometry> poGeom =
644 : std::unique_ptr<OGRGeometry>(OGRGeometry::FromHandle(
645 856 : OGR_G_CreateFromGML(osElementString.c_str())));
646 428 : if (poGeom && !poGeom->IsEmpty())
647 : {
648 : // The specification only accounts for 2-dimensional datasets
649 428 : if (poGeom->Is3D())
650 315 : poGeom->flattenTo2D();
651 :
652 : #ifdef HAVE_GEOS
653 428 : if (bFixInvalidData && !poGeom->IsValid())
654 : {
655 : std::unique_ptr<OGRGeometry> poSubGeom =
656 8 : std::unique_ptr<OGRGeometry>{poGeom->MakeValid()};
657 4 : if (poSubGeom && poSubGeom->IsValid())
658 4 : poGeom.reset(poSubGeom.release());
659 : }
660 : #endif
661 :
662 : OGRGeomFieldDefn *poGeomField =
663 428 : poFeatureDefn->GetGeomFieldDefn(0);
664 428 : if (!poGeomField->GetSpatialRef())
665 0 : poGeomField->SetSpatialRef(poGeom->getSpatialReference());
666 428 : if (poGeomField->GetType() == wkbUnknown)
667 0 : poGeomField->SetType(poGeom->getGeometryType());
668 :
669 428 : if (poGeomField->GetType() == wkbPoint)
670 : {
671 7 : switch (poGeom->getGeometryType())
672 : {
673 0 : case wkbPolygon:
674 : case wkbMultiPolygon:
675 : {
676 0 : auto poPoint = std::make_unique<OGRPoint>();
677 : #ifdef HAVE_GEOS
678 0 : if (poGeom->Centroid(poPoint.get()) == OGRERR_NONE)
679 0 : poGeom.reset(poPoint.release());
680 : #else
681 : CPLError(CE_Warning, CPLE_AppDefined,
682 : "Cannot shape geometry, GEOS support not "
683 : "enabled.");
684 : poGeom.reset(poPoint.release());
685 : #endif
686 0 : break;
687 : }
688 :
689 7 : default:
690 7 : break;
691 : }
692 : }
693 520 : else if (poGeomField->GetType() == wkbMultiPolygon &&
694 99 : poGeom->getGeometryType() == wkbPolygon)
695 : {
696 198 : auto poMultiPolygon = std::make_unique<OGRMultiPolygon>();
697 99 : poMultiPolygon->addGeometry(poGeom.get());
698 99 : poGeom.reset(poMultiPolygon.release());
699 : }
700 322 : else if (poGeomField->GetType() == wkbMultiPolygon &&
701 0 : poGeom->getGeometryType() == wkbGeometryCollection &&
702 0 : poGeom->toGeometryCollection()->getNumGeometries() >
703 322 : 0 &&
704 : poGeom->toGeometryCollection()
705 0 : ->getGeometryRef(0)
706 0 : ->getGeometryType() == wkbPolygon)
707 : {
708 0 : auto poMultiPolygon = std::make_unique<OGRMultiPolygon>();
709 0 : for (const auto &poChildGeom :
710 0 : poGeom->toGeometryCollection())
711 0 : poMultiPolygon->addGeometry(poChildGeom);
712 0 : poGeom.reset(poMultiPolygon.release());
713 : }
714 644 : else if (poGeomField->GetType() == wkbPolygon &&
715 322 : (poGeom->getGeometryType() == wkbMultiPolygon ||
716 319 : poGeom->getGeometryType() == wkbGeometryCollection))
717 : {
718 4 : const OGRPolygon *poSubGeomLargest = nullptr;
719 8 : for (const auto &poChildGeom :
720 12 : poGeom->toGeometryCollection())
721 : {
722 8 : if (poChildGeom->getGeometryType() == wkbPolygon)
723 : {
724 7 : if (!poSubGeomLargest)
725 4 : poSubGeomLargest = poChildGeom->toPolygon();
726 3 : else if (poChildGeom->toPolygon()->get_Area() >
727 3 : poSubGeomLargest->get_Area())
728 0 : poSubGeomLargest = poChildGeom->toPolygon();
729 : }
730 : }
731 4 : if (poSubGeomLargest)
732 4 : poGeom.reset(poSubGeomLargest->clone());
733 : }
734 :
735 428 : if (poGeomField->GetSpatialRef())
736 856 : poGeom->assignSpatialReference(
737 428 : poGeomField->GetSpatialRef());
738 428 : m_poFeature->SetGeometryDirectly(poGeom.release());
739 : }
740 : else
741 : {
742 0 : CPLError(CE_Failure, CPLE_AppDefined,
743 : "Parsing geometry as GML failed");
744 0 : XML_StopParser(oParser.get(), XML_FALSE);
745 : }
746 : }
747 :
748 428 : osElementString.Clear();
749 428 : osAttributeString.Clear();
750 428 : nGeometryElementDepth = 0;
751 : }
752 3408 : else if (nFeatureElementDepth == nCurrentDepth)
753 : {
754 541 : nFeatureElementDepth = 0;
755 541 : XML_StopParser(oParser.get(), XML_TRUE);
756 : }
757 2867 : else if (nFeatureCollectionDepth == nCurrentDepth)
758 127 : nFeatureCollectionDepth = 0;
759 2740 : else if (EQUAL("sl:objecttype", pszName) && !poFeatureDefn->GetFieldCount())
760 : {
761 24 : StopDataCollect();
762 24 : if (osElementString.empty())
763 : {
764 0 : CPLError(CE_Failure, CPLE_AppDefined,
765 : "Parsing LV BAG extract failed");
766 0 : XML_StopParser(oParser.get(), XML_FALSE);
767 : }
768 :
769 24 : if (!bHasReadSchema)
770 : {
771 24 : CreateFeatureDefn(osElementString.c_str());
772 : }
773 24 : bHasReadSchema = true;
774 :
775 : // The parser is suspended but never resumed. Stop
776 : // without resume indicated an error.
777 24 : if (bSchemaOnly)
778 : {
779 24 : XML_StopParser(oParser.get(), XML_TRUE);
780 : }
781 : }
782 14278 : }
783 :
784 : /************************************************************************/
785 : /* ConfigureParser() */
786 : /************************************************************************/
787 :
788 205 : void OGRLVBAGLayer::ConfigureParser()
789 : {
790 205 : ResetReading();
791 :
792 : const auto startElementWrapper =
793 14546 : [](void *pUserData, const char *pszName, const char **ppszAttr)
794 : {
795 14546 : static_cast<OGRLVBAGLayer *>(pUserData)->StartElementCbk(pszName,
796 : ppszAttr);
797 14546 : };
798 :
799 14278 : const auto endElementWrapper = [](void *pUserData, const char *pszName)
800 14278 : { static_cast<OGRLVBAGLayer *>(pUserData)->EndElementCbk(pszName); };
801 :
802 : const auto dataHandlerWrapper =
803 48281 : [](void *pUserData, const XML_Char *data, int nLen)
804 48281 : { static_cast<OGRLVBAGLayer *>(pUserData)->DataHandlerCbk(data, nLen); };
805 :
806 205 : oParser = OGRExpatUniquePtr{OGRCreateExpatXMLParser()};
807 205 : XML_SetElementHandler(oParser.get(), startElementWrapper,
808 : endElementWrapper);
809 205 : XML_SetCharacterDataHandler(oParser.get(), dataHandlerWrapper);
810 205 : XML_SetUserData(oParser.get(), this);
811 205 : }
812 :
813 : /************************************************************************/
814 : /* IsParserFinished() */
815 : /************************************************************************/
816 :
817 1248 : bool OGRLVBAGLayer::IsParserFinished(XML_Status status)
818 : {
819 1248 : switch (status)
820 : {
821 681 : case XML_STATUS_OK:
822 681 : return false;
823 :
824 2 : case XML_STATUS_ERROR:
825 2 : CPLError(
826 : CE_Failure, CPLE_AppDefined,
827 : "Parsing of LV BAG file failed : %s at line %d, "
828 : "column %d",
829 : XML_ErrorString(XML_GetErrorCode(oParser.get())),
830 2 : static_cast<int>(XML_GetCurrentLineNumber(oParser.get())),
831 2 : static_cast<int>(XML_GetCurrentColumnNumber(oParser.get())));
832 :
833 2 : delete m_poFeature;
834 2 : m_poFeature = nullptr;
835 2 : return true;
836 :
837 565 : case XML_STATUS_SUSPENDED:
838 565 : return true;
839 : }
840 :
841 0 : return true;
842 : }
843 :
844 : /************************************************************************/
845 : /* ParseDocument() */
846 : /************************************************************************/
847 :
848 1384 : void OGRLVBAGLayer::ParseDocument()
849 : {
850 : while (true)
851 : {
852 : XML_ParsingStatus status;
853 1384 : XML_GetParsingStatus(oParser.get(), &status);
854 1384 : switch (status.parsing)
855 : {
856 759 : case XML_INITIALIZED:
857 : case XML_PARSING:
858 : {
859 : const unsigned int nLen = static_cast<unsigned int>(
860 759 : VSIFReadL(aBuf.data(), 1, aBuf.size(), fp));
861 :
862 759 : if (IsParserFinished(XML_Parse(oParser.get(), aBuf.data(), nLen,
863 759 : nLen < aBuf.size())))
864 703 : return;
865 :
866 409 : break;
867 : }
868 :
869 489 : case XML_SUSPENDED:
870 : {
871 489 : if (IsParserFinished(XML_ResumeParser(oParser.get())))
872 217 : return;
873 :
874 272 : break;
875 : }
876 :
877 136 : case XML_FINISHED:
878 : default:
879 136 : return;
880 : }
881 681 : }
882 : }
883 :
884 : /************************************************************************/
885 : /* GetNextFeature() */
886 : /************************************************************************/
887 :
888 569 : OGRFeature *OGRLVBAGLayer::GetNextFeature()
889 : {
890 569 : if (!TouchLayer())
891 : {
892 0 : return nullptr;
893 : }
894 :
895 569 : GetLayerDefn();
896 569 : if (!bHasReadSchema)
897 : {
898 1 : CPLError(CE_Failure, CPLE_AppDefined,
899 : "Parsing LV BAG extract failed : invalid layer definition");
900 1 : return nullptr;
901 : }
902 :
903 568 : return OGRGetNextFeatureThroughRaw<OGRLVBAGLayer>::GetNextFeature();
904 : }
905 :
906 : /************************************************************************/
907 : /* GetNextRawFeature() */
908 : /************************************************************************/
909 :
910 677 : OGRFeature *OGRLVBAGLayer::GetNextRawFeature()
911 : {
912 677 : bSchemaOnly = false;
913 :
914 677 : if (nNextFID == 0)
915 : {
916 179 : ConfigureParser();
917 : }
918 :
919 677 : if (m_poFeature)
920 : {
921 0 : delete m_poFeature;
922 0 : m_poFeature = nullptr;
923 : }
924 :
925 677 : ParseDocument();
926 677 : OGRFeature *poFeatureRet = m_poFeature;
927 677 : m_poFeature = nullptr;
928 677 : return poFeatureRet;
929 : }
930 :
931 : /************************************************************************/
932 : /* TestCapability() */
933 : /************************************************************************/
934 :
935 110 : int OGRLVBAGLayer::TestCapability(const char *pszCap) const
936 : {
937 110 : if (EQUAL(pszCap, OLCStringsAsUTF8))
938 : {
939 39 : return TRUE;
940 : }
941 :
942 71 : return FALSE;
943 : }
|