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 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_conv.h"
31 : #include "cpl_string.h"
32 :
33 : #include "ili1reader.h"
34 : #include "ogr_ili1.h"
35 :
36 : #include <string>
37 :
38 : /************************************************************************/
39 : /* OGRILI1DataSource() */
40 : /************************************************************************/
41 :
42 130 : OGRILI1DataSource::OGRILI1DataSource()
43 130 : : pszName(nullptr), poImdReader(new ImdReader(1)), poReader(nullptr),
44 130 : fpTransfer(nullptr), pszTopic(nullptr), nLayers(0), papoLayers(nullptr)
45 : {
46 130 : }
47 :
48 : /************************************************************************/
49 : /* ~OGRILI1DataSource() */
50 : /************************************************************************/
51 :
52 260 : OGRILI1DataSource::~OGRILI1DataSource()
53 :
54 : {
55 167 : for (int i = 0; i < nLayers; i++)
56 : {
57 37 : delete papoLayers[i];
58 : }
59 130 : CPLFree(papoLayers);
60 :
61 130 : CPLFree(pszName);
62 130 : CPLFree(pszTopic);
63 130 : DestroyILI1Reader(poReader);
64 130 : delete poImdReader;
65 130 : if (fpTransfer)
66 : {
67 21 : VSIFPrintfL(fpTransfer, "ETAB\n");
68 21 : VSIFPrintfL(fpTransfer, "ETOP\n");
69 21 : VSIFPrintfL(fpTransfer, "EMOD\n");
70 21 : VSIFPrintfL(fpTransfer, "ENDE\n");
71 21 : VSIFCloseL(fpTransfer);
72 : }
73 260 : }
74 :
75 : /************************************************************************/
76 : /* Open() */
77 : /************************************************************************/
78 :
79 108 : int OGRILI1DataSource::Open(const char *pszNewName, char **papszOpenOptionsIn,
80 : int bTestOpen)
81 :
82 : {
83 108 : if (strlen(pszNewName) == 0)
84 : {
85 0 : return FALSE;
86 : }
87 :
88 216 : std::string osBasename;
89 216 : std::string osModelFilename;
90 108 : if (CSLFetchNameValue(papszOpenOptionsIn, "MODEL") != nullptr)
91 : {
92 0 : osBasename = pszNewName;
93 0 : osModelFilename = CSLFetchNameValue(papszOpenOptionsIn, "MODEL");
94 : }
95 : else
96 : {
97 108 : char **filenames = CSLTokenizeString2(pszNewName, ",", 0);
98 108 : int nCount = CSLCount(filenames);
99 108 : if (nCount == 0)
100 : {
101 0 : CSLDestroy(filenames);
102 0 : return FALSE;
103 : }
104 108 : osBasename = filenames[0];
105 :
106 108 : if (nCount > 1)
107 73 : osModelFilename = filenames[1];
108 :
109 108 : CSLDestroy(filenames);
110 : }
111 :
112 : /* -------------------------------------------------------------------- */
113 : /* Open the source file. */
114 : /* -------------------------------------------------------------------- */
115 108 : VSILFILE *fp = VSIFOpenL(osBasename.c_str(), "r");
116 108 : if (fp == nullptr)
117 : {
118 57 : if (!bTestOpen)
119 0 : CPLError(CE_Failure, CPLE_OpenFailed,
120 : "Failed to open ILI1 file `%s'.", pszNewName);
121 :
122 57 : return FALSE;
123 : }
124 :
125 : /* -------------------------------------------------------------------- */
126 : /* If we aren't sure it is ILI1, load a header chunk and check */
127 : /* for signs it is ILI1 */
128 : /* -------------------------------------------------------------------- */
129 : char szHeader[1000];
130 :
131 51 : if (bTestOpen)
132 : {
133 51 : int nLen = (int)VSIFReadL(szHeader, 1, sizeof(szHeader), fp);
134 51 : if (nLen == sizeof(szHeader))
135 5 : szHeader[sizeof(szHeader) - 1] = '\0';
136 : else
137 46 : szHeader[nLen] = '\0';
138 :
139 51 : if (strstr(szHeader, "SCNT") == nullptr)
140 : {
141 3 : VSIFCloseL(fp);
142 3 : return FALSE;
143 : }
144 : }
145 :
146 : /* -------------------------------------------------------------------- */
147 : /* We assume now that it is ILI1. Close and instantiate a */
148 : /* ILI1Reader on it. */
149 : /* -------------------------------------------------------------------- */
150 48 : VSIFCloseL(fp);
151 :
152 48 : poReader = CreateILI1Reader();
153 48 : if (poReader == nullptr)
154 : {
155 0 : CPLError(CE_Failure, CPLE_AppDefined,
156 : "File %s appears to be ILI1 but the ILI1 reader cannot\n"
157 : "be instantiated, likely because Xerces support was not\n"
158 : "configured in.",
159 : pszNewName);
160 0 : return FALSE;
161 : }
162 :
163 48 : poReader->OpenFile(osBasename.c_str());
164 :
165 48 : pszName = CPLStrdup(osBasename.c_str());
166 :
167 48 : if (osModelFilename.length() > 0)
168 16 : poReader->ReadModel(poImdReader, osModelFilename.c_str(), this);
169 :
170 48 : int bResetConfigOption = FALSE;
171 48 : if (EQUAL(CPLGetConfigOption("OGR_ARC_STEPSIZE", ""), ""))
172 : {
173 48 : bResetConfigOption = TRUE;
174 48 : CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", "0.96");
175 : }
176 :
177 : // Parse model and read data - without surface join and area polygonizing.
178 48 : poReader->ReadFeatures();
179 :
180 48 : if (bResetConfigOption)
181 48 : CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", nullptr);
182 :
183 48 : return TRUE;
184 : }
185 :
186 : /************************************************************************/
187 : /* Create() */
188 : /************************************************************************/
189 :
190 22 : int OGRILI1DataSource::Create(const char *pszFilename,
191 : char ** /* papszOptions */)
192 : {
193 22 : char **filenames = CSLTokenizeString2(pszFilename, ",", 0);
194 :
195 44 : std::string osBasename = filenames[0];
196 :
197 44 : std::string osModelFilename;
198 22 : if (CSLCount(filenames) > 1)
199 3 : osModelFilename = filenames[1];
200 :
201 22 : CSLDestroy(filenames);
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Create the empty file. */
205 : /* -------------------------------------------------------------------- */
206 22 : fpTransfer = VSIFOpenL(osBasename.c_str(), "w+b");
207 :
208 22 : if (fpTransfer == nullptr)
209 : {
210 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s:\n%s",
211 1 : osBasename.c_str(), VSIStrerror(errno));
212 :
213 1 : return FALSE;
214 : }
215 :
216 : /* -------------------------------------------------------------------- */
217 : /* Parse model */
218 : /* -------------------------------------------------------------------- */
219 21 : if (osModelFilename.length() == 0)
220 : {
221 18 : CPLError(CE_Warning, CPLE_AppDefined,
222 : "Creating Interlis transfer file without model definition.");
223 : }
224 : else
225 : {
226 3 : poImdReader->ReadModel(osModelFilename.c_str());
227 : }
228 :
229 21 : pszTopic = CPLStrdup(poImdReader->mainTopicName.c_str());
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Write headers */
233 : /* -------------------------------------------------------------------- */
234 21 : VSIFPrintfL(fpTransfer, "SCNT\n");
235 21 : VSIFPrintfL(fpTransfer, "OGR/GDAL %s, INTERLIS Driver\n",
236 : GDALVersionInfo("RELEASE_NAME"));
237 21 : VSIFPrintfL(fpTransfer, "////\n");
238 21 : VSIFPrintfL(fpTransfer, "MTID INTERLIS1\n");
239 21 : const char *modelname = poImdReader->mainModelName.c_str();
240 21 : VSIFPrintfL(fpTransfer, "MODL %s\n", modelname);
241 :
242 21 : return TRUE;
243 : }
244 :
245 37 : static char *ExtractTopic(const char *pszLayerName)
246 : {
247 37 : const char *table = strchr(pszLayerName, '_');
248 37 : while (table && table[1] != '_')
249 0 : table = strchr(table + 1, '_');
250 40 : return (table) ? CPLScanString(pszLayerName,
251 3 : static_cast<int>(table - pszLayerName),
252 : FALSE, FALSE)
253 37 : : nullptr;
254 : }
255 :
256 : /************************************************************************/
257 : /* ICreateLayer() */
258 : /************************************************************************/
259 :
260 : OGRLayer *
261 37 : OGRILI1DataSource::ICreateLayer(const char *pszLayerName,
262 : const OGRGeomFieldDefn *poGeomFieldDefn,
263 : CSLConstList /*papszOptions*/)
264 : {
265 37 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
266 :
267 : FeatureDefnInfo featureDefnInfo =
268 37 : poImdReader->GetFeatureDefnInfo(pszLayerName);
269 37 : const char *table = pszLayerName;
270 37 : char *topic = ExtractTopic(pszLayerName);
271 37 : if (nLayers)
272 16 : VSIFPrintfL(fpTransfer, "ETAB\n");
273 37 : if (topic)
274 : {
275 3 : table = pszLayerName + strlen(topic) + 2; // after "__"
276 3 : if (pszTopic == nullptr || !EQUAL(topic, pszTopic))
277 : {
278 1 : if (pszTopic)
279 : {
280 1 : VSIFPrintfL(fpTransfer, "ETOP\n");
281 1 : CPLFree(pszTopic);
282 : }
283 1 : pszTopic = topic;
284 1 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
285 : }
286 : else
287 : {
288 2 : CPLFree(topic);
289 : }
290 : }
291 : else
292 : {
293 34 : if (pszTopic == nullptr)
294 0 : pszTopic = CPLStrdup("Unknown");
295 34 : VSIFPrintfL(fpTransfer, "TOPI %s\n", pszTopic);
296 : }
297 37 : VSIFPrintfL(fpTransfer, "TABL %s\n", table);
298 :
299 37 : OGRFeatureDefn *poFeatureDefn = new OGRFeatureDefn(table);
300 37 : poFeatureDefn->SetGeomType(eType);
301 : OGRILI1Layer *poLayer =
302 37 : new OGRILI1Layer(poFeatureDefn, featureDefnInfo.poGeomFieldInfos, this);
303 :
304 37 : nLayers++;
305 37 : papoLayers = static_cast<OGRILI1Layer **>(
306 37 : CPLRealloc(papoLayers, sizeof(OGRILI1Layer *) * nLayers));
307 37 : papoLayers[nLayers - 1] = poLayer;
308 :
309 74 : return poLayer;
310 : }
311 :
312 : /************************************************************************/
313 : /* TestCapability() */
314 : /************************************************************************/
315 :
316 49 : int OGRILI1DataSource::TestCapability(const char *pszCap)
317 :
318 : {
319 49 : if (EQUAL(pszCap, ODsCCreateLayer))
320 32 : return TRUE;
321 17 : else if (EQUAL(pszCap, ODsCCurveGeometries))
322 1 : return TRUE;
323 16 : else if (EQUAL(pszCap, ODsCZGeometries))
324 0 : return TRUE;
325 :
326 16 : return FALSE;
327 : }
328 :
329 : /************************************************************************/
330 : /* GetLayer() */
331 : /************************************************************************/
332 :
333 23 : OGRLayer *OGRILI1DataSource::GetLayer(int iLayer)
334 : {
335 23 : if (!poReader)
336 : {
337 0 : if (iLayer < 0 || iLayer >= nLayers)
338 0 : return nullptr;
339 0 : return papoLayers[iLayer];
340 : }
341 23 : return poReader->GetLayer(iLayer);
342 : }
343 :
344 : /************************************************************************/
345 : /* GetLayerByName() */
346 : /************************************************************************/
347 :
348 44 : OGRILI1Layer *OGRILI1DataSource::GetLayerByName(const char *pszLayerName)
349 : {
350 44 : if (!poReader)
351 : {
352 : return reinterpret_cast<OGRILI1Layer *>(
353 0 : OGRDataSource::GetLayerByName(pszLayerName));
354 : }
355 :
356 : return reinterpret_cast<OGRILI1Layer *>(
357 44 : poReader->GetLayerByName(pszLayerName));
358 : }
|