LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/libkml - ogrlibkmlstyle.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 391 498 78.5 %
Date: 2024-11-21 22:18:42 Functions: 13 14 92.9 %

          Line data    Source code
       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             :  * Copyright (c) 2011-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  *****************************************************************************/
      13             : 
      14             : #include "libkml_headers.h"
      15             : 
      16             : #include <set>
      17             : #include <string>
      18             : 
      19             : #include "ogr_featurestyle.h"
      20             : #include "ogrlibkmlstyle.h"
      21             : #include "ogr_libkml.h"
      22             : 
      23             : using kmlbase::Color32;
      24             : using kmldom::BalloonStylePtr;
      25             : using kmldom::ContainerPtr;
      26             : using kmldom::DocumentPtr;
      27             : using kmldom::ElementPtr;
      28             : using kmldom::FeaturePtr;
      29             : using kmldom::HotSpotPtr;
      30             : using kmldom::IconStyleIconPtr;
      31             : using kmldom::IconStylePtr;
      32             : using kmldom::ItemIconPtr;
      33             : using kmldom::KmlFactory;
      34             : using kmldom::KmlPtr;
      35             : using kmldom::LabelStylePtr;
      36             : using kmldom::LineStylePtr;
      37             : using kmldom::ListStylePtr;
      38             : using kmldom::ObjectPtr;
      39             : using kmldom::PairPtr;
      40             : using kmldom::PolyStylePtr;
      41             : using kmldom::StyleMapPtr;
      42             : using kmldom::StylePtr;
      43             : using kmldom::StyleSelectorPtr;
      44             : using kmldom::STYLESTATE_HIGHLIGHT;
      45             : using kmldom::STYLESTATE_NORMAL;
      46             : 
      47             : /******************************************************************************
      48             :  Generic function to parse a stylestring and add to a kml style.
      49             : 
      50             : Args:
      51             :             pszStyleString  the stylestring to parse
      52             :             poKmlStyle      the kml style to add to (or NULL)
      53             :             poKmlFactory    the kml dom factory
      54             : 
      55             : Returns:
      56             :             the kml style
      57             : 
      58             : ******************************************************************************/
      59             : 
      60          11 : StylePtr addstylestring2kml(const char *pszStyleString, StylePtr poKmlStyle,
      61             :                             KmlFactory *poKmlFactory, FeaturePtr poKmlFeature)
      62             : {
      63             :     /***** just bail now if stylestring is empty *****/
      64          11 :     if (!pszStyleString || !*pszStyleString)
      65             :     {
      66           0 :         return poKmlStyle;
      67             :     }
      68             : 
      69          22 :     LineStylePtr poKmlLineStyle = nullptr;
      70          22 :     PolyStylePtr poKmlPolyStyle = nullptr;
      71          22 :     IconStylePtr poKmlIconStyle = nullptr;
      72          22 :     LabelStylePtr poKmlLabelStyle = nullptr;
      73             : 
      74             :     /***** create and init a style mamager with the style string *****/
      75          11 :     OGRStyleMgr *const poOgrSM = new OGRStyleMgr;
      76             : 
      77          11 :     poOgrSM->InitStyleString(pszStyleString);
      78             : 
      79             :     /***** loop though the style parts *****/
      80          30 :     for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
      81             :     {
      82          19 :         OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
      83             : 
      84          19 :         if (!poOgrST)
      85             :         {
      86           0 :             continue;
      87             :         }
      88             : 
      89          19 :         switch (poOgrST->GetType())
      90             :         {
      91           4 :             case OGRSTCPen:
      92             :             {
      93           4 :                 poKmlLineStyle = poKmlFactory->CreateLineStyle();
      94             : 
      95             :                 OGRStylePen *poStylePen =
      96           4 :                     cpl::down_cast<OGRStylePen *>(poOgrST);
      97             : 
      98             :                 /***** pen color *****/
      99           4 :                 GBool nullcheck = FALSE;
     100           4 :                 const char *const pszColor = poStylePen->Color(nullcheck);
     101             : 
     102           4 :                 int nR = 0;
     103           4 :                 int nG = 0;
     104           4 :                 int nB = 0;
     105           4 :                 int nA = 0;
     106           8 :                 if (!nullcheck &&
     107           4 :                     poStylePen->GetRGBFromString(pszColor, nR, nG, nB, nA))
     108             :                 {
     109           4 :                     poKmlLineStyle->set_color(Color32(
     110             :                         static_cast<GByte>(nA), static_cast<GByte>(nB),
     111             :                         static_cast<GByte>(nG), static_cast<GByte>(nR)));
     112             :                 }
     113           4 :                 poStylePen->SetUnit(OGRSTUPixel);
     114           4 :                 double dfWidth = poStylePen->Width(nullcheck);
     115             : 
     116           4 :                 if (nullcheck)
     117           0 :                     dfWidth = 1.0;
     118             : 
     119           4 :                 poKmlLineStyle->set_width(dfWidth);
     120             : 
     121           4 :                 break;
     122             :             }
     123           4 :             case OGRSTCBrush:
     124             :             {
     125             :                 OGRStyleBrush *const poStyleBrush =
     126           4 :                     cpl::down_cast<OGRStyleBrush *>(poOgrST);
     127             : 
     128             :                 /***** brush color *****/
     129           4 :                 GBool nullcheck = FALSE;
     130           4 :                 const char *pszColor = poStyleBrush->ForeColor(nullcheck);
     131             : 
     132           4 :                 int nR = 0;
     133           4 :                 int nG = 0;
     134           4 :                 int nB = 0;
     135           4 :                 int nA = 0;
     136           8 :                 if (!nullcheck &&
     137           4 :                     poStyleBrush->GetRGBFromString(pszColor, nR, nG, nB, nA))
     138             :                 {
     139           4 :                     poKmlPolyStyle = poKmlFactory->CreatePolyStyle();
     140           4 :                     poKmlPolyStyle->set_color(Color32(
     141             :                         static_cast<GByte>(nA), static_cast<GByte>(nB),
     142             :                         static_cast<GByte>(nG), static_cast<GByte>(nR)));
     143             :                 }
     144           4 :                 break;
     145             :             }
     146           8 :             case OGRSTCSymbol:
     147             :             {
     148             :                 OGRStyleSymbol *const poStyleSymbol =
     149           8 :                     cpl::down_cast<OGRStyleSymbol *>(poOgrST);
     150             : 
     151             :                 /***** id (kml icon) *****/
     152           8 :                 GBool nullcheck = FALSE;
     153           8 :                 const char *pszId = poStyleSymbol->Id(nullcheck);
     154             : 
     155           8 :                 if (!nullcheck)
     156             :                 {
     157           8 :                     if (!poKmlIconStyle)
     158           8 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     159             : 
     160             :                     /***** split it at the ,'s *****/
     161           8 :                     char **papszTokens = CSLTokenizeString2(
     162             :                         pszId, ",",
     163             :                         CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES |
     164             :                             CSLT_STRIPENDSPACES);
     165             : 
     166           8 :                     if (papszTokens)
     167             :                     {
     168             :                         // Just take the first one.
     169             :                         // TODO: Come up with a better idea.
     170           8 :                         if (papszTokens[0])
     171             :                         {
     172             :                             IconStyleIconPtr poKmlIcon =
     173          16 :                                 poKmlFactory->CreateIconStyleIcon();
     174           8 :                             poKmlIcon->set_href(papszTokens[0]);
     175           8 :                             poKmlIconStyle->set_icon(poKmlIcon);
     176             :                         }
     177             : 
     178           8 :                         CSLDestroy(papszTokens);
     179             :                     }
     180             :                 }
     181             : 
     182             :                 /***** heading *****/
     183           8 :                 double heading = poStyleSymbol->Angle(nullcheck);
     184             : 
     185           8 :                 if (!nullcheck)
     186             :                 {
     187           3 :                     if (!poKmlIconStyle)
     188           0 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     189           3 :                     poKmlIconStyle->set_heading(heading);
     190             :                 }
     191             : 
     192             :                 /***** scale *****/
     193           8 :                 double dfScale = poStyleSymbol->Size(nullcheck);
     194             : 
     195           8 :                 if (!nullcheck)
     196             :                 {
     197           3 :                     if (!poKmlIconStyle)
     198           0 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     199             : 
     200           3 :                     poKmlIconStyle->set_scale(dfScale);
     201             :                 }
     202             : 
     203             :                 /***** color *****/
     204           8 :                 const char *const pszcolor = poStyleSymbol->Color(nullcheck);
     205             : 
     206           8 :                 int nR = 0;
     207           8 :                 int nG = 0;
     208           8 :                 int nB = 0;
     209           8 :                 int nA = 0;
     210          15 :                 if (!nullcheck &&
     211           7 :                     poOgrST->GetRGBFromString(pszcolor, nR, nG, nB, nA))
     212             :                 {
     213           7 :                     poKmlIconStyle->set_color(Color32(
     214             :                         static_cast<GByte>(nA), static_cast<GByte>(nB),
     215             :                         static_cast<GByte>(nG), static_cast<GByte>(nR)));
     216             :                 }
     217             : 
     218             :                 /***** hotspot *****/
     219             : 
     220           8 :                 double dfDx = poStyleSymbol->SpacingX(nullcheck);
     221           8 :                 GBool nullcheck2 = FALSE;
     222           8 :                 double dfDy = poStyleSymbol->SpacingY(nullcheck2);
     223             : 
     224           8 :                 if (!nullcheck && !nullcheck2)
     225             :                 {
     226           2 :                     if (!poKmlIconStyle)
     227           0 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     228             : 
     229           4 :                     HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot();
     230           2 :                     if (poKmlHotSpot)
     231             :                     {
     232           2 :                         poKmlHotSpot->set_x(dfDx);
     233           2 :                         poKmlHotSpot->set_y(dfDy);
     234             : 
     235           2 :                         poKmlIconStyle->set_hotspot(poKmlHotSpot);
     236             :                     }
     237             :                 }
     238             : 
     239           8 :                 break;
     240             :             }
     241           3 :             case OGRSTCLabel:
     242             :             {
     243             :                 GBool nullcheck;
     244             :                 GBool nullcheck2;
     245             : 
     246             :                 OGRStyleLabel *poStyleLabel =
     247           3 :                     cpl::down_cast<OGRStyleLabel *>(poOgrST);
     248             : 
     249             :                 /***** color *****/
     250           3 :                 const char *pszcolor = poStyleLabel->ForeColor(nullcheck);
     251             : 
     252           3 :                 int nR = 0;
     253           3 :                 int nG = 0;
     254           3 :                 int nB = 0;
     255           3 :                 int nA = 0;
     256           6 :                 if (!nullcheck &&
     257           3 :                     poStyleLabel->GetRGBFromString(pszcolor, nR, nG, nB, nA))
     258             :                 {
     259           3 :                     if (!poKmlLabelStyle)
     260           3 :                         poKmlLabelStyle = poKmlFactory->CreateLabelStyle();
     261           3 :                     poKmlLabelStyle->set_color(Color32(
     262             :                         static_cast<GByte>(nA), static_cast<GByte>(nB),
     263             :                         static_cast<GByte>(nG), static_cast<GByte>(nR)));
     264             :                 }
     265             : 
     266             :                 /***** scale *****/
     267           3 :                 double dfScale = poStyleLabel->Stretch(nullcheck);
     268             : 
     269           3 :                 if (!nullcheck)
     270             :                 {
     271           3 :                     dfScale /= 100.0;
     272           3 :                     if (!poKmlLabelStyle)
     273           0 :                         poKmlLabelStyle = poKmlFactory->CreateLabelStyle();
     274           3 :                     poKmlLabelStyle->set_scale(dfScale);
     275             :                 }
     276             : 
     277             :                 /***** heading *****/
     278           3 :                 const double heading = poStyleLabel->Angle(nullcheck);
     279             : 
     280           3 :                 if (!nullcheck)
     281             :                 {
     282           0 :                     if (!poKmlIconStyle)
     283             :                     {
     284           0 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     285             :                         const IconStyleIconPtr poKmlIcon =
     286           0 :                             poKmlFactory->CreateIconStyleIcon();
     287           0 :                         poKmlIconStyle->set_icon(poKmlIcon);
     288             :                     }
     289             : 
     290           0 :                     poKmlIconStyle->set_heading(heading);
     291             :                 }
     292             : 
     293             :                 /***** hotspot *****/
     294           3 :                 const double dfDx = poStyleLabel->SpacingX(nullcheck);
     295           3 :                 const double dfDy = poStyleLabel->SpacingY(nullcheck2);
     296             : 
     297           3 :                 if (!nullcheck && !nullcheck2)
     298             :                 {
     299           0 :                     if (!poKmlIconStyle)
     300             :                     {
     301           0 :                         poKmlIconStyle = poKmlFactory->CreateIconStyle();
     302             :                         const IconStyleIconPtr poKmlIcon =
     303           0 :                             poKmlFactory->CreateIconStyleIcon();
     304           0 :                         poKmlIconStyle->set_icon(poKmlIcon);
     305             :                     }
     306             : 
     307           0 :                     HotSpotPtr poKmlHotSpot = poKmlFactory->CreateHotSpot();
     308           0 :                     if (poKmlHotSpot)
     309             :                     {
     310           0 :                         poKmlHotSpot->set_x(dfDx);
     311           0 :                         poKmlHotSpot->set_y(dfDy);
     312             : 
     313           0 :                         poKmlIconStyle->set_hotspot(poKmlHotSpot);
     314             :                     }
     315             :                 }
     316             : 
     317             :                 /***** label text *****/
     318           3 :                 const char *const pszText = poStyleLabel->TextString(nullcheck);
     319             : 
     320           3 :                 if (!nullcheck && poKmlFeature)
     321             :                 {
     322           0 :                     poKmlFeature->set_name(pszText);
     323             :                 }
     324             : 
     325           3 :                 break;
     326             :             }
     327           0 :             case OGRSTCNone:
     328             :             default:
     329             :             {
     330           0 :                 break;
     331             :             }
     332             :         }
     333             : 
     334          19 :         delete poOgrST;
     335             :     }
     336             : 
     337          11 :     if (poKmlLineStyle || poKmlPolyStyle || poKmlIconStyle || poKmlLabelStyle)
     338             :     {
     339          11 :         if (!poKmlStyle)
     340           1 :             poKmlStyle = poKmlFactory->CreateStyle();
     341             : 
     342          11 :         if (poKmlLineStyle)
     343           4 :             poKmlStyle->set_linestyle(poKmlLineStyle);
     344             : 
     345          11 :         if (poKmlPolyStyle)
     346           4 :             poKmlStyle->set_polystyle(poKmlPolyStyle);
     347             : 
     348          11 :         if (poKmlIconStyle)
     349           8 :             poKmlStyle->set_iconstyle(poKmlIconStyle);
     350             : 
     351          11 :         if (poKmlLabelStyle)
     352           3 :             poKmlStyle->set_labelstyle(poKmlLabelStyle);
     353             :     }
     354             : 
     355          11 :     delete poOgrSM;
     356             : 
     357          11 :     return poKmlStyle;
     358             : }
     359             : 
     360             : /******************************************************************************
     361             :  kml2pen
     362             : ******************************************************************************/
     363             : 
     364         103 : static OGRStylePen *kml2pen(LineStylePtr poKmlLineStyle,
     365             :                             OGRStylePen *poOgrStylePen)
     366             : {
     367         103 :     if (!poOgrStylePen)
     368         103 :         poOgrStylePen = new OGRStylePen();
     369             : 
     370             :     /***** <LineStyle> should always have a width in pixels *****/
     371         103 :     poOgrStylePen->SetUnit(OGRSTUPixel);
     372             : 
     373             :     /***** width *****/
     374         103 :     if (poKmlLineStyle->has_width())
     375          83 :         poOgrStylePen->SetWidth(poKmlLineStyle->get_width());
     376             : 
     377             :     /***** color *****/
     378         103 :     if (poKmlLineStyle->has_color())
     379             :     {
     380          53 :         Color32 poKmlColor = poKmlLineStyle->get_color();
     381          53 :         char szColor[10] = {};
     382          53 :         snprintf(szColor, sizeof(szColor), "#%02X%02X%02X%02X",
     383             :                  poKmlColor.get_red(), poKmlColor.get_green(),
     384             :                  poKmlColor.get_blue(), poKmlColor.get_alpha());
     385          53 :         poOgrStylePen->SetColor(szColor);
     386             :     }
     387             : 
     388         103 :     return poOgrStylePen;
     389             : }
     390             : 
     391             : /******************************************************************************
     392             :  kml2brush
     393             : ******************************************************************************/
     394             : 
     395          83 : static OGRStyleBrush *kml2brush(PolyStylePtr poKmlPolyStyle,
     396             :                                 OGRStyleBrush *poOgrStyleBrush)
     397             : {
     398          83 :     if (!poOgrStyleBrush)
     399          83 :         poOgrStyleBrush = new OGRStyleBrush();
     400             : 
     401             :     /***** color *****/
     402          83 :     if (poKmlPolyStyle->has_color())
     403             :     {
     404          83 :         Color32 poKmlColor = poKmlPolyStyle->get_color();
     405          83 :         char szColor[10] = {};
     406          83 :         snprintf(szColor, sizeof(szColor), "#%02X%02X%02X%02X",
     407             :                  poKmlColor.get_red(), poKmlColor.get_green(),
     408             :                  poKmlColor.get_blue(), poKmlColor.get_alpha());
     409          83 :         poOgrStyleBrush->SetForeColor(szColor);
     410             :     }
     411             : 
     412          83 :     return poOgrStyleBrush;
     413             : }
     414             : 
     415             : /******************************************************************************
     416             :  kml2symbol
     417             : ******************************************************************************/
     418             : 
     419          52 : static OGRStyleSymbol *kml2symbol(IconStylePtr poKmlIconStyle,
     420             :                                   OGRStyleSymbol *poOgrStyleSymbol)
     421             : {
     422          52 :     if (!poOgrStyleSymbol)
     423          52 :         poOgrStyleSymbol = new OGRStyleSymbol();
     424             : 
     425             :     /***** id (kml icon) *****/
     426          52 :     if (poKmlIconStyle->has_icon())
     427             :     {
     428         104 :         IconStyleIconPtr poKmlIcon = poKmlIconStyle->get_icon();
     429             : 
     430          52 :         if (poKmlIcon->has_href())
     431             :         {
     432         104 :             std::string oIcon = "\"";
     433          52 :             oIcon.append(poKmlIcon->get_href().c_str());
     434          52 :             oIcon.append("\"");
     435          52 :             poOgrStyleSymbol->SetId(oIcon.c_str());
     436             :         }
     437             :     }
     438             : 
     439             :     /***** heading *****/
     440          52 :     if (poKmlIconStyle->has_heading())
     441           3 :         poOgrStyleSymbol->SetAngle(poKmlIconStyle->get_heading());
     442             : 
     443             :     /***** scale *****/
     444          52 :     if (poKmlIconStyle->has_scale())
     445           3 :         poOgrStyleSymbol->SetSize(poKmlIconStyle->get_scale());
     446             : 
     447             :     /***** color *****/
     448          52 :     if (poKmlIconStyle->has_color())
     449             :     {
     450          11 :         Color32 poKmlColor = poKmlIconStyle->get_color();
     451          11 :         char szColor[10] = {};
     452          11 :         snprintf(szColor, sizeof(szColor), "#%02X%02X%02X%02X",
     453             :                  poKmlColor.get_red(), poKmlColor.get_green(),
     454             :                  poKmlColor.get_blue(), poKmlColor.get_alpha());
     455          11 :         poOgrStyleSymbol->SetColor(szColor);
     456             :     }
     457             : 
     458             :     /***** hotspot *****/
     459          52 :     if (poKmlIconStyle->has_hotspot())
     460             :     {
     461           4 :         const HotSpotPtr poKmlHotSpot = poKmlIconStyle->get_hotspot();
     462             : 
     463           2 :         if (poKmlHotSpot->has_x())
     464           2 :             poOgrStyleSymbol->SetSpacingX(poKmlHotSpot->get_x());
     465           2 :         if (poKmlHotSpot->has_y())
     466           2 :             poOgrStyleSymbol->SetSpacingY(poKmlHotSpot->get_y());
     467             :     }
     468             : 
     469          52 :     return poOgrStyleSymbol;
     470             : }
     471             : 
     472             : /******************************************************************************
     473             :  kml2label
     474             : ******************************************************************************/
     475             : 
     476           5 : static OGRStyleLabel *kml2label(LabelStylePtr poKmlLabelStyle,
     477             :                                 OGRStyleLabel *poOgrStyleLabel)
     478             : {
     479           5 :     if (!poOgrStyleLabel)
     480           5 :         poOgrStyleLabel = new OGRStyleLabel();
     481             : 
     482             :     /***** color *****/
     483           5 :     if (poKmlLabelStyle->has_color())
     484             :     {
     485           5 :         Color32 poKmlColor = poKmlLabelStyle->get_color();
     486           5 :         char szColor[10] = {};
     487           5 :         snprintf(szColor, sizeof(szColor), "#%02X%02X%02X%02X",
     488             :                  poKmlColor.get_red(), poKmlColor.get_green(),
     489             :                  poKmlColor.get_blue(), poKmlColor.get_alpha());
     490           5 :         poOgrStyleLabel->SetForColor(szColor);
     491             :     }
     492             : 
     493           5 :     if (poKmlLabelStyle->has_scale())
     494             :     {
     495           5 :         double dfScale = poKmlLabelStyle->get_scale();
     496           5 :         dfScale *= 100.0;
     497             : 
     498           5 :         poOgrStyleLabel->SetStretch(dfScale);
     499             :     }
     500             : 
     501           5 :     return poOgrStyleLabel;
     502             : }
     503             : 
     504             : /******************************************************************************
     505             :  Function to add a kml style to a style table.
     506             : ******************************************************************************/
     507             : 
     508         155 : static void kml2styletable(OGRStyleTable *poOgrStyleTable, StylePtr poKmlStyle)
     509             : {
     510             :     /***** No reason to add it if it don't have an id. *****/
     511         155 :     if (!poKmlStyle->has_id())
     512             :     {
     513           0 :         CPLError(CE_Warning, CPLE_AppDefined, "ERROR parsing kml Style: No id");
     514           0 :         return;
     515             :     }
     516             : 
     517         155 :     OGRStyleMgr *poOgrSM = new OGRStyleMgr(poOgrStyleTable);
     518             : 
     519         155 :     poOgrSM->InitStyleString(nullptr);
     520             : 
     521             :     /***** read the style *****/
     522         155 :     kml2stylestring(poKmlStyle, poOgrSM);
     523             : 
     524             :     /***** add the style to the style table *****/
     525         310 :     const std::string oName = poKmlStyle->get_id();
     526             : 
     527         155 :     poOgrSM->AddStyle(CPLString().Printf("%s", oName.c_str()), nullptr);
     528             : 
     529             :     /***** Cleanup the style manager. *****/
     530         155 :     delete poOgrSM;
     531             : }
     532             : 
     533             : /******************************************************************************
     534             :  Function to follow the kml stylemap if one exists.
     535             : ******************************************************************************/
     536             : 
     537             : StyleSelectorPtr
     538           1 : StyleFromStyleSelector(const StyleSelectorPtr &poKmlStyleSelector,
     539             :                        OGRStyleTable *poStyleTable)
     540             : {
     541             :     /***** Is it a style? *****/
     542           1 :     if (poKmlStyleSelector->IsA(kmldom::Type_Style))
     543           1 :         return poKmlStyleSelector;
     544             : 
     545             :     /***** Is it a style map? *****/
     546             : 
     547           0 :     else if (poKmlStyleSelector->IsA(kmldom::Type_StyleMap))
     548           0 :         return StyleFromStyleMap(kmldom::AsStyleMap(poKmlStyleSelector),
     549           0 :                                  poStyleTable);
     550             : 
     551             :     /***** Not a style or a style map. *****/
     552           0 :     return nullptr;
     553             : }
     554             : 
     555             : /******************************************************************************
     556             :  kml2stylemgr
     557             : ******************************************************************************/
     558             : 
     559         156 : void kml2stylestring(StylePtr poKmlStyle, OGRStyleMgr *poOgrSM)
     560             : 
     561             : {
     562         156 :     OGRStyleMgr *const poOgrNewSM = new OGRStyleMgr(nullptr);
     563             : 
     564             :     /***** linestyle / pen *****/
     565         156 :     if (poKmlStyle->has_linestyle())
     566             :     {
     567         103 :         poOgrNewSM->InitStyleString(nullptr);
     568             : 
     569         206 :         LineStylePtr poKmlLineStyle = poKmlStyle->get_linestyle();
     570             : 
     571         103 :         OGRStyleTool *poOgrTmpST = nullptr;
     572         103 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     573             :         {
     574           0 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     575             : 
     576           0 :             if (!poOgrST)
     577           0 :                 continue;
     578             : 
     579           0 :             if (poOgrST->GetType() == OGRSTCPen && poOgrTmpST == nullptr)
     580             :             {
     581           0 :                 poOgrTmpST = poOgrST;
     582             :             }
     583             :             else
     584             :             {
     585           0 :                 poOgrNewSM->AddPart(poOgrST);
     586           0 :                 delete poOgrST;
     587             :             }
     588             :         }
     589             : 
     590             :         OGRStylePen *poOgrStylePen =
     591         103 :             kml2pen(std::move(poKmlLineStyle), (OGRStylePen *)poOgrTmpST);
     592             : 
     593         103 :         poOgrNewSM->AddPart(poOgrStylePen);
     594             : 
     595         103 :         delete poOgrStylePen;
     596         103 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     597             :     }
     598             : 
     599             :     /***** polystyle / brush *****/
     600         156 :     if (poKmlStyle->has_polystyle())
     601             :     {
     602          83 :         poOgrNewSM->InitStyleString(nullptr);
     603             : 
     604         166 :         PolyStylePtr poKmlPolyStyle = poKmlStyle->get_polystyle();
     605             : 
     606          83 :         OGRStyleTool *poOgrTmpST = nullptr;
     607         166 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     608             :         {
     609          83 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     610             : 
     611          83 :             if (!poOgrST)
     612           0 :                 continue;
     613             : 
     614          83 :             if (poOgrST->GetType() == OGRSTCBrush && poOgrTmpST == nullptr)
     615             :             {
     616           0 :                 poOgrTmpST = poOgrST;
     617             :             }
     618             :             else
     619             :             {
     620          83 :                 poOgrNewSM->AddPart(poOgrST);
     621          83 :                 delete poOgrST;
     622             :             }
     623             :         }
     624             : 
     625             :         OGRStyleBrush *poOgrStyleBrush =
     626          83 :             kml2brush(std::move(poKmlPolyStyle), (OGRStyleBrush *)poOgrTmpST);
     627             : 
     628          83 :         poOgrNewSM->AddPart(poOgrStyleBrush);
     629             : 
     630          83 :         delete poOgrStyleBrush;
     631          83 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     632             :     }
     633             : 
     634             :     /***** iconstyle / symbol *****/
     635         156 :     if (poKmlStyle->has_iconstyle())
     636             :     {
     637          52 :         poOgrNewSM->InitStyleString(nullptr);
     638             : 
     639         104 :         IconStylePtr poKmlIconStyle = poKmlStyle->get_iconstyle();
     640             : 
     641          52 :         OGRStyleTool *poOgrTmpST = nullptr;
     642          64 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     643             :         {
     644          12 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     645             : 
     646          12 :             if (!poOgrST)
     647           0 :                 continue;
     648             : 
     649          12 :             if (poOgrST->GetType() == OGRSTCSymbol && poOgrTmpST == nullptr)
     650             :             {
     651           0 :                 poOgrTmpST = poOgrST;
     652             :             }
     653             :             else
     654             :             {
     655          12 :                 poOgrNewSM->AddPart(poOgrST);
     656          12 :                 delete poOgrST;
     657             :             }
     658             :         }
     659             : 
     660             :         OGRStyleSymbol *poOgrStyleSymbol =
     661          52 :             kml2symbol(std::move(poKmlIconStyle), (OGRStyleSymbol *)poOgrTmpST);
     662             : 
     663          52 :         poOgrNewSM->AddPart(poOgrStyleSymbol);
     664             : 
     665          52 :         delete poOgrStyleSymbol;
     666          52 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     667             :     }
     668             : 
     669             :     /***** labelstyle / label *****/
     670         156 :     if (poKmlStyle->has_labelstyle())
     671             :     {
     672           5 :         poOgrNewSM->InitStyleString(nullptr);
     673             : 
     674          10 :         LabelStylePtr poKmlLabelStyle = poKmlStyle->get_labelstyle();
     675             : 
     676           5 :         OGRStyleTool *poOgrTmpST = nullptr;
     677          10 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     678             :         {
     679           5 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     680             : 
     681           5 :             if (!poOgrST)
     682           0 :                 continue;
     683             : 
     684           5 :             if (poOgrST->GetType() == OGRSTCLabel && poOgrTmpST == nullptr)
     685             :             {
     686           0 :                 poOgrTmpST = poOgrST;
     687             :             }
     688             :             else
     689             :             {
     690           5 :                 poOgrNewSM->AddPart(poOgrST);
     691           5 :                 delete poOgrST;
     692             :             }
     693             :         }
     694             : 
     695             :         OGRStyleLabel *poOgrStyleLabel =
     696           5 :             kml2label(std::move(poKmlLabelStyle), (OGRStyleLabel *)poOgrTmpST);
     697             : 
     698           5 :         poOgrNewSM->AddPart(poOgrStyleLabel);
     699             : 
     700           5 :         delete poOgrStyleLabel;
     701           5 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     702             :     }
     703             : 
     704         156 :     delete poOgrNewSM;
     705         156 : }
     706             : 
     707             : /******************************************************************************
     708             :  Function to get the container from the kmlroot.
     709             : 
     710             :  Args:          poKmlRoot   the root element
     711             : 
     712             :  Returns:       root if its a container, if its a kml the container it
     713             :                 contains, or NULL
     714             : 
     715             : ******************************************************************************/
     716             : 
     717           0 : static ContainerPtr MyGetContainerFromRoot(KmlFactory *poKmlFactory,
     718             :                                            ElementPtr poKmlRoot)
     719             : {
     720           0 :     ContainerPtr poKmlContainer = nullptr;
     721             : 
     722           0 :     if (poKmlRoot)
     723             :     {
     724             :         /***** skip over the <kml> we want the container *****/
     725           0 :         if (poKmlRoot->IsA(kmldom::Type_kml))
     726             :         {
     727           0 :             KmlPtr poKmlKml = AsKml(poKmlRoot);
     728             : 
     729           0 :             if (poKmlKml && poKmlKml->has_feature())
     730             :             {
     731           0 :                 FeaturePtr poKmlFeat = poKmlKml->get_feature();
     732             : 
     733           0 :                 if (poKmlFeat->IsA(kmldom::Type_Container))
     734             :                 {
     735           0 :                     poKmlContainer = AsContainer(poKmlFeat);
     736             :                 }
     737           0 :                 else if (poKmlFeat->IsA(kmldom::Type_Placemark))
     738             :                 {
     739           0 :                     poKmlContainer = poKmlFactory->CreateDocument();
     740           0 :                     poKmlContainer->add_feature(
     741           0 :                         kmldom::AsFeature(kmlengine::Clone(poKmlFeat)));
     742             :                 }
     743             :             }
     744             :         }
     745           0 :         else if (poKmlRoot->IsA(kmldom::Type_Container))
     746             :         {
     747           0 :             poKmlContainer = AsContainer(std::move(poKmlRoot));
     748             :         }
     749             :     }
     750             : 
     751           0 :     return poKmlContainer;
     752             : }
     753             : 
     754          15 : static StyleSelectorPtr StyleFromStyleURL(const StyleMapPtr &stylemap,
     755             :                                           const string &styleurl,
     756             :                                           OGRStyleTable *poStyleTable)
     757             : {
     758             :     // TODO:: Parse the styleURL.
     759          15 :     char *pszUrl = CPLStrdup(styleurl.c_str());
     760          15 :     char *pszStyleMapId = CPLStrdup(stylemap->get_id().c_str());
     761             : 
     762             :     /***** Is it an internal style ref that starts with a #? *****/
     763          15 :     if (*pszUrl == '#' && poStyleTable)
     764             :     {
     765             :         /***** Search the style table for the style we *****/
     766             :         /***** want and copy it back into the table.   *****/
     767          15 :         const char *pszTest = poStyleTable->Find(pszUrl + 1);
     768          15 :         if (pszTest)
     769             :         {
     770          15 :             poStyleTable->AddStyle(pszStyleMapId, pszTest);
     771          15 :         }
     772             :     }
     773             : 
     774             :     /***** We have a real URL and need to go out and fetch it *****/
     775             :     /***** FIXME this could be a relative path in a kmz *****/
     776           0 :     else if (strchr(pszUrl, '#'))
     777             :     {
     778             :         const char *pszFetch =
     779           0 :             CPLGetConfigOption("LIBKML_EXTERNAL_STYLE", "no");
     780           0 :         if (CPLTestBool(pszFetch))
     781             :         {
     782             :             /***** Lets go out and fetch the style from the external URL *****/
     783           0 :             char *pszUrlTmp = CPLStrdup(pszUrl);
     784           0 :             char *pszPound = strchr(pszUrlTmp, '#');
     785           0 :             char *pszRemoteStyleName = nullptr;
     786             :             // Chop off the stuff (style id) after the URL
     787           0 :             if (pszPound != nullptr)
     788             :             {
     789           0 :                 *pszPound = '\0';
     790           0 :                 pszRemoteStyleName = pszPound + 1;
     791             :             }
     792             : 
     793             :             /***** try it as a url then a file *****/
     794           0 :             VSILFILE *fp = nullptr;
     795           0 :             if ((fp =
     796           0 :                      VSIFOpenL(CPLFormFilename("/vsicurl/", pszUrlTmp, nullptr),
     797           0 :                                "r")) != nullptr ||
     798           0 :                 (fp = VSIFOpenL(pszUrlTmp, "r")) != nullptr)
     799             :             {
     800           0 :                 char szbuf[1025] = {};
     801           0 :                 std::string oStyle = "";
     802             : 
     803             :                 /***** loop, read and copy to a string *****/
     804           0 :                 do
     805             :                 {
     806             :                     const size_t nRead =
     807           0 :                         VSIFReadL(szbuf, 1, sizeof(szbuf) - 1, fp);
     808           0 :                     if (nRead == 0)
     809           0 :                         break;
     810             : 
     811             :                     /***** copy buf to the string *****/
     812           0 :                     szbuf[nRead] = '\0';
     813           0 :                     oStyle.append(szbuf);
     814           0 :                 } while (!VSIFEofL(fp) && !VSIFErrorL(fp));
     815             : 
     816           0 :                 VSIFCloseL(fp);
     817             : 
     818             :                 /***** parse the kml into the dom *****/
     819           0 :                 std::string oKmlErrors;
     820           0 :                 ElementPtr poKmlRoot = kmldom::Parse(oStyle, &oKmlErrors);
     821             : 
     822           0 :                 if (!poKmlRoot)
     823             :                 {
     824           0 :                     CPLError(CE_Warning, CPLE_OpenFailed,
     825             :                              "ERROR parsing style kml %s :%s", pszUrlTmp,
     826             :                              oKmlErrors.c_str());
     827           0 :                     CPLFree(pszUrlTmp);
     828           0 :                     CPLFree(pszUrl);
     829           0 :                     CPLFree(pszStyleMapId);
     830             : 
     831           0 :                     return nullptr;
     832             :                 }
     833             : 
     834             :                 /***** get the root container *****/
     835             :                 kmldom::KmlFactory *poKmlFactory =
     836           0 :                     kmldom::KmlFactory::GetFactory();
     837           0 :                 ContainerPtr poKmlContainer;
     838           0 :                 if (!(poKmlContainer = MyGetContainerFromRoot(
     839           0 :                           poKmlFactory, std::move(poKmlRoot))))
     840             :                 {
     841           0 :                     CPLFree(pszUrlTmp);
     842           0 :                     CPLFree(pszUrl);
     843           0 :                     CPLFree(pszStyleMapId);
     844             : 
     845           0 :                     return nullptr;
     846             :                 }
     847             : 
     848             :                 /**** parse the styles into the table *****/
     849           0 :                 ParseStyles(AsDocument(poKmlContainer), &poStyleTable);
     850             : 
     851             :                 /***** look for the style we need to map to in the table *****/
     852           0 :                 const char *pszTest = poStyleTable->Find(pszRemoteStyleName);
     853             : 
     854             :                 /***** if found copy it to the table as a new style *****/
     855           0 :                 if (pszTest)
     856           0 :                     poStyleTable->AddStyle(pszStyleMapId, pszTest);
     857             :             }
     858           0 :             CPLFree(pszUrlTmp);
     859             :         }
     860             :     }
     861             : 
     862             :     /***** FIXME Add support here for relative links inside KML. *****/
     863          15 :     CPLFree(pszUrl);
     864          15 :     CPLFree(pszStyleMapId);
     865             : 
     866          15 :     return nullptr;
     867             : }
     868             : 
     869          16 : StyleSelectorPtr StyleFromStyleMap(const StyleMapPtr &poKmlStyleMap,
     870             :                                    OGRStyleTable *poStyleTable)
     871             : {
     872             :     /***** check the config option to see if the    *****/
     873             :     /***** user wants normal or highlighted mapping *****/
     874             :     const char *pszStyleMapKey =
     875          16 :         CPLGetConfigOption("LIBKML_STYLEMAP_KEY", "normal");
     876          32 :     const int nStyleMapKey = EQUAL(pszStyleMapKey, "highlight")
     877          16 :                                  ? STYLESTATE_HIGHLIGHT
     878             :                                  : STYLESTATE_NORMAL;
     879             : 
     880             :     /*****  Loop through the stylemap pairs and look for the "normal" one *****/
     881          17 :     for (size_t i = 0; i < poKmlStyleMap->get_pair_array_size(); ++i)
     882             :     {
     883          17 :         PairPtr myPair = poKmlStyleMap->get_pair_array_at(i);
     884             : 
     885             :         /***** is it the right one of the pair? *****/
     886          17 :         if (myPair->get_key() == nStyleMapKey)
     887             :         {
     888          16 :             if (myPair->has_styleselector())
     889             :                 return StyleFromStyleSelector(myPair->get_styleselector(),
     890           1 :                                               poStyleTable);
     891          15 :             else if (myPair->has_styleurl())
     892             :                 return StyleFromStyleURL(poKmlStyleMap, myPair->get_styleurl(),
     893          15 :                                          poStyleTable);
     894             :         }
     895             :     }
     896             : 
     897           0 :     return nullptr;
     898             : }
     899             : 
     900             : /******************************************************************************
     901             :  Function to parse a style table out of a document.
     902             : ******************************************************************************/
     903             : 
     904         209 : void ParseStyles(DocumentPtr poKmlDocument, OGRStyleTable **poStyleTable)
     905             : {
     906             :     /***** if document is null just bail now *****/
     907         209 :     if (!poKmlDocument)
     908           2 :         return;
     909             : 
     910             :     /***** loop over the Styles *****/
     911         207 :     const size_t nKmlStyles = poKmlDocument->get_styleselector_array_size();
     912             : 
     913             :     /***** Lets first build the style table.    *****/
     914             :     /***** to begin this is just proper styles. *****/
     915         377 :     for (size_t iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++)
     916             :     {
     917             :         StyleSelectorPtr poKmlStyle =
     918         170 :             poKmlDocument->get_styleselector_array_at(iKmlStyle);
     919             : 
     920             :         /***** Everything that is not a style you skip *****/
     921         170 :         if (!poKmlStyle->IsA(kmldom::Type_Style))
     922          16 :             continue;
     923             : 
     924             :         /***** We need to check to see if this is the first style. if it *****/
     925             :         /***** is we will not have a style table and need to create one  *****/
     926             : 
     927         154 :         if (!*poStyleTable)
     928          28 :             *poStyleTable = new OGRStyleTable();
     929             : 
     930         154 :         kml2styletable(*poStyleTable, AsStyle(AsElement(poKmlStyle)));
     931             :     }
     932             : 
     933             :     /***** Now we have to loop back around and get the style maps. We    *****/
     934             :     /***** have to do this a second time since the stylemap might matter *****/
     935             :     /***** and we are just looping reference styles that are farther     *****/
     936             :     /***** down in the file. Order through the XML as it is parsed.      *****/
     937             : 
     938         377 :     for (size_t iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++)
     939             :     {
     940             :         StyleSelectorPtr poKmlStyle =
     941         170 :             poKmlDocument->get_styleselector_array_at(iKmlStyle);
     942             : 
     943             :         /***** Everything that is not a stylemap you skip *****/
     944         170 :         if (!poKmlStyle->IsA(kmldom::Type_StyleMap))
     945         154 :             continue;
     946             : 
     947             :         /***** We need to check to see if this is the first style. if it *****/
     948             :         /***** is we will not have a style table and need to create one  *****/
     949          16 :         if (!*poStyleTable)
     950           0 :             *poStyleTable = new OGRStyleTable();
     951             : 
     952             :         /***** copy the style the style map points to since *****/
     953             : 
     954          16 :         char *pszStyleMapId = CPLStrdup(poKmlStyle->get_id().c_str());
     955             :         poKmlStyle =
     956          16 :             StyleFromStyleMap(kmldom::AsStyleMap(poKmlStyle), *poStyleTable);
     957          16 :         if (!poKmlStyle)
     958             :         {
     959          15 :             CPLFree(pszStyleMapId);
     960          15 :             continue;
     961             :         }
     962           1 :         char *pszStyleId = CPLStrdup(poKmlStyle->get_id().c_str());
     963             : 
     964           1 :         kml2styletable(*poStyleTable, AsStyle(AsElement(poKmlStyle)));
     965             : 
     966             :         // Change the name of the new style in the style table
     967             : 
     968           1 :         const char *pszTest = (*poStyleTable)->Find(pszStyleId);
     969             :         // If we found the style we want in the style table we...
     970           1 :         if (pszTest)
     971             :         {
     972           1 :             (*poStyleTable)->AddStyle(pszStyleMapId, pszTest);
     973           1 :             (*poStyleTable)->RemoveStyle(pszStyleId);
     974             :         }
     975           1 :         CPLFree(pszStyleId);
     976           1 :         CPLFree(pszStyleMapId);
     977             :     }
     978             : }
     979             : 
     980             : /******************************************************************************
     981             :  Function to add a style table to a kml container.
     982             : ******************************************************************************/
     983             : 
     984           6 : void styletable2kml(OGRStyleTable *poOgrStyleTable, KmlFactory *poKmlFactory,
     985             :                     ContainerPtr poKmlContainer, char **papszOptions)
     986             : {
     987             :     /***** just return if the styletable is null *****/
     988           6 :     if (!poOgrStyleTable)
     989           2 :         return;
     990             : 
     991           8 :     std::set<CPLString> aoSetNormalStyles;
     992           8 :     std::set<CPLString> aoSetHighlightStyles;
     993           4 :     poOgrStyleTable->ResetStyleStringReading();
     994             : 
     995             :     // Collect styles that end with _normal or _highlight.
     996          14 :     while (poOgrStyleTable->GetNextStyle() != nullptr)
     997             :     {
     998          10 :         const char *pszStyleName = poOgrStyleTable->GetLastStyleName();
     999             : 
    1000          10 :         if (strlen(pszStyleName) > strlen("_normal") &&
    1001           6 :             EQUAL(pszStyleName + strlen(pszStyleName) - strlen("_normal"),
    1002             :                   "_normal"))
    1003             :         {
    1004           4 :             CPLString osName(pszStyleName);
    1005           2 :             osName.resize(strlen(pszStyleName) - strlen("_normal"));
    1006           4 :             aoSetNormalStyles.insert(osName);
    1007             :         }
    1008           8 :         else if (strlen(pszStyleName) > strlen("_highlight") &&
    1009           4 :                  EQUAL(pszStyleName + strlen(pszStyleName) -
    1010             :                            strlen("_highlight"),
    1011             :                        "_highlight"))
    1012             :         {
    1013           4 :             CPLString osName(pszStyleName);
    1014           2 :             osName.resize(strlen(pszStyleName) - strlen("_highlight"));
    1015           2 :             aoSetHighlightStyles.insert(osName);
    1016             :         }
    1017             :     }
    1018             : 
    1019             :     /***** parse the style table *****/
    1020           4 :     poOgrStyleTable->ResetStyleStringReading();
    1021             : 
    1022           4 :     const char *pszStyleString = nullptr;
    1023          14 :     while ((pszStyleString = poOgrStyleTable->GetNextStyle()) != nullptr)
    1024             :     {
    1025          10 :         const char *pszStyleName = poOgrStyleTable->GetLastStyleName();
    1026             : 
    1027          20 :         if (aoSetNormalStyles.find(pszStyleName) != aoSetNormalStyles.end() &&
    1028          10 :             aoSetHighlightStyles.find(pszStyleName) !=
    1029          10 :                 aoSetHighlightStyles.end())
    1030             :         {
    1031           0 :             continue;
    1032             :         }
    1033             : 
    1034             :         /***** add the style header to the kml *****/
    1035          20 :         StylePtr poKmlStyle = poKmlFactory->CreateStyle();
    1036             : 
    1037          10 :         poKmlStyle->set_id(pszStyleName);
    1038             : 
    1039             :         /***** parse the style string *****/
    1040          10 :         addstylestring2kml(pszStyleString, poKmlStyle, poKmlFactory, nullptr);
    1041             : 
    1042             :         /***** add balloon style *****/
    1043          10 :         const char *pszBalloonStyleBgColor = CSLFetchNameValue(
    1044             :             papszOptions, CPLSPrintf("%s_balloonstyle_bgcolor", pszStyleName));
    1045          10 :         const char *pszBalloonStyleText = CSLFetchNameValue(
    1046             :             papszOptions, CPLSPrintf("%s_balloonstyle_text", pszStyleName));
    1047          10 :         int nR = 0;
    1048          10 :         int nG = 0;
    1049          10 :         int nB = 0;
    1050          10 :         int nA = 0;
    1051          20 :         OGRStylePen oStyleTool;
    1052          11 :         if ((pszBalloonStyleBgColor != nullptr &&
    1053           1 :              oStyleTool.GetRGBFromString(pszBalloonStyleBgColor, nR, nG, nB,
    1054          11 :                                          nA)) ||
    1055             :             pszBalloonStyleText != nullptr)
    1056             :         {
    1057             :             const BalloonStylePtr poKmlBalloonStyle =
    1058           2 :                 poKmlFactory->CreateBalloonStyle();
    1059           2 :             if (pszBalloonStyleBgColor != nullptr &&
    1060           1 :                 oStyleTool.GetRGBFromString(pszBalloonStyleBgColor, nR, nG, nB,
    1061             :                                             nA))
    1062           2 :                 poKmlBalloonStyle->set_bgcolor(
    1063           2 :                     Color32(static_cast<GByte>(nA), static_cast<GByte>(nB),
    1064             :                             static_cast<GByte>(nG), static_cast<GByte>(nR)));
    1065           1 :             if (pszBalloonStyleText != nullptr)
    1066           1 :                 poKmlBalloonStyle->set_text(pszBalloonStyleText);
    1067           1 :             poKmlStyle->set_balloonstyle(poKmlBalloonStyle);
    1068             :         }
    1069             : 
    1070             :         /***** add the style to the container *****/
    1071          10 :         const DocumentPtr poKmlDocument = AsDocument(poKmlContainer);
    1072          10 :         poKmlDocument->add_styleselector(poKmlStyle);
    1073             :     }
    1074             : 
    1075             :     // Find style name that end with _normal and _highlight to create
    1076             :     // a StyleMap from both.
    1077             :     std::set<CPLString>::iterator aoSetNormalStylesIter =
    1078           4 :         aoSetNormalStyles.begin();
    1079           6 :     for (; aoSetNormalStylesIter != aoSetNormalStyles.end();
    1080           2 :          ++aoSetNormalStylesIter)
    1081             :     {
    1082           4 :         CPLString osStyleName(*aoSetNormalStylesIter);
    1083           2 :         if (aoSetHighlightStyles.find(osStyleName) !=
    1084           4 :             aoSetHighlightStyles.end())
    1085             :         {
    1086           4 :             StyleMapPtr poKmlStyleMap = poKmlFactory->CreateStyleMap();
    1087           2 :             poKmlStyleMap->set_id(osStyleName);
    1088             : 
    1089           4 :             PairPtr poKmlPairNormal = poKmlFactory->CreatePair();
    1090           2 :             poKmlPairNormal->set_key(STYLESTATE_NORMAL);
    1091           2 :             poKmlPairNormal->set_styleurl(
    1092             :                 CPLSPrintf("#%s_normal", osStyleName.c_str()));
    1093           2 :             poKmlStyleMap->add_pair(poKmlPairNormal);
    1094             : 
    1095           4 :             PairPtr poKmlPairHighlight = poKmlFactory->CreatePair();
    1096           2 :             poKmlPairHighlight->set_key(STYLESTATE_HIGHLIGHT);
    1097           2 :             poKmlPairHighlight->set_styleurl(
    1098             :                 CPLSPrintf("#%s_highlight", osStyleName.c_str()));
    1099           2 :             poKmlStyleMap->add_pair(poKmlPairHighlight);
    1100             : 
    1101             :             /***** add the style to the container *****/
    1102           2 :             DocumentPtr poKmlDocument = AsDocument(poKmlContainer);
    1103           2 :             poKmlDocument->add_styleselector(poKmlStyleMap);
    1104             :         }
    1105             :     }
    1106             : }
    1107             : 
    1108             : /******************************************************************************
    1109             :  Function to add a ListStyle and select it to a container.
    1110             : ******************************************************************************/
    1111             : 
    1112         212 : void createkmlliststyle(KmlFactory *poKmlFactory, const char *pszBaseName,
    1113             :                         ContainerPtr poKmlLayerContainer,
    1114             :                         DocumentPtr poKmlDocument,
    1115             :                         const CPLString &osListStyleType,
    1116             :                         const CPLString &osListStyleIconHref)
    1117             : {
    1118         212 :     if (!osListStyleType.empty() || !osListStyleIconHref.empty())
    1119             :     {
    1120          16 :         StylePtr poKmlStyle = poKmlFactory->CreateStyle();
    1121             : 
    1122           8 :         const char *pszStyleName = CPLSPrintf(
    1123          16 :             "%s_liststyle", OGRLIBKMLGetSanitizedNCName(pszBaseName).c_str());
    1124           8 :         poKmlStyle->set_id(pszStyleName);
    1125             : 
    1126           8 :         ListStylePtr poKmlListStyle = poKmlFactory->CreateListStyle();
    1127           8 :         poKmlStyle->set_liststyle(poKmlListStyle);
    1128           8 :         if (!osListStyleType.empty())
    1129             :         {
    1130           5 :             if (EQUAL(osListStyleType, "check"))
    1131           1 :                 poKmlListStyle->set_listitemtype(kmldom::LISTITEMTYPE_CHECK);
    1132           4 :             else if (EQUAL(osListStyleType, "radioFolder"))
    1133           1 :                 poKmlListStyle->set_listitemtype(
    1134             :                     kmldom::LISTITEMTYPE_RADIOFOLDER);
    1135           3 :             else if (EQUAL(osListStyleType, "checkOffOnly"))
    1136           1 :                 poKmlListStyle->set_listitemtype(
    1137             :                     kmldom::LISTITEMTYPE_CHECKOFFONLY);
    1138           2 :             else if (EQUAL(osListStyleType, "checkHideChildren"))
    1139           1 :                 poKmlListStyle->set_listitemtype(
    1140             :                     kmldom::LISTITEMTYPE_CHECKHIDECHILDREN);
    1141             :             else
    1142             :             {
    1143           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1144             :                          "Invalid value for list style type: %s. "
    1145             :                          "Defaulting to Check",
    1146             :                          osListStyleType.c_str());
    1147           1 :                 poKmlListStyle->set_listitemtype(kmldom::LISTITEMTYPE_CHECK);
    1148             :             }
    1149             :         }
    1150             : 
    1151           8 :         if (!osListStyleIconHref.empty())
    1152             :         {
    1153           6 :             ItemIconPtr poItemIcon = poKmlFactory->CreateItemIcon();
    1154           3 :             poItemIcon->set_href(osListStyleIconHref.c_str());
    1155           3 :             poKmlListStyle->add_itemicon(poItemIcon);
    1156             :         }
    1157             : 
    1158           8 :         poKmlDocument->add_styleselector(poKmlStyle);
    1159           8 :         poKmlLayerContainer->set_styleurl(CPLSPrintf("#%s", pszStyleName));
    1160             :     }
    1161         212 : }

Generated by: LCOV version 1.14