Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OGR
4 : * Purpose: Implements OGRNASDataSource class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2010-2013, 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 : #include "ogr_nas.h"
33 :
34 : static const char *const apszURNNames[] = {
35 : "DE_DHDN_3GK2_*", "EPSG:31466", "DE_DHDN_3GK3_*", "EPSG:31467",
36 : "ETRS89_UTM32", "EPSG:25832", "ETRS89_UTM33", "EPSG:25833",
37 : nullptr, nullptr};
38 :
39 : /************************************************************************/
40 : /* OGRNASDataSource() */
41 : /************************************************************************/
42 :
43 3 : OGRNASDataSource::OGRNASDataSource()
44 3 : : papoLayers(nullptr), nLayers(0), pszName(nullptr), poReader(nullptr)
45 : {
46 3 : }
47 :
48 : /************************************************************************/
49 : /* ~OGRNASDataSource() */
50 : /************************************************************************/
51 :
52 6 : OGRNASDataSource::~OGRNASDataSource()
53 :
54 : {
55 3 : CPLFree(pszName);
56 :
57 6 : for (int i = 0; i < nLayers; i++)
58 3 : delete papoLayers[i];
59 :
60 3 : CPLFree(papoLayers);
61 :
62 3 : if (poReader)
63 3 : delete poReader;
64 6 : }
65 :
66 : /************************************************************************/
67 : /* Open() */
68 : /************************************************************************/
69 :
70 3 : int OGRNASDataSource::Open(const char *pszNewName)
71 :
72 : {
73 3 : poReader = CreateNASReader();
74 3 : if (poReader == nullptr)
75 : {
76 0 : CPLError(CE_Failure, CPLE_AppDefined,
77 : "File %s appears to be NAS but the NAS reader cannot\n"
78 : "be instantiated, likely because Xerces support was not\n"
79 : "configured in.",
80 : pszNewName);
81 0 : return FALSE;
82 : }
83 :
84 3 : poReader->SetSourceFile(pszNewName);
85 :
86 3 : pszName = CPLStrdup(pszNewName);
87 :
88 3 : bool bHaveSchema = false;
89 3 : bool bHaveTemplate = false;
90 : const char *pszGFSFilename;
91 : VSIStatBufL sGFSStatBuf;
92 :
93 : // Is some NAS Feature Schema (.gfs) TEMPLATE required?
94 3 : const char *pszNASTemplateName = CPLGetConfigOption("NAS_GFS_TEMPLATE", "");
95 3 : if (!EQUAL(pszNASTemplateName, ""))
96 : {
97 : // Load the TEMPLATE.
98 0 : if (!poReader->LoadClasses(pszNASTemplateName))
99 : {
100 0 : CPLError(CE_Failure, CPLE_AppDefined,
101 : "NAS schema %s could not be loaded\n", pszNASTemplateName);
102 0 : return FALSE;
103 : }
104 :
105 0 : bHaveTemplate = true;
106 :
107 0 : CPLDebug("NAS", "Schema loaded.");
108 : }
109 : else
110 : {
111 : /* --------------------------------------------------------------------
112 : */
113 : /* Can we find a NAS Feature Schema (.gfs) for the input file? */
114 : /* --------------------------------------------------------------------
115 : */
116 3 : pszGFSFilename = CPLResetExtension(pszNewName, "gfs");
117 3 : if (VSIStatL(pszGFSFilename, &sGFSStatBuf) == 0)
118 : {
119 : VSIStatBufL sNASStatBuf;
120 0 : if (VSIStatL(pszNewName, &sNASStatBuf) == 0 &&
121 0 : sNASStatBuf.st_mtime > sGFSStatBuf.st_mtime)
122 : {
123 0 : CPLDebug("NAS",
124 : "Found %s but ignoring because it appears "
125 : "be older than the associated NAS file.",
126 : pszGFSFilename);
127 : }
128 : else
129 : {
130 0 : bHaveSchema = poReader->LoadClasses(pszGFSFilename);
131 : }
132 : }
133 :
134 3 : if (!bHaveSchema)
135 : {
136 3 : CPLError(CE_Failure, CPLE_AppDefined,
137 : "No schema information loaded");
138 : }
139 : }
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Force a first pass to establish the schema. The loaded schema */
143 : /* if any will be cleaned from any unavailable classes. */
144 : /* -------------------------------------------------------------------- */
145 3 : CPLErrorReset();
146 4 : if (!bHaveSchema && !poReader->PrescanForSchema(TRUE) &&
147 1 : CPLGetLastErrorType() == CE_Failure)
148 : {
149 : // Assume an error has been reported.
150 0 : return FALSE;
151 : }
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Save the schema file if possible. Do not make a fuss if we */
155 : /* cannot. It could be read-only directory or something. */
156 : /* -------------------------------------------------------------------- */
157 3 : if (!bHaveTemplate && !bHaveSchema && poReader->GetClassCount() > 0 &&
158 2 : !STARTS_WITH_CI(pszNewName, "/vsitar/") &&
159 2 : !STARTS_WITH_CI(pszNewName, "/vsizip/") &&
160 2 : !STARTS_WITH_CI(pszNewName, "/vsigzip/vsi") &&
161 2 : !STARTS_WITH_CI(pszNewName, "/vsigzip//vsi") &&
162 8 : !STARTS_WITH_CI(pszNewName, "/vsicurl/") &&
163 2 : !STARTS_WITH_CI(pszNewName, "/vsicurl_streaming/"))
164 : {
165 2 : VSILFILE *fp = nullptr;
166 :
167 2 : pszGFSFilename = CPLResetExtension(pszNewName, "gfs");
168 4 : if (VSIStatL(pszGFSFilename, &sGFSStatBuf) != 0 &&
169 2 : (fp = VSIFOpenL(pszGFSFilename, "wt")) != nullptr)
170 : {
171 2 : VSIFCloseL(fp);
172 2 : poReader->SaveClasses(pszGFSFilename);
173 : }
174 : else
175 : {
176 0 : CPLDebug("NAS",
177 : "Not saving %s. File already exists or can't be created.",
178 : pszGFSFilename);
179 : }
180 : }
181 :
182 : /* -------------------------------------------------------------------- */
183 : /* Translate the GMLFeatureClasses into layers. */
184 : /* -------------------------------------------------------------------- */
185 6 : papoLayers = (OGRLayer **)CPLCalloc(sizeof(OGRNASLayer *),
186 3 : poReader->GetClassCount() + 1);
187 3 : nLayers = 0;
188 :
189 6 : while (nLayers < poReader->GetClassCount())
190 : {
191 3 : papoLayers[nLayers] = TranslateNASSchema(poReader->GetClass(nLayers));
192 3 : nLayers++;
193 : }
194 :
195 3 : return TRUE;
196 : }
197 :
198 : /************************************************************************/
199 : /* TranslateNASSchema() */
200 : /************************************************************************/
201 :
202 3 : OGRNASLayer *OGRNASDataSource::TranslateNASSchema(GMLFeatureClass *poClass)
203 :
204 : {
205 : /* -------------------------------------------------------------------- */
206 : /* Translate SRS. */
207 : /* -------------------------------------------------------------------- */
208 3 : const char *pszSRSName = poClass->GetSRSName();
209 3 : OGRSpatialReference *poSRS = nullptr;
210 3 : if (pszSRSName)
211 : {
212 0 : const char *pszHandle = strrchr(pszSRSName, ':');
213 0 : if (pszHandle != nullptr)
214 : {
215 0 : pszHandle += 1;
216 :
217 0 : poSRS = new OGRSpatialReference();
218 0 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
219 :
220 0 : for (int i = 0; apszURNNames[i * 2 + 0] != nullptr; i++)
221 : {
222 0 : const char *pszTarget = apszURNNames[i * 2 + 0];
223 0 : const int nTLen = static_cast<int>(strlen(pszTarget));
224 :
225 : // Are we just looking for a prefix match?
226 0 : if (pszTarget[nTLen - 1] == '*')
227 : {
228 0 : if (EQUALN(pszTarget, pszHandle, nTLen - 1))
229 0 : pszSRSName = apszURNNames[i * 2 + 1];
230 : }
231 : else
232 : {
233 0 : if (EQUAL(pszTarget, pszHandle))
234 0 : pszSRSName = apszURNNames[i * 2 + 1];
235 : }
236 : }
237 :
238 0 : if (poSRS->SetFromUserInput(
239 : pszSRSName,
240 : OGRSpatialReference::
241 0 : SET_FROM_USER_INPUT_LIMITATIONS_get()) != OGRERR_NONE)
242 : {
243 0 : CPLDebug("NAS", "Failed to translate srsName='%s'", pszSRSName);
244 0 : delete poSRS;
245 0 : poSRS = nullptr;
246 : }
247 : }
248 : }
249 :
250 : /* -------------------------------------------------------------------- */
251 : /* Create an empty layer. */
252 : /* -------------------------------------------------------------------- */
253 3 : OGRNASLayer *poLayer = new OGRNASLayer(poClass->GetName(), this);
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Added attributes (properties). */
257 : /* -------------------------------------------------------------------- */
258 45 : for (int iField = 0; iField < poClass->GetPropertyCount(); iField++)
259 : {
260 42 : GMLPropertyDefn *poProperty = poClass->GetProperty(iField);
261 : OGRFieldType eFType;
262 :
263 42 : if (poProperty->GetType() == GMLPT_Untyped)
264 2 : eFType = OFTString;
265 40 : else if (poProperty->GetType() == GMLPT_String)
266 22 : eFType = OFTString;
267 18 : else if (poProperty->GetType() == GMLPT_Integer)
268 11 : eFType = OFTInteger;
269 7 : else if (poProperty->GetType() == GMLPT_Real)
270 1 : eFType = OFTReal;
271 6 : else if (poProperty->GetType() == GMLPT_StringList)
272 4 : eFType = OFTStringList;
273 2 : else if (poProperty->GetType() == GMLPT_IntegerList)
274 0 : eFType = OFTIntegerList;
275 2 : else if (poProperty->GetType() == GMLPT_RealList)
276 0 : eFType = OFTRealList;
277 : else
278 2 : eFType = OFTString;
279 :
280 84 : OGRFieldDefn oField(poProperty->GetName(), eFType);
281 42 : if (STARTS_WITH_CI(oField.GetNameRef(), "ogr:"))
282 0 : oField.SetName(poProperty->GetName() + 4);
283 42 : if (poProperty->GetWidth() > 0)
284 18 : oField.SetWidth(poProperty->GetWidth());
285 :
286 42 : poLayer->GetLayerDefn()->AddFieldDefn(&oField);
287 : }
288 :
289 4 : for (int iField = 0; iField < poClass->GetGeometryPropertyCount(); iField++)
290 : {
291 : GMLGeometryPropertyDefn *poProperty =
292 1 : poClass->GetGeometryProperty(iField);
293 : OGRGeomFieldDefn oField(poProperty->GetName(),
294 2 : (OGRwkbGeometryType)poProperty->GetType());
295 2 : if (poClass->GetGeometryPropertyCount() == 1 &&
296 1 : poClass->GetFeatureCount() == 0)
297 : {
298 0 : oField.SetType(wkbUnknown);
299 : }
300 :
301 1 : oField.SetSpatialRef(poSRS);
302 1 : oField.SetNullable(poProperty->IsNullable());
303 1 : poLayer->GetLayerDefn()->AddGeomFieldDefn(&oField);
304 : }
305 :
306 3 : if (poSRS)
307 0 : poSRS->Dereference();
308 :
309 3 : return poLayer;
310 : }
311 :
312 : /************************************************************************/
313 : /* GetLayer() */
314 : /************************************************************************/
315 :
316 4 : OGRLayer *OGRNASDataSource::GetLayer(int iLayer)
317 :
318 : {
319 4 : if (iLayer < 0 || iLayer >= nLayers)
320 0 : return nullptr;
321 :
322 4 : return papoLayers[iLayer];
323 : }
324 :
325 : /************************************************************************/
326 : /* TestCapability() */
327 : /************************************************************************/
328 :
329 0 : int OGRNASDataSource::TestCapability(const char * /* pszCap */)
330 : {
331 0 : return FALSE;
332 : }
|