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