LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/kml - ogrkmllayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 223 284 78.5 %
Date: 2025-09-10 17:48:50 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  KML Driver
       4             :  * Purpose:  Implementation of OGRKMLLayer class.
       5             :  * Author:   Christopher Condit, condit@sdsc.edu
       6             :  *           Jens Oberender, j.obi@troja.net
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2006, Christopher Condit
      10             :  * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "ogr_kml.h"
      17             : 
      18             : #include <string>
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_error.h"
      22             : #include "cpl_string.h"
      23             : #include "cpl_vsi.h"
      24             : #include "kml.h"
      25             : #include "kmlutility.h"
      26             : #include "ogr_api.h"
      27             : #include "ogr_core.h"
      28             : #include "ogr_feature.h"
      29             : #include "ogr_featurestyle.h"
      30             : #include "ogr_geometry.h"
      31             : #include "ogr_p.h"
      32             : #include "ogr_spatialref.h"
      33             : #include "ogrsf_frmts.h"
      34             : 
      35             : /* Function utility to dump OGRGeometry to KML text. */
      36             : char *OGR_G_ExportToKML(OGRGeometryH hGeometry, const char *pszAltitudeMode);
      37             : 
      38             : /************************************************************************/
      39             : /*                           OGRKMLLayer()                              */
      40             : /************************************************************************/
      41             : 
      42         141 : OGRKMLLayer::OGRKMLLayer(const char *pszName,
      43             :                          const OGRSpatialReference *poSRSIn, bool bWriterIn,
      44         141 :                          OGRwkbGeometryType eReqType, OGRKMLDataSource *poDSIn)
      45             :     : poDS_(poDSIn),
      46         141 :       poSRS_(poSRSIn ? new OGRSpatialReference(nullptr) : nullptr),
      47         141 :       poFeatureDefn_(new OGRFeatureDefn(pszName)), bWriter_(bWriterIn),
      48         423 :       pszName_(CPLStrdup(pszName))
      49             : {
      50             :     // KML should be created as WGS84.
      51         141 :     if (poSRSIn != nullptr)
      52             :     {
      53          83 :         poSRS_->SetWellKnownGeogCS("WGS84");
      54          83 :         poSRS_->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      55          83 :         if (!poSRS_->IsSame(poSRSIn))
      56             :         {
      57           1 :             poCT_ = OGRCreateCoordinateTransformation(poSRSIn, poSRS_);
      58           1 :             if (poCT_ == nullptr && poDSIn->IsFirstCTError())
      59             :             {
      60             :                 // If we can't create a transformation, issue a warning - but
      61             :                 // continue the transformation.
      62           0 :                 char *pszWKT = nullptr;
      63             : 
      64           0 :                 poSRSIn->exportToPrettyWkt(&pszWKT, FALSE);
      65             : 
      66           0 :                 CPLError(
      67             :                     CE_Warning, CPLE_AppDefined,
      68             :                     "Failed to create coordinate transformation between the "
      69             :                     "input coordinate system and WGS84.  This may be because "
      70             :                     "they are not transformable.  "
      71             :                     "KML geometries may not render correctly.  "
      72             :                     "This message will not be issued any more."
      73             :                     "\nSource:\n%s\n",
      74             :                     pszWKT);
      75             : 
      76           0 :                 CPLFree(pszWKT);
      77           0 :                 poDSIn->IssuedFirstCTError();
      78             :             }
      79             :         }
      80             :     }
      81             : 
      82         141 :     SetDescription(poFeatureDefn_->GetName());
      83         141 :     poFeatureDefn_->Reference();
      84         141 :     poFeatureDefn_->SetGeomType(eReqType);
      85         141 :     if (poFeatureDefn_->GetGeomFieldCount() != 0)
      86         137 :         poFeatureDefn_->GetGeomFieldDefn(0)->SetSpatialRef(poSRS_);
      87             : 
      88         282 :     OGRFieldDefn oFieldName("Name", OFTString);
      89         141 :     poFeatureDefn_->AddFieldDefn(&oFieldName);
      90             : 
      91         141 :     OGRFieldDefn oFieldDesc("Description", OFTString);
      92         141 :     poFeatureDefn_->AddFieldDefn(&oFieldDesc);
      93             : 
      94         141 :     bClosedForWriting = !bWriterIn;
      95         141 : }
      96             : 
      97             : /************************************************************************/
      98             : /*                           ~OGRKMLLayer()                             */
      99             : /************************************************************************/
     100             : 
     101         282 : OGRKMLLayer::~OGRKMLLayer()
     102             : {
     103         141 :     if (nullptr != poFeatureDefn_)
     104         141 :         poFeatureDefn_->Release();
     105             : 
     106         141 :     if (nullptr != poSRS_)
     107          83 :         poSRS_->Release();
     108             : 
     109         141 :     if (nullptr != poCT_)
     110           1 :         delete poCT_;
     111             : 
     112         141 :     CPLFree(pszName_);
     113         282 : }
     114             : 
     115             : /************************************************************************/
     116             : /*                            GetLayerDefn()                            */
     117             : /************************************************************************/
     118             : 
     119        2342 : const OGRFeatureDefn *OGRKMLLayer::GetLayerDefn() const
     120             : {
     121        2342 :     return poFeatureDefn_;
     122             : }
     123             : 
     124             : /************************************************************************/
     125             : /*                            ResetReading()                            */
     126             : /************************************************************************/
     127             : 
     128         614 : void OGRKMLLayer::ResetReading()
     129             : {
     130         614 :     iNextKMLId_ = 0;
     131         614 :     nLastAsked = -1;
     132         614 :     nLastCount = -1;
     133         614 : }
     134             : 
     135             : /************************************************************************/
     136             : /*                           GetNextFeature()                           */
     137             : /************************************************************************/
     138             : 
     139         792 : OGRFeature *OGRKMLLayer::GetNextFeature()
     140             : {
     141             : #ifndef HAVE_EXPAT
     142             :     return nullptr;
     143             : #else
     144             :     /* -------------------------------------------------------------------- */
     145             :     /*      Loop till we find a feature matching our criteria.              */
     146             :     /* -------------------------------------------------------------------- */
     147         792 :     KML *poKMLFile = poDS_->GetKMLFile();
     148         792 :     if (poKMLFile == nullptr)
     149          16 :         return nullptr;
     150             : 
     151         776 :     poKMLFile->selectLayer(nLayerNumber_);
     152             : 
     153             :     while (true)
     154             :     {
     155             :         auto poFeatureKML = std::unique_ptr<Feature>(
     156         959 :             poKMLFile->getFeature(iNextKMLId_++, nLastAsked, nLastCount));
     157             : 
     158         959 :         if (poFeatureKML == nullptr)
     159         207 :             return nullptr;
     160             : 
     161         752 :         auto poFeature = std::make_unique<OGRFeature>(poFeatureDefn_);
     162             : 
     163         752 :         if (poFeatureKML->poGeom)
     164             :         {
     165         752 :             poFeature->SetGeometry(std::move(poFeatureKML->poGeom));
     166             :         }
     167             : 
     168             :         // Add fields.
     169        1504 :         poFeature->SetField(poFeatureDefn_->GetFieldIndex("Name"),
     170         752 :                             poFeatureKML->sName.c_str());
     171        1504 :         poFeature->SetField(poFeatureDefn_->GetFieldIndex("Description"),
     172         752 :                             poFeatureKML->sDescription.c_str());
     173         752 :         poFeature->SetFID(iNextKMLId_ - 1);
     174             : 
     175         752 :         if (poFeature->GetGeometryRef() != nullptr && poSRS_ != nullptr)
     176             :         {
     177         752 :             poFeature->GetGeometryRef()->assignSpatialReference(poSRS_);
     178             :         }
     179             : 
     180             :         // Check spatial/attribute filters.
     181        1713 :         if ((m_poFilterGeom == nullptr ||
     182        1428 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     183         676 :             (m_poAttrQuery == nullptr ||
     184         215 :              m_poAttrQuery->Evaluate(poFeature.get())))
     185             :         {
     186         569 :             return poFeature.release();
     187             :         }
     188         183 :     }
     189             : 
     190             : #endif /* HAVE_EXPAT */
     191             : }
     192             : 
     193             : /************************************************************************/
     194             : /*                          GetFeatureCount()                           */
     195             : /************************************************************************/
     196             : 
     197             : #ifndef HAVE_EXPAT
     198             : GIntBig OGRKMLLayer::GetFeatureCount(int /* bForce */)
     199             : {
     200             :     return 0;
     201             : }
     202             : #else
     203             : 
     204          97 : GIntBig OGRKMLLayer::GetFeatureCount(int bForce)
     205             : {
     206          97 :     if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
     207          36 :         return OGRLayer::GetFeatureCount(bForce);
     208             : 
     209          61 :     KML *poKMLFile = poDS_->GetKMLFile();
     210          61 :     if (nullptr == poKMLFile)
     211           0 :         return 0;
     212             : 
     213          61 :     poKMLFile->selectLayer(nLayerNumber_);
     214             : 
     215          61 :     return poKMLFile->getNumFeatures();
     216             : }
     217             : #endif
     218             : 
     219             : /************************************************************************/
     220             : /*                           WriteSchema()                              */
     221             : /************************************************************************/
     222             : 
     223          40 : CPLString OGRKMLLayer::WriteSchema()
     224             : {
     225          40 :     if (bSchemaWritten_)
     226           0 :         return "";
     227             : 
     228          80 :     CPLString osRet;
     229             : 
     230          40 :     const OGRFeatureDefn *featureDefinition = GetLayerDefn();
     231         231 :     for (int j = 0; j < featureDefinition->GetFieldCount(); j++)
     232             :     {
     233             :         const OGRFieldDefn *fieldDefinition =
     234         191 :             featureDefinition->GetFieldDefn(j);
     235             : 
     236         382 :         if (nullptr != poDS_->GetNameField() &&
     237         191 :             EQUAL(fieldDefinition->GetNameRef(), poDS_->GetNameField()))
     238          40 :             continue;
     239             : 
     240         302 :         if (nullptr != poDS_->GetDescriptionField() &&
     241         151 :             EQUAL(fieldDefinition->GetNameRef(), poDS_->GetDescriptionField()))
     242          40 :             continue;
     243             : 
     244         111 :         if (osRet.empty())
     245             :         {
     246             :             osRet += CPLSPrintf("<Schema name=\"%s\" id=\"%s\">\n", pszName_,
     247          37 :                                 pszName_);
     248             :         }
     249             : 
     250         111 :         const char *pszKMLType = nullptr;
     251         111 :         const char *pszKMLEltName = nullptr;
     252             :         // Match the OGR type to the GDAL type.
     253         111 :         switch (fieldDefinition->GetType())
     254             :         {
     255          20 :             case OFTInteger:
     256          20 :                 pszKMLType = "int";
     257          20 :                 pszKMLEltName = "SimpleField";
     258          20 :                 break;
     259           0 :             case OFTIntegerList:
     260           0 :                 pszKMLType = "int";
     261           0 :                 pszKMLEltName = "SimpleArrayField";
     262           0 :                 break;
     263          21 :             case OFTReal:
     264          21 :                 pszKMLType = "float";
     265          21 :                 pszKMLEltName = "SimpleField";
     266          21 :                 break;
     267           0 :             case OFTRealList:
     268           0 :                 pszKMLType = "float";
     269           0 :                 pszKMLEltName = "SimpleArrayField";
     270           0 :                 break;
     271          38 :             case OFTString:
     272          38 :                 pszKMLType = "string";
     273          38 :                 pszKMLEltName = "SimpleField";
     274          38 :                 break;
     275           0 :             case OFTStringList:
     276           0 :                 pszKMLType = "string";
     277           0 :                 pszKMLEltName = "SimpleArrayField";
     278           0 :                 break;
     279             :                 // TODO: KML doesn't handle these data types yet...
     280          32 :             case OFTDate:
     281             :             case OFTTime:
     282             :             case OFTDateTime:
     283          32 :                 pszKMLType = "string";
     284          32 :                 pszKMLEltName = "SimpleField";
     285          32 :                 break;
     286             : 
     287           0 :             default:
     288           0 :                 pszKMLType = "string";
     289           0 :                 pszKMLEltName = "SimpleField";
     290           0 :                 break;
     291             :         }
     292             :         osRet += CPLSPrintf("\t<%s name=\"%s\" type=\"%s\"></%s>\n",
     293             :                             pszKMLEltName, fieldDefinition->GetNameRef(),
     294         111 :                             pszKMLType, pszKMLEltName);
     295             :     }
     296             : 
     297          40 :     if (!osRet.empty())
     298          37 :         osRet += CPLSPrintf("%s", "</Schema>\n");
     299             : 
     300          40 :     return osRet;
     301             : }
     302             : 
     303             : /************************************************************************/
     304             : /*                           ICreateFeature()                            */
     305             : /************************************************************************/
     306             : 
     307         129 : OGRErr OGRKMLLayer::ICreateFeature(OGRFeature *poFeature)
     308             : {
     309         129 :     CPLAssert(nullptr != poFeature);
     310         129 :     CPLAssert(nullptr != poDS_);
     311             : 
     312         129 :     if (!bWriter_)
     313           0 :         return OGRERR_FAILURE;
     314             : 
     315         129 :     if (bClosedForWriting)
     316             :     {
     317           1 :         CPLError(
     318             :             CE_Failure, CPLE_NotSupported,
     319             :             "Interleaved feature adding to different layers is not supported");
     320           1 :         return OGRERR_FAILURE;
     321             :     }
     322             : 
     323         128 :     VSILFILE *fp = poDS_->GetOutputFP();
     324         128 :     CPLAssert(nullptr != fp);
     325             : 
     326         128 :     if (poDS_->GetLayerCount() == 1 && nWroteFeatureCount_ == 0)
     327             :     {
     328          44 :         CPLString osRet = WriteSchema();
     329          22 :         if (!osRet.empty())
     330          20 :             VSIFPrintfL(fp, "%s", osRet.c_str());
     331          22 :         bSchemaWritten_ = true;
     332             : 
     333          22 :         VSIFPrintfL(fp, "<Folder><name>%s</name>\n", pszName_);
     334             :     }
     335             : 
     336         128 :     ++nWroteFeatureCount_;
     337         128 :     char *pszEscapedLayerName = OGRGetXML_UTF8_EscapedString(GetDescription());
     338         128 :     VSIFPrintfL(fp, "  <Placemark id=\"%s." CPL_FRMT_GIB "\">\n",
     339             :                 pszEscapedLayerName, nWroteFeatureCount_);
     340         128 :     CPLFree(pszEscapedLayerName);
     341             : 
     342         128 :     if (poFeature->GetFID() == OGRNullFID)
     343         128 :         poFeature->SetFID(iNextKMLId_++);
     344             : 
     345             :     // Find and write the name element
     346         128 :     if (nullptr != poDS_->GetNameField())
     347             :     {
     348         834 :         for (int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++)
     349             :         {
     350         706 :             OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn(iField);
     351             : 
     352        1063 :             if (poFeature->IsFieldSetAndNotNull(iField) &&
     353         357 :                 EQUAL(poField->GetNameRef(), poDS_->GetNameField()))
     354             :             {
     355           2 :                 const char *pszRaw = poFeature->GetFieldAsString(iField);
     356           2 :                 while (*pszRaw == ' ')
     357           0 :                     pszRaw++;
     358             : 
     359           2 :                 char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
     360             : 
     361           2 :                 VSIFPrintfL(fp, "\t<name>%s</name>\n", pszEscaped);
     362           2 :                 CPLFree(pszEscaped);
     363             :             }
     364             :         }
     365             :     }
     366             : 
     367         128 :     if (nullptr != poDS_->GetDescriptionField())
     368             :     {
     369         834 :         for (int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++)
     370             :         {
     371         706 :             OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn(iField);
     372             : 
     373        1063 :             if (poFeature->IsFieldSetAndNotNull(iField) &&
     374         357 :                 EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()))
     375             :             {
     376           1 :                 const char *pszRaw = poFeature->GetFieldAsString(iField);
     377           1 :                 while (*pszRaw == ' ')
     378           0 :                     pszRaw++;
     379             : 
     380           1 :                 char *pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
     381             : 
     382           1 :                 VSIFPrintfL(fp, "\t<description>%s</description>\n",
     383             :                             pszEscaped);
     384           1 :                 CPLFree(pszEscaped);
     385             :             }
     386             :         }
     387             :     }
     388             : 
     389         128 :     OGRwkbGeometryType eGeomType = wkbNone;
     390         128 :     if (poFeature->GetGeometryRef() != nullptr)
     391          90 :         eGeomType = wkbFlatten(poFeature->GetGeometryRef()->getGeometryType());
     392             : 
     393         128 :     if (wkbPolygon == eGeomType || wkbMultiPolygon == eGeomType ||
     394          72 :         wkbLineString == eGeomType || wkbMultiLineString == eGeomType)
     395             :     {
     396          63 :         OGRStylePen *poPen = nullptr;
     397         126 :         OGRStyleMgr oSM;
     398             : 
     399          63 :         if (poFeature->GetStyleString() != nullptr)
     400             :         {
     401           0 :             oSM.InitFromFeature(poFeature);
     402             : 
     403           0 :             for (int i = 0; i < oSM.GetPartCount(); i++)
     404             :             {
     405           0 :                 OGRStyleTool *poTool = oSM.GetPart(i);
     406           0 :                 if (poTool && poTool->GetType() == OGRSTCPen)
     407             :                 {
     408           0 :                     poPen = cpl::down_cast<OGRStylePen *>(poTool);
     409           0 :                     break;
     410             :                 }
     411           0 :                 delete poTool;
     412             :             }
     413             :         }
     414             : 
     415          63 :         VSIFPrintfL(fp, "\t<Style>");
     416          63 :         if (poPen != nullptr)
     417             :         {
     418           0 :             GBool bDefault = FALSE;
     419             : 
     420             :             /* Require width to be returned in pixel */
     421           0 :             poPen->SetUnit(OGRSTUPixel);
     422           0 :             double fW = poPen->Width(bDefault);
     423           0 :             if (bDefault)
     424           0 :                 fW = 1;
     425           0 :             const char *pszColor = poPen->Color(bDefault);
     426           0 :             const int nColorLen = static_cast<int>(CPLStrnlen(pszColor, 10));
     427           0 :             if (pszColor != nullptr && pszColor[0] == '#' && !bDefault &&
     428             :                 nColorLen >= 7)
     429             :             {
     430           0 :                 char acColor[9] = {0};
     431             :                 /* Order of KML color is aabbggrr, whereas OGR color is
     432             :                  * #rrggbb[aa] ! */
     433           0 :                 if (nColorLen == 9)
     434             :                 {
     435           0 :                     acColor[0] = pszColor[7]; /* A */
     436           0 :                     acColor[1] = pszColor[8];
     437             :                 }
     438             :                 else
     439             :                 {
     440           0 :                     acColor[0] = 'F';
     441           0 :                     acColor[1] = 'F';
     442             :                 }
     443           0 :                 acColor[2] = pszColor[5]; /* B */
     444           0 :                 acColor[3] = pszColor[6];
     445           0 :                 acColor[4] = pszColor[3]; /* G */
     446           0 :                 acColor[5] = pszColor[4];
     447           0 :                 acColor[6] = pszColor[1]; /* R */
     448           0 :                 acColor[7] = pszColor[2];
     449           0 :                 VSIFPrintfL(fp, "<LineStyle><color>%s</color>", acColor);
     450           0 :                 VSIFPrintfL(fp, "<width>%g</width>", fW);
     451           0 :                 VSIFPrintfL(fp, "</LineStyle>");
     452             :             }
     453             :             else
     454             :             {
     455           0 :                 VSIFPrintfL(fp,
     456             :                             "<LineStyle><color>ff0000ff</color></LineStyle>");
     457             :             }
     458             :         }
     459             :         else
     460             :         {
     461          63 :             VSIFPrintfL(fp, "<LineStyle><color>ff0000ff</color></LineStyle>");
     462             :         }
     463          63 :         delete poPen;
     464             :         // If we're dealing with a polygon, add a line style that will stand out
     465             :         // a bit.
     466          63 :         VSIFPrintfL(fp, "<PolyStyle><fill>0</fill></PolyStyle></Style>\n");
     467             :     }
     468             : 
     469         128 :     bool bHasFoundOtherField = false;
     470             : 
     471             :     // Write all fields as SchemaData
     472         834 :     for (int iField = 0; iField < poFeatureDefn_->GetFieldCount(); iField++)
     473             :     {
     474         706 :         OGRFieldDefn *poField = poFeatureDefn_->GetFieldDefn(iField);
     475             : 
     476         706 :         if (poFeature->IsFieldSetAndNotNull(iField))
     477             :         {
     478         714 :             if (nullptr != poDS_->GetNameField() &&
     479         357 :                 EQUAL(poField->GetNameRef(), poDS_->GetNameField()))
     480           2 :                 continue;
     481             : 
     482         710 :             if (nullptr != poDS_->GetDescriptionField() &&
     483         355 :                 EQUAL(poField->GetNameRef(), poDS_->GetDescriptionField()))
     484           1 :                 continue;
     485             : 
     486         354 :             if (!bHasFoundOtherField)
     487             :             {
     488          86 :                 VSIFPrintfL(fp,
     489             :                             "\t<ExtendedData><SchemaData schemaUrl=\"#%s\">\n",
     490             :                             pszName_);
     491          86 :                 bHasFoundOtherField = true;
     492             :             }
     493         354 :             const char *pszRaw = poFeature->GetFieldAsString(iField);
     494             : 
     495         354 :             while (*pszRaw == ' ')
     496           0 :                 pszRaw++;
     497             : 
     498         354 :             char *pszEscaped = nullptr;
     499         354 :             if (poFeatureDefn_->GetFieldDefn(iField)->GetType() == OFTReal)
     500             :             {
     501         152 :                 pszEscaped = CPLStrdup(pszRaw);
     502             :             }
     503             :             else
     504             :             {
     505         202 :                 pszEscaped = OGRGetXML_UTF8_EscapedString(pszRaw);
     506             :             }
     507             : 
     508         354 :             VSIFPrintfL(fp, "\t\t<SimpleData name=\"%s\">%s</SimpleData>\n",
     509             :                         poField->GetNameRef(), pszEscaped);
     510             : 
     511         354 :             CPLFree(pszEscaped);
     512             :         }
     513             :     }
     514             : 
     515         128 :     if (bHasFoundOtherField)
     516             :     {
     517          86 :         VSIFPrintfL(fp, "\t</SchemaData></ExtendedData>\n");
     518             :     }
     519             : 
     520             :     // Write out Geometry - for now it isn't indented properly.
     521         128 :     if (poFeature->GetGeometryRef() != nullptr)
     522             :     {
     523          90 :         char *pszGeometry = nullptr;
     524          90 :         OGREnvelope sGeomBounds;
     525          90 :         OGRGeometry *poWGS84Geom = nullptr;
     526             : 
     527          90 :         if (nullptr != poCT_)
     528             :         {
     529           1 :             poWGS84Geom = poFeature->GetGeometryRef()->clone();
     530           1 :             poWGS84Geom->transform(poCT_);
     531             :         }
     532             :         else
     533             :         {
     534          89 :             poWGS84Geom = poFeature->GetGeometryRef();
     535             :         }
     536             : 
     537          90 :         pszGeometry = OGR_G_ExportToKML(OGRGeometry::ToHandle(poWGS84Geom),
     538          90 :                                         poDS_->GetAltitudeMode());
     539          90 :         if (pszGeometry != nullptr)
     540             :         {
     541          90 :             VSIFPrintfL(fp, "      %s\n", pszGeometry);
     542             :         }
     543             :         else
     544             :         {
     545           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     546             :                      "Export of geometry to KML failed");
     547             :         }
     548          90 :         CPLFree(pszGeometry);
     549             : 
     550          90 :         poWGS84Geom->getEnvelope(&sGeomBounds);
     551          90 :         poDS_->GrowExtents(&sGeomBounds);
     552             : 
     553          90 :         if (nullptr != poCT_)
     554             :         {
     555           1 :             delete poWGS84Geom;
     556             :         }
     557             :     }
     558             : 
     559         128 :     VSIFPrintfL(fp, "  </Placemark>\n");
     560         128 :     return OGRERR_NONE;
     561             : }
     562             : 
     563             : /************************************************************************/
     564             : /*                           TestCapability()                           */
     565             : /************************************************************************/
     566             : 
     567         339 : int OGRKMLLayer::TestCapability(const char *pszCap) const
     568             : {
     569         339 :     if (EQUAL(pszCap, OLCSequentialWrite))
     570             :     {
     571          22 :         return bWriter_;
     572             :     }
     573         317 :     else if (EQUAL(pszCap, OLCCreateField))
     574             :     {
     575          28 :         return bWriter_ && iNextKMLId_ == 0;
     576             :     }
     577         289 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
     578             :     {
     579             :         //        if( poFClass == NULL
     580             :         //            || m_poFilterGeom != NULL
     581             :         //            || m_poAttrQuery != NULL )
     582           0 :         return FALSE;
     583             : 
     584             :         //        return poFClass->GetFeatureCount() != -1;
     585             :     }
     586             : 
     587         289 :     else if (EQUAL(pszCap, OLCStringsAsUTF8))
     588          78 :         return TRUE;
     589         211 :     else if (EQUAL(pszCap, OLCZGeometries))
     590          18 :         return TRUE;
     591             : 
     592         193 :     return FALSE;
     593             : }
     594             : 
     595             : /************************************************************************/
     596             : /*                            CreateField()                             */
     597             : /************************************************************************/
     598             : 
     599         111 : OGRErr OGRKMLLayer::CreateField(const OGRFieldDefn *poField,
     600             :                                 CPL_UNUSED int bApproxOK)
     601             : {
     602         111 :     if (!bWriter_ || iNextKMLId_ != 0)
     603           0 :         return OGRERR_FAILURE;
     604             : 
     605         111 :     OGRFieldDefn oCleanCopy(poField);
     606         111 :     poFeatureDefn_->AddFieldDefn(&oCleanCopy);
     607             : 
     608         111 :     return OGRERR_NONE;
     609             : }
     610             : 
     611             : /************************************************************************/
     612             : /*                           SetLayerNumber()                           */
     613             : /************************************************************************/
     614             : 
     615          81 : void OGRKMLLayer::SetLayerNumber(int nLayer)
     616             : {
     617          81 :     nLayerNumber_ = nLayer;
     618          81 : }
     619             : 
     620             : /************************************************************************/
     621             : /*                             GetDataset()                             */
     622             : /************************************************************************/
     623             : 
     624          17 : GDALDataset *OGRKMLLayer::GetDataset()
     625             : {
     626          17 :     return poDS_;
     627             : }

Generated by: LCOV version 1.14