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 "ogr_libkml.h"
30 : //#include "cpl_conv.h"
31 : //#include "cpl_string.h"
32 : #include "cpl_error.h"
33 :
34 : #include <kml/dom.h>
35 :
36 : using kmldom::KmlFactory;
37 : using kmldom::PlacemarkPtr;
38 : using kmldom::Placemark;
39 : using kmldom::DocumentPtr;
40 : using kmldom::ContainerPtr;
41 : using kmldom::FeaturePtr;
42 : using kmldom::KmlPtr;
43 : using kmldom::Kml;
44 : using kmlengine::KmzFile;
45 : using kmlengine::KmlFile;
46 : using kmlengine::Bbox;
47 : using kmldom::ExtendedDataPtr;
48 : using kmldom::SchemaDataPtr;
49 : using kmldom::DataPtr;
50 :
51 : #include "ogrlibkmlfeature.h"
52 : #include "ogrlibkmlfield.h"
53 : #include "ogrlibkmlstyle.h"
54 :
55 : /******************************************************************************
56 : OGRLIBKMLLayer constructor
57 :
58 : Args: pszLayerName the name of the layer
59 : poSpatialRef the spacial Refrance for the layer
60 : eGType the layers geometry type
61 : poOgrDS pointer to the datasource the layer is in
62 : poKmlRoot pointer to the root kml element of the layer
63 : pszFileName the filename of the layer
64 : bNew true if its a new layer
65 : bUpdate true if the layer is writeable
66 :
67 : Returns: nothing
68 :
69 : ******************************************************************************/
70 :
71 46 : OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
72 : OGRSpatialReference * poSpatialRef,
73 : OGRwkbGeometryType eGType,
74 : OGRLIBKMLDataSource * poOgrDS,
75 : ElementPtr poKmlRoot,
76 : ContainerPtr poKmlContainer,
77 : const char *pszFileName,
78 : int bNew,
79 46 : int bUpdate )
80 : {
81 :
82 46 : m_poStyleTable = NULL;
83 46 : iFeature = 0;
84 46 : nFeatures = 0;
85 46 : nFID = 1;
86 :
87 46 : this->bUpdate = bUpdate;
88 46 : m_pszName = CPLStrdup ( pszLayerName );
89 46 : m_pszFileName = CPLStrdup ( pszFileName );
90 46 : m_poOgrDS = poOgrDS;
91 :
92 46 : m_poOgrSRS = new OGRSpatialReference ( NULL );
93 46 : m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );
94 :
95 46 : m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
96 46 : m_poOgrFeatureDefn->Reference ( );
97 46 : m_poOgrFeatureDefn->SetGeomType ( eGType );
98 :
99 : /***** store the root element pointer *****/
100 :
101 46 : m_poKmlLayerRoot = poKmlRoot;
102 :
103 : /***** store the layers container *****/
104 :
105 46 : m_poKmlLayer = poKmlContainer;
106 :
107 : /***** was the layer created from a DS::Open *****/
108 :
109 46 : if ( !bNew ) {
110 :
111 : /***** get the number of features on the layer *****/
112 :
113 40 : nFeatures = m_poKmlLayer->get_feature_array_size ( );
114 :
115 : /***** add the name and desc fields *****/
116 :
117 : const char *namefield =
118 40 : CPLGetConfigOption ( "LIBKML_NAME_FIELD", "Name" );
119 : const char *descfield =
120 40 : CPLGetConfigOption ( "LIBKML_DESCRIPTION_FIELD", "description" );
121 : const char *tsfield =
122 40 : CPLGetConfigOption ( "LIBKML_TIMESTAMP_FIELD", "timestamp" );
123 : const char *beginfield =
124 40 : CPLGetConfigOption ( "LIBKML_BEGIN_FIELD", "begin" );
125 : const char *endfield =
126 40 : CPLGetConfigOption ( "LIBKML_END_FIELD", "end" );
127 : const char *altitudeModefield =
128 40 : CPLGetConfigOption ( "LIBKML_ALTITUDEMODE_FIELD", "altitudeMode" );
129 : const char *tessellatefield =
130 40 : CPLGetConfigOption ( "LIBKML_TESSELLATE_FIELD", "tessellate" );
131 : const char *extrudefield =
132 40 : CPLGetConfigOption ( "LIBKML_EXTRUDE_FIELD", "extrude" );
133 : const char *visibilityfield =
134 40 : CPLGetConfigOption ( "LIBKML_VISIBILITY_FIELD", "visibility" );
135 :
136 : OGRFieldDefn oOgrFieldName (
137 : namefield,
138 40 : OFTString );
139 :
140 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
141 :
142 : OGRFieldDefn oOgrFieldDesc (
143 : descfield,
144 40 : OFTString );
145 :
146 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldDesc );
147 :
148 : OGRFieldDefn oOgrFieldTs (
149 : tsfield,
150 40 : OFTDateTime );
151 :
152 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTs );
153 :
154 : OGRFieldDefn oOgrFieldBegin (
155 : beginfield,
156 40 : OFTDateTime );
157 :
158 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldBegin );
159 :
160 : OGRFieldDefn oOgrFieldEnd (
161 : endfield,
162 40 : OFTDateTime );
163 :
164 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldEnd );
165 :
166 : OGRFieldDefn oOgrFieldAltitudeMode (
167 : altitudeModefield,
168 40 : OFTString );
169 :
170 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldAltitudeMode );
171 :
172 : OGRFieldDefn oOgrFieldTessellate (
173 : tessellatefield,
174 40 : OFTInteger );
175 :
176 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldTessellate );
177 :
178 : OGRFieldDefn oOgrFieldExtrude (
179 : extrudefield,
180 40 : OFTInteger );
181 :
182 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldExtrude );
183 :
184 : OGRFieldDefn oOgrFieldVisibility (
185 : visibilityfield,
186 40 : OFTInteger );
187 :
188 40 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldVisibility );
189 :
190 : /***** get the styles *****/
191 :
192 40 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) )
193 12 : ParseStyles ( AsDocument ( m_poKmlLayer ), &m_poStyleTable );
194 :
195 : /***** get the schema if the layer is a Document *****/
196 :
197 40 : m_poKmlSchema = NULL;
198 :
199 40 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
200 12 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
201 :
202 12 : if ( poKmlDocument->get_schema_array_size ( ) ) {
203 2 : m_poKmlSchema = poKmlDocument->get_schema_array_at ( 0 );
204 2 : kml2FeatureDef ( m_poKmlSchema, m_poOgrFeatureDefn );
205 12 : }
206 : }
207 :
208 : /***** the schema is somewhere else *****/
209 :
210 40 : if (m_poKmlSchema == NULL) {
211 :
212 : /***** try to find the correct schema *****/
213 :
214 38 : FeaturePtr poKmlFeature;
215 :
216 : /***** find the first placemark *****/
217 :
218 132 : do {
219 76 : if ( iFeature >= nFeatures )
220 10 : break;
221 :
222 : poKmlFeature =
223 66 : m_poKmlLayer->get_feature_array_at ( iFeature++ );
224 :
225 66 : } while ( poKmlFeature->Type ( ) != kmldom::Type_Placemark );
226 :
227 76 : if ( iFeature <= nFeatures && poKmlFeature &&
228 38 : poKmlFeature->Type ( ) == kmldom::Type_Placemark &&
229 : poKmlFeature->has_extendeddata ( ) ) {
230 :
231 : ExtendedDataPtr poKmlExtendedData = poKmlFeature->
232 1 : get_extendeddata ( );
233 :
234 1 : if ( poKmlExtendedData->get_schemadata_array_size ( ) > 0 ) {
235 : SchemaDataPtr poKmlSchemaData = poKmlExtendedData->
236 1 : get_schemadata_array_at ( 0 );
237 :
238 1 : if ( poKmlSchemaData->has_schemaurl ( ) ) {
239 :
240 : std::string oKmlSchemaUrl = poKmlSchemaData->
241 1 : get_schemaurl ( );
242 1 : if ( ( m_poKmlSchema =
243 : m_poOgrDS->FindSchema ( oKmlSchemaUrl.
244 : c_str ( ) ) ) ) {
245 : kml2FeatureDef ( m_poKmlSchema,
246 1 : m_poOgrFeatureDefn );
247 1 : }
248 1 : }
249 : }
250 0 : else if ( poKmlExtendedData->get_data_array_size() > 0 )
251 : {
252 : /* Use the <Data> of the first placemark to build the feature definition */
253 : /* If others have different fields, too bad... */
254 : int bLaunderFieldNames =
255 0 : CSLTestBoolean(CPLGetConfigOption("LIBKML_LAUNDER_FIELD_NAMES", "YES"));
256 0 : size_t nDataArraySize = poKmlExtendedData->get_data_array_size();
257 0 : for(size_t i=0; i < nDataArraySize; i++)
258 : {
259 0 : const DataPtr& data = poKmlExtendedData->get_data_array_at(i);
260 0 : if (data->has_name())
261 : {
262 0 : CPLString osName = data->get_name();
263 0 : if (bLaunderFieldNames)
264 0 : osName = LaunderFieldNames(osName);
265 : OGRFieldDefn oOgrField ( osName,
266 0 : OFTString );
267 0 : m_poOgrFeatureDefn->AddFieldDefn ( &oOgrField );
268 : }
269 : }
270 1 : }
271 : }
272 :
273 38 : iFeature = 0;
274 :
275 : }
276 :
277 :
278 :
279 : /***** check if any features are another layer *****/
280 :
281 40 : m_poOgrDS->ParseLayers ( m_poKmlLayer, poSpatialRef );
282 :
283 : }
284 :
285 : /***** it was from a DS::CreateLayer *****/
286 :
287 : else {
288 :
289 : /***** mark the layer as updated *****/
290 :
291 6 : bUpdated = TRUE;
292 :
293 : /***** create a new schema *****/
294 :
295 6 : KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
296 :
297 6 : m_poKmlSchema = poKmlFactory->CreateSchema ( );
298 :
299 : /***** set the id on the new schema *****/
300 :
301 6 : std::string oKmlSchemaID = m_pszName;
302 6 : oKmlSchemaID.append ( ".schema" );
303 6 : m_poKmlSchema->set_id ( oKmlSchemaID );
304 : }
305 :
306 :
307 :
308 :
309 46 : }
310 :
311 : /******************************************************************************
312 : OGRLIBKMLLayer Destructor
313 :
314 : Args: none
315 :
316 : Returns: nothing
317 :
318 : ******************************************************************************/
319 :
320 46 : OGRLIBKMLLayer::~OGRLIBKMLLayer ( )
321 : {
322 :
323 46 : CPLFree ( ( void * )m_pszName );
324 46 : CPLFree ( ( void * )m_pszFileName );
325 46 : delete m_poOgrSRS;
326 :
327 46 : m_poOgrFeatureDefn->Release ( );
328 :
329 :
330 46 : }
331 :
332 :
333 : /******************************************************************************
334 : Method to get the next feature on the layer
335 :
336 : Args: none
337 :
338 : Returns: The next feature, or NULL if there is no more
339 :
340 : this function copyed from the sqlite driver
341 : ******************************************************************************/
342 :
343 354 : OGRFeature *OGRLIBKMLLayer::GetNextFeature()
344 :
345 : {
346 65 : for( ; TRUE; )
347 : {
348 : OGRFeature *poFeature;
349 :
350 354 : poFeature = GetNextRawFeature();
351 354 : if( poFeature == NULL )
352 78 : return NULL;
353 :
354 276 : if( (m_poFilterGeom == NULL
355 : || FilterGeometry( poFeature->GetGeometryRef() ) )
356 : && (m_poAttrQuery == NULL
357 : || m_poAttrQuery->Evaluate( poFeature )) )
358 211 : return poFeature;
359 :
360 65 : delete poFeature;
361 : }
362 : }
363 :
364 : /******************************************************************************
365 : Method to get the next feature on the layer
366 :
367 : Args: none
368 :
369 : Returns: The next feature, or NULL if there is no more
370 :
371 : ******************************************************************************/
372 :
373 354 : OGRFeature *OGRLIBKMLLayer::GetNextRawFeature (
374 : )
375 : {
376 354 : FeaturePtr poKmlFeature;
377 354 : OGRFeature *poOgrFeature = NULL;
378 :
379 680 : do {
380 418 : if ( iFeature >= nFeatures )
381 78 : break;
382 :
383 340 : poKmlFeature = m_poKmlLayer->get_feature_array_at ( iFeature++ );
384 :
385 340 : } while ( poKmlFeature->Type ( ) != kmldom::Type_Placemark );
386 :
387 :
388 645 : if ( iFeature <= nFeatures && poKmlFeature
389 291 : && poKmlFeature->Type ( ) == kmldom::Type_Placemark ) {
390 : poOgrFeature =
391 : kml2feat ( AsPlacemark ( poKmlFeature ), m_poOgrDS, this,
392 276 : m_poOgrFeatureDefn, m_poOgrSRS );
393 276 : poOgrFeature->SetFID(nFID ++);
394 : }
395 :
396 354 : return poOgrFeature;
397 : }
398 :
399 : /******************************************************************************
400 : method to add a feature to a layer
401 :
402 : Args: poOgrFeat pointer to the feature to add
403 :
404 : Returns: OGRERR_NONE, or OGRERR_UNSUPPORTED_OPERATION of the layer is
405 : not writeable
406 :
407 : ******************************************************************************/
408 :
409 27 : OGRErr OGRLIBKMLLayer::CreateFeature (
410 : OGRFeature * poOgrFeat )
411 : {
412 :
413 27 : if ( !bUpdate )
414 0 : return OGRERR_UNSUPPORTED_OPERATION;
415 :
416 : PlacemarkPtr poKmlPlacemark =
417 27 : feat2kml ( m_poOgrDS, this, poOgrFeat, m_poOgrDS->GetKmlFactory ( ) );
418 :
419 27 : m_poKmlLayer->add_feature ( poKmlPlacemark );
420 :
421 : /***** mark the layer as updated *****/
422 :
423 27 : bUpdated = TRUE;
424 27 : m_poOgrDS->Updated ( );
425 :
426 27 : return OGRERR_NONE;
427 : }
428 :
429 : /******************************************************************************
430 : method to get the number of features on the layer
431 :
432 : Args: bForce no effect as of now
433 :
434 : Returns: the number of feateres on the layer
435 :
436 : Note: the result can include links, folders and other items that are
437 : not supported by OGR
438 :
439 : ******************************************************************************/
440 :
441 68 : int OGRLIBKMLLayer::GetFeatureCount (
442 : int bForce )
443 : {
444 :
445 :
446 68 : int i = 0;
447 94 : if (m_poFilterGeom != NULL || m_poAttrQuery != NULL ) {
448 26 : i = OGRLayer::GetFeatureCount( bForce );
449 : }
450 :
451 : else {
452 : size_t iKmlFeature;
453 42 : size_t nKmlFeatures = m_poKmlLayer->get_feature_array_size ( );
454 :
455 188 : for ( iKmlFeature = 0; iKmlFeature < nKmlFeatures; iKmlFeature++ ) {
456 292 : if ( m_poKmlLayer->get_feature_array_at ( iKmlFeature )->
457 146 : IsA ( kmldom::Type_Placemark ) ) {
458 108 : i++;
459 : }
460 : }
461 : }
462 :
463 68 : return i;
464 : }
465 :
466 : /******************************************************************************
467 : GetExtent()
468 :
469 : Args: psExtent pointer to the Envelope to store the result in
470 : bForce no effect as of now
471 :
472 : Returns: nothing
473 :
474 : ******************************************************************************/
475 :
476 10 : OGRErr OGRLIBKMLLayer::GetExtent (
477 : OGREnvelope * psExtent,
478 : int bForce )
479 : {
480 10 : Bbox oKmlBbox;
481 :
482 10 : if ( kmlengine::
483 : GetFeatureBounds ( AsFeature ( m_poKmlLayer ), &oKmlBbox ) ) {
484 8 : psExtent->MinX = oKmlBbox.get_west ( );
485 8 : psExtent->MinY = oKmlBbox.get_south ( );
486 8 : psExtent->MaxX = oKmlBbox.get_east ( );
487 8 : psExtent->MaxY = oKmlBbox.get_north ( );
488 :
489 8 : return OGRERR_NONE;
490 : }
491 :
492 2 : return OGRERR_FAILURE;
493 : }
494 :
495 :
496 :
497 :
498 : /******************************************************************************
499 : Method to create a field on a layer
500 :
501 : Args: poField pointer to the Field Definition to add
502 : bApproxOK no effect as of now
503 :
504 : Returns: OGRERR_NONE on success or OGRERR_UNSUPPORTED_OPERATION if the
505 : layer is not writeable
506 :
507 : ******************************************************************************/
508 :
509 9 : OGRErr OGRLIBKMLLayer::CreateField (
510 : OGRFieldDefn * poField,
511 : int bApproxOK )
512 : {
513 :
514 9 : if ( !bUpdate )
515 0 : return OGRERR_UNSUPPORTED_OPERATION;
516 :
517 9 : SimpleFieldPtr poKmlSimpleField = NULL;
518 :
519 9 : if ( (poKmlSimpleField =
520 : FieldDef2kml ( poField, m_poOgrDS->GetKmlFactory ( ) )) != NULL )
521 3 : m_poKmlSchema->add_simplefield ( poKmlSimpleField );
522 :
523 9 : m_poOgrFeatureDefn->AddFieldDefn ( poField );
524 :
525 : /***** mark the layer as updated *****/
526 :
527 9 : bUpdated = TRUE;
528 9 : m_poOgrDS->Updated ( );
529 :
530 9 : return OGRERR_NONE;
531 : }
532 :
533 :
534 : /******************************************************************************
535 : method to write the datasource to disk
536 :
537 : Args: none
538 :
539 : Returns nothing
540 :
541 : ******************************************************************************/
542 :
543 0 : OGRErr OGRLIBKMLLayer::SyncToDisk (
544 : )
545 : {
546 :
547 0 : return OGRERR_NONE;
548 : }
549 :
550 : /******************************************************************************
551 : method to get a layers style table
552 :
553 : Args: none
554 :
555 : Returns: pointer to the layers style table, or NULL if it does
556 : not have one
557 :
558 : ******************************************************************************/
559 :
560 162 : OGRStyleTable *OGRLIBKMLLayer::GetStyleTable (
561 : )
562 : {
563 :
564 162 : return m_poStyleTable;
565 : }
566 :
567 : /******************************************************************************
568 : method to write a style table to a layer
569 :
570 : Args: poStyleTable pointer to the style table to add
571 :
572 : Returns: nothing
573 :
574 : note: this method assumes ownership of the style table
575 : ******************************************************************************/
576 :
577 0 : void OGRLIBKMLLayer::SetStyleTableDirectly (
578 : OGRStyleTable * poStyleTable )
579 : {
580 :
581 0 : if ( !bUpdate )
582 0 : return;
583 :
584 0 : KmlFactory *poKmlFactory = m_poOgrDS->GetKmlFactory ( );
585 :
586 0 : if ( m_poStyleTable )
587 0 : delete m_poStyleTable;
588 :
589 0 : m_poStyleTable = poStyleTable;
590 :
591 0 : if ( m_poKmlLayer->IsA ( kmldom::Type_Document ) ) {
592 :
593 : /***** delete all the styles *****/
594 :
595 0 : DocumentPtr poKmlDocument = AsDocument ( m_poKmlLayer );
596 0 : size_t nKmlStyles = poKmlDocument->get_schema_array_size ( );
597 : int iKmlStyle;
598 :
599 0 : for ( iKmlStyle = nKmlStyles - 1; iKmlStyle >= 0; iKmlStyle-- ) {
600 0 : poKmlDocument->DeleteStyleSelectorAt ( iKmlStyle );
601 : }
602 :
603 : /***** add the new style table to the document *****/
604 :
605 : styletable2kml ( poStyleTable, poKmlFactory,
606 0 : AsContainer ( poKmlDocument ) );
607 :
608 : }
609 :
610 : /***** mark the layer as updated *****/
611 :
612 0 : bUpdated = TRUE;
613 0 : m_poOgrDS->Updated ( );
614 :
615 0 : return;
616 : }
617 :
618 : /******************************************************************************
619 : method to write a style table to a layer
620 :
621 : Args: poStyleTable pointer to the style table to add
622 :
623 : Returns: nothing
624 :
625 : note: this method copys the style table, and the user will still be
626 : responsible for its destruction
627 : ******************************************************************************/
628 :
629 0 : void OGRLIBKMLLayer::SetStyleTable (
630 : OGRStyleTable * poStyleTable )
631 : {
632 :
633 0 : if ( !bUpdate )
634 0 : return;
635 :
636 0 : if ( poStyleTable )
637 0 : SetStyleTableDirectly ( poStyleTable->Clone ( ) );
638 : else
639 0 : SetStyleTableDirectly ( NULL );
640 0 : return;
641 : }
642 :
643 : /******************************************************************************
644 : Test if capability is available.
645 :
646 : Args: pszCap layer capability name to test
647 :
648 : Returns: True if the layer supports the capability, otherwise false
649 :
650 : ******************************************************************************/
651 :
652 40 : int OGRLIBKMLLayer::TestCapability (
653 : const char *pszCap )
654 : {
655 40 : int result = FALSE;
656 :
657 40 : if ( EQUAL ( pszCap, OLCRandomRead ) )
658 10 : result = FALSE;
659 30 : else if ( EQUAL ( pszCap, OLCSequentialWrite ) )
660 0 : result = bUpdate;
661 30 : else if ( EQUAL ( pszCap, OLCRandomWrite ) )
662 10 : result = FALSE;
663 20 : else if ( EQUAL ( pszCap, OLCFastFeatureCount ) )
664 0 : result = FALSE;
665 20 : else if ( EQUAL ( pszCap, OLCFastSetNextByIndex ) )
666 10 : result = FALSE;
667 10 : else if ( EQUAL ( pszCap, OLCCreateField ) )
668 0 : result = bUpdate;
669 10 : else if ( EQUAL ( pszCap, OLCDeleteFeature ) )
670 0 : result = FALSE;
671 10 : else if ( EQUAL(pszCap, OLCStringsAsUTF8) )
672 10 : result = TRUE;
673 :
674 40 : return result;
675 : }
676 :
677 : /************************************************************************/
678 : /* LaunderFieldNames() */
679 : /************************************************************************/
680 :
681 0 : CPLString OGRLIBKMLLayer::LaunderFieldNames(CPLString osName)
682 : {
683 0 : CPLString osLaunderedName;
684 0 : for(int i=0;i<(int)osName.size();i++)
685 : {
686 0 : char ch = osName[i];
687 0 : if ((ch >= '0' && ch <= '9') ||
688 : (ch >= 'a' && ch <= 'z') ||
689 : (ch >= 'A' && ch <= 'Z') ||
690 : (ch == '_'))
691 0 : osLaunderedName += ch;
692 : else
693 0 : osLaunderedName += "_";
694 : }
695 0 : return osLaunderedName;
696 : }
|