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