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