/src/gdal/ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: VDV Translator |
4 | | * Purpose: Implements OGRVDVFDriver. |
5 | | * Author: Even Rouault, even.rouault at spatialys.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogr_vdv.h" |
14 | | #include "cpl_conv.h" |
15 | | #include "cpl_time.h" |
16 | | |
17 | | #include "memdataset.h" |
18 | | |
19 | | #include <map> |
20 | | |
21 | | #ifdef EMBED_RESOURCE_FILES |
22 | | #include "embedded_resources.h" |
23 | | #endif |
24 | | |
25 | | #ifndef STARTS_WITH_CI |
26 | | #define STARTS_WITH(a, b) (strncmp(a, b, strlen(b)) == 0) |
27 | | #define STARTS_WITH_CI(a, b) EQUALN(a, b, strlen(b)) |
28 | | #endif |
29 | | |
30 | | typedef enum |
31 | | { |
32 | | LAYER_OTHER, |
33 | | LAYER_NODE, |
34 | | LAYER_LINK, |
35 | | LAYER_LINKCOORDINATE |
36 | | } IDFLayerType; |
37 | | |
38 | | /************************************************************************/ |
39 | | /* OGRVDVParseAtrFrm() */ |
40 | | /************************************************************************/ |
41 | | |
42 | | static void OGRVDVParseAtrFrm(OGRLayer *poLayer, OGRFeatureDefn *poFeatureDefn, |
43 | | char **papszAtr, char **papszFrm) |
44 | 75.8k | { |
45 | 308k | for (int i = 0; papszAtr[i]; i++) |
46 | 232k | { |
47 | 232k | OGRFieldType eType = OFTString; |
48 | 232k | int nWidth = 0; |
49 | 232k | OGRFieldSubType eSubType = OFSTNone; |
50 | 232k | if (STARTS_WITH_CI(papszFrm[i], "decimal")) |
51 | 42.4k | { |
52 | 42.4k | if (papszFrm[i][strlen("decimal")] == '(') |
53 | 33.5k | { |
54 | 33.5k | if (strchr(papszFrm[i], ',') && |
55 | 33.5k | atoi(strchr(papszFrm[i], ',') + 1) > 0) |
56 | 15.7k | { |
57 | 15.7k | eType = OFTReal; |
58 | 15.7k | } |
59 | 17.7k | else |
60 | 17.7k | { |
61 | 17.7k | nWidth = atoi(papszFrm[i] + strlen("decimal") + 1); |
62 | 17.7k | if (nWidth >= 10) |
63 | 9.38k | eType = OFTInteger64; |
64 | 8.37k | else |
65 | 8.37k | eType = OFTInteger; |
66 | 17.7k | } |
67 | 33.5k | } |
68 | 8.97k | else |
69 | 8.97k | eType = OFTInteger; |
70 | 42.4k | } |
71 | 190k | else if (STARTS_WITH_CI(papszFrm[i], "num")) |
72 | 25.5k | { |
73 | 25.5k | if (papszFrm[i][strlen("num")] == '[') |
74 | 19.4k | { |
75 | 19.4k | if (strchr(papszFrm[i], '.') && |
76 | 19.4k | atoi(strchr(papszFrm[i], '.') + 1) > 0) |
77 | 4.23k | { |
78 | 4.23k | eType = OFTReal; |
79 | 4.23k | } |
80 | 15.1k | else |
81 | 15.1k | { |
82 | 15.1k | nWidth = atoi(papszFrm[i] + strlen("num") + 1); |
83 | 15.1k | if (nWidth < 0 || nWidth >= 100) |
84 | 3.52k | { |
85 | 3.52k | nWidth = 0; |
86 | 3.52k | eType = OFTInteger; |
87 | 3.52k | } |
88 | 11.6k | else |
89 | 11.6k | { |
90 | 11.6k | nWidth += 1; /* VDV-451 width is without sign */ |
91 | 11.6k | if (nWidth >= 10) |
92 | 3.48k | eType = OFTInteger64; |
93 | 8.17k | else |
94 | 8.17k | eType = OFTInteger; |
95 | 11.6k | } |
96 | 15.1k | } |
97 | 19.4k | } |
98 | 6.14k | else |
99 | 6.14k | eType = OFTInteger; |
100 | 25.5k | } |
101 | 164k | else if (STARTS_WITH_CI(papszFrm[i], "char")) |
102 | 3.99k | { |
103 | 3.99k | if (papszFrm[i][strlen("char")] == '[') |
104 | 2.26k | { |
105 | 2.26k | nWidth = atoi(papszFrm[i] + strlen("char") + 1); |
106 | 2.26k | if (nWidth < 0) |
107 | 414 | nWidth = 0; |
108 | 2.26k | } |
109 | 3.99k | } |
110 | 160k | else if (STARTS_WITH_CI(papszFrm[i], "boolean")) |
111 | 4.61k | { |
112 | 4.61k | eType = OFTInteger; |
113 | 4.61k | eSubType = OFSTBoolean; |
114 | 4.61k | } |
115 | 232k | OGRFieldDefn oFieldDefn(papszAtr[i], eType); |
116 | 232k | oFieldDefn.SetSubType(eSubType); |
117 | 232k | oFieldDefn.SetWidth(nWidth); |
118 | 232k | if (poLayer) |
119 | 163k | poLayer->CreateField(&oFieldDefn); |
120 | 69.2k | else if (poFeatureDefn) |
121 | 69.2k | poFeatureDefn->AddFieldDefn(&oFieldDefn); |
122 | 0 | else |
123 | 0 | { |
124 | 0 | CPLAssert(false); |
125 | 0 | } |
126 | 232k | } |
127 | 75.8k | } |
128 | | |
129 | | /************************************************************************/ |
130 | | /* OGRIDFDataSource() */ |
131 | | /************************************************************************/ |
132 | | |
133 | | OGRIDFDataSource::OGRIDFDataSource(const char *pszFilename, VSILFILE *fpLIn) |
134 | 3.06k | : m_osFilename(pszFilename), m_fpL(fpLIn), m_bHasParsed(false), |
135 | 3.06k | m_poTmpDS(nullptr) |
136 | 3.06k | { |
137 | 3.06k | } |
138 | | |
139 | | /************************************************************************/ |
140 | | /* ~OGRIDFDataSource() */ |
141 | | /************************************************************************/ |
142 | | |
143 | | OGRIDFDataSource::~OGRIDFDataSource() |
144 | 3.06k | { |
145 | 3.06k | CPLString osTmpFilename; |
146 | 3.06k | if (m_bDestroyTmpDS && m_poTmpDS) |
147 | 0 | { |
148 | 0 | osTmpFilename = m_poTmpDS->GetDescription(); |
149 | 0 | } |
150 | 3.06k | delete m_poTmpDS; |
151 | 3.06k | if (m_bDestroyTmpDS) |
152 | 0 | { |
153 | 0 | VSIUnlink(osTmpFilename); |
154 | 0 | } |
155 | 3.06k | if (m_fpL) |
156 | 3.06k | { |
157 | 3.06k | VSIFCloseL(m_fpL); |
158 | 3.06k | } |
159 | 3.06k | } |
160 | | |
161 | | /************************************************************************/ |
162 | | /* Parse() */ |
163 | | /************************************************************************/ |
164 | | |
165 | | void OGRIDFDataSource::Parse() |
166 | 2.98k | { |
167 | 2.98k | m_bHasParsed = true; |
168 | | |
169 | 2.98k | VSIStatBufL sStatBuf; |
170 | 2.98k | bool bGPKG = false; |
171 | 2.98k | vsi_l_offset nFileSize = 0; |
172 | 2.98k | bool bSpatialIndex = false; |
173 | 2.98k | if (VSIStatL(m_osFilename, &sStatBuf) == 0 && |
174 | 2.98k | sStatBuf.st_size > CPLAtoGIntBig(CPLGetConfigOption( |
175 | 2.98k | "OGR_IDF_TEMP_DB_THRESHOLD", "100000000"))) |
176 | 228 | { |
177 | 228 | nFileSize = sStatBuf.st_size; |
178 | | |
179 | 228 | GDALDriver *poGPKGDriver = |
180 | 228 | reinterpret_cast<GDALDriver *>(GDALGetDriverByName("GPKG")); |
181 | 228 | if (poGPKGDriver) |
182 | 228 | { |
183 | 228 | CPLString osTmpFilename(m_osFilename + "_tmp.gpkg"); |
184 | 228 | VSILFILE *fp = VSIFOpenL(osTmpFilename, "wb"); |
185 | 228 | if (fp) |
186 | 0 | { |
187 | 0 | VSIFCloseL(fp); |
188 | 0 | } |
189 | 228 | else |
190 | 228 | { |
191 | 228 | osTmpFilename = CPLGenerateTempFilenameSafe( |
192 | 228 | CPLGetBasenameSafe(m_osFilename).c_str()); |
193 | 228 | osTmpFilename += ".gpkg"; |
194 | 228 | } |
195 | 228 | VSIUnlink(osTmpFilename); |
196 | 228 | { |
197 | 228 | CPLConfigOptionSetter oSetter1("OGR_SQLITE_JOURNAL", "OFF", |
198 | 228 | false); |
199 | | // For use of OGR VSI-based SQLite3 VFS implementation, as |
200 | | // the regular SQLite3 implementation has some issues to deal |
201 | | // with a file that is deleted after having been created. |
202 | | // For example on MacOS Big Sur system's sqlite 3.32.3 |
203 | | // when chaining ogr_sqlite.py and ogr_vdv.py, or in Vagrant |
204 | | // Ubuntu 22.04 environment with sqlite 3.37.2 |
205 | 228 | CPLConfigOptionSetter oSetter2("SQLITE_USE_OGR_VFS", "YES", |
206 | 228 | false); |
207 | 228 | m_poTmpDS = poGPKGDriver->Create(osTmpFilename, 0, 0, 0, |
208 | 228 | GDT_Unknown, nullptr); |
209 | 228 | } |
210 | 228 | bGPKG = m_poTmpDS != nullptr; |
211 | 228 | m_bDestroyTmpDS = CPLTestBool(CPLGetConfigOption( |
212 | 228 | "OGR_IDF_DELETE_TEMP_DB", "YES")) && |
213 | 228 | m_poTmpDS != nullptr; |
214 | 228 | if (m_bDestroyTmpDS) |
215 | 228 | { |
216 | 228 | CPLPushErrorHandler(CPLQuietErrorHandler); |
217 | 228 | m_bDestroyTmpDS = VSIUnlink(osTmpFilename) != 0; |
218 | 228 | CPLPopErrorHandler(); |
219 | 228 | } |
220 | 0 | else |
221 | 0 | { |
222 | 0 | bSpatialIndex = true; |
223 | 0 | } |
224 | 228 | } |
225 | 228 | } |
226 | | |
227 | 2.98k | bool bIsMEMLayer = false; |
228 | 2.98k | if (m_poTmpDS == nullptr) |
229 | 2.75k | { |
230 | 2.75k | bIsMEMLayer = true; |
231 | 2.75k | m_poTmpDS = MEMDataset::Create("", 0, 0, 0, GDT_Unknown, nullptr); |
232 | 2.75k | } |
233 | | |
234 | 2.98k | m_poTmpDS->StartTransaction(); |
235 | | |
236 | 2.98k | OGRLayer *poCurLayer = nullptr; |
237 | | |
238 | 2.98k | struct Point |
239 | 2.98k | { |
240 | 2.98k | double x; |
241 | 2.98k | double y; |
242 | 2.98k | double z; |
243 | | |
244 | 2.98k | explicit Point(double xIn = 0, double yIn = 0, double zIn = 0) |
245 | 148k | : x(xIn), y(yIn), z(zIn) |
246 | 148k | { |
247 | 148k | } |
248 | 2.98k | }; |
249 | | |
250 | 2.98k | std::map<GIntBig, Point> oMapNode; // map from NODE_ID to Point |
251 | 2.98k | std::map<GIntBig, OGRLineString *> |
252 | 2.98k | oMapLinkCoordinate; // map from LINK_ID to OGRLineString* |
253 | 2.98k | CPLString osTablename, osAtr, osFrm; |
254 | 2.98k | int iX = -1, iY = -1, iZ = -1; |
255 | 2.98k | bool bAdvertiseUTF8 = false; |
256 | 2.98k | bool bRecodeFromLatin1 = false; |
257 | 2.98k | int iNodeID = -1; |
258 | 2.98k | int iLinkID = -1; |
259 | 2.98k | int iFromNode = -1; |
260 | 2.98k | int iToNode = -1; |
261 | 2.98k | IDFLayerType eLayerType = LAYER_OTHER; |
262 | | |
263 | | // We assume that layers are in the order Node, Link, LinkCoordinate |
264 | | |
265 | 2.98k | GUIntBig nLineCount = 0; |
266 | 4.11M | while (true) |
267 | 4.11M | { |
268 | 4.11M | if (nFileSize) |
269 | 747k | { |
270 | 747k | ++nLineCount; |
271 | 747k | if ((nLineCount % 32768) == 0) |
272 | 11 | { |
273 | 11 | const vsi_l_offset nPos = VSIFTellL(m_fpL); |
274 | 11 | CPLDebug("IDF", "Reading progress: %.2f %%", |
275 | 11 | 100.0 * nPos / nFileSize); |
276 | 11 | } |
277 | 747k | } |
278 | | |
279 | 4.11M | const char *pszLine = CPLReadLineL(m_fpL); |
280 | 4.11M | if (pszLine == nullptr) |
281 | 2.92k | break; |
282 | | |
283 | 4.11M | if (strcmp(pszLine, "chs;ISO_LATIN_1") == 0) |
284 | 4.78k | { |
285 | 4.78k | bAdvertiseUTF8 = true; |
286 | 4.78k | bRecodeFromLatin1 = true; |
287 | 4.78k | } |
288 | 4.10M | else if (STARTS_WITH(pszLine, "tbl;")) |
289 | 158k | { |
290 | 158k | poCurLayer = nullptr; |
291 | 158k | osTablename = pszLine + 4; |
292 | 158k | osAtr = ""; |
293 | 158k | osFrm = ""; |
294 | 158k | iX = iY = iNodeID = iLinkID = iFromNode = iToNode = -1; |
295 | 158k | eLayerType = LAYER_OTHER; |
296 | 158k | } |
297 | 3.94M | else if (STARTS_WITH(pszLine, "atr;")) |
298 | 157k | { |
299 | 157k | osAtr = pszLine + 4; |
300 | 157k | osAtr.Trim(); |
301 | 157k | } |
302 | 3.79M | else if (STARTS_WITH(pszLine, "frm;")) |
303 | 138k | { |
304 | 138k | osFrm = pszLine + 4; |
305 | 138k | osFrm.Trim(); |
306 | 138k | } |
307 | 3.65M | else if (STARTS_WITH(pszLine, "rec;")) |
308 | 433k | { |
309 | 433k | if (poCurLayer == nullptr) |
310 | 115k | { |
311 | 115k | char **papszAtr = CSLTokenizeString2(osAtr, ";", |
312 | 115k | CSLT_ALLOWEMPTYTOKENS | |
313 | 115k | CSLT_STRIPLEADSPACES | |
314 | 115k | CSLT_STRIPENDSPACES); |
315 | 115k | char **papszFrm = CSLTokenizeString2(osFrm, ";", |
316 | 115k | CSLT_ALLOWEMPTYTOKENS | |
317 | 115k | CSLT_STRIPLEADSPACES | |
318 | 115k | CSLT_STRIPENDSPACES); |
319 | 115k | char *apszOptions[2] = {nullptr, nullptr}; |
320 | 115k | if (bAdvertiseUTF8 && !bGPKG) |
321 | 33.2k | apszOptions[0] = (char *)"ADVERTIZE_UTF8=YES"; |
322 | 82.1k | else if (bGPKG && !bSpatialIndex) |
323 | 840 | apszOptions[0] = (char *)"SPATIAL_INDEX=NO"; |
324 | | |
325 | 115k | if (EQUAL(osTablename, "Node") && |
326 | 115k | (iX = CSLFindString(papszAtr, "X")) >= 0 && |
327 | 115k | (iY = CSLFindString(papszAtr, "Y")) >= 0) |
328 | 28.7k | { |
329 | 28.7k | iZ = CSLFindString(papszAtr, "Z"); |
330 | 28.7k | eLayerType = LAYER_NODE; |
331 | 28.7k | iNodeID = CSLFindString(papszAtr, "NODE_ID"); |
332 | 28.7k | OGRSpatialReference *poSRS = |
333 | 28.7k | new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG); |
334 | 28.7k | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
335 | 28.7k | poCurLayer = m_poTmpDS->CreateLayer( |
336 | 28.7k | osTablename, poSRS, iZ < 0 ? wkbPoint : wkbPoint25D, |
337 | 28.7k | apszOptions); |
338 | 28.7k | poSRS->Release(); |
339 | 28.7k | } |
340 | 86.6k | else if (EQUAL(osTablename, "Link") && |
341 | 86.6k | (iLinkID = CSLFindString(papszAtr, "LINK_ID")) >= 0 && |
342 | 86.6k | ((iFromNode = CSLFindString(papszAtr, "FROM_NODE")) >= |
343 | 6.27k | 0) && |
344 | 86.6k | ((iToNode = CSLFindString(papszAtr, "TO_NODE")) >= 0)) |
345 | 4.56k | { |
346 | 4.56k | eLayerType = LAYER_LINK; |
347 | 4.56k | OGRSpatialReference *poSRS = |
348 | 4.56k | new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG); |
349 | 4.56k | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
350 | 4.56k | poCurLayer = m_poTmpDS->CreateLayer( |
351 | 4.56k | osTablename, poSRS, |
352 | 4.56k | iZ < 0 ? wkbLineString : wkbLineString25D, apszOptions); |
353 | 4.56k | poSRS->Release(); |
354 | 4.56k | } |
355 | 82.0k | else if (EQUAL(osTablename, "LinkCoordinate") && |
356 | 82.0k | (iLinkID = CSLFindString(papszAtr, "LINK_ID")) >= 0 && |
357 | 82.0k | CSLFindString(papszAtr, "COUNT") >= 0 && |
358 | 82.0k | (iX = CSLFindString(papszAtr, "X")) >= 0 && |
359 | 82.0k | (iY = CSLFindString(papszAtr, "Y")) >= 0) |
360 | 3.05k | { |
361 | 3.05k | iZ = CSLFindString(papszAtr, "Z"); |
362 | 3.05k | eLayerType = LAYER_LINKCOORDINATE; |
363 | 3.05k | OGRSpatialReference *poSRS = |
364 | 3.05k | new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG); |
365 | 3.05k | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
366 | 3.05k | poCurLayer = m_poTmpDS->CreateLayer( |
367 | 3.05k | osTablename, poSRS, iZ < 0 ? wkbPoint : wkbPoint25D, |
368 | 3.05k | apszOptions); |
369 | 3.05k | poSRS->Release(); |
370 | 3.05k | } |
371 | 78.9k | else |
372 | 78.9k | { |
373 | 78.9k | poCurLayer = m_poTmpDS->CreateLayer(osTablename, nullptr, |
374 | 78.9k | wkbNone, apszOptions); |
375 | 78.9k | } |
376 | 115k | if (poCurLayer == nullptr) |
377 | 53 | { |
378 | 53 | CSLDestroy(papszAtr); |
379 | 53 | CSLDestroy(papszFrm); |
380 | 53 | break; |
381 | 53 | } |
382 | | |
383 | 115k | if (!osAtr.empty() && CSLCount(papszAtr) == CSLCount(papszFrm)) |
384 | 37.4k | { |
385 | 37.4k | OGRVDVParseAtrFrm(poCurLayer, nullptr, papszAtr, papszFrm); |
386 | 37.4k | } |
387 | 115k | CSLDestroy(papszAtr); |
388 | 115k | CSLDestroy(papszFrm); |
389 | 115k | } |
390 | | |
391 | 433k | OGRErr eErr = OGRERR_NONE; |
392 | 433k | char **papszTokens = |
393 | 433k | CSLTokenizeStringComplex(pszLine + 4, ";", TRUE, TRUE); |
394 | 433k | OGRFeatureDefn *poFDefn = poCurLayer->GetLayerDefn(); |
395 | 433k | OGRFeature *poFeature = new OGRFeature(poFDefn); |
396 | 433k | for (int i = 0; |
397 | 944k | i < poFDefn->GetFieldCount() && papszTokens[i] != nullptr; i++) |
398 | 510k | { |
399 | 510k | if (papszTokens[i][0]) |
400 | 474k | { |
401 | 474k | if (bRecodeFromLatin1 && |
402 | 474k | poFDefn->GetFieldDefn(i)->GetType() == OFTString) |
403 | 137k | { |
404 | 137k | char *pszRecoded = CPLRecode( |
405 | 137k | papszTokens[i], CPL_ENC_ISO8859_1, CPL_ENC_UTF8); |
406 | 137k | poFeature->SetField(i, pszRecoded); |
407 | 137k | CPLFree(pszRecoded); |
408 | 137k | } |
409 | 337k | else |
410 | 337k | { |
411 | 337k | poFeature->SetField(i, papszTokens[i]); |
412 | 337k | } |
413 | 474k | } |
414 | 510k | } |
415 | | |
416 | 433k | if (eLayerType == LAYER_NODE && iX >= 0 && iY >= 0 && iNodeID >= 0) |
417 | 140k | { |
418 | 140k | double dfX = poFeature->GetFieldAsDouble(iX); |
419 | 140k | double dfY = poFeature->GetFieldAsDouble(iY); |
420 | 140k | OGRGeometry *poGeom; |
421 | 140k | if (iZ >= 0) |
422 | 58.6k | { |
423 | 58.6k | double dfZ = poFeature->GetFieldAsDouble(iZ); |
424 | 58.6k | oMapNode[poFeature->GetFieldAsInteger64(iNodeID)] = |
425 | 58.6k | Point(dfX, dfY, dfZ); |
426 | 58.6k | poGeom = new OGRPoint(dfX, dfY, dfZ); |
427 | 58.6k | } |
428 | 81.4k | else |
429 | 81.4k | { |
430 | 81.4k | oMapNode[poFeature->GetFieldAsInteger64(iNodeID)] = |
431 | 81.4k | Point(dfX, dfY); |
432 | 81.4k | poGeom = new OGRPoint(dfX, dfY); |
433 | 81.4k | } |
434 | 140k | poGeom->assignSpatialReference( |
435 | 140k | poFDefn->GetGeomFieldDefn(0)->GetSpatialRef()); |
436 | 140k | poFeature->SetGeometryDirectly(poGeom); |
437 | 140k | } |
438 | 293k | else if (eLayerType == LAYER_LINK && iFromNode >= 0 && iToNode >= 0) |
439 | 27.9k | { |
440 | 27.9k | GIntBig nFromNode = poFeature->GetFieldAsInteger64(iFromNode); |
441 | 27.9k | GIntBig nToNode = poFeature->GetFieldAsInteger64(iToNode); |
442 | 27.9k | std::map<GIntBig, Point>::iterator oIterFrom = |
443 | 27.9k | oMapNode.find(nFromNode); |
444 | 27.9k | std::map<GIntBig, Point>::iterator oIterTo = |
445 | 27.9k | oMapNode.find(nToNode); |
446 | 27.9k | if (oIterFrom != oMapNode.end() && oIterTo != oMapNode.end()) |
447 | 19.1k | { |
448 | 19.1k | OGRLineString *poLS = new OGRLineString(); |
449 | 19.1k | if (iZ >= 0) |
450 | 3.04k | { |
451 | 3.04k | poLS->addPoint(oIterFrom->second.x, oIterFrom->second.y, |
452 | 3.04k | oIterFrom->second.z); |
453 | 3.04k | poLS->addPoint(oIterTo->second.x, oIterTo->second.y, |
454 | 3.04k | oIterTo->second.z); |
455 | 3.04k | } |
456 | 16.1k | else |
457 | 16.1k | { |
458 | 16.1k | poLS->addPoint(oIterFrom->second.x, |
459 | 16.1k | oIterFrom->second.y); |
460 | 16.1k | poLS->addPoint(oIterTo->second.x, oIterTo->second.y); |
461 | 16.1k | } |
462 | 19.1k | poLS->assignSpatialReference( |
463 | 19.1k | poFDefn->GetGeomFieldDefn(0)->GetSpatialRef()); |
464 | 19.1k | poFeature->SetGeometryDirectly(poLS); |
465 | 19.1k | } |
466 | 27.9k | } |
467 | 265k | else if (eLayerType == LAYER_LINKCOORDINATE && iX >= 0 && iY >= 0 && |
468 | 265k | iLinkID >= 0) |
469 | 11.5k | { |
470 | 11.5k | double dfX = poFeature->GetFieldAsDouble(iX); |
471 | 11.5k | double dfY = poFeature->GetFieldAsDouble(iY); |
472 | 11.5k | double dfZ = 0.0; |
473 | 11.5k | OGRGeometry *poGeom; |
474 | 11.5k | if (iZ >= 0) |
475 | 7.06k | { |
476 | 7.06k | dfZ = poFeature->GetFieldAsDouble(iZ); |
477 | 7.06k | poGeom = new OGRPoint(dfX, dfY, dfZ); |
478 | 7.06k | } |
479 | 4.50k | else |
480 | 4.50k | { |
481 | 4.50k | poGeom = new OGRPoint(dfX, dfY); |
482 | 4.50k | } |
483 | 11.5k | poGeom->assignSpatialReference( |
484 | 11.5k | poFDefn->GetGeomFieldDefn(0)->GetSpatialRef()); |
485 | 11.5k | poFeature->SetGeometryDirectly(poGeom); |
486 | | |
487 | 11.5k | GIntBig nCurLinkID = poFeature->GetFieldAsInteger64(iLinkID); |
488 | 11.5k | std::map<GIntBig, OGRLineString *>::iterator |
489 | 11.5k | oMapLinkCoordinateIter = |
490 | 11.5k | oMapLinkCoordinate.find(nCurLinkID); |
491 | 11.5k | if (oMapLinkCoordinateIter == oMapLinkCoordinate.end()) |
492 | 811 | { |
493 | 811 | OGRLineString *poLS = new OGRLineString(); |
494 | 811 | if (iZ >= 0) |
495 | 567 | poLS->addPoint(dfX, dfY, dfZ); |
496 | 244 | else |
497 | 244 | poLS->addPoint(dfX, dfY); |
498 | 811 | oMapLinkCoordinate[nCurLinkID] = poLS; |
499 | 811 | } |
500 | 10.7k | else |
501 | 10.7k | { |
502 | 10.7k | if (iZ >= 0) |
503 | 6.49k | { |
504 | 6.49k | oMapLinkCoordinateIter->second->addPoint(dfX, dfY, dfZ); |
505 | 6.49k | } |
506 | 4.26k | else |
507 | 4.26k | { |
508 | 4.26k | oMapLinkCoordinateIter->second->addPoint(dfX, dfY); |
509 | 4.26k | } |
510 | 10.7k | } |
511 | 11.5k | } |
512 | 433k | eErr = poCurLayer->CreateFeature(poFeature); |
513 | 433k | delete poFeature; |
514 | | |
515 | 433k | CSLDestroy(papszTokens); |
516 | | |
517 | 433k | if (eErr == OGRERR_FAILURE) |
518 | 8 | break; |
519 | 433k | } |
520 | 4.11M | } |
521 | | |
522 | 2.98k | oMapNode.clear(); |
523 | | |
524 | | // Patch Link geometries with the intermediate points of LinkCoordinate |
525 | 2.98k | OGRLayer *poLinkLyr = m_poTmpDS->GetLayerByName("Link"); |
526 | 2.98k | if (poLinkLyr && poLinkLyr->GetLayerDefn()->GetGeomFieldCount()) |
527 | 165 | { |
528 | 165 | iLinkID = poLinkLyr->GetLayerDefn()->GetFieldIndex("LINK_ID"); |
529 | 165 | if (iLinkID >= 0) |
530 | 142 | { |
531 | 142 | poLinkLyr->ResetReading(); |
532 | 142 | const OGRSpatialReference *poSRS = |
533 | 142 | poLinkLyr->GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef(); |
534 | 142 | for (auto &&poFeat : poLinkLyr) |
535 | 2.06k | { |
536 | 2.06k | GIntBig nLinkID = poFeat->GetFieldAsInteger64(iLinkID); |
537 | 2.06k | std::map<GIntBig, OGRLineString *>::iterator |
538 | 2.06k | oMapLinkCoordinateIter = oMapLinkCoordinate.find(nLinkID); |
539 | 2.06k | OGRGeometry *poGeom = poFeat->GetGeometryRef(); |
540 | 2.06k | if (poGeom && |
541 | 2.06k | oMapLinkCoordinateIter != oMapLinkCoordinate.end()) |
542 | 384 | { |
543 | 384 | OGRLineString *poLS = poGeom->toLineString(); |
544 | 384 | if (poLS) |
545 | 384 | { |
546 | 384 | OGRLineString *poLSIntermediate = |
547 | 384 | oMapLinkCoordinateIter->second; |
548 | 384 | OGRLineString *poLSNew = new OGRLineString(); |
549 | 384 | if (poLS->getGeometryType() == wkbLineString25D) |
550 | 78 | { |
551 | 78 | poLSNew->addPoint(poLS->getX(0), poLS->getY(0), |
552 | 78 | poLS->getZ(0)); |
553 | 78 | for (int i = 0; |
554 | 2.13k | i < poLSIntermediate->getNumPoints(); i++) |
555 | 2.05k | { |
556 | 2.05k | poLSNew->addPoint(poLSIntermediate->getX(i), |
557 | 2.05k | poLSIntermediate->getY(i), |
558 | 2.05k | poLSIntermediate->getZ(i)); |
559 | 2.05k | } |
560 | 78 | poLSNew->addPoint(poLS->getX(1), poLS->getY(1), |
561 | 78 | poLS->getZ(1)); |
562 | 78 | } |
563 | 306 | else |
564 | 306 | { |
565 | 306 | poLSNew->addPoint(poLS->getX(0), poLS->getY(0)); |
566 | 306 | for (int i = 0; |
567 | 1.25k | i < poLSIntermediate->getNumPoints(); i++) |
568 | 950 | { |
569 | 950 | poLSNew->addPoint(poLSIntermediate->getX(i), |
570 | 950 | poLSIntermediate->getY(i)); |
571 | 950 | } |
572 | 306 | poLSNew->addPoint(poLS->getX(1), poLS->getY(1)); |
573 | 306 | } |
574 | 384 | poLSNew->assignSpatialReference(poSRS); |
575 | 384 | poFeat->SetGeometryDirectly(poLSNew); |
576 | 384 | CPL_IGNORE_RET_VAL(poLinkLyr->SetFeature(poFeat.get())); |
577 | 384 | } |
578 | 384 | } |
579 | 2.06k | } |
580 | 142 | poLinkLyr->ResetReading(); |
581 | 142 | } |
582 | 165 | } |
583 | | |
584 | 2.98k | m_poTmpDS->CommitTransaction(); |
585 | | |
586 | 2.98k | if (bIsMEMLayer) |
587 | 2.75k | m_poTmpDS->ExecuteSQL("PRAGMA read_only=1", nullptr, nullptr); |
588 | | |
589 | 2.98k | std::map<GIntBig, OGRLineString *>::iterator oMapLinkCoordinateIter = |
590 | 2.98k | oMapLinkCoordinate.begin(); |
591 | 3.79k | for (; oMapLinkCoordinateIter != oMapLinkCoordinate.end(); |
592 | 2.98k | ++oMapLinkCoordinateIter) |
593 | 811 | delete oMapLinkCoordinateIter->second; |
594 | 2.98k | } |
595 | | |
596 | | /************************************************************************/ |
597 | | /* GetLayerCount() */ |
598 | | /************************************************************************/ |
599 | | |
600 | | int OGRIDFDataSource::GetLayerCount() |
601 | 137k | { |
602 | 137k | if (!m_bHasParsed) |
603 | 2.98k | Parse(); |
604 | 137k | if (m_poTmpDS == nullptr) |
605 | 0 | return 0; |
606 | 137k | return m_poTmpDS->GetLayerCount(); |
607 | 137k | } |
608 | | |
609 | | /************************************************************************/ |
610 | | /* GetLayer() */ |
611 | | /************************************************************************/ |
612 | | |
613 | | OGRLayer *OGRIDFDataSource::GetLayer(int iLayer) |
614 | 71.1k | { |
615 | 71.1k | if (iLayer < 0 || iLayer >= GetLayerCount()) |
616 | 0 | return nullptr; |
617 | 71.1k | if (m_poTmpDS == nullptr) |
618 | 0 | return nullptr; |
619 | 71.1k | return m_poTmpDS->GetLayer(iLayer); |
620 | 71.1k | } |
621 | | |
622 | | /************************************************************************/ |
623 | | /* TestCapability() */ |
624 | | /************************************************************************/ |
625 | | |
626 | | int OGRIDFDataSource::TestCapability(const char *pszCap) |
627 | 0 | { |
628 | 0 | if (EQUAL(pszCap, ODsCMeasuredGeometries)) |
629 | 0 | return true; |
630 | 0 | else if (EQUAL(pszCap, ODsCCurveGeometries)) |
631 | 0 | return true; |
632 | 0 | else if (EQUAL(pszCap, ODsCZGeometries)) |
633 | 0 | return true; |
634 | | |
635 | 0 | return false; |
636 | 0 | } |
637 | | |
638 | | /************************************************************************/ |
639 | | /* OGRVDVDataSource() */ |
640 | | /************************************************************************/ |
641 | | |
642 | | OGRVDVDataSource::OGRVDVDataSource(const char *pszFilename, VSILFILE *fpL, |
643 | | bool bUpdate, bool bSingleFile, bool bNew) |
644 | 2.59k | : m_osFilename(pszFilename), m_fpL(fpL), m_bUpdate(bUpdate), |
645 | 2.59k | m_bSingleFile(bSingleFile), m_bNew(bNew), |
646 | 2.59k | m_bLayersDetected(bNew || fpL == nullptr), m_nLayerCount(0), |
647 | 2.59k | m_papoLayers(nullptr), m_poCurrentWriterLayer(nullptr), |
648 | 2.59k | m_bMustWriteEof(false), m_bVDV452Loaded(false) |
649 | 2.59k | { |
650 | 2.59k | } |
651 | | |
652 | | /************************************************************************/ |
653 | | /* ~OGRVDVDataSource() */ |
654 | | /************************************************************************/ |
655 | | |
656 | | OGRVDVDataSource::~OGRVDVDataSource() |
657 | 2.59k | { |
658 | 2.59k | if (m_poCurrentWriterLayer) |
659 | 4 | { |
660 | 4 | m_poCurrentWriterLayer->StopAsCurrentLayer(); |
661 | 4 | m_poCurrentWriterLayer = nullptr; |
662 | 4 | } |
663 | | |
664 | 134k | for (int i = 0; i < m_nLayerCount; i++) |
665 | 131k | delete m_papoLayers[i]; |
666 | 2.59k | CPLFree(m_papoLayers); |
667 | | |
668 | | // Close after destroying layers since they might use it (single file write) |
669 | 2.59k | if (m_fpL) |
670 | 2.52k | { |
671 | 2.52k | if (m_bMustWriteEof) |
672 | 4 | { |
673 | 4 | VSIFPrintfL(m_fpL, "eof; %d\n", m_nLayerCount); |
674 | 4 | } |
675 | 2.52k | VSIFCloseL(m_fpL); |
676 | 2.52k | } |
677 | 2.59k | } |
678 | | |
679 | | /************************************************************************/ |
680 | | /* GetLayerCount() */ |
681 | | /************************************************************************/ |
682 | | |
683 | | int OGRVDVDataSource::GetLayerCount() |
684 | 146k | { |
685 | 146k | if (!m_bLayersDetected) |
686 | 2.35k | DetectLayers(); |
687 | 146k | return m_nLayerCount; |
688 | 146k | } |
689 | | |
690 | | /************************************************************************/ |
691 | | /* GetLayer() */ |
692 | | /************************************************************************/ |
693 | | |
694 | | OGRLayer *OGRVDVDataSource::GetLayer(int iLayer) |
695 | 76.4k | { |
696 | 76.4k | if (iLayer < 0 || iLayer >= GetLayerCount()) |
697 | 0 | return nullptr; |
698 | 76.4k | return m_papoLayers[iLayer]; |
699 | 76.4k | } |
700 | | |
701 | | /************************************************************************/ |
702 | | /* DetectLayers() */ |
703 | | /************************************************************************/ |
704 | | |
705 | | void OGRVDVDataSource::DetectLayers() |
706 | 2.35k | { |
707 | 2.35k | m_bLayersDetected = true; |
708 | | |
709 | 2.35k | char szBuffer[1 + 1024 + 1]; |
710 | 2.35k | char chNextExpected = 't'; |
711 | 2.35k | char chNextExpected2 = 'r'; |
712 | 2.35k | char chNextExpected3 = 'e'; |
713 | 2.35k | bool bInTableName = false; |
714 | 2.35k | CPLString osTableName; |
715 | 2.35k | GIntBig nFeatureCount = 0; |
716 | 2.35k | vsi_l_offset nStartOffset = 0; |
717 | 2.35k | OGRVDVLayer *poLayer = nullptr; |
718 | 2.35k | bool bFirstBuffer = true; |
719 | 2.35k | bool bRecodeFromLatin1 = false; |
720 | | |
721 | 2.35k | VSIFSeekL(m_fpL, 0, SEEK_SET); |
722 | | |
723 | 51.4k | while (true) |
724 | 51.4k | { |
725 | 51.4k | size_t nRead = VSIFReadL(szBuffer, 1, 1024, m_fpL); |
726 | 51.4k | szBuffer[nRead] = '\0'; |
727 | 51.4k | if (bFirstBuffer) |
728 | 2.35k | { |
729 | 2.35k | const char *pszChs = strstr(szBuffer, "\nchs;"); |
730 | 2.35k | if (pszChs) |
731 | 491 | { |
732 | 491 | pszChs += 5; |
733 | 491 | CPLString osChs; |
734 | 16.7k | for (; *pszChs != '\0' && *pszChs != '\r' && *pszChs != '\n'; |
735 | 16.2k | ++pszChs) |
736 | 16.2k | { |
737 | 16.2k | if (*pszChs != ' ' && *pszChs != '"') |
738 | 13.9k | osChs += *pszChs; |
739 | 16.2k | } |
740 | 491 | bRecodeFromLatin1 = |
741 | 491 | EQUAL(osChs, "ISO8859-1") || EQUAL(osChs, "ISO_LATIN_1"); |
742 | 491 | } |
743 | 2.35k | bFirstBuffer = false; |
744 | 2.35k | } |
745 | 51.4M | for (size_t i = 0; i < nRead; i++) |
746 | 51.4M | { |
747 | 51.4M | if (bInTableName) |
748 | 1.63M | { |
749 | 1.63M | if (szBuffer[i] == '\r' || szBuffer[i] == '\n') |
750 | 131k | { |
751 | 131k | bInTableName = false; |
752 | 131k | poLayer = new OGRVDVLayer(this, osTableName, m_fpL, false, |
753 | 131k | bRecodeFromLatin1, nStartOffset); |
754 | 131k | m_papoLayers = static_cast<OGRLayer **>( |
755 | 131k | CPLRealloc(m_papoLayers, |
756 | 131k | sizeof(OGRLayer *) * (m_nLayerCount + 1))); |
757 | 131k | m_papoLayers[m_nLayerCount] = poLayer; |
758 | 131k | m_nLayerCount++; |
759 | 131k | } |
760 | 1.50M | else if (szBuffer[i] != ' ') |
761 | 1.45M | { |
762 | 1.45M | osTableName += szBuffer[i]; |
763 | 1.45M | continue; |
764 | 1.45M | } |
765 | 1.63M | } |
766 | | |
767 | | // Reset state on end of line characters |
768 | 49.9M | if (szBuffer[i] == '\n' || szBuffer[i] == '\r') |
769 | 2.44M | { |
770 | 2.44M | chNextExpected = szBuffer[i]; |
771 | 2.44M | chNextExpected2 = szBuffer[i]; |
772 | 2.44M | chNextExpected3 = szBuffer[i]; |
773 | 2.44M | } |
774 | | |
775 | | // Detect tbl; |
776 | 49.9M | if (szBuffer[i] == chNextExpected) |
777 | 6.50M | { |
778 | 6.50M | if (chNextExpected == '\n' || chNextExpected == '\r') |
779 | 2.44M | chNextExpected = 't'; |
780 | 4.06M | else if (chNextExpected == 't') |
781 | 202k | chNextExpected = 'b'; |
782 | 3.85M | else if (chNextExpected == 'b') |
783 | 167k | chNextExpected = 'l'; |
784 | 3.69M | else if (chNextExpected == 'l') |
785 | 145k | chNextExpected = ';'; |
786 | 3.54M | else if (chNextExpected == ';') |
787 | 131k | { |
788 | 131k | if (poLayer != nullptr) |
789 | 122k | poLayer->SetFeatureCount(nFeatureCount); |
790 | 131k | poLayer = nullptr; |
791 | 131k | nFeatureCount = 0; |
792 | 131k | nStartOffset = VSIFTellL(m_fpL) + i + 1 - nRead - 4; |
793 | 131k | bInTableName = true; |
794 | 131k | osTableName.resize(0); |
795 | 131k | chNextExpected = 0; |
796 | 131k | } |
797 | 6.50M | } |
798 | 43.4M | else |
799 | 43.4M | chNextExpected = 0; |
800 | | |
801 | | // Detect rec; |
802 | 49.9M | if (szBuffer[i] == chNextExpected2) |
803 | 6.41M | { |
804 | 6.41M | if (chNextExpected2 == '\n' || chNextExpected2 == '\r') |
805 | 2.44M | chNextExpected2 = 'r'; |
806 | 3.97M | else if (chNextExpected2 == 'r') |
807 | 176k | chNextExpected2 = 'e'; |
808 | 3.79M | else if (chNextExpected2 == 'e') |
809 | 155k | chNextExpected2 = 'c'; |
810 | 3.64M | else if (chNextExpected2 == 'c') |
811 | 115k | chNextExpected2 = ';'; |
812 | 3.52M | else if (chNextExpected2 == ';') |
813 | 105k | { |
814 | 105k | nFeatureCount++; |
815 | 105k | chNextExpected2 = 0; |
816 | 105k | } |
817 | 6.41M | } |
818 | 43.5M | else |
819 | 43.5M | chNextExpected2 = 0; |
820 | | |
821 | | // Detect end; |
822 | 49.9M | if (szBuffer[i] == chNextExpected3) |
823 | 5.92M | { |
824 | 5.92M | if (chNextExpected3 == '\n' || chNextExpected3 == '\r') |
825 | 2.44M | chNextExpected3 = 'e'; |
826 | 3.47M | else if (chNextExpected3 == 'e') |
827 | 24.0k | chNextExpected3 = 'n'; |
828 | 3.45M | else if (chNextExpected3 == 'n') |
829 | 12.2k | chNextExpected3 = 'd'; |
830 | 3.43M | else if (chNextExpected3 == 'd') |
831 | 11.0k | chNextExpected3 = ';'; |
832 | 3.42M | else if (chNextExpected3 == ';') |
833 | 9.31k | { |
834 | 9.31k | if (poLayer != nullptr) |
835 | 6.29k | poLayer->SetFeatureCount(nFeatureCount); |
836 | 9.31k | poLayer = nullptr; |
837 | 9.31k | chNextExpected3 = 0; |
838 | 9.31k | } |
839 | 5.92M | } |
840 | 44.0M | else |
841 | 44.0M | chNextExpected3 = 0; |
842 | 49.9M | } |
843 | 51.4k | if (nRead < 1024) |
844 | 2.35k | break; |
845 | 51.4k | } |
846 | 2.35k | if (poLayer != nullptr) |
847 | 2.17k | poLayer->SetFeatureCount(nFeatureCount); |
848 | 2.35k | } |
849 | | |
850 | | /************************************************************************/ |
851 | | /* OGRVDVLayer() */ |
852 | | /************************************************************************/ |
853 | | |
854 | | OGRVDVLayer::OGRVDVLayer(GDALDataset *poDS, const CPLString &osTableName, |
855 | | VSILFILE *fpL, bool bOwnFP, bool bRecodeFromLatin1, |
856 | | vsi_l_offset nStartOffset) |
857 | 131k | : m_poDS(poDS), m_fpL(fpL), m_bOwnFP(bOwnFP), |
858 | 131k | m_bRecodeFromLatin1(bRecodeFromLatin1), m_nStartOffset(nStartOffset), |
859 | 131k | m_nCurOffset(0), m_nTotalFeatureCount(0), m_nFID(0), m_bEOF(false), |
860 | 131k | m_iLongitudeVDV452(-1), m_iLatitudeVDV452(-1) |
861 | 131k | { |
862 | 131k | m_poFeatureDefn = new OGRFeatureDefn(osTableName); |
863 | 131k | m_poFeatureDefn->SetGeomType(wkbNone); |
864 | 131k | m_poFeatureDefn->Reference(); |
865 | 131k | SetDescription(osTableName); |
866 | 131k | vsi_l_offset nCurOffset = VSIFTellL(fpL); |
867 | 131k | VSIFSeekL(m_fpL, m_nStartOffset, SEEK_SET); |
868 | 131k | CPLString osAtr, osFrm; |
869 | | |
870 | | /* skip until first tbl; */ |
871 | 131k | bool bFoundTbl = false; |
872 | 1.06M | for (int i = 0; i < 20; i++) |
873 | 1.05M | { |
874 | 1.05M | const char *pszLine = CPLReadLineL(m_fpL); |
875 | 1.05M | if (pszLine == nullptr) |
876 | 1.15k | break; |
877 | 1.05M | if (STARTS_WITH(pszLine, "chs;")) |
878 | 32.1k | { |
879 | 32.1k | CPLString osChs(pszLine + 4); |
880 | 32.1k | osChs.Trim(); |
881 | 32.1k | if (osChs.size() >= 2 && osChs[0] == '"' && osChs.back() == '"') |
882 | 4.73k | osChs = osChs.substr(1, osChs.size() - 2); |
883 | 32.1k | m_bRecodeFromLatin1 = |
884 | 32.1k | EQUAL(osChs, "ISO8859-1") || EQUAL(osChs, "ISO_LATIN_1"); |
885 | 32.1k | } |
886 | 1.02M | else if (STARTS_WITH(pszLine, "tbl;")) |
887 | 208k | { |
888 | 208k | if (bFoundTbl) |
889 | 77.4k | break; /* shouldn't happen in correctly formed files */ |
890 | 131k | bFoundTbl = true; |
891 | 131k | m_nStartOffset = VSIFTellL(fpL); |
892 | 131k | } |
893 | 813k | else if (STARTS_WITH(pszLine, "atr;")) |
894 | 122k | { |
895 | 122k | osAtr = pszLine + 4; |
896 | 122k | osAtr.Trim(); |
897 | 122k | } |
898 | 690k | else if (STARTS_WITH(pszLine, "frm;")) |
899 | 99.7k | { |
900 | 99.7k | osFrm = pszLine + 4; |
901 | 99.7k | osFrm.Trim(); |
902 | 99.7k | } |
903 | 590k | else if (STARTS_WITH(pszLine, "rec;") || STARTS_WITH(pszLine, "end;")) |
904 | 42.4k | break; |
905 | 1.05M | } |
906 | 131k | if (!bFoundTbl) |
907 | 610 | CPLDebug("VDV", "Didn't find tbl; line"); |
908 | | |
909 | 131k | VSIFSeekL(m_fpL, nCurOffset, SEEK_SET); |
910 | 131k | if (!osAtr.empty() && !osFrm.empty()) |
911 | 50.3k | { |
912 | 50.3k | char **papszAtr = CSLTokenizeString2( |
913 | 50.3k | osAtr, ";", |
914 | 50.3k | CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); |
915 | 50.3k | char **papszFrm = CSLTokenizeString2( |
916 | 50.3k | osFrm, ";", |
917 | 50.3k | CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); |
918 | 50.3k | if (CSLCount(papszAtr) == CSLCount(papszFrm)) |
919 | 38.3k | { |
920 | 38.3k | OGRVDVParseAtrFrm(nullptr, m_poFeatureDefn, papszAtr, papszFrm); |
921 | 38.3k | } |
922 | 50.3k | CSLDestroy(papszAtr); |
923 | 50.3k | CSLDestroy(papszFrm); |
924 | 50.3k | } |
925 | | |
926 | | // Identify longitude, latitude columns of VDV-452 STOP table |
927 | 131k | if (EQUAL(osTableName, "STOP")) /* English */ |
928 | 2.24k | { |
929 | 2.24k | m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldIndex("POINT_LONGITUDE"); |
930 | 2.24k | m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldIndex("POINT_LATITUDE"); |
931 | 2.24k | } |
932 | 129k | else if (EQUAL(osTableName, "REC_ORT")) /* German */ |
933 | 78 | { |
934 | 78 | m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldIndex("ORT_POS_LAENGE"); |
935 | 78 | m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldIndex("ORT_POS_BREITE"); |
936 | 78 | } |
937 | 131k | if (m_iLongitudeVDV452 >= 0 && m_iLatitudeVDV452 >= 0) |
938 | 0 | { |
939 | 0 | m_poFeatureDefn->SetGeomType(wkbPoint); |
940 | 0 | OGRSpatialReference *poSRS = |
941 | 0 | new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG); |
942 | 0 | poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
943 | 0 | m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); |
944 | 0 | poSRS->Release(); |
945 | 0 | } |
946 | 131k | else |
947 | 131k | m_iLongitudeVDV452 = m_iLatitudeVDV452 = -1; |
948 | 131k | } |
949 | | |
950 | | /************************************************************************/ |
951 | | /* ~OGRVDVLayer() */ |
952 | | /************************************************************************/ |
953 | | |
954 | | OGRVDVLayer::~OGRVDVLayer() |
955 | 131k | { |
956 | 131k | m_poFeatureDefn->Release(); |
957 | 131k | if (m_bOwnFP) |
958 | 730 | VSIFCloseL(m_fpL); |
959 | 131k | } |
960 | | |
961 | | /************************************************************************/ |
962 | | /* ResetReading() */ |
963 | | /************************************************************************/ |
964 | | |
965 | | void OGRVDVLayer::ResetReading() |
966 | 9.51k | { |
967 | 9.51k | VSIFSeekL(m_fpL, m_nStartOffset, SEEK_SET); |
968 | 9.51k | m_nCurOffset = m_nStartOffset; |
969 | 9.51k | m_nFID = 1; |
970 | 9.51k | m_bEOF = false; |
971 | 9.51k | } |
972 | | |
973 | | /************************************************************************/ |
974 | | /* OGRVDVUnescapeString() */ |
975 | | /************************************************************************/ |
976 | | |
977 | | static CPLString OGRVDVUnescapeString(const char *pszValue) |
978 | 4.90k | { |
979 | 4.90k | CPLString osRet; |
980 | 47.6k | for (; *pszValue != '\0'; ++pszValue) |
981 | 42.7k | { |
982 | 42.7k | if (*pszValue == '"' && pszValue[1] == '"') |
983 | 986 | { |
984 | 986 | osRet += '"'; |
985 | 986 | ++pszValue; |
986 | 986 | } |
987 | 41.7k | else |
988 | 41.7k | { |
989 | 41.7k | osRet += *pszValue; |
990 | 41.7k | } |
991 | 42.7k | } |
992 | 4.90k | return osRet; |
993 | 4.90k | } |
994 | | |
995 | | /************************************************************************/ |
996 | | /* GetNextFeature() */ |
997 | | /************************************************************************/ |
998 | | |
999 | | OGRFeature *OGRVDVLayer::GetNextFeature() |
1000 | 48.8k | { |
1001 | 48.8k | if (m_nFID == 0) |
1002 | 9.49k | ResetReading(); |
1003 | 48.8k | VSIFSeekL(m_fpL, m_nCurOffset, SEEK_SET); |
1004 | 48.8k | OGRFeature *poFeature = nullptr; |
1005 | 351k | while (!m_bEOF) |
1006 | 351k | { |
1007 | 351k | const char *pszLine = CPLReadLineL(m_fpL); |
1008 | 351k | if (pszLine == nullptr) |
1009 | 1.45k | break; |
1010 | 349k | if (strncmp(pszLine, "end;", 4) == 0 || |
1011 | 349k | strncmp(pszLine, "tbl;", 4) == 0) |
1012 | 8.05k | { |
1013 | 8.05k | m_bEOF = true; |
1014 | 8.05k | break; |
1015 | 8.05k | } |
1016 | 341k | if (strncmp(pszLine, "rec;", 4) != 0) |
1017 | 302k | continue; |
1018 | | |
1019 | 39.3k | char **papszTokens = CSLTokenizeString2( |
1020 | 39.3k | pszLine + 4, ";", |
1021 | 39.3k | CSLT_ALLOWEMPTYTOKENS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES); |
1022 | 39.3k | poFeature = new OGRFeature(m_poFeatureDefn); |
1023 | 39.3k | poFeature->SetFID(m_nFID++); |
1024 | 39.3k | for (int i = 0; |
1025 | 109k | i < m_poFeatureDefn->GetFieldCount() && papszTokens[i] != nullptr; |
1026 | 69.9k | i++) |
1027 | 69.9k | { |
1028 | 69.9k | if (papszTokens[i][0] && !EQUAL(papszTokens[i], "NULL")) |
1029 | 56.7k | { |
1030 | 56.7k | size_t nLen = strlen(papszTokens[i]); |
1031 | 56.7k | CPLString osToken; |
1032 | 56.7k | if (nLen >= 2 && papszTokens[i][0] == '"' && |
1033 | 56.7k | papszTokens[i][nLen - 1] == '"') |
1034 | 4.90k | { |
1035 | 4.90k | papszTokens[i][nLen - 1] = 0; |
1036 | 4.90k | osToken = OGRVDVUnescapeString(papszTokens[i] + 1); |
1037 | 4.90k | } |
1038 | 51.8k | else |
1039 | 51.8k | osToken = papszTokens[i]; |
1040 | | // Strip trailing spaces |
1041 | 60.5k | while (!osToken.empty() && osToken.back() == ' ') |
1042 | 3.75k | osToken.pop_back(); |
1043 | 56.7k | OGRFieldType eFieldType = |
1044 | 56.7k | m_poFeatureDefn->GetFieldDefn(i)->GetType(); |
1045 | 56.7k | if (m_bRecodeFromLatin1 && eFieldType == OFTString) |
1046 | 4.44k | { |
1047 | 4.44k | char *pszRecoded = |
1048 | 4.44k | CPLRecode(osToken, CPL_ENC_ISO8859_1, CPL_ENC_UTF8); |
1049 | 4.44k | poFeature->SetField(i, pszRecoded); |
1050 | 4.44k | CPLFree(pszRecoded); |
1051 | 4.44k | } |
1052 | 52.3k | else if (eFieldType == OFTString || !EQUAL(osToken, "NULL")) |
1053 | 52.3k | { |
1054 | 52.3k | poFeature->SetField(i, osToken); |
1055 | 52.3k | } |
1056 | 56.7k | } |
1057 | 69.9k | } |
1058 | 39.3k | CSLDestroy(papszTokens); |
1059 | | |
1060 | 39.3k | if (m_iLongitudeVDV452 >= 0 && m_iLatitudeVDV452 >= 0) |
1061 | 0 | { |
1062 | 0 | int nLongDegMinMS = |
1063 | 0 | poFeature->GetFieldAsInteger(m_iLongitudeVDV452); |
1064 | 0 | int nLongSign = 1; |
1065 | 0 | if (nLongDegMinMS < 0) |
1066 | 0 | { |
1067 | 0 | nLongSign = -1; |
1068 | 0 | nLongDegMinMS = -nLongDegMinMS; |
1069 | 0 | } |
1070 | 0 | const int nLongDeg = nLongDegMinMS / (100 * 100000); |
1071 | 0 | const int nLongMin = (nLongDegMinMS / 100000) % 100; |
1072 | 0 | const int nLongMS = nLongDegMinMS % 100000; |
1073 | 0 | const double dfLong = |
1074 | 0 | (nLongDeg + nLongMin / 60.0 + nLongMS / (3600.0 * 1000.0)) * |
1075 | 0 | nLongSign; |
1076 | |
|
1077 | 0 | int nLatDegMinMS = poFeature->GetFieldAsInteger(m_iLatitudeVDV452); |
1078 | 0 | int nLatSign = 1; |
1079 | 0 | if (nLatDegMinMS < 0) |
1080 | 0 | { |
1081 | 0 | nLatSign = -1; |
1082 | 0 | nLatDegMinMS = -nLatDegMinMS; |
1083 | 0 | } |
1084 | 0 | const int nLatDeg = nLatDegMinMS / (100 * 100000); |
1085 | 0 | const int nLatMin = (nLatDegMinMS / 100000) % 100; |
1086 | 0 | const int nLatMS = nLatDegMinMS % 100000; |
1087 | 0 | const double dfLat = |
1088 | 0 | (nLatDeg + nLatMin / 60.0 + nLatMS / (3600.0 * 1000.0)) * |
1089 | 0 | nLatSign; |
1090 | |
|
1091 | 0 | if (dfLong != 0.0 || dfLat != 0.0) |
1092 | 0 | { |
1093 | 0 | OGRPoint *poPoint = new OGRPoint(dfLong, dfLat); |
1094 | 0 | poPoint->assignSpatialReference( |
1095 | 0 | m_poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef()); |
1096 | 0 | poFeature->SetGeometryDirectly(poPoint); |
1097 | 0 | } |
1098 | 0 | } |
1099 | | |
1100 | 39.3k | if ((m_poFilterGeom == nullptr || |
1101 | 39.3k | FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) && |
1102 | 39.3k | (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) |
1103 | 39.3k | { |
1104 | 39.3k | break; |
1105 | 39.3k | } |
1106 | 0 | delete poFeature; |
1107 | 0 | poFeature = nullptr; |
1108 | 0 | } |
1109 | 48.8k | m_nCurOffset = VSIFTellL(m_fpL); |
1110 | 48.8k | return poFeature; |
1111 | 48.8k | } |
1112 | | |
1113 | | /************************************************************************/ |
1114 | | /* TestCapability() */ |
1115 | | /************************************************************************/ |
1116 | | |
1117 | | int OGRVDVLayer::TestCapability(const char *pszCap) |
1118 | 18 | { |
1119 | 18 | if (EQUAL(pszCap, OLCFastFeatureCount) && m_nTotalFeatureCount > 0 && |
1120 | 18 | m_poFilterGeom == nullptr && m_poAttrQuery == nullptr) |
1121 | 0 | { |
1122 | 0 | return TRUE; |
1123 | 0 | } |
1124 | 18 | else if (EQUAL(pszCap, OLCStringsAsUTF8)) |
1125 | 0 | { |
1126 | 0 | return m_bRecodeFromLatin1; |
1127 | 0 | } |
1128 | 18 | else if (EQUAL(pszCap, OLCZGeometries)) |
1129 | 0 | { |
1130 | 0 | return TRUE; |
1131 | 0 | } |
1132 | 18 | return FALSE; |
1133 | 18 | } |
1134 | | |
1135 | | /************************************************************************/ |
1136 | | /* GetFeatureCount() */ |
1137 | | /************************************************************************/ |
1138 | | |
1139 | | GIntBig OGRVDVLayer::GetFeatureCount(int bForce) |
1140 | 0 | { |
1141 | 0 | if (m_nTotalFeatureCount == 0 || m_poFilterGeom != nullptr || |
1142 | 0 | m_poAttrQuery != nullptr) |
1143 | 0 | { |
1144 | 0 | return OGRLayer::GetFeatureCount(bForce); |
1145 | 0 | } |
1146 | 0 | return m_nTotalFeatureCount; |
1147 | 0 | } |
1148 | | |
1149 | | /************************************************************************/ |
1150 | | /* Identify() */ |
1151 | | /************************************************************************/ |
1152 | | |
1153 | | static int OGRVDVDriverIdentify(GDALOpenInfo *poOpenInfo) |
1154 | | |
1155 | 107k | { |
1156 | 107k | if (poOpenInfo->bIsDirectory) |
1157 | 4.70k | return -1; /* perhaps... */ |
1158 | 102k | return ( |
1159 | 102k | poOpenInfo->nHeaderBytes > 0 && |
1160 | 102k | (strstr((const char *)poOpenInfo->pabyHeader, "\ntbl;") != nullptr || |
1161 | 55.5k | strncmp((const char *)poOpenInfo->pabyHeader, "tbl;", 4) == 0) && |
1162 | 102k | strstr((const char *)poOpenInfo->pabyHeader, "\natr;") != nullptr && |
1163 | 102k | strstr((const char *)poOpenInfo->pabyHeader, "\nfrm;") != nullptr); |
1164 | 107k | } |
1165 | | |
1166 | | /************************************************************************/ |
1167 | | /* Open() */ |
1168 | | /************************************************************************/ |
1169 | | |
1170 | | GDALDataset *OGRVDVDataSource::Open(GDALOpenInfo *poOpenInfo) |
1171 | | |
1172 | 7.93k | { |
1173 | 7.93k | if (!OGRVDVDriverIdentify(poOpenInfo)) |
1174 | 0 | { |
1175 | 0 | return nullptr; |
1176 | 0 | } |
1177 | 7.93k | if (poOpenInfo->bIsDirectory) |
1178 | 2.34k | { |
1179 | 2.34k | char **papszFiles = VSIReadDir(poOpenInfo->pszFilename); |
1180 | | |
1181 | | // Identify the extension with the most occurrences |
1182 | 2.34k | std::map<CPLString, int> oMapOtherExtensions; |
1183 | 2.34k | CPLString osMajorityExtension, osMajorityFile; |
1184 | 2.34k | int nFiles = 0; |
1185 | 29.7k | for (char **papszIter = papszFiles; papszIter && *papszIter; |
1186 | 27.4k | ++papszIter) |
1187 | 27.4k | { |
1188 | 27.4k | if (EQUAL(*papszIter, ".") || EQUAL(*papszIter, "..")) |
1189 | 309 | continue; |
1190 | 27.1k | nFiles++; |
1191 | 27.1k | const std::string osExtension(CPLGetExtensionSafe(*papszIter)); |
1192 | 27.1k | int nCount = ++oMapOtherExtensions[osExtension]; |
1193 | 27.1k | if (osMajorityExtension == "" || |
1194 | 27.1k | nCount > oMapOtherExtensions[osMajorityExtension]) |
1195 | 12.5k | { |
1196 | 12.5k | osMajorityExtension = osExtension; |
1197 | 12.5k | osMajorityFile = *papszIter; |
1198 | 12.5k | } |
1199 | 27.1k | } |
1200 | | |
1201 | | // Check it is at least 50% of the files in the directory |
1202 | 2.34k | if (osMajorityExtension == "" || |
1203 | 2.34k | 2 * oMapOtherExtensions[osMajorityExtension] < nFiles) |
1204 | 1.56k | { |
1205 | 1.56k | CSLDestroy(papszFiles); |
1206 | 1.56k | return nullptr; |
1207 | 1.56k | } |
1208 | | |
1209 | | // And check that one of those files is a VDV one if it isn't .x10 |
1210 | 779 | if (osMajorityExtension != "x10") |
1211 | 779 | { |
1212 | 779 | GDALOpenInfo oOpenInfo(CPLFormFilenameSafe(poOpenInfo->pszFilename, |
1213 | 779 | osMajorityFile, nullptr) |
1214 | 779 | .c_str(), |
1215 | 779 | GA_ReadOnly); |
1216 | 779 | if (OGRVDVDriverIdentify(&oOpenInfo) != TRUE) |
1217 | 712 | { |
1218 | 712 | CSLDestroy(papszFiles); |
1219 | 712 | return nullptr; |
1220 | 712 | } |
1221 | 779 | } |
1222 | | |
1223 | 67 | OGRVDVDataSource *poDS = new OGRVDVDataSource( |
1224 | 67 | poOpenInfo->pszFilename, nullptr, /* fp */ |
1225 | 67 | poOpenInfo->eAccess == GA_Update, false, /* single file */ |
1226 | 67 | false /* new */); |
1227 | | |
1228 | | // Instantiate the layers. |
1229 | 1.26k | for (char **papszIter = papszFiles; papszIter && *papszIter; |
1230 | 1.19k | ++papszIter) |
1231 | 1.19k | { |
1232 | 1.19k | if (!EQUAL(CPLGetExtensionSafe(*papszIter).c_str(), |
1233 | 1.19k | osMajorityExtension)) |
1234 | 435 | continue; |
1235 | 759 | VSILFILE *fp = |
1236 | 759 | VSIFOpenL(CPLFormFilenameSafe(poOpenInfo->pszFilename, |
1237 | 759 | *papszIter, nullptr) |
1238 | 759 | .c_str(), |
1239 | 759 | "rb"); |
1240 | 759 | if (fp == nullptr) |
1241 | 29 | continue; |
1242 | 730 | poDS->m_papoLayers = static_cast<OGRLayer **>( |
1243 | 730 | CPLRealloc(poDS->m_papoLayers, |
1244 | 730 | sizeof(OGRLayer *) * (poDS->m_nLayerCount + 1))); |
1245 | 730 | poDS->m_papoLayers[poDS->m_nLayerCount] = |
1246 | 730 | new OGRVDVLayer(poDS, CPLGetBasenameSafe(*papszIter).c_str(), |
1247 | 730 | fp, true, false, 0); |
1248 | 730 | poDS->m_nLayerCount++; |
1249 | 730 | } |
1250 | 67 | CSLDestroy(papszFiles); |
1251 | | |
1252 | 67 | if (poDS->m_nLayerCount == 0) |
1253 | 0 | { |
1254 | 0 | delete poDS; |
1255 | 0 | poDS = nullptr; |
1256 | 0 | } |
1257 | 67 | return poDS; |
1258 | 779 | } |
1259 | | |
1260 | 5.59k | VSILFILE *fpL = poOpenInfo->fpL; |
1261 | 5.59k | poOpenInfo->fpL = nullptr; |
1262 | 5.59k | const char *pszHeader = (const char *)poOpenInfo->pabyHeader; |
1263 | 5.59k | if (strstr(pszHeader, "tbl;Node\r\natr;NODE_ID;") != nullptr || |
1264 | 5.59k | strstr(pszHeader, "tbl;Node\natr;NODE_ID;") != nullptr || |
1265 | 5.59k | strstr(pszHeader, "tbl;Link\r\natr;LINK_ID;") != nullptr || |
1266 | 5.59k | strstr(pszHeader, "tbl;Link\natr;LINK_ID;") != nullptr || |
1267 | 5.59k | strstr(pszHeader, "tbl;LinkCoordinate\r\natr;LINK_ID;") != nullptr || |
1268 | 5.59k | strstr(pszHeader, "tbl;LinkCoordinate\natr;LINK_ID;") != nullptr) |
1269 | 3.06k | { |
1270 | 3.06k | return new OGRIDFDataSource(poOpenInfo->pszFilename, fpL); |
1271 | 3.06k | } |
1272 | 2.52k | else |
1273 | 2.52k | { |
1274 | 2.52k | return new OGRVDVDataSource(poOpenInfo->pszFilename, fpL, |
1275 | 2.52k | poOpenInfo->eAccess == GA_Update, |
1276 | 2.52k | true, /* single file */ |
1277 | 2.52k | false /* new */); |
1278 | 2.52k | } |
1279 | 5.59k | } |
1280 | | |
1281 | | /************************************************************************/ |
1282 | | /* OGRVDVWriterLayer */ |
1283 | | /************************************************************************/ |
1284 | | |
1285 | | OGRVDVWriterLayer::OGRVDVWriterLayer(OGRVDVDataSource *poDS, |
1286 | | const char *pszName, VSILFILE *fpL, |
1287 | | bool bOwnFP, OGRVDV452Table *poVDV452Table, |
1288 | | const CPLString &osVDV452Lang, |
1289 | | bool bProfileStrict) |
1290 | 38 | : m_poDS(poDS), m_poFeatureDefn(new OGRFeatureDefn(pszName)), |
1291 | 38 | m_bWritePossible(true), m_fpL(fpL), m_bOwnFP(bOwnFP), m_nFeatureCount(-1), |
1292 | 38 | m_poVDV452Table(poVDV452Table), m_osVDV452Lang(osVDV452Lang), |
1293 | 38 | m_bProfileStrict(bProfileStrict), m_iLongitudeVDV452(-1), |
1294 | 38 | m_iLatitudeVDV452(-1) |
1295 | 38 | { |
1296 | 38 | m_poFeatureDefn->SetGeomType(wkbNone); |
1297 | 38 | m_poFeatureDefn->Reference(); |
1298 | 38 | SetDescription(pszName); |
1299 | 38 | } |
1300 | | |
1301 | | /************************************************************************/ |
1302 | | /* ~OGRVDVWriterLayer */ |
1303 | | /************************************************************************/ |
1304 | | |
1305 | | OGRVDVWriterLayer::~OGRVDVWriterLayer() |
1306 | 38 | { |
1307 | 38 | StopAsCurrentLayer(); |
1308 | | |
1309 | 38 | m_poFeatureDefn->Release(); |
1310 | 38 | if (m_bOwnFP) |
1311 | 0 | { |
1312 | 0 | VSIFPrintfL(m_fpL, "eof; %d\n", 1); |
1313 | 0 | VSIFCloseL(m_fpL); |
1314 | 0 | } |
1315 | 38 | } |
1316 | | |
1317 | | /************************************************************************/ |
1318 | | /* ResetReading() */ |
1319 | | /************************************************************************/ |
1320 | | |
1321 | | void OGRVDVWriterLayer::ResetReading() |
1322 | 0 | { |
1323 | 0 | } |
1324 | | |
1325 | | /************************************************************************/ |
1326 | | /* GetNextFeature() */ |
1327 | | /************************************************************************/ |
1328 | | |
1329 | | OGRFeature *OGRVDVWriterLayer::GetNextFeature() |
1330 | 0 | { |
1331 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1332 | 0 | "GetNextFeature() not supported on write-only layer"); |
1333 | 0 | return nullptr; |
1334 | 0 | } |
1335 | | |
1336 | | /************************************************************************/ |
1337 | | /* OGRVDVEscapeString() */ |
1338 | | /************************************************************************/ |
1339 | | |
1340 | | static CPLString OGRVDVEscapeString(const char *pszValue) |
1341 | 36.9k | { |
1342 | 36.9k | CPLString osRet; |
1343 | 810k | for (; *pszValue != '\0'; ++pszValue) |
1344 | 773k | { |
1345 | 773k | if (*pszValue == '"') |
1346 | 5.44k | osRet += "\"\""; |
1347 | 768k | else |
1348 | 768k | osRet += *pszValue; |
1349 | 773k | } |
1350 | 36.9k | return osRet; |
1351 | 36.9k | } |
1352 | | |
1353 | | /************************************************************************/ |
1354 | | /* WriteSchemaIfNeeded() */ |
1355 | | /************************************************************************/ |
1356 | | |
1357 | | bool OGRVDVWriterLayer::WriteSchemaIfNeeded() |
1358 | 48.5k | { |
1359 | 48.5k | if (m_nFeatureCount < 0) |
1360 | 38 | { |
1361 | 38 | m_nFeatureCount = 0; |
1362 | | |
1363 | 38 | bool bOK = |
1364 | 38 | VSIFPrintfL(m_fpL, "tbl; %s\n", m_poFeatureDefn->GetName()) > 0; |
1365 | 38 | bOK &= VSIFPrintfL(m_fpL, "atr;") > 0; |
1366 | 149 | for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++) |
1367 | 111 | { |
1368 | 111 | if (i > 0) |
1369 | 73 | bOK &= VSIFPrintfL(m_fpL, ";") > 0; |
1370 | 111 | bOK &= |
1371 | 111 | VSIFPrintfL(m_fpL, " %s", |
1372 | 111 | m_poFeatureDefn->GetFieldDefn(i)->GetNameRef()) > 0; |
1373 | 111 | } |
1374 | 38 | bOK &= VSIFPrintfL(m_fpL, "\n") > 0; |
1375 | 38 | bOK &= VSIFPrintfL(m_fpL, "frm;") > 0; |
1376 | 149 | for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++) |
1377 | 111 | { |
1378 | 111 | if (i > 0) |
1379 | 73 | bOK &= VSIFPrintfL(m_fpL, ";") > 0; |
1380 | 111 | bOK &= VSIFPrintfL(m_fpL, " ") > 0; |
1381 | 111 | int nWidth = m_poFeatureDefn->GetFieldDefn(i)->GetWidth(); |
1382 | 111 | const OGRFieldType eType = |
1383 | 111 | m_poFeatureDefn->GetFieldDefn(i)->GetType(); |
1384 | 111 | switch (eType) |
1385 | 111 | { |
1386 | 3 | case OFTInteger: |
1387 | 5 | case OFTInteger64: |
1388 | 5 | if (m_poFeatureDefn->GetFieldDefn(i)->GetSubType() == |
1389 | 5 | OFSTBoolean) |
1390 | 0 | { |
1391 | 0 | bOK &= VSIFPrintfL(m_fpL, "boolean") > 0; |
1392 | 0 | } |
1393 | 5 | else |
1394 | 5 | { |
1395 | 5 | if (nWidth == 0) |
1396 | 5 | { |
1397 | 5 | if (eType == OFTInteger) |
1398 | 3 | nWidth = 11; |
1399 | 2 | else |
1400 | 2 | nWidth = 20; |
1401 | 5 | } |
1402 | 5 | nWidth--; /* VDV 451 is without sign */ |
1403 | 5 | bOK &= VSIFPrintfL(m_fpL, "num[%d.0]", nWidth) > 0; |
1404 | 5 | } |
1405 | 5 | break; |
1406 | | |
1407 | 106 | default: |
1408 | 106 | if (nWidth == 0) |
1409 | 106 | { |
1410 | 106 | nWidth = 80; |
1411 | 106 | } |
1412 | 106 | bOK &= VSIFPrintfL(m_fpL, "char[%d]", nWidth) > 0; |
1413 | 106 | break; |
1414 | 111 | } |
1415 | 111 | } |
1416 | 38 | bOK &= VSIFPrintfL(m_fpL, "\n") > 0; |
1417 | | |
1418 | 38 | if (!bOK) |
1419 | 0 | return false; |
1420 | 38 | } |
1421 | | |
1422 | 48.5k | return true; |
1423 | 48.5k | } |
1424 | | |
1425 | | /************************************************************************/ |
1426 | | /* ICreateFeature() */ |
1427 | | /************************************************************************/ |
1428 | | |
1429 | | OGRErr OGRVDVWriterLayer::ICreateFeature(OGRFeature *poFeature) |
1430 | 48.4k | { |
1431 | 48.4k | if (!m_bWritePossible) |
1432 | 1 | { |
1433 | 1 | CPLError(CE_Failure, CPLE_NotSupported, |
1434 | 1 | "Layer %s is no longer the active layer. " |
1435 | 1 | "Writing in it is no longer possible", |
1436 | 1 | m_poFeatureDefn->GetName()); |
1437 | 1 | return OGRERR_FAILURE; |
1438 | 1 | } |
1439 | 48.4k | m_poDS->SetCurrentWriterLayer(this); |
1440 | | |
1441 | 48.4k | WriteSchemaIfNeeded(); |
1442 | | |
1443 | 48.4k | bool bOK = VSIFPrintfL(m_fpL, "rec; ") > 0; |
1444 | 195k | for (int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++) |
1445 | 146k | { |
1446 | 146k | if (i > 0) |
1447 | 98.1k | bOK &= VSIFPrintfL(m_fpL, "; ") > 0; |
1448 | 146k | auto poGeom = poFeature->GetGeometryRef(); |
1449 | 146k | if (poFeature->IsFieldSetAndNotNull(i)) |
1450 | 36.9k | { |
1451 | 36.9k | const OGRFieldType eType = |
1452 | 36.9k | m_poFeatureDefn->GetFieldDefn(i)->GetType(); |
1453 | 36.9k | if (eType == OFTInteger || eType == OFTInteger64) |
1454 | 87 | { |
1455 | 87 | bOK &= VSIFPrintfL(m_fpL, CPL_FRMT_GIB, |
1456 | 87 | poFeature->GetFieldAsInteger64(i)) > 0; |
1457 | 87 | } |
1458 | 36.8k | else |
1459 | 36.8k | { |
1460 | 36.8k | char *pszRecoded = CPLRecode(poFeature->GetFieldAsString(i), |
1461 | 36.8k | CPL_ENC_UTF8, CPL_ENC_ISO8859_1); |
1462 | 36.8k | bOK &= VSIFPrintfL(m_fpL, "\"%s\"", |
1463 | 36.8k | OGRVDVEscapeString(pszRecoded).c_str()) > 0; |
1464 | 36.8k | CPLFree(pszRecoded); |
1465 | 36.8k | } |
1466 | 36.9k | } |
1467 | 109k | else if (i == m_iLongitudeVDV452 && poGeom != nullptr && |
1468 | 109k | poGeom->getGeometryType() == wkbPoint) |
1469 | 0 | { |
1470 | 0 | OGRPoint *poPoint = poGeom->toPoint(); |
1471 | 0 | const double dfDeg = poPoint->getX(); |
1472 | 0 | const double dfAbsDeg = fabs(dfDeg); |
1473 | 0 | const int nDeg = static_cast<int>(dfAbsDeg); |
1474 | 0 | const int nMin = static_cast<int>((dfAbsDeg - nDeg) * 60); |
1475 | 0 | const double dfSec = (dfAbsDeg - nDeg) * 3600 - nMin * 60; |
1476 | 0 | const int nSec = static_cast<int>(dfSec); |
1477 | 0 | int nMS = static_cast<int>((dfSec - nSec) * 1000 + 0.5); |
1478 | 0 | if (nMS == 1000) |
1479 | 0 | nMS = 999; |
1480 | 0 | if (dfDeg < 0) |
1481 | 0 | bOK &= VSIFPrintfL(m_fpL, "-") > 0; |
1482 | 0 | bOK &= VSIFPrintfL(m_fpL, "%03d%02d%02d%03d", nDeg, nMin, nSec, |
1483 | 0 | nMS) > 0; |
1484 | 0 | } |
1485 | 109k | else if (i == m_iLatitudeVDV452 && poGeom != nullptr && |
1486 | 109k | poGeom->getGeometryType() == wkbPoint) |
1487 | 0 | { |
1488 | 0 | OGRPoint *poPoint = poGeom->toPoint(); |
1489 | 0 | const double dfDeg = poPoint->getY(); |
1490 | 0 | const double dfAbsDeg = fabs(dfDeg); |
1491 | 0 | const int nDeg = static_cast<int>(dfAbsDeg); |
1492 | 0 | const int nMin = static_cast<int>((dfAbsDeg - nDeg) * 60); |
1493 | 0 | const double dfSec = (dfAbsDeg - nDeg) * 3600 - nMin * 60; |
1494 | 0 | const int nSec = static_cast<int>(dfSec); |
1495 | 0 | int nMS = static_cast<int>((dfSec - nSec) * 1000 + 0.5); |
1496 | 0 | if (nMS == 1000) |
1497 | 0 | nMS = 999; |
1498 | 0 | if (dfDeg < 0) |
1499 | 0 | bOK &= VSIFPrintfL(m_fpL, "-") > 0; |
1500 | 0 | bOK &= VSIFPrintfL(m_fpL, "%02d%02d%02d%03d", nDeg, nMin, nSec, |
1501 | 0 | nMS) > 0; |
1502 | 0 | } |
1503 | 109k | else |
1504 | 109k | { |
1505 | 109k | bOK &= VSIFPrintfL(m_fpL, "NULL") > 0; |
1506 | 109k | } |
1507 | 146k | } |
1508 | 48.4k | bOK &= VSIFPrintfL(m_fpL, "\n") > 0; |
1509 | | |
1510 | 48.4k | if (!bOK) |
1511 | 0 | return OGRERR_FAILURE; |
1512 | | |
1513 | 48.4k | m_nFeatureCount++; |
1514 | 48.4k | return OGRERR_NONE; |
1515 | 48.4k | } |
1516 | | |
1517 | | /************************************************************************/ |
1518 | | /* GetFeatureCount() */ |
1519 | | /************************************************************************/ |
1520 | | |
1521 | | GIntBig OGRVDVWriterLayer::GetFeatureCount(int) |
1522 | 0 | { |
1523 | 0 | return m_nFeatureCount >= 0 ? m_nFeatureCount : 0; |
1524 | 0 | } |
1525 | | |
1526 | | /************************************************************************/ |
1527 | | /* CreateField() */ |
1528 | | /************************************************************************/ |
1529 | | |
1530 | | OGRErr OGRVDVWriterLayer::CreateField(const OGRFieldDefn *poFieldDefn, |
1531 | | int /* bApprox */) |
1532 | 116 | { |
1533 | 116 | if (m_nFeatureCount >= 0) |
1534 | 5 | { |
1535 | 5 | CPLError(CE_Failure, CPLE_NotSupported, |
1536 | 5 | "Fields can no longer by added to layer %s", |
1537 | 5 | m_poFeatureDefn->GetName()); |
1538 | 5 | return OGRERR_FAILURE; |
1539 | 5 | } |
1540 | | |
1541 | 111 | if (m_poVDV452Table != nullptr) |
1542 | 0 | { |
1543 | 0 | bool bFound = false; |
1544 | 0 | for (size_t i = 0; i < m_poVDV452Table->aosFields.size(); i++) |
1545 | 0 | { |
1546 | 0 | const char *pszFieldName = poFieldDefn->GetNameRef(); |
1547 | 0 | if ((m_osVDV452Lang == "en" && |
1548 | 0 | EQUAL(m_poVDV452Table->aosFields[i].osEnglishName, |
1549 | 0 | pszFieldName)) || |
1550 | 0 | (m_osVDV452Lang == "de" && |
1551 | 0 | EQUAL(m_poVDV452Table->aosFields[i].osGermanName, |
1552 | 0 | pszFieldName))) |
1553 | 0 | { |
1554 | 0 | bFound = true; |
1555 | 0 | break; |
1556 | 0 | } |
1557 | 0 | } |
1558 | 0 | if (!bFound) |
1559 | 0 | { |
1560 | 0 | CPLError(m_bProfileStrict ? CE_Failure : CE_Warning, |
1561 | 0 | CPLE_AppDefined, |
1562 | 0 | "Field %s is not an allowed field for table %s", |
1563 | 0 | poFieldDefn->GetNameRef(), m_poFeatureDefn->GetName()); |
1564 | 0 | if (m_bProfileStrict) |
1565 | 0 | return OGRERR_FAILURE; |
1566 | 0 | } |
1567 | 0 | if (EQUAL(m_poFeatureDefn->GetName(), "STOP") || |
1568 | 0 | EQUAL(m_poFeatureDefn->GetName(), "REC_ORT")) |
1569 | 0 | { |
1570 | 0 | if (EQUAL(poFieldDefn->GetNameRef(), "POINT_LONGITUDE") || |
1571 | 0 | EQUAL(poFieldDefn->GetNameRef(), "ORT_POS_LAENGE")) |
1572 | 0 | { |
1573 | 0 | m_iLongitudeVDV452 = m_poFeatureDefn->GetFieldCount(); |
1574 | 0 | } |
1575 | 0 | else if (EQUAL(poFieldDefn->GetNameRef(), "POINT_LATITUDE") || |
1576 | 0 | EQUAL(poFieldDefn->GetNameRef(), "ORT_POS_BREITE")) |
1577 | 0 | { |
1578 | 0 | m_iLatitudeVDV452 = m_poFeatureDefn->GetFieldCount(); |
1579 | 0 | } |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | 111 | m_poFeatureDefn->AddFieldDefn(poFieldDefn); |
1584 | 111 | return OGRERR_NONE; |
1585 | 111 | } |
1586 | | |
1587 | | /************************************************************************/ |
1588 | | /* TestCapability() */ |
1589 | | /************************************************************************/ |
1590 | | |
1591 | | int OGRVDVWriterLayer::TestCapability(const char *pszCap) |
1592 | 112 | { |
1593 | 112 | if (EQUAL(pszCap, OLCSequentialWrite)) |
1594 | 0 | return m_bWritePossible; |
1595 | 112 | if (EQUAL(pszCap, OLCCreateField)) |
1596 | 0 | return m_nFeatureCount < 0; |
1597 | 112 | return FALSE; |
1598 | 112 | } |
1599 | | |
1600 | | /************************************************************************/ |
1601 | | /* StopAsCurrentLayer() */ |
1602 | | /************************************************************************/ |
1603 | | |
1604 | | void OGRVDVWriterLayer::StopAsCurrentLayer() |
1605 | 73 | { |
1606 | 73 | if (m_bWritePossible) |
1607 | 38 | { |
1608 | 38 | m_bWritePossible = false; |
1609 | 38 | if (m_fpL != nullptr) |
1610 | 38 | { |
1611 | 38 | WriteSchemaIfNeeded(); |
1612 | 38 | VSIFPrintfL(m_fpL, "end; " CPL_FRMT_GIB "\n", m_nFeatureCount); |
1613 | 38 | } |
1614 | 38 | } |
1615 | 73 | } |
1616 | | |
1617 | | /************************************************************************/ |
1618 | | /* GetDataset() */ |
1619 | | /************************************************************************/ |
1620 | | |
1621 | | GDALDataset *OGRVDVWriterLayer::GetDataset() |
1622 | 0 | { |
1623 | 0 | return m_poDS; |
1624 | 0 | } |
1625 | | |
1626 | | /************************************************************************/ |
1627 | | /* OGRVDVWriteHeader() */ |
1628 | | /************************************************************************/ |
1629 | | |
1630 | | static bool OGRVDVWriteHeader(VSILFILE *fpL, CSLConstList papszOptions) |
1631 | 4 | { |
1632 | 4 | bool bRet = true; |
1633 | 4 | const bool bStandardHeader = |
1634 | 4 | CPLFetchBool(papszOptions, "STANDARD_HEADER", true); |
1635 | | |
1636 | 4 | struct tm tm; |
1637 | 4 | CPLUnixTimeToYMDHMS(time(nullptr), &tm); |
1638 | 4 | const char *pszSrc = CSLFetchNameValueDef( |
1639 | 4 | papszOptions, "HEADER_SRC", (bStandardHeader) ? "UNKNOWN" : nullptr); |
1640 | 4 | const char *pszSrcDate = CSLFetchNameValueDef( |
1641 | 4 | papszOptions, "HEADER_SRC_DATE", |
1642 | 4 | (pszSrc) ? CPLSPrintf("%02d.%02d.%04d", tm.tm_mday, tm.tm_mon + 1, |
1643 | 4 | tm.tm_year + 1900) |
1644 | 4 | : nullptr); |
1645 | 4 | const char *pszSrcTime = |
1646 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_SRC_TIME", |
1647 | 4 | (pszSrc) ? CPLSPrintf("%02d.%02d.%02d", tm.tm_hour, |
1648 | 4 | tm.tm_min, tm.tm_sec) |
1649 | 4 | : nullptr); |
1650 | | |
1651 | 4 | if (pszSrc && pszSrcDate && pszSrcTime) |
1652 | 4 | { |
1653 | 4 | bRet &= VSIFPrintfL(fpL, "mod; DD.MM.YYYY; HH:MM:SS; free\n") > 0; |
1654 | 4 | bRet &= VSIFPrintfL(fpL, "src; \"%s\"; \"%s\"; \"%s\"\n", |
1655 | 4 | OGRVDVEscapeString(pszSrc).c_str(), |
1656 | 4 | OGRVDVEscapeString(pszSrcDate).c_str(), |
1657 | 4 | OGRVDVEscapeString(pszSrcTime).c_str()) > 0; |
1658 | 4 | } |
1659 | | |
1660 | 4 | if (bStandardHeader) |
1661 | 4 | { |
1662 | 4 | const char *pszChs = |
1663 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_CHS", "ISO8859-1"); |
1664 | 4 | const char *pszVer = |
1665 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_VER", "1.4"); |
1666 | 4 | const char *pszIfv = |
1667 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_IFV", "1.4"); |
1668 | 4 | const char *pszDve = |
1669 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_DVE", "1.4"); |
1670 | 4 | const char *pszFft = |
1671 | 4 | CSLFetchNameValueDef(papszOptions, "HEADER_FFT", ""); |
1672 | | |
1673 | 4 | bRet &= VSIFPrintfL(fpL, "chs; \"%s\"\n", |
1674 | 4 | OGRVDVEscapeString(pszChs).c_str()) > 0; |
1675 | 4 | bRet &= VSIFPrintfL(fpL, "ver; \"%s\"\n", |
1676 | 4 | OGRVDVEscapeString(pszVer).c_str()) > 0; |
1677 | 4 | bRet &= VSIFPrintfL(fpL, "ifv; \"%s\"\n", |
1678 | 4 | OGRVDVEscapeString(pszIfv).c_str()) > 0; |
1679 | 4 | bRet &= VSIFPrintfL(fpL, "dve; \"%s\"\n", |
1680 | 4 | OGRVDVEscapeString(pszDve).c_str()) > 0; |
1681 | 4 | bRet &= VSIFPrintfL(fpL, "fft; \"%s\"\n", |
1682 | 4 | OGRVDVEscapeString(pszFft).c_str()) > 0; |
1683 | 4 | } |
1684 | | |
1685 | 4 | for (CSLConstList papszIter = papszOptions; |
1686 | 4 | papszIter != nullptr && *papszIter != nullptr; papszIter++) |
1687 | 0 | { |
1688 | 0 | if (STARTS_WITH_CI(*papszIter, "HEADER_") && |
1689 | 0 | !STARTS_WITH_CI(*papszIter, "HEADER_SRC") && |
1690 | 0 | (!bStandardHeader || (!EQUAL(*papszIter, "HEADER_CHS") && |
1691 | 0 | !EQUAL(*papszIter, "HEADER_VER") && |
1692 | 0 | !EQUAL(*papszIter, "HEADER_IFV") && |
1693 | 0 | !EQUAL(*papszIter, "HEADER_DVE") && |
1694 | 0 | !EQUAL(*papszIter, "HEADER_FFT")))) |
1695 | 0 | { |
1696 | 0 | char *pszKey = nullptr; |
1697 | 0 | const char *pszValue = CPLParseNameValue(*papszIter, &pszKey); |
1698 | 0 | if (pszKey && strlen(pszKey) > strlen("HEADER_") && pszValue) |
1699 | 0 | { |
1700 | 0 | bRet &= |
1701 | 0 | VSIFPrintfL(fpL, "%s; \"%s\"\n", pszKey + strlen("HEADER_"), |
1702 | 0 | OGRVDVEscapeString(pszValue).c_str()) > 0; |
1703 | 0 | } |
1704 | 0 | CPLFree(pszKey); |
1705 | 0 | } |
1706 | 0 | } |
1707 | | |
1708 | 4 | return bRet; |
1709 | 4 | } |
1710 | | |
1711 | | /************************************************************************/ |
1712 | | /* OGRVDVLoadVDV452Tables() */ |
1713 | | /************************************************************************/ |
1714 | | |
1715 | | static bool OGRVDVLoadVDV452Tables(OGRVDV452Tables &oTables) |
1716 | 0 | { |
1717 | 0 | CPLXMLNode *psRoot = nullptr; |
1718 | | #if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) |
1719 | | const char *pszXMLDescFilename = nullptr; |
1720 | | #else |
1721 | 0 | const char *pszXMLDescFilename = CPLFindFile("gdal", "vdv452.xml"); |
1722 | 0 | #endif |
1723 | 0 | if (pszXMLDescFilename == nullptr || |
1724 | 0 | EQUAL(pszXMLDescFilename, "vdv452.xml")) |
1725 | 0 | { |
1726 | | #ifdef EMBED_RESOURCE_FILES |
1727 | | static const bool bOnce [[maybe_unused]] = []() |
1728 | | { |
1729 | | CPLDebug("VDV", "Using embedded vdv452.xml"); |
1730 | | return true; |
1731 | | }(); |
1732 | | psRoot = CPLParseXMLString(VDVGet452XML()); |
1733 | | #else |
1734 | 0 | CPLDebug("VDV", "Cannot find XML file : %s", "vdv452.xml"); |
1735 | 0 | return false; |
1736 | 0 | #endif |
1737 | 0 | } |
1738 | | |
1739 | | #ifdef EMBED_RESOURCE_FILES |
1740 | | if (!psRoot) |
1741 | | #endif |
1742 | 0 | { |
1743 | 0 | psRoot = CPLParseXMLFile(pszXMLDescFilename); |
1744 | 0 | } |
1745 | 0 | if (psRoot == nullptr) |
1746 | 0 | { |
1747 | 0 | return false; |
1748 | 0 | } |
1749 | 0 | CPLXMLNode *psTables = CPLGetXMLNode(psRoot, "=Layers"); |
1750 | 0 | if (psTables != nullptr) |
1751 | 0 | { |
1752 | 0 | for (CPLXMLNode *psTable = psTables->psChild; psTable != nullptr; |
1753 | 0 | psTable = psTable->psNext) |
1754 | 0 | { |
1755 | 0 | if (psTable->eType != CXT_Element || |
1756 | 0 | strcmp(psTable->pszValue, "Layer") != 0) |
1757 | 0 | continue; |
1758 | 0 | OGRVDV452Table *poTable = new OGRVDV452Table(); |
1759 | 0 | poTable->osEnglishName = CPLGetXMLValue(psTable, "name_en", ""); |
1760 | 0 | poTable->osGermanName = CPLGetXMLValue(psTable, "name_de", ""); |
1761 | 0 | oTables.aosTables.push_back(poTable); |
1762 | 0 | oTables.oMapEnglish[poTable->osEnglishName] = poTable; |
1763 | 0 | oTables.oMapGerman[poTable->osGermanName] = poTable; |
1764 | 0 | for (CPLXMLNode *psField = psTable->psChild; psField != nullptr; |
1765 | 0 | psField = psField->psNext) |
1766 | 0 | { |
1767 | 0 | if (psField->eType != CXT_Element || |
1768 | 0 | strcmp(psField->pszValue, "Field") != 0) |
1769 | 0 | continue; |
1770 | 0 | OGRVDV452Field oField; |
1771 | 0 | oField.osEnglishName = CPLGetXMLValue(psField, "name_en", ""); |
1772 | 0 | oField.osGermanName = CPLGetXMLValue(psField, "name_de", ""); |
1773 | 0 | oField.osType = CPLGetXMLValue(psField, "type", ""); |
1774 | 0 | oField.nWidth = atoi(CPLGetXMLValue(psField, "width", "0")); |
1775 | 0 | poTable->aosFields.push_back(std::move(oField)); |
1776 | 0 | } |
1777 | 0 | } |
1778 | 0 | } |
1779 | |
|
1780 | 0 | CPLDestroyXMLNode(psRoot); |
1781 | 0 | return true; |
1782 | 0 | } |
1783 | | |
1784 | | /************************************************************************/ |
1785 | | /* ICreateLayer() */ |
1786 | | /************************************************************************/ |
1787 | | |
1788 | | OGRLayer * |
1789 | | OGRVDVDataSource::ICreateLayer(const char *pszLayerName, |
1790 | | const OGRGeomFieldDefn *poGeomFieldDefn, |
1791 | | CSLConstList papszOptions) |
1792 | 38 | { |
1793 | 38 | if (!m_bUpdate) |
1794 | 0 | return nullptr; |
1795 | | |
1796 | 38 | const char *pszProfile = |
1797 | 38 | CSLFetchNameValueDef(papszOptions, "PROFILE", "GENERIC"); |
1798 | 38 | if (STARTS_WITH_CI(pszProfile, "VDV-452") && !m_bVDV452Loaded) |
1799 | 0 | { |
1800 | 0 | m_bVDV452Loaded = true; |
1801 | 0 | OGRVDVLoadVDV452Tables(m_oVDV452Tables); |
1802 | 0 | } |
1803 | 38 | const bool bProfileStrict = |
1804 | 38 | CPLFetchBool(papszOptions, "PROFILE_STRICT", false); |
1805 | 38 | const bool bCreateAllFields = |
1806 | 38 | CPLFetchBool(papszOptions, "CREATE_ALL_FIELDS", true); |
1807 | | |
1808 | 38 | CPLString osUpperLayerName(pszLayerName); |
1809 | 38 | osUpperLayerName.toupper(); |
1810 | | |
1811 | 38 | OGRVDV452Table *poVDV452Table = nullptr; |
1812 | 38 | CPLString osVDV452Lang; |
1813 | 38 | bool bOKTable = true; |
1814 | 38 | if (EQUAL(pszProfile, "VDV-452")) |
1815 | 0 | { |
1816 | 0 | if (m_oVDV452Tables.oMapEnglish.find(osUpperLayerName) != |
1817 | 0 | m_oVDV452Tables.oMapEnglish.end()) |
1818 | 0 | { |
1819 | 0 | poVDV452Table = m_oVDV452Tables.oMapEnglish[osUpperLayerName]; |
1820 | 0 | osVDV452Lang = "en"; |
1821 | 0 | } |
1822 | 0 | else if (m_oVDV452Tables.oMapGerman.find(osUpperLayerName) != |
1823 | 0 | m_oVDV452Tables.oMapGerman.end()) |
1824 | 0 | { |
1825 | 0 | poVDV452Table = m_oVDV452Tables.oMapGerman[osUpperLayerName]; |
1826 | 0 | osVDV452Lang = "de"; |
1827 | 0 | } |
1828 | 0 | else |
1829 | 0 | { |
1830 | 0 | bOKTable = false; |
1831 | 0 | } |
1832 | 0 | } |
1833 | 38 | else if (EQUAL(pszProfile, "VDV-452-ENGLISH")) |
1834 | 0 | { |
1835 | 0 | if (m_oVDV452Tables.oMapEnglish.find(osUpperLayerName) != |
1836 | 0 | m_oVDV452Tables.oMapEnglish.end()) |
1837 | 0 | { |
1838 | 0 | poVDV452Table = m_oVDV452Tables.oMapEnglish[osUpperLayerName]; |
1839 | 0 | osVDV452Lang = "en"; |
1840 | 0 | } |
1841 | 0 | else |
1842 | 0 | { |
1843 | 0 | bOKTable = false; |
1844 | 0 | } |
1845 | 0 | } |
1846 | 38 | else if (EQUAL(pszProfile, "VDV-452-GERMAN")) |
1847 | 0 | { |
1848 | 0 | if (m_oVDV452Tables.oMapGerman.find(osUpperLayerName) != |
1849 | 0 | m_oVDV452Tables.oMapGerman.end()) |
1850 | 0 | { |
1851 | 0 | poVDV452Table = m_oVDV452Tables.oMapGerman[osUpperLayerName]; |
1852 | 0 | osVDV452Lang = "de"; |
1853 | 0 | } |
1854 | 0 | else |
1855 | 0 | { |
1856 | 0 | bOKTable = false; |
1857 | 0 | } |
1858 | 0 | } |
1859 | 38 | if (!bOKTable) |
1860 | 0 | { |
1861 | 0 | CPLError(bProfileStrict ? CE_Failure : CE_Warning, CPLE_AppDefined, |
1862 | 0 | "%s is not a VDV-452 table", pszLayerName); |
1863 | 0 | if (bProfileStrict) |
1864 | 0 | return nullptr; |
1865 | 0 | } |
1866 | | |
1867 | 38 | VSILFILE *fpL = nullptr; |
1868 | 38 | if (m_bSingleFile) |
1869 | 38 | { |
1870 | 38 | fpL = m_fpL; |
1871 | 38 | if (!m_bNew && m_nLayerCount == 0) |
1872 | 0 | { |
1873 | | // Find last non-empty line in the file |
1874 | 0 | VSIFSeekL(fpL, 0, SEEK_END); |
1875 | 0 | vsi_l_offset nFileSize = VSIFTellL(fpL); |
1876 | 0 | vsi_l_offset nOffset = nFileSize; |
1877 | 0 | bool bTerminatingEOL = true; |
1878 | 0 | while (nOffset > 0) |
1879 | 0 | { |
1880 | 0 | VSIFSeekL(fpL, nOffset - 1, SEEK_SET); |
1881 | 0 | char ch = '\0'; |
1882 | 0 | VSIFReadL(&ch, 1, 1, fpL); |
1883 | 0 | if (bTerminatingEOL) |
1884 | 0 | { |
1885 | 0 | if (!(ch == '\r' || ch == '\n')) |
1886 | 0 | { |
1887 | 0 | bTerminatingEOL = false; |
1888 | 0 | } |
1889 | 0 | } |
1890 | 0 | else |
1891 | 0 | { |
1892 | 0 | if (ch == '\r' || ch == '\n') |
1893 | 0 | break; |
1894 | 0 | } |
1895 | 0 | nOffset--; |
1896 | 0 | } |
1897 | | |
1898 | | // If it is "eof;..." then overwrite it with new content |
1899 | 0 | const char *pszLine = CPLReadLineL(fpL); |
1900 | 0 | if (pszLine != nullptr && STARTS_WITH(pszLine, "eof;")) |
1901 | 0 | { |
1902 | 0 | VSIFSeekL(fpL, nOffset, SEEK_SET); |
1903 | 0 | VSIFTruncateL(fpL, VSIFTellL(fpL)); |
1904 | 0 | } |
1905 | 0 | else if (nFileSize > 0) |
1906 | 0 | { |
1907 | | // Otherwise make sure the file ends with an eol character |
1908 | 0 | VSIFSeekL(fpL, nFileSize - 1, SEEK_SET); |
1909 | 0 | char ch = '\0'; |
1910 | 0 | VSIFReadL(&ch, 1, 1, fpL); |
1911 | 0 | VSIFSeekL(fpL, nFileSize, SEEK_SET); |
1912 | 0 | if (!(ch == '\r' || ch == '\n')) |
1913 | 0 | { |
1914 | 0 | ch = '\n'; |
1915 | 0 | VSIFWriteL(&ch, 1, 1, fpL); |
1916 | 0 | } |
1917 | 0 | } |
1918 | 0 | } |
1919 | 38 | } |
1920 | 0 | else |
1921 | 0 | { |
1922 | 0 | CPLString osExtension = |
1923 | 0 | CSLFetchNameValueDef(papszOptions, "EXTENSION", "x10"); |
1924 | 0 | const CPLString osFilename = |
1925 | 0 | CPLFormFilenameSafe(m_osFilename, pszLayerName, osExtension); |
1926 | 0 | fpL = VSIFOpenL(osFilename, "wb"); |
1927 | 0 | if (fpL == nullptr) |
1928 | 0 | { |
1929 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", |
1930 | 0 | osFilename.c_str()); |
1931 | 0 | return nullptr; |
1932 | 0 | } |
1933 | 0 | } |
1934 | | |
1935 | 38 | GetLayerCount(); |
1936 | | |
1937 | 38 | if (m_nLayerCount == 0 || !m_bSingleFile) |
1938 | 4 | { |
1939 | 4 | if (!OGRVDVWriteHeader(fpL, papszOptions)) |
1940 | 0 | { |
1941 | 0 | if (!m_bSingleFile) |
1942 | 0 | VSIFCloseL(fpL); |
1943 | 0 | return nullptr; |
1944 | 0 | } |
1945 | 4 | } |
1946 | | |
1947 | 38 | m_bMustWriteEof = true; |
1948 | | |
1949 | 38 | OGRVDVWriterLayer *poLayer = |
1950 | 38 | new OGRVDVWriterLayer(this, pszLayerName, fpL, !m_bSingleFile, |
1951 | 38 | poVDV452Table, osVDV452Lang, bProfileStrict); |
1952 | 38 | m_papoLayers = static_cast<OGRLayer **>( |
1953 | 38 | CPLRealloc(m_papoLayers, sizeof(OGRLayer *) * (m_nLayerCount + 1))); |
1954 | 38 | m_papoLayers[m_nLayerCount] = poLayer; |
1955 | 38 | m_nLayerCount++; |
1956 | | |
1957 | 38 | const auto eGType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone; |
1958 | 38 | if (eGType == wkbPoint && poVDV452Table != nullptr && |
1959 | 38 | (EQUAL(pszLayerName, "STOP") || EQUAL(pszLayerName, "REC_ORT"))) |
1960 | 0 | { |
1961 | 0 | poLayer->GetLayerDefn()->SetGeomType(wkbPoint); |
1962 | 0 | } |
1963 | | |
1964 | 38 | if (bCreateAllFields && poVDV452Table != nullptr) |
1965 | 0 | { |
1966 | 0 | for (size_t i = 0; i < poVDV452Table->aosFields.size(); i++) |
1967 | 0 | { |
1968 | 0 | const char *pszFieldName = |
1969 | 0 | (osVDV452Lang == "en") |
1970 | 0 | ? poVDV452Table->aosFields[i].osEnglishName.c_str() |
1971 | 0 | : poVDV452Table->aosFields[i].osGermanName.c_str(); |
1972 | 0 | OGRFieldType eType = OFTString; |
1973 | 0 | int nWidth = poVDV452Table->aosFields[i].nWidth; |
1974 | 0 | if (poVDV452Table->aosFields[i].osType == "num" || |
1975 | 0 | poVDV452Table->aosFields[i].osType == "boolean") |
1976 | 0 | eType = OFTInteger; |
1977 | 0 | if (poVDV452Table->aosFields[i].osType == "num") |
1978 | 0 | { |
1979 | | /* VDV 451 is without sign */ |
1980 | 0 | nWidth++; |
1981 | 0 | if (nWidth >= 10) |
1982 | 0 | eType = OFTInteger64; |
1983 | 0 | } |
1984 | 0 | OGRFieldDefn oField(pszFieldName, eType); |
1985 | 0 | if (poVDV452Table->aosFields[i].osType == "boolean") |
1986 | 0 | oField.SetSubType(OFSTBoolean); |
1987 | 0 | oField.SetWidth(nWidth); |
1988 | 0 | poLayer->CreateField(&oField); |
1989 | 0 | } |
1990 | 0 | } |
1991 | | |
1992 | 38 | return poLayer; |
1993 | 38 | } |
1994 | | |
1995 | | /************************************************************************/ |
1996 | | /* SetCurrentWriterLayer() */ |
1997 | | /************************************************************************/ |
1998 | | |
1999 | | void OGRVDVDataSource::SetCurrentWriterLayer(OGRVDVWriterLayer *poLayer) |
2000 | 48.4k | { |
2001 | 48.4k | if (!m_bSingleFile) |
2002 | 0 | return; |
2003 | 48.4k | if (m_poCurrentWriterLayer != nullptr && m_poCurrentWriterLayer != poLayer) |
2004 | 31 | { |
2005 | 31 | m_poCurrentWriterLayer->StopAsCurrentLayer(); |
2006 | 31 | } |
2007 | 48.4k | m_poCurrentWriterLayer = poLayer; |
2008 | 48.4k | } |
2009 | | |
2010 | | /************************************************************************/ |
2011 | | /* TestCapability() */ |
2012 | | /************************************************************************/ |
2013 | | |
2014 | | int OGRVDVDataSource::TestCapability(const char *pszCap) |
2015 | | |
2016 | 106 | { |
2017 | 106 | if (EQUAL(pszCap, ODsCCreateLayer)) |
2018 | 38 | return m_bUpdate; |
2019 | 68 | else if (EQUAL(pszCap, ODsCZGeometries)) |
2020 | 0 | return true; |
2021 | | |
2022 | 68 | return false; |
2023 | 106 | } |
2024 | | |
2025 | | /************************************************************************/ |
2026 | | /* Create() */ |
2027 | | /************************************************************************/ |
2028 | | |
2029 | | GDALDataset *OGRVDVDataSource::Create(const char *pszName, int /*nXSize*/, |
2030 | | int /*nYSize*/, int /*nBands*/, |
2031 | | GDALDataType /*eType*/, |
2032 | | char **papszOptions) |
2033 | | |
2034 | 5 | { |
2035 | | /* -------------------------------------------------------------------- */ |
2036 | | /* First, ensure there isn't any such file yet. */ |
2037 | | /* -------------------------------------------------------------------- */ |
2038 | 5 | VSIStatBufL sStatBuf; |
2039 | 5 | if (VSIStatL(pszName, &sStatBuf) == 0) |
2040 | 0 | { |
2041 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2042 | 0 | "It seems a file system object called '%s' already exists.", |
2043 | 0 | pszName); |
2044 | |
|
2045 | 0 | return nullptr; |
2046 | 0 | } |
2047 | | |
2048 | 5 | const bool bSingleFile = CPLFetchBool(papszOptions, "SINGLE_FILE", true); |
2049 | 5 | if (!bSingleFile) |
2050 | 0 | { |
2051 | 0 | if (VSIMkdir(pszName, 0755) != 0) |
2052 | 0 | { |
2053 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2054 | 0 | "Failed to create directory %s:\n%s", pszName, |
2055 | 0 | VSIStrerror(errno)); |
2056 | 0 | return nullptr; |
2057 | 0 | } |
2058 | 0 | } |
2059 | | |
2060 | 5 | VSILFILE *fpL = nullptr; |
2061 | 5 | if (bSingleFile) |
2062 | 5 | { |
2063 | 5 | fpL = VSIFOpenL(pszName, "wb"); |
2064 | 5 | if (fpL == nullptr) |
2065 | 1 | { |
2066 | 1 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszName); |
2067 | 1 | return nullptr; |
2068 | 1 | } |
2069 | 5 | } |
2070 | 4 | OGRVDVDataSource *poDS = |
2071 | 4 | new OGRVDVDataSource(pszName, fpL, true, bSingleFile, true /* new */); |
2072 | 4 | return poDS; |
2073 | 5 | } |
2074 | | |
2075 | | /************************************************************************/ |
2076 | | /* RegisterOGRVDV() */ |
2077 | | /************************************************************************/ |
2078 | | |
2079 | | void RegisterOGRVDV() |
2080 | | |
2081 | 22 | { |
2082 | 22 | if (GDALGetDriverByName("VDV") != nullptr) |
2083 | 0 | return; |
2084 | | |
2085 | 22 | GDALDriver *poDriver = new GDALDriver(); |
2086 | | |
2087 | 22 | poDriver->SetDescription("VDV"); |
2088 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); |
2089 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); |
2090 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); |
2091 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES"); |
2092 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES"); |
2093 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_MEASURED_GEOMETRIES, "YES"); |
2094 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_CURVE_GEOMETRIES, "YES"); |
2095 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); |
2096 | 22 | poDriver->SetMetadataItem(GDAL_DMD_CREATION_FIELD_DEFN_FLAGS, |
2097 | 22 | "WidthPrecision"); |
2098 | 22 | poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS, |
2099 | 22 | "Name Type WidthPrecision"); |
2100 | 22 | poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); |
2101 | | |
2102 | 22 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, |
2103 | 22 | "VDV-451/VDV-452/INTREST Data Format"); |
2104 | 22 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/vdv.html"); |
2105 | 22 | poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "txt x10"); |
2106 | 22 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
2107 | 22 | poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES, |
2108 | 22 | "Integer Integer64 String"); |
2109 | | |
2110 | 22 | poDriver->SetMetadataItem( |
2111 | 22 | GDAL_DMD_CREATIONOPTIONLIST, |
2112 | 22 | "<CreationOptionList>" |
2113 | 22 | " <Option name='SINGLE_FILE' type='boolean' description='Whether " |
2114 | 22 | "several layers " |
2115 | 22 | "should be put in the same file. If no, the name is assumed to be a " |
2116 | 22 | "directory name' default='YES'/>" |
2117 | 22 | "</CreationOptionList>"); |
2118 | | |
2119 | 22 | poDriver->SetMetadataItem( |
2120 | 22 | GDAL_DS_LAYER_CREATIONOPTIONLIST, |
2121 | 22 | "<LayerCreationOptionList>" |
2122 | 22 | " <Option name='EXTENSION' type='string' description='Layer file " |
2123 | 22 | "extension. Only used for SINGLE_FILE=NO' default='x10'/>" |
2124 | 22 | " <Option name='PROFILE' type='string-select' description='Profile' " |
2125 | 22 | "default='GENERIC'>" |
2126 | 22 | " <Value>GENERIC</Value>" |
2127 | 22 | " <Value>VDV-452</Value>" |
2128 | 22 | " <Value>VDV-452-ENGLISH</Value>" |
2129 | 22 | " <Value>VDV-452-GERMAN</Value>" |
2130 | 22 | " </Option>" |
2131 | 22 | " <Option name='PROFILE_STRICT' type='boolean' description='Whether " |
2132 | 22 | "checks of profile should be strict' default='NO'/>" |
2133 | 22 | " <Option name='CREATE_ALL_FIELDS' type='boolean' description=" |
2134 | 22 | "'Whether all fields of predefined profiles should be created at layer " |
2135 | 22 | "creation' default='YES'/>" |
2136 | 22 | " <Option name='STANDARD_HEADER' type='boolean' description='Whether " |
2137 | 22 | "to write standard header fields' default='YES'/>" |
2138 | 22 | " <Option name='HEADER_SRC' type='string' description='Value of the " |
2139 | 22 | "src header field' default='UNKNOWN'/>" |
2140 | 22 | " <Option name='HEADER_SRC_DATE' type='string' description='Value of " |
2141 | 22 | "the date of the src header field as DD.MM.YYYY'/>" |
2142 | 22 | " <Option name='HEADER_SRC_TIME' type='string' description='Value of " |
2143 | 22 | "the time of the src header field as HH.MM.SS'/>" |
2144 | 22 | " <Option name='HEADER_CHS' type='string' description='Value of the " |
2145 | 22 | "chs header field' default='ISO8859-1'/>" |
2146 | 22 | " <Option name='HEADER_VER' type='string' description='Value of the " |
2147 | 22 | "ver header field' default='1.4'/>" |
2148 | 22 | " <Option name='HEADER_IFV' type='string' description='Value of the " |
2149 | 22 | "ifv header field' default='1.4'/>" |
2150 | 22 | " <Option name='HEADER_DVE' type='string' description='Value of the " |
2151 | 22 | "dve header field' default='1.4'/>" |
2152 | 22 | " <Option name='HEADER_FFT' type='string' description='Value of the " |
2153 | 22 | "fft header field' default=''/>" |
2154 | 22 | " <Option name='HEADER_*' type='string' description='Value of another " |
2155 | 22 | "header field'/>" |
2156 | 22 | "</LayerCreationOptionList>"); |
2157 | 22 | poDriver->pfnIdentify = OGRVDVDriverIdentify; |
2158 | 22 | poDriver->pfnOpen = OGRVDVDataSource::Open; |
2159 | 22 | poDriver->pfnCreate = OGRVDVDataSource::Create; |
2160 | | |
2161 | 22 | GetGDALDriverManager()->RegisterDriver(poDriver); |
2162 | 22 | } |