1 : /******************************************************************************
2 : *
3 : * Project: KML Translator
4 : * Purpose: Implements OGRLIBKMLDriver
5 : * Author: Brian Case, rush at winkey dot org
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2010, Brian Case
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : *****************************************************************************/
28 :
29 : //#include "cpl_conv.h"
30 : //#include "cpl_string.h"
31 : //#include "cpl_error.h"
32 : #include <iostream>
33 : //#include <sstream>
34 : #include <kml/dom.h>
35 : #include <kml/base/file.h>
36 :
37 : using kmldom::KmlFactory;
38 : using kmldom::DocumentPtr;
39 : using kmldom::FolderPtr;
40 : using kmldom::FeaturePtr;
41 : using kmldom::NetworkLinkPtr;
42 : using kmldom::StyleSelectorPtr;
43 : using kmldom::LinkPtr;
44 : using kmldom::SchemaPtr;
45 : using kmlbase::File;
46 : using kmldom::KmlPtr;
47 :
48 : #include "ogr_libkml.h"
49 : #include "ogrlibkmlstyle.h"
50 :
51 : /***** this was shamelessly swiped from the kml driver *****/
52 :
53 : #define OGRLIBKMLSRSWKT "GEOGCS[\"WGS 84\", "\
54 : " DATUM[\"WGS_1984\","\
55 : " SPHEROID[\"WGS 84\",6378137,298.257223563,"\
56 : " AUTHORITY[\"EPSG\",\"7030\"]],"\
57 : " AUTHORITY[\"EPSG\",\"6326\"]],"\
58 : " PRIMEM[\"Greenwich\",0,"\
59 : " AUTHORITY[\"EPSG\",\"8901\"]],"\
60 : " UNIT[\"degree\",0.01745329251994328,"\
61 : " AUTHORITY[\"EPSG\",\"9122\"]],"\
62 : " AUTHORITY[\"EPSG\",\"4326\"]]"
63 :
64 : /******************************************************************************
65 : OGRLIBKMLDataSource Constructor
66 :
67 : Args: none
68 :
69 : Returns: nothing
70 :
71 : ******************************************************************************/
72 :
73 16 : OGRLIBKMLDataSource::OGRLIBKMLDataSource ( KmlFactory * poKmlFactory )
74 : {
75 16 : pszName = NULL;
76 16 : papoLayers = NULL;
77 16 : nLayers = 0;
78 16 : nAlloced = 0;
79 :
80 16 : bUpdated = FALSE;
81 :
82 16 : m_isKml = FALSE;
83 16 : m_poKmlDSKml = NULL;
84 16 : m_poKmlDSContainer = NULL;
85 :
86 16 : m_isKmz = FALSE;
87 16 : m_poKmlDocKml = NULL;
88 16 : pszStylePath = "";
89 :
90 16 : m_isDir = FALSE;
91 :
92 16 : m_poKmlFactory = poKmlFactory;
93 :
94 : //m_poStyleTable = NULL;
95 :
96 16 : }
97 :
98 : /******************************************************************************
99 : method to write a single file ds .kml at ds destroy
100 :
101 : Args: none
102 :
103 : Returns: nothing
104 :
105 : ******************************************************************************/
106 :
107 : void OGRLIBKMLDataSource::WriteKml (
108 1 : )
109 : {
110 1 : std::string oKmlFilename = pszName;
111 :
112 2 : if ( m_poKmlDSContainer
113 : && m_poKmlDSContainer->IsA ( kmldom::Type_Document ) ) {
114 1 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlDSContainer );
115 : int iLayer;
116 :
117 3 : for ( iLayer = 0; iLayer < nLayers; iLayer++ ) {
118 2 : SchemaPtr poKmlSchema;
119 2 : SchemaPtr poKmlSchema2;
120 :
121 2 : if ( ( poKmlSchema = papoLayers[iLayer]->GetKmlSchema ( ) ) ) {
122 2 : size_t nKmlSchemas = poKmlDocument->get_schema_array_size ( );
123 : size_t iKmlSchema;
124 :
125 3 : for ( iKmlSchema = 0; iKmlSchema < nKmlSchemas; iKmlSchema++ ) {
126 : poKmlSchema2 =
127 1 : poKmlDocument->get_schema_array_at ( iKmlSchema );
128 1 : if ( poKmlSchema2 == poKmlSchema )
129 0 : break;
130 : }
131 :
132 2 : if ( poKmlSchema2 != poKmlSchema )
133 2 : poKmlDocument->add_schema ( poKmlSchema );
134 : }
135 1 : }
136 : }
137 :
138 :
139 :
140 1 : if ( m_poKmlDSKml ) {
141 1 : std::string oKmlOut = kmldom::SerializePretty ( m_poKmlDSKml );
142 :
143 1 : if ( !kmlbase::File::WriteStringToFile ( oKmlOut, oKmlFilename ) )
144 : CPLError ( CE_Failure, CPLE_FileIO,
145 0 : "ERROR writing %s", oKmlFilename.c_str ( ) );
146 : }
147 0 : else if ( m_poKmlDSContainer ) {
148 0 : std::string oKmlOut = kmldom::SerializePretty ( m_poKmlDSContainer );
149 :
150 0 : if ( !kmlbase::File::WriteStringToFile ( oKmlOut, oKmlFilename ) )
151 : CPLError ( CE_Failure, CPLE_FileIO,
152 0 : "ERROR writing %s", oKmlFilename.c_str ( ) );
153 :
154 : }
155 :
156 1 : return;
157 : }
158 :
159 : /******************************************************************************
160 : method to write a ds .kmz at ds destroy
161 :
162 : Args: none
163 :
164 : Returns: nothing
165 :
166 : ******************************************************************************/
167 :
168 : void OGRLIBKMLDataSource::WriteKmz (
169 0 : )
170 : {
171 :
172 0 : KmzFile *poKmlKmzfile = kmlengine::KmzFile::Create ( pszName );
173 :
174 0 : if ( !poKmlKmzfile ) {
175 : CPLError ( CE_Failure, CPLE_NoWriteAccess, "ERROR creating %s",
176 0 : pszName );
177 0 : return;
178 : }
179 :
180 : /***** write out the doc.kml ****/
181 :
182 : const char *pszUseDocKml =
183 0 : CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
184 :
185 0 : if ( EQUAL ( pszUseDocKml, "yes" ) && m_poKmlDocKml ) {
186 :
187 : /***** if we dont have the doc.kml root *****/
188 : /***** make it and add the container *****/
189 :
190 0 : if ( !m_poKmlDocKmlRoot ) {
191 0 : m_poKmlDocKmlRoot = m_poKmlFactory->CreateKml ( );
192 :
193 0 : AsKml( m_poKmlDocKmlRoot )->set_feature ( m_poKmlDocKml );
194 : }
195 :
196 0 : std::string oKmlOut = kmldom::SerializePretty ( m_poKmlDocKmlRoot );
197 :
198 0 : if ( !poKmlKmzfile->AddFile ( oKmlOut, "doc.kml" ) )
199 : CPLError ( CE_Failure, CPLE_FileIO,
200 0 : "ERROR adding %s to %s", "doc.kml", pszName );
201 :
202 : }
203 :
204 : /***** loop though the layers and write them *****/
205 :
206 : int iLayer;
207 :
208 0 : for ( iLayer = 0; iLayer < nLayers; iLayer++ ) {
209 0 : ContainerPtr poKlmContainer = papoLayers[iLayer]->GetKmlLayer ( );
210 :
211 0 : if ( poKlmContainer->IsA ( kmldom::Type_Document ) ) {
212 :
213 0 : DocumentPtr poKmlDocument = AsDocument ( poKlmContainer );
214 0 : SchemaPtr poKmlSchema = papoLayers[iLayer]->GetKmlSchema ( );
215 :
216 0 : if ( !poKmlDocument->get_schema_array_size ( ) &&
217 : poKmlSchema &&
218 : poKmlSchema->get_simplefield_array_size ( ) ) {
219 0 : poKmlDocument->add_schema ( poKmlSchema );
220 0 : }
221 : }
222 :
223 : /***** if we dont have the layers root *****/
224 : /***** make it and add the container *****/
225 :
226 0 : KmlPtr poKmlKml = NULL;
227 :
228 0 : if ( !( poKmlKml = AsKml( papoLayers[iLayer]->GetKmlLayerRoot ( ) ) ) ) {
229 :
230 0 : poKmlKml = m_poKmlFactory->CreateKml ( );
231 :
232 0 : poKmlKml->set_feature ( poKlmContainer );
233 : }
234 :
235 0 : std::string oKmlOut = kmldom::SerializePretty ( poKmlKml );
236 :
237 0 : if ( !poKmlKmzfile->
238 : AddFile ( oKmlOut, papoLayers[iLayer]->GetFileName ( ) ) )
239 : CPLError ( CE_Failure, CPLE_FileIO, "ERROR adding %s to %s",
240 0 : papoLayers[iLayer]->GetFileName ( ), pszName );
241 :
242 : }
243 :
244 : /***** write the style table *****/
245 :
246 0 : if ( m_poKmlStyleKml ) {
247 :
248 0 : KmlPtr poKmlKml = m_poKmlFactory->CreateKml ( );
249 :
250 0 : poKmlKml->set_feature ( m_poKmlStyleKml );
251 0 : std::string strKmlOut = kmldom::SerializePretty ( poKmlKml );
252 :
253 0 : if ( !poKmlKmzfile->AddFile ( strKmlOut, "style/style.kml" ) )
254 : CPLError ( CE_Failure, CPLE_FileIO,
255 0 : "ERROR adding %s to %s", "style/style.kml", pszName );
256 : }
257 :
258 0 : delete poKmlKmzfile;
259 :
260 0 : return;
261 : }
262 :
263 : /******************************************************************************
264 : method to write a dir ds at ds destroy
265 :
266 : Args: none
267 :
268 : Returns: nothing
269 :
270 : ******************************************************************************/
271 :
272 : void OGRLIBKMLDataSource::WriteDir (
273 0 : )
274 : {
275 :
276 : /***** write out the doc.kml ****/
277 :
278 : const char *pszUseDocKml =
279 0 : CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
280 :
281 0 : if ( EQUAL ( pszUseDocKml, "yes" ) && m_poKmlDocKml ) {
282 :
283 : /***** if we dont have the doc.kml root *****/
284 : /***** make it and add the container *****/
285 :
286 0 : if ( !m_poKmlDocKmlRoot ) {
287 0 : m_poKmlDocKmlRoot = m_poKmlFactory->CreateKml ( );
288 :
289 0 : AsKml( m_poKmlDocKmlRoot )->set_feature ( m_poKmlDocKml );
290 : }
291 :
292 0 : std::string oKmlOut = kmldom::SerializePretty ( m_poKmlDocKmlRoot );
293 :
294 0 : const char *pszOutfile = CPLFormFilename ( pszName, "doc.kml", NULL );
295 :
296 0 : if ( !kmlbase::File::WriteStringToFile ( oKmlOut, pszOutfile ) ) {
297 : CPLError ( CE_Failure, CPLE_FileIO,
298 0 : "ERROR Writing %s to %s", "doc.kml", pszName );
299 0 : }
300 : }
301 :
302 : /***** loop though the layers and write them *****/
303 :
304 : int iLayer;
305 :
306 0 : for ( iLayer = 0; iLayer < nLayers; iLayer++ ) {
307 0 : ContainerPtr poKmlContainer = papoLayers[iLayer]->GetKmlLayer ( );
308 :
309 0 : if ( poKmlContainer->IsA ( kmldom::Type_Document ) ) {
310 :
311 0 : DocumentPtr poKmlDocument = AsDocument ( poKmlContainer );
312 0 : SchemaPtr poKmlSchema = papoLayers[iLayer]->GetKmlSchema ( );
313 :
314 0 : if ( !poKmlDocument->get_schema_array_size ( ) &&
315 : poKmlSchema &&
316 : poKmlSchema->get_simplefield_array_size ( ) ) {
317 0 : poKmlDocument->add_schema ( poKmlSchema );
318 0 : };
319 : }
320 :
321 : /***** if we dont have the layers root *****/
322 : /***** make it and add the container *****/
323 :
324 0 : KmlPtr poKmlKml = NULL;
325 :
326 0 : if ( !( poKmlKml = AsKml( papoLayers[iLayer]->GetKmlLayerRoot ( ) ) ) ) {
327 :
328 0 : poKmlKml = m_poKmlFactory->CreateKml ( );
329 :
330 0 : poKmlKml->set_feature ( poKmlContainer );
331 : }
332 :
333 0 : std::string oKmlOut = kmldom::SerializePretty ( poKmlKml );
334 :
335 : const char *pszOutfile = CPLFormFilename ( pszName,
336 : papoLayers[iLayer]->
337 : GetFileName ( ),
338 0 : NULL );
339 :
340 0 : if ( !kmlbase::File::WriteStringToFile ( oKmlOut, pszOutfile ) ) {
341 : CPLError ( CE_Failure, CPLE_FileIO,
342 : "ERROR Writing %s to %s",
343 0 : papoLayers[iLayer]->GetFileName ( ), pszName );
344 : }
345 :
346 : }
347 :
348 : /***** write the style table *****/
349 :
350 0 : if ( m_poKmlStyleKml ) {
351 :
352 0 : KmlPtr poKmlKml = m_poKmlFactory->CreateKml ( );
353 :
354 0 : poKmlKml->set_feature ( m_poKmlStyleKml );
355 0 : std::string oKmlOut = kmldom::SerializePretty ( poKmlKml );
356 :
357 : const char *pszOutfile = CPLFormFilename ( pszName,
358 : "style.kml",
359 0 : NULL );
360 :
361 0 : if ( !kmlbase::File::WriteStringToFile ( oKmlOut, pszOutfile ) ) {
362 : CPLError ( CE_Failure, CPLE_FileIO,
363 0 : "ERROR Writing %s to %s", "style.kml", pszName );
364 0 : }
365 : }
366 :
367 : return;
368 : }
369 :
370 : /******************************************************************************
371 : method to write the datasource to disk
372 :
373 : Args: none
374 :
375 : Returns nothing
376 :
377 : ******************************************************************************/
378 :
379 : OGRErr OGRLIBKMLDataSource::SyncToDisk (
380 16 : )
381 : {
382 :
383 16 : if ( bUpdated ) {
384 :
385 : /***** kml *****/
386 :
387 1 : if ( bUpdate && IsKml ( ) )
388 1 : WriteKml ( );
389 :
390 : /***** kmz *****/
391 :
392 0 : else if ( bUpdate && IsKmz ( ) ) {
393 0 : WriteKmz ( );
394 : }
395 :
396 0 : else if ( bUpdate && IsDir ( ) ) {
397 0 : WriteDir ( );
398 : }
399 :
400 1 : bUpdated = FALSE;
401 : }
402 :
403 16 : return OGRERR_NONE;
404 : }
405 :
406 : /******************************************************************************
407 : OGRLIBKMLDataSource Destructor
408 :
409 : Args: none
410 :
411 : Returns: nothing
412 :
413 : ******************************************************************************/
414 :
415 16 : OGRLIBKMLDataSource::~OGRLIBKMLDataSource ( )
416 : {
417 :
418 :
419 : /***** sync the DS to disk *****/
420 :
421 16 : SyncToDisk ( );
422 :
423 16 : CPLFree ( pszName );
424 :
425 :
426 31 : for ( int i = 0; i < nLayers; i++ )
427 15 : delete papoLayers[i];
428 :
429 16 : CPLFree ( papoLayers );
430 :
431 : //delete m_poStyleTable;
432 :
433 16 : }
434 :
435 :
436 : /******************************************************************************
437 : method to parse a schemas out of a document
438 :
439 : Args: poKmlDocument pointer to the document to parse
440 :
441 : Returns: nothing
442 :
443 : ******************************************************************************/
444 :
445 : SchemaPtr OGRLIBKMLDataSource::FindSchema (
446 0 : const char *pszSchemaUrl )
447 : {
448 0 : char *pszID = NULL;
449 0 : char *pszFile = NULL;
450 0 : char *pszName = NULL;
451 : char *pszPound;
452 0 : DocumentPtr poKmlDocument = NULL;
453 0 : SchemaPtr poKmlSchemaResult = NULL;
454 :
455 0 : if ( !pszSchemaUrl || !*pszSchemaUrl )
456 0 : return NULL;
457 :
458 0 : if ( *pszSchemaUrl == '#' ) {
459 0 : pszID = CPLStrdup ( pszSchemaUrl + 1 );
460 :
461 : /***** kml *****/
462 :
463 0 : if ( IsKml ( ) && m_poKmlDSContainer->IsA ( kmldom::Type_Document ) )
464 0 : poKmlDocument = AsDocument ( m_poKmlDSContainer );
465 :
466 : /***** kmz *****/
467 :
468 0 : else if ( ( IsKmz ( ) || IsDir ( ) ) && m_poKmlDocKml
469 : && m_poKmlDocKml->IsA ( kmldom::Type_Document ) )
470 0 : poKmlDocument = AsDocument ( m_poKmlDocKml );
471 :
472 : }
473 :
474 :
475 0 : else if ( ( pszPound = strchr ( (char *)pszSchemaUrl, '#' ) ) ) {
476 0 : pszFile = CPLStrdup ( pszSchemaUrl );
477 0 : pszID = CPLStrdup ( pszPound + 1 );
478 0 : pszPound = strchr ( pszFile, '#' );
479 0 : *pszPound = '\0';
480 : }
481 :
482 : else {
483 0 : pszName = CPLStrdup ( pszSchemaUrl );
484 :
485 : /***** kml *****/
486 :
487 0 : if ( IsKml ( ) && m_poKmlDSContainer->IsA ( kmldom::Type_Document ) )
488 0 : poKmlDocument = AsDocument ( m_poKmlDSContainer );
489 :
490 : /***** kmz *****/
491 :
492 0 : else if ( ( IsKmz ( ) || IsDir ( ) ) && m_poKmlDocKml
493 : && m_poKmlDocKml->IsA ( kmldom::Type_Document ) )
494 0 : poKmlDocument = AsDocument ( m_poKmlDocKml );
495 :
496 : }
497 :
498 :
499 0 : if ( poKmlDocument) {
500 :
501 0 : size_t nKmlSchemas = poKmlDocument->get_schema_array_size ( );
502 : size_t iKmlSchema;
503 :
504 0 : for ( iKmlSchema = 0; iKmlSchema < nKmlSchemas; iKmlSchema++ ) {
505 : SchemaPtr poKmlSchema =
506 0 : poKmlDocument->get_schema_array_at ( iKmlSchema );
507 0 : if ( poKmlSchema->has_id ( ) && pszID) {
508 0 : if ( EQUAL ( pszID, poKmlSchema->get_id ( ).c_str ( ) ) ) {
509 0 : poKmlSchemaResult = poKmlSchema;
510 0 : break;
511 : }
512 : }
513 :
514 0 : else if ( poKmlSchema->has_name ( ) && pszName) {
515 0 : if ( EQUAL ( pszName, poKmlSchema->get_name ( ).c_str ( ) ) ) {
516 0 : poKmlSchemaResult = poKmlSchema;
517 : break;
518 : }
519 : }
520 :
521 : }
522 : }
523 :
524 0 : if ( pszFile )
525 0 : CPLFree ( pszFile );
526 0 : if ( pszID )
527 0 : CPLFree ( pszID );
528 :
529 0 : return poKmlSchemaResult;
530 :
531 : }
532 :
533 : /******************************************************************************
534 : Method to allocate memory for the layer array, create the layer,
535 : and add it to the layer array
536 :
537 : Args: pszLayerName the name of the layer
538 : poSpatialRef the spacial Refrance for the layer
539 : eGType the layers geometry type
540 : poOgrDS pointer to the datasource the layer is in
541 : poKmlRoot pointer to the root kml element of the layer
542 : pszFileName the filename of the layer
543 : bNew true if its a new layer
544 : bUpdate true if the layer is writeable
545 : nGuess a guess at the number of additional layers
546 : we are going to need
547 :
548 : Returns: Pointer to the new layer
549 : ******************************************************************************/
550 :
551 : OGRLIBKMLLayer *OGRLIBKMLDataSource::AddLayer (
552 : const char *pszLayerName,
553 : OGRSpatialReference * poSpatialRef,
554 : OGRwkbGeometryType eGType,
555 : OGRLIBKMLDataSource * poOgrDS,
556 : ElementPtr poKmlRoot,
557 : ContainerPtr poKmlContainer,
558 : const char *pszFileName,
559 : int bNew,
560 : int bUpdate,
561 15 : int nGuess )
562 : {
563 :
564 : /***** check to see if we have enough space to store the layer *****/
565 :
566 15 : if ( nLayers == nAlloced ) {
567 6 : nAlloced += nGuess;
568 : void *tmp = CPLRealloc ( papoLayers,
569 6 : sizeof ( OGRLIBKMLLayer * ) * nAlloced );
570 :
571 6 : papoLayers = ( OGRLIBKMLLayer ** ) tmp;
572 : }
573 :
574 : /***** create the layer *****/
575 :
576 15 : int iLayer = nLayers++;
577 :
578 : OGRLIBKMLLayer *poOgrLayer = new OGRLIBKMLLayer ( pszLayerName,
579 : poSpatialRef,
580 : eGType,
581 : poOgrDS,
582 : poKmlRoot,
583 : poKmlContainer,
584 : pszFileName,
585 : bNew,
586 15 : bUpdate );
587 :
588 : /***** add the layer to the array *****/
589 :
590 15 : papoLayers[iLayer] = poOgrLayer;
591 :
592 15 : return poOgrLayer;
593 : }
594 :
595 : /******************************************************************************
596 : method to parse multiple layers out of a container
597 :
598 : Args: poKmlContainer pointer to the container to parse
599 : poOgrSRS SRS to use when creating the layer
600 :
601 : Returns: number of features in the container that are not another
602 : container
603 :
604 : ******************************************************************************/
605 :
606 : int OGRLIBKMLDataSource::ParseLayers (
607 : ContainerPtr poKmlContainer,
608 16 : OGRSpatialReference * poOgrSRS )
609 : {
610 16 : int nResult = 0;
611 :
612 : /***** if container is null just bail now *****/
613 :
614 16 : if ( !poKmlContainer )
615 0 : return nResult;
616 :
617 16 : size_t nKmlFeatures = poKmlContainer->get_feature_array_size ( );
618 :
619 : /***** loop over the container to seperate the style, layers, etc *****/
620 :
621 : size_t iKmlFeature;
622 :
623 91 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
624 : FeaturePtr poKmlFeat =
625 75 : poKmlContainer->get_feature_array_at ( iKmlFeature );
626 :
627 : /***** container *****/
628 :
629 75 : if ( poKmlFeat->IsA ( kmldom::Type_Container ) ) {
630 :
631 : /***** see if the container has a name *****/
632 :
633 13 : std::string oKmlFeatName;
634 13 : if ( poKmlFeat->has_name ( ) ) {
635 13 : oKmlFeatName = poKmlFeat->get_name ( );
636 : }
637 :
638 : /***** use the feature index number as the name *****/
639 : /***** not sure i like this c++ ich *****/
640 :
641 : else {
642 0 : std::stringstream oOut;
643 0 : oOut << iKmlFeature;
644 0 : oKmlFeatName = oOut.str ( );
645 : }
646 :
647 : /***** create the layer *****/
648 :
649 : AddLayer ( oKmlFeatName.c_str ( ),
650 : poOgrSRS, wkbUnknown, this,
651 13 : NULL, AsContainer( poKmlFeat ), "", FALSE, bUpdate, nKmlFeatures );
652 :
653 : }
654 :
655 : else
656 62 : nResult++;
657 : }
658 :
659 16 : return nResult;
660 : }
661 :
662 : /******************************************************************************
663 : function to get the container from the kmlroot
664 :
665 : Args: poKmlRoot the root element
666 :
667 : Returns: root if its a container, if its a kml the container it
668 : contains, or NULL
669 :
670 : ******************************************************************************/
671 :
672 : ContainerPtr GetContainerFromRoot (
673 4 : ElementPtr poKmlRoot )
674 : {
675 4 : ContainerPtr poKmlContainer = NULL;
676 :
677 4 : if ( poKmlRoot ) {
678 :
679 : /***** skip over the <kml> we want the container *****/
680 :
681 4 : if ( poKmlRoot->IsA ( kmldom::Type_kml ) ) {
682 :
683 4 : KmlPtr poKmlKml = AsKml ( poKmlRoot );
684 :
685 4 : if ( poKmlKml->has_feature ( ) ) {
686 4 : FeaturePtr poKmlFeat = poKmlKml->get_feature ( );
687 :
688 4 : if ( poKmlFeat->IsA ( kmldom::Type_Container ) )
689 3 : poKmlContainer = AsContainer ( poKmlFeat );
690 4 : }
691 :
692 : }
693 :
694 0 : else if ( poKmlRoot->IsA ( kmldom::Type_Container ) )
695 0 : poKmlContainer = AsContainer ( poKmlRoot );
696 : }
697 :
698 0 : return poKmlContainer;
699 : }
700 :
701 : /******************************************************************************
702 : method to open a kml file
703 :
704 : Args: pszFilename file to open
705 : bUpdate update mode
706 :
707 : Returns: True on success, false on failure
708 :
709 : ******************************************************************************/
710 :
711 : int OGRLIBKMLDataSource::OpenKml (
712 : const char *pszFilename,
713 4 : int bUpdate )
714 : {
715 4 : std::string oKmlKml;
716 :
717 4 : if ( !kmlbase::File::ReadFileToString ( pszFilename, &oKmlKml ) ) {
718 : CPLError ( CE_Failure, CPLE_OpenFailed,
719 0 : "%s is not a valid kml file", pszFilename );
720 0 : return FALSE;
721 : }
722 :
723 4 : CPLLocaleC oLocaleForcer;
724 :
725 : /***** create a SRS *****/
726 :
727 : OGRSpatialReference *poOgrSRS =
728 4 : new OGRSpatialReference ( OGRLIBKMLSRSWKT );
729 :
730 : /***** parse the kml into the DOM *****/
731 :
732 4 : std::string oKmlErrors;
733 :
734 4 : ElementPtr poKmlRoot = kmldom::Parse ( oKmlKml, &oKmlErrors );
735 :
736 4 : if ( !poKmlRoot ) {
737 : CPLError ( CE_Failure, CPLE_OpenFailed,
738 : "ERROR Parseing kml %s :%s",
739 0 : pszFilename, oKmlErrors.c_str ( ) );
740 0 : delete poOgrSRS;
741 :
742 0 : return FALSE;
743 : }
744 :
745 : /***** get the container from root *****/
746 :
747 4 : if ( !( m_poKmlDSContainer = GetContainerFromRoot ( poKmlRoot ) ) ) {
748 : CPLError ( CE_Failure, CPLE_OpenFailed,
749 : "ERROR Parseing kml %s :%s %s",
750 : pszFilename, "This file does not fit the OGR model,",
751 1 : "there is no container element at the root." );
752 1 : delete poOgrSRS;
753 :
754 1 : return FALSE;
755 : }
756 :
757 3 : m_isKml = TRUE;
758 :
759 : /***** get the styles *****/
760 :
761 3 : ParseStyles ( AsDocument ( m_poKmlDSContainer ), &m_poStyleTable );
762 :
763 : /***** parse for layers *****/
764 :
765 3 : int nPlacemarks = ParseLayers ( m_poKmlDSContainer, poOgrSRS );
766 :
767 : /***** if there is placemarks in the root its a layer *****/
768 :
769 3 : if ( nPlacemarks && !nLayers ) {
770 : AddLayer ( CPLGetBasename ( pszFilename ),
771 : poOgrSRS, wkbUnknown,
772 0 : this, poKmlRoot, m_poKmlDSContainer, pszFilename, FALSE, bUpdate, 1 );
773 : }
774 :
775 3 : delete poOgrSRS;
776 :
777 3 : return TRUE;
778 : }
779 :
780 : /******************************************************************************
781 : method to open a kmz file
782 :
783 : Args: pszFilename file to open
784 : bUpdate update mode
785 :
786 : Returns: True on success, false on failure
787 :
788 : ******************************************************************************/
789 :
790 :
791 : int OGRLIBKMLDataSource::OpenKmz (
792 : const char *pszFilename,
793 0 : int bUpdate )
794 : {
795 :
796 0 : KmzFile *poKmlKmzfile = KmzFile::OpenFromFile ( pszFilename );
797 :
798 0 : if ( !poKmlKmzfile ) {
799 : CPLError ( CE_Failure, CPLE_OpenFailed,
800 0 : "%s is not a valid kmz file", pszFilename );
801 0 : return FALSE;
802 : }
803 :
804 0 : CPLLocaleC oLocaleForcer;
805 :
806 : /***** read the doc.kml *****/
807 :
808 0 : std::string oKmlKml;
809 0 : std::string oKmlKmlPath;
810 0 : if ( !poKmlKmzfile->ReadKmlAndGetPath ( &oKmlKml, &oKmlKmlPath ) ) {
811 :
812 0 : return FALSE;
813 : }
814 :
815 : /***** create a SRS *****/
816 :
817 : OGRSpatialReference *poOgrSRS =
818 0 : new OGRSpatialReference ( OGRLIBKMLSRSWKT );
819 :
820 : /***** parse the kml into the DOM *****/
821 :
822 0 : std::string oKmlErrors;
823 0 : ElementPtr poKmlDocKmlRoot = kmldom::Parse ( oKmlKml, &oKmlErrors );
824 :
825 0 : if ( !poKmlDocKmlRoot ) {
826 : CPLError ( CE_Failure, CPLE_OpenFailed,
827 : "ERROR Parseing kml layer %s from %s :%s",
828 : oKmlKmlPath.c_str ( ),
829 0 : pszFilename, oKmlErrors.c_str ( ) );
830 0 : delete poOgrSRS;
831 :
832 0 : return FALSE;
833 : }
834 :
835 : /***** get the child contianer from root *****/
836 :
837 0 : ContainerPtr poKmlContainer;
838 :
839 0 : if (!(poKmlContainer = GetContainerFromRoot ( poKmlDocKmlRoot ))) {
840 : CPLError ( CE_Failure, CPLE_OpenFailed,
841 : "ERROR Parseing %s from %s :%s",
842 : oKmlKmlPath.c_str ( ),
843 0 : pszFilename, "kml contains no Containers" );
844 0 : delete poOgrSRS;
845 :
846 0 : return FALSE;
847 : }
848 :
849 : /***** loop over the container looking for network links *****/
850 :
851 0 : size_t nKmlFeatures = poKmlContainer->get_feature_array_size ( );
852 : size_t iKmlFeature;
853 0 : int nLinks = 0;
854 :
855 0 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
856 : FeaturePtr poKmlFeat =
857 0 : poKmlContainer->get_feature_array_at ( iKmlFeature );
858 :
859 : /***** is it a network link? *****/
860 :
861 0 : if ( !poKmlFeat->IsA ( kmldom::Type_NetworkLink ) )
862 0 : continue;
863 :
864 0 : NetworkLinkPtr poKmlNetworkLink = AsNetworkLink ( poKmlFeat );
865 :
866 : /***** does it have a link? *****/
867 :
868 0 : if ( !poKmlNetworkLink->has_link ( ) )
869 : continue;
870 :
871 0 : LinkPtr poKmlLink = poKmlNetworkLink->get_link ( );
872 :
873 : /***** does the link have a href? *****/
874 :
875 0 : if ( !poKmlLink->has_href ( ) )
876 : continue;
877 :
878 : kmlengine::Href * poKmlHref =
879 0 : new kmlengine::Href ( poKmlLink->get_href ( ) );
880 :
881 : /***** is the link relative? *****/
882 :
883 0 : if ( poKmlHref->IsRelativePath ( ) ) {
884 :
885 0 : nLinks++;
886 :
887 0 : std::string oKml;
888 0 : if ( poKmlKmzfile->
889 : ReadFile ( poKmlHref->get_path ( ).c_str ( ), &oKml ) ) {
890 :
891 : /***** parse the kml into the DOM *****/
892 :
893 0 : std::string oKmlErrors;
894 0 : ElementPtr poKmlLyrRoot = kmldom::Parse ( oKml, &oKmlErrors );
895 :
896 0 : if ( !poKmlLyrRoot ) {
897 : CPLError ( CE_Failure, CPLE_OpenFailed,
898 : "ERROR Parseing kml layer %s from %s :%s",
899 : poKmlHref->get_path ( ).c_str ( ),
900 0 : pszFilename, oKmlErrors.c_str ( ) );
901 0 : delete poKmlHref;
902 :
903 : continue;
904 : }
905 :
906 : /***** get the container from root *****/
907 :
908 : ContainerPtr poKmlLyrContainer =
909 0 : GetContainerFromRoot ( poKmlLyrRoot );
910 :
911 : /***** create the layer *****/
912 :
913 : AddLayer ( CPLGetBasename
914 : ( poKmlHref->get_path ( ).c_str ( ) ), poOgrSRS,
915 : wkbUnknown, this, poKmlLyrRoot, poKmlLyrContainer,
916 : poKmlHref->get_path ( ).c_str ( ), FALSE, bUpdate,
917 0 : nKmlFeatures );
918 :
919 0 : }
920 : }
921 :
922 : /***** cleanup *****/
923 :
924 0 : delete poKmlHref;
925 : }
926 :
927 : /***** if the doc.kml has links store it so if were in update mode we can write it *****/
928 :
929 0 : if ( nLinks ) {
930 0 : m_poKmlDocKml = poKmlContainer;
931 0 : m_poKmlDocKmlRoot = poKmlDocKmlRoot;
932 : }
933 :
934 : /***** if the doc.kml has no links treat it as a normal kml file *****/
935 :
936 : else {
937 :
938 : /* todo there could still be a seperate styles file in the kmz
939 : if there is this would be a layer style table IF its only a single
940 : layer
941 : */
942 :
943 : /***** get the styles *****/
944 :
945 0 : ParseStyles ( AsDocument ( poKmlContainer ), &m_poStyleTable );
946 :
947 : /***** parse for layers *****/
948 :
949 0 : int nPlacemarks = ParseLayers ( poKmlContainer, poOgrSRS );
950 :
951 : /***** if there is placemarks in the root its a layer *****/
952 :
953 0 : if ( nPlacemarks && !nLayers ) {
954 : AddLayer ( CPLGetBasename ( pszFilename ),
955 : poOgrSRS, wkbUnknown,
956 0 : this, poKmlDocKmlRoot, poKmlContainer, pszFilename, FALSE, bUpdate, 1 );
957 : }
958 : }
959 :
960 : /***** read the style table if it has one *****/
961 :
962 0 : std::string oKmlStyleKml;
963 0 : if ( poKmlKmzfile->ReadFile ( "style/style.kml", &oKmlStyleKml ) ) {
964 :
965 : /***** parse the kml into the dom *****/
966 :
967 0 : std::string oKmlErrors;
968 0 : ElementPtr poKmlRoot = kmldom::Parse ( oKmlStyleKml, &oKmlErrors );
969 :
970 0 : if ( poKmlRoot ) {
971 :
972 0 : ContainerPtr poKmlContainer;
973 :
974 0 : if ( ( poKmlContainer = GetContainerFromRoot ( poKmlRoot ) ) ) {
975 0 : ParseStyles ( AsDocument ( poKmlContainer ), &m_poStyleTable );
976 0 : pszStylePath = "style/style.kml";
977 0 : }
978 0 : }
979 : }
980 :
981 : /***** cleanup *****/
982 :
983 0 : delete poOgrSRS;
984 :
985 0 : delete poKmlKmzfile;
986 0 : m_isKmz = TRUE;
987 :
988 0 : return TRUE;
989 : }
990 :
991 : /******************************************************************************
992 : method to open a dir
993 :
994 : Args: pszFilename Dir to open
995 : bUpdate update mode
996 :
997 : Returns: True on success, false on failure
998 :
999 : ******************************************************************************/
1000 :
1001 : int OGRLIBKMLDataSource::OpenDir (
1002 : const char *pszFilename,
1003 1 : int bUpdate )
1004 : {
1005 :
1006 1 : char **papszDirList = NULL;
1007 :
1008 1 : if ( !( papszDirList = VSIReadDir ( pszFilename ) ) )
1009 0 : return FALSE;
1010 :
1011 : /***** create a SRS *****/
1012 :
1013 : OGRSpatialReference *poOgrSRS =
1014 1 : new OGRSpatialReference ( OGRLIBKMLSRSWKT );
1015 :
1016 1 : int nFiles = CSLCount ( papszDirList );
1017 : int iFile;
1018 :
1019 6 : for ( iFile = 0; iFile < nFiles; iFile++ ) {
1020 :
1021 : /***** make sure its a .kml file *****/
1022 :
1023 5 : if ( !EQUAL ( CPLGetExtension ( papszDirList[iFile] ), "kml" ) )
1024 5 : continue;
1025 :
1026 : /***** read the file *****/
1027 0 : std::string oKmlKml;
1028 : CPLString osFilePath =
1029 0 : CPLFormFilename ( pszFilename, papszDirList[iFile], NULL );
1030 :
1031 0 : if ( !kmlbase::File::ReadFileToString ( osFilePath.c_str(), &oKmlKml ) ) {
1032 : CPLError ( CE_Failure, CPLE_OpenFailed,
1033 0 : "%s is not a valid kml file", pszFilename );
1034 0 : continue;
1035 : }
1036 :
1037 0 : CPLLocaleC oLocaleForcer;
1038 :
1039 : /***** parse the kml into the DOM *****/
1040 :
1041 0 : std::string oKmlErrors;
1042 0 : ElementPtr poKmlRoot = kmldom::Parse ( oKmlKml, &oKmlErrors );
1043 :
1044 0 : if ( !poKmlRoot ) {
1045 : CPLError ( CE_Failure, CPLE_OpenFailed,
1046 : "ERROR Parseing kml layer %s from %s :%s",
1047 0 : osFilePath.c_str(), pszFilename, oKmlErrors.c_str ( ) );
1048 :
1049 : continue;
1050 : }
1051 :
1052 : /***** get the cintainer from the root *****/
1053 :
1054 0 : ContainerPtr poKmlContainer;
1055 :
1056 0 : if ( !( poKmlContainer = GetContainerFromRoot ( poKmlRoot ) ) ) {
1057 : CPLError ( CE_Failure, CPLE_OpenFailed,
1058 : "ERROR Parseing kml %s :%s %s",
1059 : pszFilename,
1060 : "This file does not fit the OGR model,",
1061 0 : "there is no container element at the root." );
1062 : continue;
1063 : }
1064 :
1065 : /***** is it a style table? *****/
1066 :
1067 0 : if ( EQUAL ( papszDirList[iFile], "style.kml" ) ) {
1068 0 : ParseStyles ( AsDocument ( poKmlContainer ), &m_poStyleTable );
1069 0 : pszStylePath = "style.kml";
1070 : continue;
1071 : }
1072 :
1073 : /***** create the layer *****/
1074 :
1075 : AddLayer ( CPLGetBasename ( osFilePath.c_str() ),
1076 : poOgrSRS, wkbUnknown,
1077 0 : this, poKmlRoot, poKmlContainer, osFilePath.c_str(), FALSE, bUpdate, nFiles );
1078 :
1079 : }
1080 :
1081 1 : delete poOgrSRS;
1082 :
1083 1 : CSLDestroy ( papszDirList );
1084 :
1085 1 : if ( nLayers > 0 ) {
1086 0 : m_isDir = TRUE;
1087 0 : return TRUE;
1088 : }
1089 :
1090 1 : return FALSE;
1091 : }
1092 :
1093 : /******************************************************************************
1094 : Method to open a datasource
1095 :
1096 : Args: pszFilename Darasource to open
1097 : bUpdate update mode
1098 :
1099 : Returns: True on success, false on failure
1100 :
1101 : ******************************************************************************/
1102 :
1103 : int OGRLIBKMLDataSource::Open (
1104 : const char *pszFilename,
1105 15 : int bUpdate )
1106 : {
1107 :
1108 15 : this->bUpdate = bUpdate;
1109 15 : pszName = CPLStrdup ( pszFilename );
1110 :
1111 : /***** dir *****/
1112 :
1113 15 : VSIStatBufL sStatBuf = { };
1114 15 : if ( !VSIStatL ( pszFilename, &sStatBuf ) &&
1115 : VSI_ISDIR ( sStatBuf.st_mode ) )
1116 1 : return OpenDir ( pszFilename, bUpdate );
1117 :
1118 : /***** kml *****/
1119 :
1120 14 : else if ( EQUAL ( CPLGetExtension ( pszFilename ), "kml" ) )
1121 4 : return OpenKml ( pszFilename, bUpdate );
1122 :
1123 : /***** kmz *****/
1124 :
1125 10 : else if ( EQUAL ( CPLGetExtension ( pszFilename ), "kmz" ) )
1126 0 : return OpenKmz ( pszFilename, bUpdate );
1127 :
1128 : else
1129 10 : return FALSE;
1130 :
1131 : return TRUE;
1132 : }
1133 :
1134 : /******************************************************************************
1135 : method to create a single file .kml ds
1136 :
1137 : Args: pszFilename the datasource to create
1138 : papszOptions datasource creation options
1139 :
1140 : Returns: True on success, false on failure
1141 :
1142 : ******************************************************************************/
1143 :
1144 : int OGRLIBKMLDataSource::CreateKml (
1145 : const char *pszFilename,
1146 1 : char **papszOptions )
1147 : {
1148 :
1149 1 : m_poKmlDSKml = m_poKmlFactory->CreateKml ( );
1150 1 : DocumentPtr poKmlDocument = m_poKmlFactory->CreateDocument ( );
1151 :
1152 1 : m_poKmlDSKml->set_feature ( poKmlDocument );
1153 1 : m_poKmlDSContainer = poKmlDocument;
1154 1 : m_isKml = TRUE;
1155 1 : bUpdated = TRUE;
1156 :
1157 1 : return true;
1158 : }
1159 :
1160 : /******************************************************************************
1161 : method to create a .kmz ds
1162 :
1163 : Args: pszFilename the datasource to create
1164 : papszOptions datasource creation options
1165 :
1166 : Returns: True on success, false on failure
1167 :
1168 : ******************************************************************************/
1169 :
1170 : int OGRLIBKMLDataSource::CreateKmz (
1171 : const char *pszFilename,
1172 0 : char **papszOptions )
1173 : {
1174 :
1175 :
1176 : /***** create the doc.kml *****/
1177 :
1178 0 : const char *namefield = CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
1179 :
1180 0 : if ( !strcmp ( namefield, "yes" ) ) {
1181 0 : m_poKmlDocKml = m_poKmlFactory->CreateDocument ( );
1182 : }
1183 :
1184 0 : pszStylePath = "style/style.kml";
1185 :
1186 0 : m_isKmz = TRUE;
1187 0 : bUpdated = TRUE;
1188 :
1189 0 : return TRUE;
1190 : }
1191 :
1192 : /******************************************************************************
1193 : Method to create a dir datasource
1194 :
1195 : Args: pszFilename the datasource to create
1196 : papszOptions datasource creation options
1197 :
1198 : Returns: True on success, false on failure
1199 :
1200 : ******************************************************************************/
1201 :
1202 : int OGRLIBKMLDataSource::CreateDir (
1203 : const char *pszFilename,
1204 0 : char **papszOptions )
1205 : {
1206 :
1207 0 : if ( VSIMkdir ( pszFilename, 0755 ) ) {
1208 : CPLError ( CE_Failure, CPLE_AppDefined,
1209 0 : "ERROR Creating dir: %s for KML datasource", pszFilename );
1210 0 : return FALSE;
1211 : }
1212 :
1213 0 : m_isDir = TRUE;
1214 0 : bUpdated = TRUE;
1215 :
1216 :
1217 0 : const char *namefield = CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
1218 :
1219 0 : if ( !strcmp ( namefield, "yes" ) ) {
1220 0 : m_poKmlDocKml = m_poKmlFactory->CreateDocument ( );
1221 : }
1222 :
1223 0 : pszStylePath = "style.kml";
1224 :
1225 0 : return TRUE;
1226 : }
1227 :
1228 :
1229 : /******************************************************************************
1230 : method to create a datasource
1231 :
1232 : Args: pszFilename the datasource to create
1233 : papszOptions datasource creation options
1234 :
1235 : Returns: True on success, false on failure
1236 :
1237 : env vars:
1238 : LIBKML_USE_DOC.KML default: yes
1239 :
1240 : ******************************************************************************/
1241 :
1242 : int OGRLIBKMLDataSource::Create (
1243 : const char *pszFilename,
1244 1 : char **papszOptions )
1245 : {
1246 :
1247 1 : int bResult = FALSE;
1248 :
1249 1 : pszName = CPLStrdup ( pszFilename );
1250 1 : bUpdate = TRUE;
1251 :
1252 : /***** kml *****/
1253 :
1254 1 : if ( EQUAL ( CPLGetExtension ( pszFilename ), "kml" ) )
1255 1 : bResult = CreateKml ( pszFilename, papszOptions );
1256 :
1257 : /***** kmz *****/
1258 :
1259 0 : else if ( EQUAL ( CPLGetExtension ( pszFilename ), "kmz" ) )
1260 0 : bResult = CreateKmz ( pszFilename, papszOptions );
1261 :
1262 : /***** dir *****/
1263 :
1264 : else
1265 0 : bResult = CreateDir ( pszFilename, papszOptions );
1266 :
1267 1 : return bResult;
1268 : }
1269 :
1270 : /******************************************************************************
1271 : method to get a layer by index
1272 :
1273 : Args: iLayer the index of the layer to get
1274 :
1275 : Returns: pointer to the layer, or NULL if the layer does not exist
1276 :
1277 : ******************************************************************************/
1278 :
1279 : OGRLayer *OGRLIBKMLDataSource::GetLayer (
1280 1 : int iLayer )
1281 : {
1282 1 : if ( iLayer < 0 || iLayer >= nLayers )
1283 0 : return NULL;
1284 : else
1285 1 : return papoLayers[iLayer];
1286 :
1287 : }
1288 :
1289 : /******************************************************************************
1290 : method to get a layer by name
1291 :
1292 : Args: pszname name of the layer to get
1293 :
1294 : Returns: pointer to the layer, or NULL if the layer does not exist
1295 :
1296 : ******************************************************************************/
1297 :
1298 : OGRLayer *OGRLIBKMLDataSource::GetLayerByName (
1299 8 : const char *pszname )
1300 : {
1301 8 : int iLayer = 0;
1302 :
1303 35 : for ( iLayer = 0; iLayer < nLayers; iLayer++ ) {
1304 35 : if ( EQUAL ( pszname, papoLayers[iLayer]->GetName ( ) ) )
1305 8 : return papoLayers[iLayer];
1306 : }
1307 :
1308 0 : return NULL;
1309 : }
1310 :
1311 :
1312 : /******************************************************************************
1313 : method to DeleteLayers in a .kml datasource
1314 :
1315 : Args: iLayer index of the layer to delete
1316 :
1317 : Returns: OGRERR_NONE on success, OGRERR_FAILURE on failure
1318 :
1319 : ******************************************************************************/
1320 :
1321 : OGRErr OGRLIBKMLDataSource::DeleteLayerKml (
1322 0 : int iLayer )
1323 : {
1324 0 : OGRLIBKMLLayer *poOgrLayer = ( OGRLIBKMLLayer * ) papoLayers[iLayer];
1325 :
1326 : /***** loop over the features *****/
1327 :
1328 0 : size_t nKmlFeatures = m_poKmlDSContainer->get_feature_array_size ( );
1329 : size_t iKmlFeature;
1330 :
1331 0 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
1332 : FeaturePtr poKmlFeat =
1333 0 : m_poKmlDSContainer->get_feature_array_at ( iKmlFeature );
1334 :
1335 0 : if ( poKmlFeat == poOgrLayer->GetKmlLayer ( ) ) {
1336 0 : m_poKmlDSContainer->DeleteFeatureAt ( iKmlFeature );
1337 0 : break;
1338 : }
1339 :
1340 : }
1341 :
1342 :
1343 0 : return OGRERR_NONE;
1344 : }
1345 :
1346 : /******************************************************************************
1347 : method to DeleteLayers in a .kmz datasource
1348 :
1349 : Args: iLayer index of the layer to delete
1350 :
1351 : Returns: OGRERR_NONE on success, OGRERR_FAILURE on failure
1352 :
1353 : ******************************************************************************/
1354 :
1355 : OGRErr OGRLIBKMLDataSource::DeleteLayerKmz (
1356 0 : int iLayer )
1357 : {
1358 0 : OGRLIBKMLLayer *poOgrLayer = ( OGRLIBKMLLayer * ) papoLayers[iLayer];
1359 :
1360 : const char *pszUseDocKml =
1361 0 : CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
1362 :
1363 0 : if ( EQUAL ( pszUseDocKml, "yes" ) && m_poKmlDocKml ) {
1364 :
1365 : /***** loop over the features *****/
1366 :
1367 0 : size_t nKmlFeatures = m_poKmlDocKml->get_feature_array_size ( );
1368 : size_t iKmlFeature;
1369 :
1370 0 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
1371 : FeaturePtr poKmlFeat =
1372 0 : m_poKmlDocKml->get_feature_array_at ( iKmlFeature );
1373 :
1374 0 : if ( poKmlFeat->IsA ( kmldom::Type_NetworkLink ) ) {
1375 0 : NetworkLinkPtr poKmlNetworkLink = AsNetworkLink ( poKmlFeat );
1376 :
1377 : /***** does it have a link? *****/
1378 :
1379 0 : if ( poKmlNetworkLink->has_link ( ) ) {
1380 0 : LinkPtr poKmlLink = poKmlNetworkLink->get_link ( );
1381 :
1382 : /***** does the link have a href? *****/
1383 :
1384 0 : if ( poKmlLink->has_href ( ) ) {
1385 : kmlengine::Href * poKmlHref =
1386 0 : new kmlengine::Href ( poKmlLink->get_href ( ) );
1387 :
1388 : /***** is the link relative? *****/
1389 :
1390 0 : if ( poKmlHref->IsRelativePath ( ) ) {
1391 :
1392 : const char *pszLink =
1393 0 : poKmlHref->get_path ( ).c_str ( );
1394 :
1395 0 : if ( EQUAL
1396 : ( pszLink, poOgrLayer->GetFileName ( ) ) ) {
1397 0 : m_poKmlDocKml->DeleteFeatureAt ( iKmlFeature );
1398 0 : break;
1399 : }
1400 :
1401 :
1402 : }
1403 0 : }
1404 0 : }
1405 : }
1406 : }
1407 :
1408 : }
1409 :
1410 0 : return OGRERR_NONE;
1411 : }
1412 :
1413 : /******************************************************************************
1414 : method to delete a layer in a datasource
1415 :
1416 : Args: iLayer index of the layer to delete
1417 :
1418 : Returns: OGRERR_NONE on success, OGRERR_FAILURE on failure
1419 :
1420 : ******************************************************************************/
1421 :
1422 : OGRErr OGRLIBKMLDataSource::DeleteLayer (
1423 0 : int iLayer )
1424 : {
1425 :
1426 0 : if ( !bUpdate )
1427 0 : return OGRERR_UNSUPPORTED_OPERATION;
1428 :
1429 0 : if ( iLayer >= nLayers )
1430 0 : return OGRERR_FAILURE;
1431 :
1432 0 : if ( IsKml ( ) )
1433 0 : DeleteLayerKml ( iLayer );
1434 :
1435 0 : else if ( IsKmz ( ) )
1436 0 : DeleteLayerKmz ( iLayer );
1437 :
1438 0 : else if ( IsDir ( ) ) {
1439 0 : DeleteLayerKmz ( iLayer );
1440 :
1441 : /***** delete the file the layer corisponds to *****/
1442 :
1443 : const char *pszFilePath =
1444 : CPLFormFilename ( pszName, papoLayers[iLayer]->GetFileName ( ),
1445 0 : NULL );
1446 0 : VSIStatBufL oStatBufL = { };
1447 0 : if ( !VSIStatL ( pszFilePath, &oStatBufL ) ) {
1448 0 : if ( VSIUnlink ( pszFilePath ) ) {
1449 : CPLError ( CE_Failure, CPLE_AppDefined,
1450 : "ERROR Deleteing Layer %s from filesystem as %s",
1451 0 : papoLayers[iLayer]->GetName ( ), pszFilePath );
1452 : }
1453 : }
1454 : }
1455 :
1456 :
1457 0 : delete papoLayers[iLayer];
1458 : memmove ( papoLayers + iLayer, papoLayers + iLayer + 1,
1459 0 : sizeof ( void * ) * ( nLayers - iLayer - 1 ) );
1460 0 : nLayers--;
1461 0 : bUpdated = TRUE;
1462 :
1463 0 : return OGRERR_NONE;
1464 : }
1465 :
1466 : /******************************************************************************
1467 : method to create a layer in a single file .kml
1468 :
1469 : Args: pszLayerName name of the layer to create
1470 : poOgrSRS the SRS of the layer
1471 : eGType the layers geometry type
1472 : papszOptions layer creation options
1473 :
1474 : Returns: return a pointer to the new layer or NULL on failure
1475 :
1476 : ******************************************************************************/
1477 :
1478 : OGRLayer *OGRLIBKMLDataSource::CreateLayerKml (
1479 : const char *pszLayerName,
1480 : OGRSpatialReference * poOgrSRS,
1481 : OGRwkbGeometryType eGType,
1482 2 : char **papszOptions )
1483 : {
1484 :
1485 2 : OGRLIBKMLLayer *poOgrLayer = NULL;
1486 :
1487 2 : DocumentPtr poKmlDocument = m_poKmlFactory->CreateDocument ( );
1488 :
1489 2 : m_poKmlDSContainer->add_feature ( poKmlDocument );
1490 :
1491 : /***** create the layer *****/
1492 :
1493 : poOgrLayer = AddLayer ( pszLayerName, poOgrSRS, eGType, this,
1494 2 : NULL, poKmlDocument, "", TRUE, bUpdate, 1 );
1495 :
1496 : /***** add the layer name as a <Name> *****/
1497 :
1498 2 : poKmlDocument->set_name ( pszLayerName );
1499 :
1500 2 : return ( OGRLayer * ) poOgrLayer;
1501 : }
1502 :
1503 : /******************************************************************************
1504 : method to create a layer in a .kmz or dir
1505 :
1506 : Args: pszLayerName name of the layer to create
1507 : poOgrSRS the SRS of the layer
1508 : eGType the layers geometry type
1509 : papszOptions layer creation options
1510 :
1511 : Returns: return a pointer to the new layer or NULL on failure
1512 :
1513 : ******************************************************************************/
1514 :
1515 : OGRLayer *OGRLIBKMLDataSource::CreateLayerKmz (
1516 : const char *pszLayerName,
1517 : OGRSpatialReference * poOgrSRS,
1518 : OGRwkbGeometryType eGType,
1519 0 : char **papszOptions )
1520 : {
1521 :
1522 : /***** add a network link to doc.kml *****/
1523 :
1524 : const char *pszUseDocKml =
1525 0 : CPLGetConfigOption ( "LIBKML_USE_DOC.KML", "yes" );
1526 :
1527 0 : if ( EQUAL ( pszUseDocKml, "yes" ) && m_poKmlDocKml ) {
1528 :
1529 0 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlDocKml );
1530 :
1531 0 : NetworkLinkPtr poKmlNetLink = m_poKmlFactory->CreateNetworkLink ( );
1532 0 : LinkPtr poKmlLink = m_poKmlFactory->CreateLink ( );
1533 :
1534 0 : std::string oHref;
1535 0 : oHref.append ( pszLayerName );
1536 0 : oHref.append ( ".kml" );
1537 0 : poKmlLink->set_href ( oHref );
1538 :
1539 0 : poKmlNetLink->set_link ( poKmlLink );
1540 0 : poKmlDocument->add_feature ( poKmlNetLink );
1541 :
1542 : }
1543 :
1544 : /***** create the layer *****/
1545 :
1546 0 : OGRLIBKMLLayer *poOgrLayer = NULL;
1547 :
1548 0 : DocumentPtr poKmlDocument = m_poKmlFactory->CreateDocument ( );
1549 :
1550 : poOgrLayer = AddLayer ( pszLayerName, poOgrSRS, eGType, this,
1551 : NULL, poKmlDocument,
1552 : CPLFormFilename ( NULL, pszLayerName, ".kml" ),
1553 0 : TRUE, bUpdate, 1 );
1554 :
1555 : /***** add the layer name as a <Name> *****/
1556 :
1557 0 : poKmlDocument->set_name ( pszLayerName );
1558 :
1559 0 : return ( OGRLayer * ) poOgrLayer;
1560 : }
1561 :
1562 : /******************************************************************************
1563 : CreateLayer()
1564 :
1565 : Args: pszLayerName name of the layer to create
1566 : poOgrSRS the SRS of the layer
1567 : eGType the layers geometry type
1568 : papszOptions layer creation options
1569 :
1570 : Returns: return a pointer to the new layer or NULL on failure
1571 :
1572 : ******************************************************************************/
1573 :
1574 : OGRLayer *OGRLIBKMLDataSource::CreateLayer (
1575 : const char *pszLayerName,
1576 : OGRSpatialReference * poOgrSRS,
1577 : OGRwkbGeometryType eGType,
1578 2 : char **papszOptions )
1579 : {
1580 :
1581 2 : if ( !bUpdate )
1582 0 : return NULL;
1583 :
1584 2 : OGRLayer *poOgrLayer = NULL;
1585 :
1586 : /***** kml DS *****/
1587 :
1588 2 : if ( IsKml ( ) ) {
1589 : poOgrLayer = CreateLayerKml ( pszLayerName, poOgrSRS,
1590 2 : eGType, papszOptions );
1591 :
1592 : }
1593 :
1594 0 : else if ( IsKmz ( ) || IsDir ( ) ) {
1595 : poOgrLayer = CreateLayerKmz ( pszLayerName, poOgrSRS,
1596 0 : eGType, papszOptions );
1597 :
1598 : }
1599 :
1600 :
1601 :
1602 :
1603 : /***** mark the dataset as updated *****/
1604 :
1605 2 : if ( poOgrLayer )
1606 2 : bUpdated = TRUE;
1607 :
1608 2 : return poOgrLayer;
1609 : }
1610 :
1611 : /******************************************************************************
1612 : method to get a datasources style table
1613 :
1614 : Args: none
1615 :
1616 : Returns: pointer to the datasources style table, or NULL if it does
1617 : not have one
1618 :
1619 : ******************************************************************************/
1620 :
1621 : OGRStyleTable *OGRLIBKMLDataSource::GetStyleTable (
1622 0 : )
1623 : {
1624 :
1625 0 : return m_poStyleTable;
1626 : }
1627 :
1628 : /******************************************************************************
1629 : method to write a style table to a single file .kml ds
1630 :
1631 : Args: poStyleTable pointer to the style table to add
1632 :
1633 : Returns: nothing
1634 :
1635 : ******************************************************************************/
1636 :
1637 : void OGRLIBKMLDataSource::SetStyleTable2Kml (
1638 0 : OGRStyleTable * poStyleTable )
1639 : {
1640 :
1641 : /***** delete all the styles *****/
1642 :
1643 0 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlDSContainer );
1644 0 : size_t nKmlStyles = poKmlDocument->get_styleselector_array_size ( );
1645 : int iKmlStyle;
1646 :
1647 0 : for ( iKmlStyle = nKmlStyles - 1; iKmlStyle >= 0; iKmlStyle-- ) {
1648 0 : poKmlDocument->DeleteStyleSelectorAt ( iKmlStyle );
1649 : }
1650 :
1651 : /***** add the new style table to the document *****/
1652 :
1653 : styletable2kml ( poStyleTable, m_poKmlFactory,
1654 0 : AsContainer ( poKmlDocument ) );
1655 :
1656 0 : return;
1657 : }
1658 :
1659 : /******************************************************************************
1660 : method to write a style table to a kmz ds
1661 :
1662 : Args: poStyleTable pointer to the style table to add
1663 :
1664 : Returns: nothing
1665 :
1666 : ******************************************************************************/
1667 :
1668 : void OGRLIBKMLDataSource::SetStyleTable2Kmz (
1669 0 : OGRStyleTable * poStyleTable )
1670 : {
1671 :
1672 : /***** replace the style document with a new one *****/
1673 :
1674 0 : m_poKmlStyleKml = m_poKmlFactory->CreateDocument ( );
1675 :
1676 0 : styletable2kml ( poStyleTable, m_poKmlFactory, m_poKmlStyleKml );
1677 :
1678 : return;
1679 : }
1680 :
1681 : /******************************************************************************
1682 : method to write a style table to a datasource
1683 :
1684 : Args: poStyleTable pointer to the style table to add
1685 :
1686 : Returns: nothing
1687 :
1688 : note: this method assumes ownership of the style table
1689 :
1690 : ******************************************************************************/
1691 :
1692 : void OGRLIBKMLDataSource::SetStyleTableDirectly (
1693 0 : OGRStyleTable * poStyleTable )
1694 : {
1695 :
1696 0 : if ( !bUpdate )
1697 0 : return;
1698 :
1699 0 : if ( m_poStyleTable )
1700 0 : delete m_poStyleTable;
1701 :
1702 0 : m_poStyleTable = poStyleTable;
1703 :
1704 : /***** a kml datasource? *****/
1705 :
1706 0 : if ( IsKml ( ) )
1707 0 : SetStyleTable2Kml ( m_poStyleTable );
1708 :
1709 0 : else if ( IsKmz ( ) || IsDir ( ) )
1710 0 : SetStyleTable2Kmz ( m_poStyleTable );
1711 :
1712 0 : bUpdated = TRUE;
1713 :
1714 :
1715 :
1716 :
1717 0 : return;
1718 : }
1719 :
1720 : /******************************************************************************
1721 : method to write a style table to a datasource
1722 :
1723 : Args: poStyleTable pointer to the style table to add
1724 :
1725 : Returns: nothing
1726 :
1727 : note: this method copys the style table, and the user will still be
1728 : responsible for its destruction
1729 :
1730 : ******************************************************************************/
1731 :
1732 : void OGRLIBKMLDataSource::SetStyleTable (
1733 0 : OGRStyleTable * poStyleTable )
1734 : {
1735 :
1736 0 : if ( !bUpdate )
1737 0 : return;
1738 :
1739 0 : if ( poStyleTable )
1740 0 : SetStyleTableDirectly ( poStyleTable->Clone ( ) );
1741 : else
1742 0 : SetStyleTableDirectly ( NULL );
1743 0 : return;
1744 : }
1745 :
1746 :
1747 : /******************************************************************************
1748 : Test if capability is available.
1749 :
1750 : Args: pszCap datasource capability name to test
1751 :
1752 : Returns: nothing
1753 :
1754 : ODsCCreateLayer: True if this datasource can create new layers.
1755 : ODsCDeleteLayer: True if this datasource can delete existing layers.
1756 :
1757 : ******************************************************************************/
1758 :
1759 : int OGRLIBKMLDataSource::TestCapability (
1760 0 : const char *pszCap )
1761 : {
1762 :
1763 0 : if ( EQUAL ( pszCap, ODsCCreateLayer ) )
1764 0 : return bUpdate;
1765 0 : else if ( EQUAL ( pszCap, ODsCDeleteLayer ) )
1766 0 : return bUpdate;
1767 : else
1768 0 : return FALSE;
1769 :
1770 896 : }
|