1 : /******************************************************************************
2 : * $Id: ogrkmldatasource.cpp 23978 2012-02-14 20:42:34Z 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 94 : OGRKMLDataSource::OGRKMLDataSource()
42 : {
43 94 : pszName_ = NULL;
44 94 : pszNameField_ = NULL;
45 94 : pszDescriptionField_ = NULL;
46 94 : pszAltitudeMode_ = NULL;
47 94 : papoLayers_ = NULL;
48 94 : nLayers_ = 0;
49 :
50 94 : fpOutput_ = NULL;
51 :
52 94 : papszCreateOptions_ = NULL;
53 :
54 94 : bIssuedCTError_ = false;
55 :
56 : #ifdef HAVE_EXPAT
57 94 : poKMLFile_ = NULL;
58 : #endif
59 94 : }
60 :
61 : /************************************************************************/
62 : /* ~OGRKMLDataSource() */
63 : /************************************************************************/
64 :
65 94 : OGRKMLDataSource::~OGRKMLDataSource()
66 : {
67 94 : if( fpOutput_ != NULL )
68 : {
69 2 : VSIFPrintfL( fpOutput_, "%s", "</Folder></Document></kml>\n" );
70 :
71 2 : VSIFCloseL( fpOutput_ );
72 : }
73 :
74 94 : CSLDestroy( papszCreateOptions_ );
75 94 : CPLFree( pszName_ );
76 94 : CPLFree( pszNameField_ );
77 94 : CPLFree( pszDescriptionField_ );
78 94 : CPLFree( pszAltitudeMode_ );
79 :
80 123 : for( int i = 0; i < nLayers_; i++ )
81 : {
82 29 : delete papoLayers_[i];
83 : }
84 :
85 94 : CPLFree( papoLayers_ );
86 :
87 : #ifdef HAVE_EXPAT
88 94 : delete poKMLFile_;
89 : #endif
90 94 : }
91 :
92 : /************************************************************************/
93 : /* Open() */
94 : /************************************************************************/
95 :
96 : #ifdef HAVE_EXPAT
97 92 : int OGRKMLDataSource::Open( const char * pszNewName, int bTestOpen )
98 : {
99 92 : CPLAssert( NULL != pszNewName );
100 :
101 92 : int nCount = 0;
102 92 : OGRKMLLayer *poLayer = NULL;
103 : OGRwkbGeometryType poGeotype;
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Create a KML object and open the source file. */
107 : /* -------------------------------------------------------------------- */
108 92 : poKMLFile_ = new KMLVector();
109 :
110 92 : if( !poKMLFile_->open( pszNewName ) )
111 : {
112 28 : delete poKMLFile_;
113 28 : poKMLFile_ = NULL;
114 28 : return FALSE;
115 : }
116 :
117 64 : pszName_ = CPLStrdup( pszNewName );
118 :
119 : /* -------------------------------------------------------------------- */
120 : /* If we aren't sure it is KML, validate it by start parsing */
121 : /* -------------------------------------------------------------------- */
122 64 : if( bTestOpen && !poKMLFile_->isValid() )
123 : {
124 55 : delete poKMLFile_;
125 55 : poKMLFile_ = NULL;
126 55 : return FALSE;
127 : }
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Prescan the KML file so we can later work with the structure */
131 : /* -------------------------------------------------------------------- */
132 9 : poKMLFile_->parse();
133 :
134 : /* -------------------------------------------------------------------- */
135 : /* Classify the nodes */
136 : /* -------------------------------------------------------------------- */
137 9 : if( !poKMLFile_->classifyNodes() )
138 : {
139 0 : delete poKMLFile_;
140 0 : poKMLFile_ = NULL;
141 0 : return FALSE;
142 : }
143 :
144 :
145 : /* -------------------------------------------------------------------- */
146 : /* Eliminate the empty containers (if there is at least one */
147 : /* valid container !) */
148 : /* -------------------------------------------------------------------- */
149 9 : int bHasOnlyEmpty = poKMLFile_->hasOnlyEmpty();
150 9 : if (bHasOnlyEmpty)
151 2 : CPLDebug("KML", "Has only empty containers");
152 : else
153 7 : poKMLFile_->eliminateEmpty();
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* Find layers to use in the KML structure */
157 : /* -------------------------------------------------------------------- */
158 9 : poKMLFile_->findLayers(NULL, bHasOnlyEmpty);
159 :
160 : /* -------------------------------------------------------------------- */
161 : /* Print the structure */
162 : /* -------------------------------------------------------------------- */
163 9 : if( CPLGetConfigOption("KML_DEBUG",NULL) != NULL )
164 0 : poKMLFile_->print(3);
165 :
166 9 : nLayers_ = poKMLFile_->getNumLayers();
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Allocate memory for the Layers */
170 : /* -------------------------------------------------------------------- */
171 : papoLayers_ = (OGRKMLLayer **)
172 9 : CPLMalloc( sizeof(OGRKMLLayer *) * nLayers_ );
173 :
174 : OGRSpatialReference *poSRS = new OGRSpatialReference("GEOGCS[\"WGS 84\", "
175 : " DATUM[\"WGS_1984\","
176 : " SPHEROID[\"WGS 84\",6378137,298.257223563,"
177 : " AUTHORITY[\"EPSG\",\"7030\"]],"
178 : " AUTHORITY[\"EPSG\",\"6326\"]],"
179 : " PRIMEM[\"Greenwich\",0,"
180 : " AUTHORITY[\"EPSG\",\"8901\"]],"
181 : " UNIT[\"degree\",0.01745329251994328,"
182 : " AUTHORITY[\"EPSG\",\"9122\"]],"
183 9 : " AUTHORITY[\"EPSG\",\"4326\"]]");
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Create the Layers and fill them */
187 : /* -------------------------------------------------------------------- */
188 34 : for( nCount = 0; nCount < nLayers_; nCount++ )
189 : {
190 25 : if( !poKMLFile_->selectLayer(nCount) )
191 : {
192 : CPLError( CE_Failure, CPLE_AppDefined,
193 0 : "There are no layers or a layer can not be found!");
194 0 : break;
195 : }
196 :
197 25 : if( poKMLFile_->getCurrentType() == Point )
198 9 : poGeotype = wkbPoint;
199 16 : else if( poKMLFile_->getCurrentType() == LineString )
200 3 : poGeotype = wkbLineString;
201 13 : else if( poKMLFile_->getCurrentType() == Polygon )
202 9 : poGeotype = wkbPolygon;
203 4 : else if( poKMLFile_->getCurrentType() == MultiPoint )
204 0 : poGeotype = wkbMultiPoint;
205 4 : else if( poKMLFile_->getCurrentType() == MultiLineString )
206 0 : poGeotype = wkbMultiLineString;
207 4 : else if( poKMLFile_->getCurrentType() == MultiPolygon )
208 0 : poGeotype = wkbMultiPolygon;
209 4 : else if( poKMLFile_->getCurrentType() == MultiGeometry )
210 0 : poGeotype = wkbGeometryCollection;
211 : else
212 4 : poGeotype = wkbUnknown;
213 :
214 25 : if (poGeotype != wkbUnknown && poKMLFile_->is25D())
215 20 : poGeotype = (OGRwkbGeometryType) (poGeotype | wkb25DBit);
216 :
217 : /* -------------------------------------------------------------------- */
218 : /* Create the layer object. */
219 : /* -------------------------------------------------------------------- */
220 25 : CPLString sName( poKMLFile_->getCurrentName() );
221 :
222 25 : if( sName.empty() )
223 : {
224 2 : sName.Printf( "Layer #%d", nCount );
225 : }
226 :
227 25 : poLayer = new OGRKMLLayer( sName.c_str(), poSRS, FALSE, poGeotype, this );
228 :
229 25 : poLayer->SetLayerNumber( nCount );
230 :
231 : /* -------------------------------------------------------------------- */
232 : /* Add layer to data source layer list. */
233 : /* -------------------------------------------------------------------- */
234 25 : papoLayers_[nCount] = poLayer;
235 : }
236 :
237 9 : poSRS->Release();
238 :
239 9 : return TRUE;
240 : }
241 : #endif /* HAVE_EXPAT */
242 :
243 : /************************************************************************/
244 : /* Create() */
245 : /************************************************************************/
246 :
247 2 : int OGRKMLDataSource::Create( const char* pszName, char** papszOptions )
248 : {
249 2 : CPLAssert( NULL != pszName );
250 :
251 2 : if( fpOutput_ != NULL )
252 : {
253 0 : CPLAssert( FALSE );
254 0 : return FALSE;
255 : }
256 :
257 2 : if (CSLFetchNameValue(papszOptions, "NameField"))
258 0 : pszNameField_ = CPLStrdup(CSLFetchNameValue(papszOptions, "NameField"));
259 : else
260 2 : pszNameField_ = CPLStrdup("Name");
261 :
262 2 : if (CSLFetchNameValue(papszOptions, "DescriptionField"))
263 0 : pszDescriptionField_ = CPLStrdup(CSLFetchNameValue(papszOptions, "DescriptionField"));
264 : else
265 2 : pszDescriptionField_ = CPLStrdup("Description");
266 :
267 2 : pszAltitudeMode_ = CPLStrdup(CSLFetchNameValue(papszOptions, "AltitudeMode"));
268 2 : if( (NULL != pszAltitudeMode_) && strlen(pszAltitudeMode_) > 0)
269 : {
270 : //Check to see that the specified AltitudeMode is valid
271 0 : if ( EQUAL(pszAltitudeMode_, "clampToGround")
272 : || EQUAL(pszAltitudeMode_, "relativeToGround")
273 : || EQUAL(pszAltitudeMode_, "absolute"))
274 : {
275 0 : CPLDebug("KML", "Using '%s' for AltitudeMode", pszAltitudeMode_);
276 : }
277 : else
278 : {
279 0 : CPLFree( pszAltitudeMode_ );
280 0 : pszAltitudeMode_ = NULL;
281 0 : CPLError( CE_Warning, CPLE_AppDefined, "Invalide AltitideMode specified, ignoring" );
282 : }
283 : }
284 : else
285 : {
286 2 : CPLFree( pszAltitudeMode_ );
287 2 : pszAltitudeMode_ = NULL;
288 : }
289 :
290 : /* -------------------------------------------------------------------- */
291 : /* Create the output file. */
292 : /* -------------------------------------------------------------------- */
293 :
294 2 : if (strcmp(pszName, "/dev/stdout") == 0)
295 0 : pszName = "/vsistdout/";
296 :
297 2 : pszName_ = CPLStrdup( pszName );
298 :
299 2 : fpOutput_ = VSIFOpenL( pszName, "wb" );
300 2 : if( fpOutput_ == NULL )
301 : {
302 : CPLError( CE_Failure, CPLE_OpenFailed,
303 0 : "Failed to create KML file %s.", pszName );
304 0 : return FALSE;
305 : }
306 :
307 : /* -------------------------------------------------------------------- */
308 : /* Write out "standard" header. */
309 : /* -------------------------------------------------------------------- */
310 2 : VSIFPrintfL( fpOutput_, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" );
311 :
312 2 : VSIFPrintfL( fpOutput_, "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document>" );
313 :
314 2 : return TRUE;
315 : }
316 :
317 : /************************************************************************/
318 : /* CreateLayer() */
319 : /************************************************************************/
320 :
321 : OGRLayer *
322 4 : OGRKMLDataSource::CreateLayer( const char * pszLayerName,
323 : OGRSpatialReference *poSRS,
324 : OGRwkbGeometryType eType,
325 : char ** papszOptions )
326 : {
327 4 : CPLAssert( NULL != pszLayerName);
328 :
329 : /* -------------------------------------------------------------------- */
330 : /* Verify we are in update mode. */
331 : /* -------------------------------------------------------------------- */
332 4 : if( fpOutput_ == NULL )
333 : {
334 : CPLError( CE_Failure, CPLE_NoWriteAccess,
335 : "Data source %s opened for read access.\n"
336 : "New layer %s cannot be created.\n",
337 0 : pszName_, pszLayerName );
338 :
339 0 : return NULL;
340 : }
341 :
342 : /* -------------------------------------------------------------------- */
343 : /* Close the previous layer (if there is one open) */
344 : /* -------------------------------------------------------------------- */
345 4 : if (GetLayerCount() > 0)
346 : {
347 2 : VSIFPrintfL( fpOutput_, "</Folder>\n");
348 2 : ((OGRKMLLayer*)GetLayer(GetLayerCount()-1))->SetClosedForWriting();
349 : }
350 :
351 : /* -------------------------------------------------------------------- */
352 : /* Ensure name is safe as an element name. */
353 : /* -------------------------------------------------------------------- */
354 4 : char *pszCleanLayerName = CPLStrdup( pszLayerName );
355 :
356 4 : CPLCleanXMLElementName( pszCleanLayerName );
357 4 : if( strcmp(pszCleanLayerName, pszLayerName) != 0 )
358 : {
359 : CPLError( CE_Warning, CPLE_AppDefined,
360 : "Layer name '%s' adjusted to '%s' for XML validity.",
361 0 : pszLayerName, pszCleanLayerName );
362 : }
363 4 : VSIFPrintfL( fpOutput_, "<Folder><name>%s</name>\n", pszCleanLayerName);
364 :
365 : /* -------------------------------------------------------------------- */
366 : /* Create the layer object. */
367 : /* -------------------------------------------------------------------- */
368 : OGRKMLLayer *poLayer;
369 4 : poLayer = new OGRKMLLayer( pszCleanLayerName, poSRS, TRUE, eType, this );
370 :
371 4 : CPLFree( pszCleanLayerName );
372 :
373 : /* -------------------------------------------------------------------- */
374 : /* Add layer to data source layer list. */
375 : /* -------------------------------------------------------------------- */
376 : papoLayers_ = (OGRKMLLayer **)
377 4 : CPLRealloc( papoLayers_, sizeof(OGRKMLLayer *) * (nLayers_+1) );
378 :
379 4 : papoLayers_[nLayers_++] = poLayer;
380 :
381 4 : return poLayer;
382 : }
383 :
384 : /************************************************************************/
385 : /* TestCapability() */
386 : /************************************************************************/
387 :
388 1 : int OGRKMLDataSource::TestCapability( const char * pszCap )
389 :
390 : {
391 1 : if( EQUAL(pszCap, ODsCCreateLayer) )
392 0 : return TRUE;
393 : else
394 1 : return FALSE;
395 : }
396 :
397 : /************************************************************************/
398 : /* GetLayer() */
399 : /************************************************************************/
400 :
401 175 : OGRLayer *OGRKMLDataSource::GetLayer( int iLayer )
402 : {
403 175 : if( iLayer < 0 || iLayer >= nLayers_ )
404 2 : return NULL;
405 : else
406 173 : return papoLayers_[iLayer];
407 : }
408 :
409 : /************************************************************************/
410 : /* GrowExtents() */
411 : /************************************************************************/
412 :
413 9 : void OGRKMLDataSource::GrowExtents( OGREnvelope *psGeomBounds )
414 : {
415 9 : CPLAssert( NULL != psGeomBounds );
416 :
417 9 : oEnvelope_.Merge( *psGeomBounds );
418 2148 : }
|