Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Interlis 2 Translator
4 : * Purpose: Implements OGRILI2DataSource class.
5 : * Author: Markus Schnider, 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 "ili2reader.h"
18 :
19 : #include "ogr_ili2.h"
20 :
21 : using namespace std;
22 :
23 : /************************************************************************/
24 : /* OGRILI2DataSource() */
25 : /************************************************************************/
26 :
27 81 : OGRILI2DataSource::OGRILI2DataSource()
28 81 : : pszName(nullptr), poImdReader(new ImdReader(2)), poReader(nullptr),
29 81 : fpOutput(nullptr), nLayers(0), papoLayers(nullptr)
30 : {
31 81 : }
32 :
33 : /************************************************************************/
34 : /* ~OGRILI2DataSource() */
35 : /************************************************************************/
36 :
37 162 : OGRILI2DataSource::~OGRILI2DataSource()
38 :
39 : {
40 83 : for (int i = 0; i < nLayers; i++)
41 : {
42 2 : delete papoLayers[i];
43 : }
44 81 : CPLFree(papoLayers);
45 :
46 81 : if (fpOutput != nullptr)
47 : {
48 1 : VSIFPrintfL(fpOutput, "</%s>\n", poImdReader->mainBasketName.c_str());
49 1 : VSIFPrintfL(fpOutput, "</DATASECTION>\n");
50 1 : VSIFPrintfL(fpOutput, "</TRANSFER>\n");
51 1 : VSIFCloseL(fpOutput);
52 : }
53 :
54 81 : DestroyILI2Reader(poReader);
55 81 : delete poImdReader;
56 81 : CPLFree(pszName);
57 162 : }
58 :
59 : /************************************************************************/
60 : /* Open() */
61 : /************************************************************************/
62 :
63 61 : int OGRILI2DataSource::Open(const char *pszNewName, char **papszOpenOptionsIn,
64 : int bTestOpen)
65 :
66 : {
67 122 : CPLString osBasename;
68 122 : CPLString osModelFilename;
69 :
70 61 : if (CSLFetchNameValue(papszOpenOptionsIn, "MODEL") != nullptr)
71 : {
72 0 : osBasename = pszNewName;
73 0 : osModelFilename = CSLFetchNameValue(papszOpenOptionsIn, "MODEL");
74 : }
75 : else
76 : {
77 61 : char **filenames = CSLTokenizeString2(pszNewName, ",", 0);
78 61 : int nCount = CSLCount(filenames);
79 61 : if (nCount == 0)
80 : {
81 0 : CSLDestroy(filenames);
82 0 : return FALSE;
83 : }
84 61 : osBasename = filenames[0];
85 :
86 61 : if (nCount > 1)
87 57 : osModelFilename = filenames[1];
88 :
89 61 : CSLDestroy(filenames);
90 : }
91 :
92 61 : pszName = CPLStrdup(osBasename);
93 :
94 : /* -------------------------------------------------------------------- */
95 : /* Open the source file. */
96 : /* -------------------------------------------------------------------- */
97 61 : VSILFILE *fp = VSIFOpenL(pszName, "r");
98 61 : if (fp == nullptr)
99 : {
100 57 : if (!bTestOpen)
101 0 : CPLError(CE_Failure, CPLE_OpenFailed,
102 : "Failed to open ILI2 file `%s'.", pszNewName);
103 :
104 57 : return FALSE;
105 : }
106 :
107 : /* -------------------------------------------------------------------- */
108 : /* If we aren't sure it is ILI2, load a header chunk and check */
109 : /* for signs it is ILI2 */
110 : /* -------------------------------------------------------------------- */
111 : char szHeader[1000];
112 4 : if (bTestOpen)
113 : {
114 : int nLen =
115 4 : static_cast<int>(VSIFReadL(szHeader, 1, sizeof(szHeader), fp));
116 4 : if (nLen == sizeof(szHeader))
117 4 : szHeader[sizeof(szHeader) - 1] = '\0';
118 : else
119 0 : szHeader[nLen] = '\0';
120 :
121 4 : if (szHeader[0] != '<' ||
122 4 : strstr(szHeader, "interlis.ch/INTERLIS2") == nullptr)
123 : {
124 : // "www.interlis.ch/INTERLIS2.3"
125 0 : VSIFCloseL(fp);
126 0 : return FALSE;
127 : }
128 : }
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* We assume now that it is ILI2. Close and instantiate a */
132 : /* ILI2Reader on it. */
133 : /* -------------------------------------------------------------------- */
134 4 : VSIFCloseL(fp);
135 :
136 4 : poReader = CreateILI2Reader();
137 4 : if (poReader == nullptr)
138 : {
139 0 : CPLError(CE_Failure, CPLE_AppDefined,
140 : "File %s appears to be ILI2 but the ILI2 reader cannot\n"
141 : "be instantiated, likely because Xerces support was not\n"
142 : "configured in.",
143 : pszNewName);
144 0 : return FALSE;
145 : }
146 :
147 4 : if (!osModelFilename.empty())
148 3 : poReader->ReadModel(this, poImdReader, osModelFilename);
149 :
150 4 : poReader->SetSourceFile(pszName);
151 :
152 4 : poReader->SaveClasses(pszName);
153 :
154 4 : listLayer = poReader->GetLayers();
155 4 : list<OGRLayer *>::const_iterator layerIt;
156 48 : for (layerIt = listLayer.begin(); layerIt != listLayer.end(); ++layerIt)
157 : {
158 44 : (*layerIt)->ResetReading();
159 : }
160 :
161 4 : return TRUE;
162 : }
163 :
164 : /************************************************************************/
165 : /* Create() */
166 : /************************************************************************/
167 :
168 20 : int OGRILI2DataSource::Create(const char *pszFilename,
169 : CPL_UNUSED char **papszOptions)
170 :
171 : {
172 20 : char **filenames = CSLTokenizeString2(pszFilename, ",", 0);
173 20 : pszName = CPLStrdup(filenames[0]);
174 : const char *pszModelFilename =
175 20 : (CSLCount(filenames) > 1) ? filenames[1] : nullptr;
176 :
177 20 : if (pszModelFilename == nullptr)
178 : {
179 18 : CPLError(
180 : CE_Failure, CPLE_AppDefined,
181 : "ILI2 Create(): model file not specified in destination filename.");
182 18 : CSLDestroy(filenames);
183 18 : return FALSE;
184 : }
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Create the output file. */
188 : /* -------------------------------------------------------------------- */
189 :
190 2 : if (strcmp(pszName, "/vsistdout/") == 0 ||
191 2 : STARTS_WITH(pszName, "/vsigzip/"))
192 : {
193 0 : fpOutput = VSIFOpenL(pszName, "wb");
194 : }
195 2 : else if (STARTS_WITH(pszName, "/vsizip/"))
196 : {
197 0 : if (EQUAL(CPLGetExtension(pszName), "zip"))
198 : {
199 : char *pszNewName =
200 0 : CPLStrdup(CPLFormFilename(pszName, "out.xtf", nullptr));
201 0 : CPLFree(pszName);
202 0 : pszName = pszNewName;
203 : }
204 :
205 0 : fpOutput = VSIFOpenL(pszName, "wb");
206 : }
207 : else
208 2 : fpOutput = VSIFOpenL(pszName, "wb+");
209 2 : if (fpOutput == nullptr)
210 : {
211 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create XTF file %s.",
212 : pszName);
213 1 : CSLDestroy(filenames);
214 1 : return FALSE;
215 : }
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Parse model */
219 : /* -------------------------------------------------------------------- */
220 1 : poImdReader->ReadModel(pszModelFilename);
221 :
222 : /* -------------------------------------------------------------------- */
223 : /* Write headers */
224 : /* -------------------------------------------------------------------- */
225 1 : VSIFPrintfL(fpOutput, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
226 1 : VSIFPrintfL(fpOutput,
227 : "<TRANSFER xmlns=\"http://www.interlis.ch/INTERLIS2.3\">\n");
228 1 : VSIFPrintfL(fpOutput,
229 : "<HEADERSECTION SENDER=\"OGR/GDAL %s\" VERSION=\"2.3\">\n",
230 : GDALVersionInfo("RELEASE_NAME"));
231 1 : VSIFPrintfL(fpOutput, "<MODELS>\n");
232 3 : for (IliModelInfos::const_iterator it = poImdReader->modelInfos.begin();
233 5 : it != poImdReader->modelInfos.end(); ++it)
234 : {
235 6 : VSIFPrintfL(fpOutput,
236 : "<MODEL NAME=\"%s\" URI=\"%s\" VERSION=\"%s\"/>\n",
237 6 : it->name.c_str(), it->uri.c_str(), it->version.c_str());
238 : }
239 1 : VSIFPrintfL(fpOutput, "</MODELS>\n");
240 1 : VSIFPrintfL(fpOutput, "</HEADERSECTION>\n");
241 1 : VSIFPrintfL(fpOutput, "<DATASECTION>\n");
242 1 : const char *basketName = poImdReader->mainBasketName.c_str();
243 1 : VSIFPrintfL(fpOutput, "<%s BID=\"%s\">\n", basketName, basketName);
244 :
245 1 : CSLDestroy(filenames);
246 1 : return TRUE;
247 : }
248 :
249 : /************************************************************************/
250 : /* ICreateLayer() */
251 : /************************************************************************/
252 :
253 : OGRLayer *
254 2 : OGRILI2DataSource::ICreateLayer(const char *pszLayerName,
255 : const OGRGeomFieldDefn *poGeomFieldDefn,
256 : CSLConstList /*papszOptions*/)
257 : {
258 2 : if (fpOutput == nullptr)
259 0 : return nullptr;
260 :
261 2 : const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
262 :
263 : FeatureDefnInfo featureDefnInfo =
264 2 : poImdReader->GetFeatureDefnInfo(pszLayerName);
265 2 : OGRFeatureDefn *poFeatureDefn = featureDefnInfo.GetTableDefnRef();
266 2 : if (poFeatureDefn == nullptr)
267 : {
268 0 : CPLError(CE_Warning, CPLE_AppDefined,
269 : "Layer '%s' not found in model definition. "
270 : "Creating adhoc layer",
271 : pszLayerName);
272 0 : poFeatureDefn = new OGRFeatureDefn(pszLayerName);
273 0 : poFeatureDefn->SetGeomType(eType);
274 : }
275 : OGRILI2Layer *poLayer =
276 2 : new OGRILI2Layer(poFeatureDefn, featureDefnInfo.poGeomFieldInfos, this);
277 :
278 2 : nLayers++;
279 2 : papoLayers = static_cast<OGRILI2Layer **>(
280 2 : CPLRealloc(papoLayers, sizeof(OGRILI2Layer *) * nLayers));
281 2 : papoLayers[nLayers - 1] = poLayer;
282 :
283 2 : return poLayer;
284 : }
285 :
286 : /************************************************************************/
287 : /* TestCapability() */
288 : /************************************************************************/
289 :
290 0 : int OGRILI2DataSource::TestCapability(const char *pszCap)
291 :
292 : {
293 0 : if (EQUAL(pszCap, ODsCCreateLayer))
294 0 : return TRUE;
295 0 : else if (EQUAL(pszCap, ODsCCurveGeometries))
296 0 : return TRUE;
297 0 : else if (EQUAL(pszCap, ODsCZGeometries))
298 0 : return TRUE;
299 :
300 0 : return FALSE;
301 : }
302 :
303 : /************************************************************************/
304 : /* GetLayer() */
305 : /************************************************************************/
306 :
307 81 : OGRLayer *OGRILI2DataSource::GetLayer(int iLayer)
308 :
309 : {
310 81 : list<OGRLayer *>::const_iterator layerIt = listLayer.begin();
311 81 : int i = 0;
312 730 : while (i < iLayer && layerIt != listLayer.end())
313 : {
314 649 : ++i;
315 649 : ++layerIt;
316 : }
317 :
318 81 : if (i == iLayer && layerIt != listLayer.end())
319 : {
320 81 : OGRILI2Layer *tmpLayer = reinterpret_cast<OGRILI2Layer *>(*layerIt);
321 81 : return tmpLayer;
322 : }
323 :
324 0 : return nullptr;
325 : }
|