Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Interlis 1 Translator
4 : * Purpose: Implements OGRILI1DataSource class.
5 : * Author: Pirmin Kalberer, Sourcepole AG
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
9 : * Copyright (c) 2007-2008, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_conv.h"
15 : #include "cpl_string.h"
16 :
17 : #include "ili1reader.h"
18 : #include "ogr_ili1.h"
19 :
20 : #include <string>
21 :
22 : /************************************************************************/
23 : /* OGRILI1DataSource() */
24 : /************************************************************************/
25 :
26 130 : OGRILI1DataSource::OGRILI1DataSource()
27 130 : : poImdReader(new ImdReader(1)), poReader(nullptr), fpTransfer(nullptr),
28 130 : pszTopic(nullptr), nLayers(0), papoLayers(nullptr)
29 : {
30 130 : }
31 :
32 : /************************************************************************/
33 : /* ~OGRILI1DataSource() */
34 : /************************************************************************/
35 :
36 260 : OGRILI1DataSource::~OGRILI1DataSource()
37 :
38 : {
39 167 : for (int i = 0; i < nLayers; i++)
40 : {
41 37 : delete papoLayers[i];
42 : }
43 130 : CPLFree(papoLayers);
44 :
45 130 : CPLFree(pszTopic);
46 130 : DestroyILI1Reader(poReader);
47 130 : delete poImdReader;
48 130 : if (fpTransfer)
49 : {
50 21 : VSIFPrintfL(fpTransfer, "ETAB\n");
51 21 : VSIFPrintfL(fpTransfer, "ETOP\n");
52 21 : VSIFPrintfL(fpTransfer, "EMOD\n");
53 21 : VSIFPrintfL(fpTransfer, "ENDE\n");
54 21 : VSIFCloseL(fpTransfer);
55 : }
56 260 : }
57 :
58 : /************************************************************************/
59 : /* Open() */
60 : /************************************************************************/
61 :
62 108 : int OGRILI1DataSource::Open(const char *pszNewName, char **papszOpenOptionsIn,
63 : int bTestOpen)
64 :
65 : {
66 108 : if (strlen(pszNewName) == 0)
67 : {
68 0 : return FALSE;
69 : }
70 :
71 216 : std::string osBasename;
72 216 : std::string osModelFilename;
73 108 : if (CSLFetchNameValue(papszOpenOptionsIn, "MODEL") != nullptr)
74 : {
75 0 : osBasename = pszNewName;
76 0 : osModelFilename = CSLFetchNameValue(papszOpenOptionsIn, "MODEL");
77 : }
78 : else
79 : {
80 108 : char **filenames = CSLTokenizeString2(pszNewName, ",", 0);
81 108 : int nCount = CSLCount(filenames);
82 108 : if (nCount == 0)
83 : {
84 0 : CSLDestroy(filenames);
85 0 : return FALSE;
86 : }
87 108 : osBasename = filenames[0];
88 :
89 108 : if (nCount > 1)
90 73 : osModelFilename = filenames[1];
91 :
92 108 : CSLDestroy(filenames);
93 : }
94 :
95 : /* -------------------------------------------------------------------- */
96 : /* Open the source file. */
97 : /* -------------------------------------------------------------------- */
98 108 : VSILFILE *fp = VSIFOpenL(osBasename.c_str(), "r");
99 108 : if (fp == nullptr)
100 : {
101 57 : if (!bTestOpen)
102 0 : CPLError(CE_Failure, CPLE_OpenFailed,
103 : "Failed to open ILI1 file `%s'.", pszNewName);
104 :
105 57 : return FALSE;
106 : }
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* If we aren't sure it is ILI1, load a header chunk and check */
110 : /* for signs it is ILI1 */
111 : /* -------------------------------------------------------------------- */
112 : char szHeader[1000];
113 :
114 51 : if (bTestOpen)
115 : {
116 51 : int nLen = (int)VSIFReadL(szHeader, 1, sizeof(szHeader), fp);
117 51 : if (nLen == sizeof(szHeader))
118 5 : szHeader[sizeof(szHeader) - 1] = '\0';
119 : else
120 46 : szHeader[nLen] = '\0';
121 :
122 51 : if (strstr(szHeader, "SCNT") == nullptr)
123 : {
124 3 : VSIFCloseL(fp);
125 3 : return FALSE;
126 : }
127 : }
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* We assume now that it is ILI1. Close and instantiate a */
131 : /* ILI1Reader on it. */
132 : /* -------------------------------------------------------------------- */
133 48 : VSIFCloseL(fp);
134 :
135 48 : poReader = CreateILI1Reader();
136 48 : if (poReader == nullptr)
137 : {
138 0 : CPLError(CE_Failure, CPLE_AppDefined,
139 : "File %s appears to be ILI1 but the ILI1 reader cannot\n"
140 : "be instantiated, likely because Xerces support was not\n"
141 : "configured in.",
142 : pszNewName);
143 0 : return FALSE;
144 : }
145 :
146 48 : poReader->OpenFile(osBasename.c_str());
147 :
148 48 : if (osModelFilename.length() > 0)
149 16 : poReader->ReadModel(poImdReader, osModelFilename.c_str(), this);
150 :
151 48 : int bResetConfigOption = FALSE;
152 48 : if (EQUAL(CPLGetConfigOption("OGR_ARC_STEPSIZE", ""), ""))
153 : {
154 48 : bResetConfigOption = TRUE;
155 48 : CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", "0.96");
156 : }
157 :
158 : // Parse model and read data - without surface join and area polygonizing.
159 48 : poReader->ReadFeatures();
160 :
161 48 : if (bResetConfigOption)
162 48 : CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", nullptr);
163 :
164 48 : return TRUE;
165 : }
166 :
167 : /************************************************************************/
168 : /* Create() */
169 : /************************************************************************/
170 :
171 22 : int OGRILI1DataSource::Create(const char *pszFilename,
172 : char ** /* papszOptions */)
173 : {
174 22 : char **filenames = CSLTokenizeString2(pszFilename, ",", 0);
175 :
176 44 : std::string osBasename = filenames[0];
177 :
178 44 : std::string osModelFilename;
179 22 : if (CSLCount(filenames) > 1)
180 3 : osModelFilename = filenames[1];
181 :
182 22 : CSLDestroy(filenames);
183 :
184 : /* -------------------------------------------------------------------- */
185 : /* Create the empty file. */
186 : /* -------------------------------------------------------------------- */
187 22 : fpTransfer = VSIFOpenL(osBasename.c_str(), "w+b");
188 :
189 22 : if (fpTransfer == nullptr)
190 : {
191 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
192 1 : osBasename.c_str(), VSIStrerror(errno));
193 :
194 1 : return FALSE;
195 : }
196 :
197 : /* -------------------------------------------------------------------- */
198 : /* Parse model */
199 : /* -------------------------------------------------------------------- */
200 21 : if (osModelFilename.length() == 0)
201 : {
202 18 : CPLError(CE_Warning, CPLE_AppDefined,
203 : "Creating Interlis transfer file without model definition.");
204 : }
205 : else
206 : {
207 3 : poImdReader->ReadModel(osModelFilename.c_str());
208 : }
209 :
210 21 : pszTopic = CPLStrdup(poImdReader->mainTopicName.c_str());
211 :
212 : /* -------------------------------------------------------------------- */
213 : /* Write headers */
214 : /* -------------------------------------------------------------------- */
215 21 : VSIFPrintfL(fpTransfer, "SCNT\n");
216 21 : VSIFPrintfL(fpTransfer, "OGR/GDAL %s, INTERLIS Driver\n",
217 : GDALVersionInfo("RELEASE_NAME"));
218 21 : VSIFPrintfL(fpTransfer, "////\n");
219 21 : VSIFPrintfL(fpTransfer, "MTID INTERLIS1\n");
220 21 : const char *modelname = poImdReader->mainModelName.c_str();
221 21 : VSIFPrintfL(fpTransfer, "MODL %s\n", modelname);
222 :
223 21 : return TRUE;
224 : }
225 :
226 37 : static char *ExtractTopic(const char *pszLayerName)
227 : {
228 37 : const char *table = strchr(pszLayerName, '_');
229 37 : while (table && table[1] != '_')
230 0 : table = strchr(table + 1, '_');
231 40 : return (table) ? CPLScanString(pszLayerName,
232 3 : static_cast<int>(table - pszLayerName),
233 : FALSE, FALSE)
234 37 : : nullptr;
235 : }
236 :
237 : /************************************************************************/
238 : /* ICreateLayer() */
239 : /************************************************************************/
240 :
241 : OGRLayer *
242 37 : OGRILI1DataSource::ICreateLayer(const char *pszLayerName,
243 : const OGRGeomFieldDefn *poGeomFieldDefn,
244 : CSLConstList /*papszOptions*/)
245 : {
246 37 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
247 :
248 : FeatureDefnInfo featureDefnInfo =
249 37 : poImdReader->GetFeatureDefnInfo(pszLayerName);
250 37 : const char *table = pszLayerName;
251 37 : char *topic = ExtractTopic(pszLayerName);
252 37 : if (nLayers)
253 16 : VSIFPrintfL(fpTransfer, "ETAB\n");
254 37 : if (topic)
255 : {
256 3 : table = pszLayerName + strlen(topic) + 2; // after "__"
257 3 : if (pszTopic == nullptr || !EQUAL(topic, pszTopic))
258 : {
259 1 : if (pszTopic)
260 : {
261 1 : VSIFPrintfL(fpTransfer, "ETOP\n");
262 1 : CPLFree(pszTopic);
263 : }
264 1 : pszTopic = topic;
265 1 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
266 : }
267 : else
268 : {
269 2 : CPLFree(topic);
270 : }
271 : }
272 : else
273 : {
274 34 : if (pszTopic == nullptr)
275 0 : pszTopic = CPLStrdup("Unknown");
276 34 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
277 : }
278 37 : VSIFPrintfL(fpTransfer, "TABL %s\n", table);
279 :
280 37 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(table);
281 37 : poFeatureDefn->SetGeomType(eType);
282 : OGRILI1Layer *poLayer =
283 37 : new OGRILI1Layer(poFeatureDefn, featureDefnInfo.poGeomFieldInfos, this);
284 :
285 37 : nLayers++;
286 37 : papoLayers = static_cast<OGRILI1Layer **>(
287 37 : CPLRealloc(papoLayers, sizeof(OGRILI1Layer *) * nLayers));
288 37 : papoLayers[nLayers - 1] = poLayer;
289 :
290 74 : return poLayer;
291 : }
292 :
293 : /************************************************************************/
294 : /* TestCapability() */
295 : /************************************************************************/
296 :
297 49 : int OGRILI1DataSource::TestCapability(const char *pszCap)
298 :
299 : {
300 49 : if (EQUAL(pszCap, ODsCCreateLayer))
301 32 : return TRUE;
302 17 : else if (EQUAL(pszCap, ODsCCurveGeometries))
303 1 : return TRUE;
304 16 : else if (EQUAL(pszCap, ODsCZGeometries))
305 0 : return TRUE;
306 :
307 16 : return FALSE;
308 : }
309 :
310 : /************************************************************************/
311 : /* GetLayer() */
312 : /************************************************************************/
313 :
314 23 : OGRLayer *OGRILI1DataSource::GetLayer(int iLayer)
315 : {
316 23 : if (!poReader)
317 : {
318 0 : if (iLayer < 0 || iLayer >= nLayers)
319 0 : return nullptr;
320 0 : return papoLayers[iLayer];
321 : }
322 23 : return poReader->GetLayer(iLayer);
323 : }
324 :
325 : /************************************************************************/
326 : /* GetLayerByName() */
327 : /************************************************************************/
328 :
329 44 : OGRILI1Layer *OGRILI1DataSource::GetLayerByName(const char *pszLayerName)
330 : {
331 44 : if (!poReader)
332 : {
333 0 : return cpl::down_cast<OGRILI1Layer *>(
334 0 : GDALDataset::GetLayerByName(pszLayerName));
335 : }
336 :
337 44 : return cpl::down_cast<OGRILI1Layer *>(
338 88 : poReader->GetLayerByName(pszLayerName));
339 : }
|