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