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