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