1 : /******************************************************************************
2 : * $Id: ogrgmldatasource.cpp 12743 2007-11-13 13:59:37Z dron $
3 : *
4 : * Project: OGR
5 : * Purpose: Implements OGRNASDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.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 "ogr_nas.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrgmldatasource.cpp 12743 2007-11-13 13:59:37Z dron $");
35 :
36 : /************************************************************************/
37 : /* OGRNASDataSource() */
38 : /************************************************************************/
39 :
40 118 : OGRNASDataSource::OGRNASDataSource()
41 :
42 : {
43 118 : pszName = NULL;
44 118 : papoLayers = NULL;
45 118 : nLayers = 0;
46 :
47 118 : poReader = NULL;
48 118 : }
49 :
50 : /************************************************************************/
51 : /* ~OGRNASDataSource() */
52 : /************************************************************************/
53 :
54 118 : OGRNASDataSource::~OGRNASDataSource()
55 :
56 : {
57 118 : CPLFree( pszName );
58 :
59 159 : for( int i = 0; i < nLayers; i++ )
60 41 : delete papoLayers[i];
61 :
62 118 : CPLFree( papoLayers );
63 :
64 118 : if( poReader )
65 1 : delete poReader;
66 118 : }
67 :
68 : /************************************************************************/
69 : /* Open() */
70 : /************************************************************************/
71 :
72 118 : int OGRNASDataSource::Open( const char * pszNewName, int bTestOpen )
73 :
74 : {
75 : FILE *fp;
76 : char szHeader[8192];
77 :
78 : /* -------------------------------------------------------------------- */
79 : /* Open the source file. */
80 : /* -------------------------------------------------------------------- */
81 118 : fp = VSIFOpen( pszNewName, "r" );
82 118 : if( fp == NULL )
83 : {
84 11 : if( !bTestOpen )
85 : CPLError( CE_Failure, CPLE_OpenFailed,
86 : "Failed to open NAS file `%s'.",
87 0 : pszNewName );
88 :
89 11 : return FALSE;
90 : }
91 :
92 : /* -------------------------------------------------------------------- */
93 : /* If we aren't sure it is NAS, load a header chunk and check */
94 : /* for signs it is NAS */
95 : /* -------------------------------------------------------------------- */
96 107 : if( bTestOpen )
97 : {
98 107 : size_t nRead = VSIFRead( szHeader, 1, sizeof(szHeader), fp );
99 107 : if (nRead <= 0)
100 : {
101 1 : VSIFClose( fp );
102 1 : return FALSE;
103 : }
104 106 : szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Check for a UTF-8 BOM and skip if found */
108 : /* */
109 : /* TODO: BOM is variable-lenght parameter and depends on encoding. */
110 : /* Add BOM detection for other encodings. */
111 : /* -------------------------------------------------------------------- */
112 :
113 : // Used to skip to actual beginning of XML data
114 106 : char* szPtr = szHeader;
115 :
116 106 : if( ( (unsigned char)szHeader[0] == 0xEF )
117 : && ( (unsigned char)szHeader[1] == 0xBB )
118 : && ( (unsigned char)szHeader[2] == 0xBF) )
119 : {
120 1 : szPtr += 3;
121 : }
122 :
123 : /* -------------------------------------------------------------------- */
124 : /* Here, we expect the opening chevrons of NAS tree root element */
125 : /* -------------------------------------------------------------------- */
126 106 : if( szPtr[0] != '<'
127 : || strstr(szPtr,"opengis.net/gml") == NULL
128 : || strstr(szPtr,"NAS") == NULL )
129 : {
130 105 : VSIFClose( fp );
131 105 : return FALSE;
132 : }
133 : }
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* We assume now that it is NAS. Close and instantiate a */
137 : /* NASReader on it. */
138 : /* -------------------------------------------------------------------- */
139 1 : VSIFClose( fp );
140 :
141 1 : poReader = CreateNASReader();
142 1 : if( poReader == NULL )
143 : {
144 : CPLError( CE_Failure, CPLE_AppDefined,
145 : "File %s appears to be NAS but the NAS reader can't\n"
146 : "be instantiated, likely because Xerces support wasn't\n"
147 : "configured in.",
148 0 : pszNewName );
149 0 : return FALSE;
150 : }
151 :
152 1 : poReader->SetSourceFile( pszNewName );
153 :
154 1 : pszName = CPLStrdup( pszNewName );
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* Can we find a NAS Feature Schema (.gfs) for the input file? */
158 : /* -------------------------------------------------------------------- */
159 : const char *pszGFSFilename;
160 : VSIStatBuf sGFSStatBuf, sNASStatBuf;
161 1 : int bHaveSchema = FALSE;
162 :
163 1 : pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
164 1 : if( CPLStat( pszGFSFilename, &sGFSStatBuf ) == 0 )
165 : {
166 1 : CPLStat( pszNewName, &sNASStatBuf );
167 :
168 1 : if( sNASStatBuf.st_mtime > sGFSStatBuf.st_mtime )
169 : {
170 : CPLDebug( "NAS",
171 : "Found %s but ignoring because it appears\n"
172 : "be older than the associated NAS file.",
173 0 : pszGFSFilename );
174 : }
175 : else
176 : {
177 1 : bHaveSchema = poReader->LoadClasses( pszGFSFilename );
178 : }
179 : }
180 :
181 : /* -------------------------------------------------------------------- */
182 : /* Force a first pass to establish the schema. Eventually we */
183 : /* will have mechanisms for remembering the schema and related */
184 : /* information. */
185 : /* -------------------------------------------------------------------- */
186 1 : if( !bHaveSchema && !poReader->PrescanForSchema( TRUE ) )
187 : {
188 : // we assume an errors have been reported.
189 0 : return FALSE;
190 : }
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Save the schema file if possible. Don't make a fuss if we */
194 : /* can't ... could be read-only directory or something. */
195 : /* -------------------------------------------------------------------- */
196 1 : if( !bHaveSchema )
197 : {
198 0 : FILE *fp = NULL;
199 :
200 0 : pszGFSFilename = CPLResetExtension( pszNewName, "gfs" );
201 0 : if( CPLStat( pszGFSFilename, &sGFSStatBuf ) != 0
202 : && (fp = VSIFOpen( pszGFSFilename, "wt" )) != NULL )
203 : {
204 0 : VSIFClose( fp );
205 0 : poReader->SaveClasses( pszGFSFilename );
206 : }
207 : else
208 : {
209 : CPLDebug("NAS",
210 : "Not saving %s files already exists or can't be created.",
211 0 : pszGFSFilename );
212 : }
213 : }
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* Translate the NASFeatureClasses into layers. */
217 : /* -------------------------------------------------------------------- */
218 : papoLayers = (OGRLayer **)
219 1 : CPLCalloc( sizeof(OGRNASLayer *), poReader->GetClassCount()+1 );
220 1 : nLayers = 0;
221 :
222 42 : while( nLayers < poReader->GetClassCount() )
223 : {
224 40 : papoLayers[nLayers] = TranslateNASSchema(poReader->GetClass(nLayers));
225 40 : nLayers++;
226 : }
227 :
228 1 : poRelationLayer = new OGRNASRelationLayer( this );
229 1 : papoLayers[nLayers++] = poRelationLayer;
230 :
231 1 : return TRUE;
232 : }
233 :
234 : /************************************************************************/
235 : /* TranslateNASSchema() */
236 : /************************************************************************/
237 :
238 40 : OGRNASLayer *OGRNASDataSource::TranslateNASSchema( GMLFeatureClass *poClass )
239 :
240 : {
241 : OGRNASLayer *poLayer;
242 : OGRwkbGeometryType eGType
243 40 : = (OGRwkbGeometryType) poClass->GetGeometryType();
244 :
245 40 : if( poClass->GetFeatureCount() == 0 )
246 0 : eGType = wkbUnknown;
247 :
248 : /* -------------------------------------------------------------------- */
249 : /* Create an empty layer. */
250 : /* -------------------------------------------------------------------- */
251 40 : poLayer = new OGRNASLayer( poClass->GetName(), NULL, eGType, this );
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Added attributes (properties). */
255 : /* -------------------------------------------------------------------- */
256 227 : for( int iField = 0; iField < poClass->GetPropertyCount(); iField++ )
257 : {
258 187 : GMLPropertyDefn *poProperty = poClass->GetProperty( iField );
259 : OGRFieldType eFType;
260 :
261 187 : if( poProperty->GetType() == GMLPT_Untyped )
262 7 : eFType = OFTString;
263 180 : else if( poProperty->GetType() == GMLPT_String )
264 127 : eFType = OFTString;
265 53 : else if( poProperty->GetType() == GMLPT_Integer )
266 50 : eFType = OFTInteger;
267 3 : else if( poProperty->GetType() == GMLPT_Real )
268 1 : eFType = OFTReal;
269 2 : else if( poProperty->GetType() == GMLPT_StringList )
270 1 : eFType = OFTStringList;
271 1 : else if( poProperty->GetType() == GMLPT_IntegerList )
272 1 : eFType = OFTIntegerList;
273 0 : else if( poProperty->GetType() == GMLPT_RealList )
274 0 : eFType = OFTRealList;
275 : else
276 0 : eFType = OFTString;
277 :
278 187 : OGRFieldDefn oField( poProperty->GetName(), eFType );
279 187 : if ( EQUALN(oField.GetNameRef(), "ogr:", 4) )
280 0 : oField.SetName(poProperty->GetName()+4);
281 187 : if( poProperty->GetWidth() > 0 )
282 127 : oField.SetWidth( poProperty->GetWidth() );
283 :
284 187 : poLayer->GetLayerDefn()->AddFieldDefn( &oField );
285 : }
286 :
287 40 : return poLayer;
288 : }
289 :
290 : /************************************************************************/
291 : /* GetLayer() */
292 : /************************************************************************/
293 :
294 80 : OGRLayer *OGRNASDataSource::GetLayer( int iLayer )
295 :
296 : {
297 80 : if( iLayer < 0 || iLayer >= nLayers )
298 0 : return NULL;
299 : else
300 80 : return papoLayers[iLayer];
301 : }
302 :
303 : /************************************************************************/
304 : /* TestCapability() */
305 : /************************************************************************/
306 :
307 0 : int OGRNASDataSource::TestCapability( const char * pszCap )
308 :
309 : {
310 0 : return FALSE;
311 : }
312 :
313 : /************************************************************************/
314 : /* PopulateRelations() */
315 : /************************************************************************/
316 :
317 1 : void OGRNASDataSource::PopulateRelations()
318 :
319 : {
320 : GMLFeature *poFeature;
321 :
322 1 : poReader->ResetReading();
323 8394 : while( (poFeature = poReader->NextFeature()) != NULL )
324 : {
325 8392 : char **papszOBProperties = poFeature->GetOBProperties();
326 : int i;
327 :
328 10228 : for( i = 0; papszOBProperties != NULL && papszOBProperties[i] != NULL;
329 : i++ )
330 : {
331 1836 : const char *pszGMLId = poFeature->GetProperty( "gml_id" );
332 1836 : char *pszName = NULL;
333 : const char *pszValue = CPLParseNameValue( papszOBProperties[i],
334 1836 : &pszName );
335 :
336 1836 : if( EQUALN(pszValue,"urn:adv:oid:",12)
337 : && pszGMLId != NULL )
338 : {
339 : poRelationLayer->AddRelation( pszGMLId,
340 : pszName,
341 1836 : pszValue + 12 );
342 : }
343 1836 : CPLFree( pszName );
344 : }
345 :
346 8392 : delete poFeature;
347 : }
348 :
349 1 : poRelationLayer->MarkRelationsPopulated();
350 1 : }
|