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 : CPLConfigOptionSetter oSetter("OGR_ARC_STEPSIZE", "0.96",
152 48 : /* bSetOnlyIfUndefined = */ true);
153 :
154 : // Parse model and read data - without surface join and area polygonizing.
155 48 : poReader->ReadFeatures();
156 :
157 48 : return TRUE;
158 : }
159 :
160 : /************************************************************************/
161 : /* Create() */
162 : /************************************************************************/
163 :
164 22 : int OGRILI1DataSource::Create(const char *pszFilename,
165 : char ** /* papszOptions */)
166 : {
167 22 : char **filenames = CSLTokenizeString2(pszFilename, ",", 0);
168 :
169 44 : std::string osBasename = filenames[0];
170 :
171 44 : std::string osModelFilename;
172 22 : if (CSLCount(filenames) > 1)
173 3 : osModelFilename = filenames[1];
174 :
175 22 : CSLDestroy(filenames);
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Create the empty file. */
179 : /* -------------------------------------------------------------------- */
180 22 : fpTransfer = VSIFOpenL(osBasename.c_str(), "w+b");
181 :
182 22 : if (fpTransfer == nullptr)
183 : {
184 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
185 1 : osBasename.c_str(), VSIStrerror(errno));
186 :
187 1 : return FALSE;
188 : }
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Parse model */
192 : /* -------------------------------------------------------------------- */
193 21 : if (osModelFilename.length() == 0)
194 : {
195 18 : CPLError(CE_Warning, CPLE_AppDefined,
196 : "Creating Interlis transfer file without model definition.");
197 : }
198 : else
199 : {
200 3 : poImdReader->ReadModel(osModelFilename.c_str());
201 : }
202 :
203 21 : pszTopic = CPLStrdup(poImdReader->mainTopicName.c_str());
204 :
205 : /* -------------------------------------------------------------------- */
206 : /* Write headers */
207 : /* -------------------------------------------------------------------- */
208 21 : VSIFPrintfL(fpTransfer, "SCNT\n");
209 21 : VSIFPrintfL(fpTransfer, "OGR/GDAL %s, INTERLIS Driver\n",
210 : GDALVersionInfo("RELEASE_NAME"));
211 21 : VSIFPrintfL(fpTransfer, "////\n");
212 21 : VSIFPrintfL(fpTransfer, "MTID INTERLIS1\n");
213 21 : const char *modelname = poImdReader->mainModelName.c_str();
214 21 : VSIFPrintfL(fpTransfer, "MODL %s\n", modelname);
215 :
216 21 : return TRUE;
217 : }
218 :
219 37 : static char *ExtractTopic(const char *pszLayerName)
220 : {
221 37 : const char *table = strchr(pszLayerName, '_');
222 37 : while (table && table[1] != '_')
223 0 : table = strchr(table + 1, '_');
224 40 : return (table) ? CPLScanString(pszLayerName,
225 3 : static_cast<int>(table - pszLayerName),
226 : FALSE, FALSE)
227 37 : : nullptr;
228 : }
229 :
230 : /************************************************************************/
231 : /* ICreateLayer() */
232 : /************************************************************************/
233 :
234 : OGRLayer *
235 37 : OGRILI1DataSource::ICreateLayer(const char *pszLayerName,
236 : const OGRGeomFieldDefn *poGeomFieldDefn,
237 : CSLConstList /*papszOptions*/)
238 : {
239 37 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
240 :
241 : FeatureDefnInfo featureDefnInfo =
242 37 : poImdReader->GetFeatureDefnInfo(pszLayerName);
243 37 : const char *table = pszLayerName;
244 37 : char *topic = ExtractTopic(pszLayerName);
245 37 : if (nLayers)
246 16 : VSIFPrintfL(fpTransfer, "ETAB\n");
247 37 : if (topic)
248 : {
249 3 : table = pszLayerName + strlen(topic) + 2; // after "__"
250 3 : if (pszTopic == nullptr || !EQUAL(topic, pszTopic))
251 : {
252 1 : if (pszTopic)
253 : {
254 1 : VSIFPrintfL(fpTransfer, "ETOP\n");
255 1 : CPLFree(pszTopic);
256 : }
257 1 : pszTopic = topic;
258 1 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
259 : }
260 : else
261 : {
262 2 : CPLFree(topic);
263 : }
264 : }
265 : else
266 : {
267 34 : if (pszTopic == nullptr)
268 0 : pszTopic = CPLStrdup("Unknown");
269 34 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
270 : }
271 37 : VSIFPrintfL(fpTransfer, "TABL %s\n", table);
272 :
273 37 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(table);
274 37 : poFeatureDefn->SetGeomType(eType);
275 : OGRILI1Layer *poLayer =
276 37 : new OGRILI1Layer(poFeatureDefn, featureDefnInfo.poGeomFieldInfos, this);
277 :
278 37 : nLayers++;
279 37 : papoLayers = static_cast<OGRILI1Layer **>(
280 37 : CPLRealloc(papoLayers, sizeof(OGRILI1Layer *) * nLayers));
281 37 : papoLayers[nLayers - 1] = poLayer;
282 :
283 74 : return poLayer;
284 : }
285 :
286 : /************************************************************************/
287 : /* TestCapability() */
288 : /************************************************************************/
289 :
290 49 : int OGRILI1DataSource::TestCapability(const char *pszCap)
291 :
292 : {
293 49 : if (EQUAL(pszCap, ODsCCreateLayer))
294 32 : return TRUE;
295 17 : else if (EQUAL(pszCap, ODsCCurveGeometries))
296 1 : return TRUE;
297 16 : else if (EQUAL(pszCap, ODsCZGeometries))
298 0 : return TRUE;
299 :
300 16 : return FALSE;
301 : }
302 :
303 : /************************************************************************/
304 : /* GetLayer() */
305 : /************************************************************************/
306 :
307 23 : OGRLayer *OGRILI1DataSource::GetLayer(int iLayer)
308 : {
309 23 : if (!poReader)
310 : {
311 0 : if (iLayer < 0 || iLayer >= nLayers)
312 0 : return nullptr;
313 0 : return papoLayers[iLayer];
314 : }
315 23 : return poReader->GetLayer(iLayer);
316 : }
317 :
318 : /************************************************************************/
319 : /* GetLayerByName() */
320 : /************************************************************************/
321 :
322 44 : OGRILI1Layer *OGRILI1DataSource::GetLayerByName(const char *pszLayerName)
323 : {
324 44 : if (!poReader)
325 : {
326 0 : return cpl::down_cast<OGRILI1Layer *>(
327 0 : GDALDataset::GetLayerByName(pszLayerName));
328 : }
329 :
330 44 : return cpl::down_cast<OGRILI1Layer *>(
331 88 : poReader->GetLayerByName(pszLayerName));
332 : }
|