1 : /******************************************************************************
2 : * $Id: ogrkmldatasource.cpp 16908 2009-05-02 14:53:26Z rouault $
3 : *
4 : * Project: KML Driver
5 : * Purpose: Implementation of OGRKMLDataSource class.
6 : * Author: Christopher Condit, condit@sdsc.edu;
7 : * Jens Oberender, j.obi@troja.net
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2006, Christopher Condit
11 : * 2007, Jens Oberender
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 : #include "ogr_kml.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 : #include "cpl_error.h"
35 : #include "cpl_minixml.h"
36 :
37 : /************************************************************************/
38 : /* OGRKMLDataSource() */
39 : /************************************************************************/
40 :
41 62 : OGRKMLDataSource::OGRKMLDataSource()
42 : {
43 62 : pszName_ = NULL;
44 62 : pszNameField_ = NULL;
45 62 : pszDescriptionField_ = NULL;
46 62 : pszAltitudeMode_ = NULL;
47 62 : papoLayers_ = NULL;
48 62 : nLayers_ = 0;
49 :
50 62 : fpOutput_ = NULL;
51 :
52 62 : papszCreateOptions_ = NULL;
53 :
54 62 : bIssuedCTError_ = false;
55 :
56 : #ifdef HAVE_EXPAT
57 62 : poKMLFile_ = NULL;
58 : #endif
59 62 : }
60 :
61 : /************************************************************************/
62 : /* ~OGRKMLDataSource() */
63 : /************************************************************************/
64 :
65 124 : OGRKMLDataSource::~OGRKMLDataSource()
66 : {
67 62 : if( fpOutput_ != NULL )
68 : {
69 1 : VSIFPrintf( fpOutput_, "%s", "</Folder></Document></kml>\n" );
70 :
71 1 : if( fpOutput_ != stdout )
72 1 : VSIFClose( fpOutput_ );
73 : }
74 :
75 62 : CSLDestroy( papszCreateOptions_ );
76 62 : CPLFree( pszName_ );
77 62 : CPLFree( pszNameField_ );
78 62 : CPLFree( pszDescriptionField_ );
79 62 : CPLFree( pszAltitudeMode_ );
80 :
81 73 : for( int i = 0; i < nLayers_; i++ )
82 : {
83 11 : delete papoLayers_[i];
84 : }
85 :
86 62 : CPLFree( papoLayers_ );
87 :
88 : #ifdef HAVE_EXPAT
89 62 : delete poKMLFile_;
90 : #endif
91 124 : }
92 :
93 : /************************************************************************/
94 : /* Open() */
95 : /************************************************************************/
96 :
97 : #ifdef HAVE_EXPAT
98 61 : int OGRKMLDataSource::Open( const char * pszNewName, int bTestOpen )
99 : {
100 : CPLAssert( NULL != pszNewName );
101 :
102 61 : int nCount = 0;
103 61 : OGRKMLLayer *poLayer = NULL;
104 : OGRwkbGeometryType poGeotype;
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* Create a KML object and open the source file. */
108 : /* -------------------------------------------------------------------- */
109 61 : poKMLFile_ = new KMLVector();
110 :
111 61 : if( !poKMLFile_->open( pszNewName ) )
112 : {
113 5 : delete poKMLFile_;
114 5 : poKMLFile_ = NULL;
115 5 : return FALSE;
116 : }
117 :
118 56 : pszName_ = CPLStrdup( pszNewName );
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* If we aren't sure it is KML, validate it by start parsing */
122 : /* -------------------------------------------------------------------- */
123 56 : if( bTestOpen && !poKMLFile_->isValid() )
124 : {
125 53 : delete poKMLFile_;
126 53 : poKMLFile_ = NULL;
127 53 : return FALSE;
128 : }
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Prescan the KML file so we can later work with the structure */
132 : /* -------------------------------------------------------------------- */
133 3 : poKMLFile_->parse();
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* Classify the nodes */
137 : /* -------------------------------------------------------------------- */
138 3 : poKMLFile_->classifyNodes();
139 :
140 : /* -------------------------------------------------------------------- */
141 : /* Eliminate the empty containers */
142 : /* -------------------------------------------------------------------- */
143 3 : poKMLFile_->eliminateEmpty();
144 :
145 : /* -------------------------------------------------------------------- */
146 : /* Find layers to use in the KML structure */
147 : /* -------------------------------------------------------------------- */
148 3 : poKMLFile_->findLayers(NULL);
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Print the structure */
152 : /* -------------------------------------------------------------------- */
153 3 : if( CPLGetConfigOption("KML_DEBUG",NULL) != NULL )
154 0 : poKMLFile_->print(3);
155 :
156 3 : nLayers_ = poKMLFile_->getNumLayers();
157 :
158 : /* -------------------------------------------------------------------- */
159 : /* Allocate memory for the Layers */
160 : /* -------------------------------------------------------------------- */
161 : papoLayers_ = (OGRKMLLayer **)
162 3 : CPLMalloc( sizeof(OGRKMLLayer *) * nLayers_ );
163 :
164 : OGRSpatialReference *poSRS = new OGRSpatialReference("GEOGCS[\"WGS 84\", "
165 : " DATUM[\"WGS_1984\","
166 : " SPHEROID[\"WGS 84\",6378137,298.257223563,"
167 : " AUTHORITY[\"EPSG\",\"7030\"]],"
168 : " AUTHORITY[\"EPSG\",\"6326\"]],"
169 : " PRIMEM[\"Greenwich\",0,"
170 : " AUTHORITY[\"EPSG\",\"8901\"]],"
171 : " UNIT[\"degree\",0.01745329251994328,"
172 : " AUTHORITY[\"EPSG\",\"9122\"]],"
173 3 : " AUTHORITY[\"EPSG\",\"4326\"]]");
174 :
175 : /* -------------------------------------------------------------------- */
176 : /* Create the Layers and fill them */
177 : /* -------------------------------------------------------------------- */
178 12 : for( nCount = 0; nCount < nLayers_; nCount++ )
179 : {
180 9 : if( !poKMLFile_->selectLayer(nCount) )
181 : {
182 : CPLError( CE_Failure, CPLE_AppDefined,
183 0 : "There are no layers or a layer can not be found!");
184 0 : break;
185 : }
186 :
187 9 : if( poKMLFile_->getCurrentType() == Point )
188 4 : poGeotype = wkbPoint;
189 5 : else if( poKMLFile_->getCurrentType() == LineString )
190 1 : poGeotype = wkbLineString;
191 4 : else if( poKMLFile_->getCurrentType() == Polygon )
192 3 : poGeotype = wkbPolygon;
193 1 : else if( poKMLFile_->getCurrentType() == MultiPoint )
194 0 : poGeotype = wkbMultiPoint;
195 1 : else if( poKMLFile_->getCurrentType() == MultiLineString )
196 0 : poGeotype = wkbMultiLineString;
197 1 : else if( poKMLFile_->getCurrentType() == MultiPolygon )
198 0 : poGeotype = wkbMultiPolygon;
199 1 : else if( poKMLFile_->getCurrentType() == MultiGeometry )
200 0 : poGeotype = wkbGeometryCollection;
201 : else
202 1 : poGeotype = wkbUnknown;
203 :
204 9 : if (poGeotype != wkbUnknown && poKMLFile_->is25D())
205 7 : poGeotype = (OGRwkbGeometryType) (poGeotype | wkb25DBit);
206 :
207 : /* -------------------------------------------------------------------- */
208 : /* Create the layer object. */
209 : /* -------------------------------------------------------------------- */
210 9 : CPLString sName( poKMLFile_->getCurrentName() );
211 :
212 9 : if( sName.empty() )
213 : {
214 1 : sName.Printf( "Layer #%d", nCount );
215 : }
216 :
217 9 : poLayer = new OGRKMLLayer( sName.c_str(), poSRS, FALSE, poGeotype, this );
218 :
219 9 : poLayer->SetLayerNumber( nCount );
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Add layer to data source layer list. */
223 : /* -------------------------------------------------------------------- */
224 9 : papoLayers_[nCount] = poLayer;
225 : }
226 :
227 3 : poSRS->Release();
228 :
229 3 : return TRUE;
230 : }
231 : #endif /* HAVE_EXPAT */
232 :
233 : /************************************************************************/
234 : /* Create() */
235 : /************************************************************************/
236 :
237 1 : int OGRKMLDataSource::Create( const char* pszName, char** papszOptions )
238 : {
239 : CPLAssert( NULL != pszName );
240 :
241 1 : if( fpOutput_ != NULL )
242 : {
243 : CPLAssert( FALSE );
244 0 : return FALSE;
245 : }
246 :
247 1 : if (CSLFetchNameValue(papszOptions, "NameField"))
248 0 : pszNameField_ = CPLStrdup(CSLFetchNameValue(papszOptions, "NameField"));
249 : else
250 1 : pszNameField_ = CPLStrdup("Name");
251 :
252 1 : if (CSLFetchNameValue(papszOptions, "DescriptionField"))
253 0 : pszDescriptionField_ = CPLStrdup(CSLFetchNameValue(papszOptions, "DescriptionField"));
254 : else
255 1 : pszDescriptionField_ = CPLStrdup("Description");
256 :
257 1 : pszAltitudeMode_ = CPLStrdup(CSLFetchNameValue(papszOptions, "AltitudeMode"));
258 1 : if( (NULL != pszAltitudeMode_) && strlen(pszAltitudeMode_) > 0)
259 : {
260 : //Check to see that the specified AltitudeMode is valid
261 0 : if ( EQUAL(pszAltitudeMode_, "clampToGround")
262 : || EQUAL(pszAltitudeMode_, "relativeToGround")
263 : || EQUAL(pszAltitudeMode_, "absolute"))
264 : {
265 0 : CPLDebug("KML", "Using '%s' for AltitudeMode", pszAltitudeMode_);
266 : }
267 : else
268 : {
269 0 : CPLFree( pszAltitudeMode_ );
270 0 : pszAltitudeMode_ = NULL;
271 0 : CPLError( CE_Warning, CPLE_AppDefined, "Invalide AltitideMode specified, ignoring" );
272 : }
273 : }
274 : else
275 : {
276 1 : CPLFree( pszAltitudeMode_ );
277 1 : pszAltitudeMode_ = NULL;
278 : }
279 :
280 : /* -------------------------------------------------------------------- */
281 : /* Create the output file. */
282 : /* -------------------------------------------------------------------- */
283 1 : pszName_ = CPLStrdup( pszName );
284 :
285 1 : if( EQUAL(pszName, "stdout") )
286 0 : fpOutput_ = stdout;
287 : else
288 1 : fpOutput_ = VSIFOpen( pszName, "wt+" );
289 :
290 1 : if( fpOutput_ == NULL )
291 : {
292 : CPLError( CE_Failure, CPLE_OpenFailed,
293 0 : "Failed to create KML file %s.", pszName );
294 0 : return FALSE;
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Write out "standard" header. */
299 : /* -------------------------------------------------------------------- */
300 1 : VSIFPrintf( fpOutput_, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" );
301 :
302 1 : nSchemaInsertLocation_ = VSIFTell( fpOutput_ );
303 :
304 1 : VSIFPrintf( fpOutput_, "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document>" );
305 :
306 1 : return TRUE;
307 : }
308 :
309 : /************************************************************************/
310 : /* CreateLayer() */
311 : /************************************************************************/
312 :
313 : OGRLayer *
314 2 : OGRKMLDataSource::CreateLayer( const char * pszLayerName,
315 : OGRSpatialReference *poSRS,
316 : OGRwkbGeometryType eType,
317 : char ** papszOptions )
318 : {
319 : CPLAssert( NULL != pszLayerName);
320 :
321 : /* -------------------------------------------------------------------- */
322 : /* Verify we are in update mode. */
323 : /* -------------------------------------------------------------------- */
324 2 : if( fpOutput_ == NULL )
325 : {
326 : CPLError( CE_Failure, CPLE_NoWriteAccess,
327 : "Data source %s opened for read access.\n"
328 : "New layer %s cannot be created.\n",
329 0 : pszName_, pszLayerName );
330 :
331 0 : return NULL;
332 : }
333 :
334 : /* -------------------------------------------------------------------- */
335 : /* Close the previous layer (if there is one open) */
336 : /* -------------------------------------------------------------------- */
337 2 : if (GetLayerCount() > 0)
338 : {
339 1 : VSIFPrintf( fpOutput_, "</Folder>\n");
340 : }
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Ensure name is safe as an element name. */
344 : /* -------------------------------------------------------------------- */
345 2 : char *pszCleanLayerName = CPLStrdup( pszLayerName );
346 :
347 2 : CPLCleanXMLElementName( pszCleanLayerName );
348 2 : if( strcmp(pszCleanLayerName, pszLayerName) != 0 )
349 : {
350 : CPLError( CE_Warning, CPLE_AppDefined,
351 : "Layer name '%s' adjusted to '%s' for XML validity.",
352 0 : pszLayerName, pszCleanLayerName );
353 : }
354 2 : VSIFPrintf( fpOutput_, "<Folder><name>%s</name>\n", pszCleanLayerName);
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* Create the layer object. */
358 : /* -------------------------------------------------------------------- */
359 : OGRKMLLayer *poLayer;
360 2 : poLayer = new OGRKMLLayer( pszCleanLayerName, poSRS, TRUE, eType, this );
361 :
362 2 : CPLFree( pszCleanLayerName );
363 :
364 : /* -------------------------------------------------------------------- */
365 : /* Add layer to data source layer list. */
366 : /* -------------------------------------------------------------------- */
367 : papoLayers_ = (OGRKMLLayer **)
368 2 : CPLRealloc( papoLayers_, sizeof(OGRKMLLayer *) * (nLayers_+1) );
369 :
370 2 : papoLayers_[nLayers_++] = poLayer;
371 :
372 2 : return poLayer;
373 : }
374 :
375 : /************************************************************************/
376 : /* TestCapability() */
377 : /************************************************************************/
378 :
379 0 : int OGRKMLDataSource::TestCapability( const char * pszCap )
380 :
381 : {
382 0 : if( EQUAL(pszCap, ODsCCreateLayer) )
383 0 : return TRUE;
384 : else
385 0 : return FALSE;
386 : }
387 :
388 : /************************************************************************/
389 : /* GetLayer() */
390 : /************************************************************************/
391 :
392 21 : OGRLayer *OGRKMLDataSource::GetLayer( int iLayer )
393 : {
394 21 : if( iLayer < 0 || iLayer >= nLayers_ )
395 0 : return NULL;
396 : else
397 21 : return papoLayers_[iLayer];
398 : }
399 :
400 : /************************************************************************/
401 : /* GrowExtents() */
402 : /************************************************************************/
403 :
404 9 : void OGRKMLDataSource::GrowExtents( OGREnvelope *psGeomBounds )
405 : {
406 : CPLAssert( NULL != psGeomBounds );
407 :
408 9 : oEnvelope_.Merge( *psGeomBounds );
409 1149 : }
|