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: 2025-05-31 00:00:17 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),
     592             :                     cpl::down_cast<OGRStylePen *>(poOgrTmpST));
     593             : 
     594         103 :         poOgrNewSM->AddPart(poOgrStylePen);
     595             : 
     596         103 :         delete poOgrStylePen;
     597         103 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     598             :     }
     599             : 
     600             :     /***** polystyle / brush *****/
     601         156 :     if (poKmlStyle->has_polystyle())
     602             :     {
     603          83 :         poOgrNewSM->InitStyleString(nullptr);
     604             : 
     605         166 :         PolyStylePtr poKmlPolyStyle = poKmlStyle->get_polystyle();
     606             : 
     607          83 :         OGRStyleTool *poOgrTmpST = nullptr;
     608         166 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     609             :         {
     610          83 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     611             : 
     612          83 :             if (!poOgrST)
     613           0 :                 continue;
     614             : 
     615          83 :             if (poOgrST->GetType() == OGRSTCBrush && poOgrTmpST == nullptr)
     616             :             {
     617           0 :                 poOgrTmpST = poOgrST;
     618             :             }
     619             :             else
     620             :             {
     621          83 :                 poOgrNewSM->AddPart(poOgrST);
     622          83 :                 delete poOgrST;
     623             :             }
     624             :         }
     625             : 
     626             :         OGRStyleBrush *poOgrStyleBrush =
     627          83 :             kml2brush(std::move(poKmlPolyStyle),
     628             :                       cpl::down_cast<OGRStyleBrush *>(poOgrTmpST));
     629             : 
     630          83 :         poOgrNewSM->AddPart(poOgrStyleBrush);
     631             : 
     632          83 :         delete poOgrStyleBrush;
     633          83 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     634             :     }
     635             : 
     636             :     /***** iconstyle / symbol *****/
     637         156 :     if (poKmlStyle->has_iconstyle())
     638             :     {
     639          52 :         poOgrNewSM->InitStyleString(nullptr);
     640             : 
     641         104 :         IconStylePtr poKmlIconStyle = poKmlStyle->get_iconstyle();
     642             : 
     643          52 :         OGRStyleTool *poOgrTmpST = nullptr;
     644          64 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     645             :         {
     646          12 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     647             : 
     648          12 :             if (!poOgrST)
     649           0 :                 continue;
     650             : 
     651          12 :             if (poOgrST->GetType() == OGRSTCSymbol && poOgrTmpST == nullptr)
     652             :             {
     653           0 :                 poOgrTmpST = poOgrST;
     654             :             }
     655             :             else
     656             :             {
     657          12 :                 poOgrNewSM->AddPart(poOgrST);
     658          12 :                 delete poOgrST;
     659             :             }
     660             :         }
     661             : 
     662             :         OGRStyleSymbol *poOgrStyleSymbol =
     663          52 :             kml2symbol(std::move(poKmlIconStyle),
     664             :                        cpl::down_cast<OGRStyleSymbol *>(poOgrTmpST));
     665             : 
     666          52 :         poOgrNewSM->AddPart(poOgrStyleSymbol);
     667             : 
     668          52 :         delete poOgrStyleSymbol;
     669          52 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     670             :     }
     671             : 
     672             :     /***** labelstyle / label *****/
     673         156 :     if (poKmlStyle->has_labelstyle())
     674             :     {
     675           5 :         poOgrNewSM->InitStyleString(nullptr);
     676             : 
     677          10 :         LabelStylePtr poKmlLabelStyle = poKmlStyle->get_labelstyle();
     678             : 
     679           5 :         OGRStyleTool *poOgrTmpST = nullptr;
     680          10 :         for (int i = 0; i < poOgrSM->GetPartCount(nullptr); i++)
     681             :         {
     682           5 :             OGRStyleTool *poOgrST = poOgrSM->GetPart(i, nullptr);
     683             : 
     684           5 :             if (!poOgrST)
     685           0 :                 continue;
     686             : 
     687           5 :             if (poOgrST->GetType() == OGRSTCLabel && poOgrTmpST == nullptr)
     688             :             {
     689           0 :                 poOgrTmpST = poOgrST;
     690             :             }
     691             :             else
     692             :             {
     693           5 :                 poOgrNewSM->AddPart(poOgrST);
     694           5 :                 delete poOgrST;
     695             :             }
     696             :         }
     697             : 
     698             :         OGRStyleLabel *poOgrStyleLabel =
     699           5 :             kml2label(std::move(poKmlLabelStyle),
     700             :                       cpl::down_cast<OGRStyleLabel *>(poOgrTmpST));
     701             : 
     702           5 :         poOgrNewSM->AddPart(poOgrStyleLabel);
     703             : 
     704           5 :         delete poOgrStyleLabel;
     705           5 :         poOgrSM->InitStyleString(poOgrNewSM->GetStyleString(nullptr));
     706             :     }
     707             : 
     708         156 :     delete poOgrNewSM;
     709         156 : }
     710             : 
     711             : /******************************************************************************
     712             :  Function to get the container from the kmlroot.
     713             : 
     714             :  Args:          poKmlRoot   the root element
     715             : 
     716             :  Returns:       root if its a container, if its a kml the container it
     717             :                 contains, or NULL
     718             : 
     719             : ******************************************************************************/
     720             : 
     721           0 : static ContainerPtr MyGetContainerFromRoot(KmlFactory *poKmlFactory,
     722             :                                            ElementPtr poKmlRoot)
     723             : {
     724           0 :     ContainerPtr poKmlContainer = nullptr;
     725             : 
     726           0 :     if (poKmlRoot)
     727             :     {
     728             :         /***** skip over the <kml> we want the container *****/
     729           0 :         if (poKmlRoot->IsA(kmldom::Type_kml))
     730             :         {
     731           0 :             KmlPtr poKmlKml = AsKml(poKmlRoot);
     732             : 
     733           0 :             if (poKmlKml && poKmlKml->has_feature())
     734             :             {
     735           0 :                 FeaturePtr poKmlFeat = poKmlKml->get_feature();
     736             : 
     737           0 :                 if (poKmlFeat->IsA(kmldom::Type_Container))
     738             :                 {
     739           0 :                     poKmlContainer = AsContainer(poKmlFeat);
     740             :                 }
     741           0 :                 else if (poKmlFeat->IsA(kmldom::Type_Placemark))
     742             :                 {
     743           0 :                     poKmlContainer = poKmlFactory->CreateDocument();
     744           0 :                     poKmlContainer->add_feature(
     745           0 :                         kmldom::AsFeature(kmlengine::Clone(poKmlFeat)));
     746             :                 }
     747             :             }
     748             :         }
     749           0 :         else if (poKmlRoot->IsA(kmldom::Type_Container))
     750             :         {
     751           0 :             poKmlContainer = AsContainer(std::move(poKmlRoot));
     752             :         }
     753             :     }
     754             : 
     755           0 :     return poKmlContainer;
     756             : }
     757             : 
     758          15 : static StyleSelectorPtr StyleFromStyleURL(const StyleMapPtr &stylemap,
     759             :                                           const string &styleurl,
     760             :                                           OGRStyleTable *poStyleTable)
     761             : {
     762             :     // TODO:: Parse the styleURL.
     763          15 :     char *pszUrl = CPLStrdup(styleurl.c_str());
     764          15 :     char *pszStyleMapId = CPLStrdup(stylemap->get_id().c_str());
     765             : 
     766             :     /***** Is it an internal style ref that starts with a #? *****/
     767          15 :     if (*pszUrl == '#' && poStyleTable)
     768             :     {
     769             :         /***** Search the style table for the style we *****/
     770             :         /***** want and copy it back into the table.   *****/
     771          15 :         const char *pszTest = poStyleTable->Find(pszUrl + 1);
     772          15 :         if (pszTest)
     773             :         {
     774          15 :             poStyleTable->AddStyle(pszStyleMapId, pszTest);
     775          15 :         }
     776             :     }
     777             : 
     778             :     /***** We have a real URL and need to go out and fetch it *****/
     779             :     /***** FIXME this could be a relative path in a kmz *****/
     780           0 :     else if (strchr(pszUrl, '#'))
     781             :     {
     782             :         const char *pszFetch =
     783           0 :             CPLGetConfigOption("LIBKML_EXTERNAL_STYLE", "no");
     784           0 :         if (CPLTestBool(pszFetch))
     785             :         {
     786             :             /***** Lets go out and fetch the style from the external URL *****/
     787           0 :             char *pszUrlTmp = CPLStrdup(pszUrl);
     788           0 :             char *pszPound = strchr(pszUrlTmp, '#');
     789           0 :             char *pszRemoteStyleName = nullptr;
     790             :             // Chop off the stuff (style id) after the URL
     791           0 :             if (pszPound != nullptr)
     792             :             {
     793           0 :                 *pszPound = '\0';
     794           0 :                 pszRemoteStyleName = pszPound + 1;
     795             :             }
     796             : 
     797             :             /***** try it as a url then a file *****/
     798           0 :             VSILFILE *fp = nullptr;
     799           0 :             if ((fp = VSIFOpenL(
     800           0 :                      CPLFormFilenameSafe("/vsicurl/", pszUrlTmp, nullptr)
     801             :                          .c_str(),
     802           0 :                      "r")) != nullptr ||
     803           0 :                 (fp = VSIFOpenL(pszUrlTmp, "r")) != nullptr)
     804             :             {
     805           0 :                 char szbuf[1025] = {};
     806           0 :                 std::string oStyle = "";
     807             : 
     808             :                 /***** loop, read and copy to a string *****/
     809           0 :                 do
     810             :                 {
     811             :                     const size_t nRead =
     812           0 :                         VSIFReadL(szbuf, 1, sizeof(szbuf) - 1, fp);
     813           0 :                     if (nRead == 0)
     814           0 :                         break;
     815             : 
     816             :                     /***** copy buf to the string *****/
     817           0 :                     szbuf[nRead] = '\0';
     818           0 :                     oStyle.append(szbuf);
     819           0 :                 } while (!VSIFEofL(fp) && !VSIFErrorL(fp));
     820             : 
     821           0 :                 VSIFCloseL(fp);
     822             : 
     823             :                 /***** parse the kml into the dom *****/
     824           0 :                 std::string oKmlErrors;
     825           0 :                 ElementPtr poKmlRoot = kmldom::Parse(oStyle, &oKmlErrors);
     826             : 
     827           0 :                 if (!poKmlRoot)
     828             :                 {
     829           0 :                     CPLError(CE_Warning, CPLE_OpenFailed,
     830             :                              "ERROR parsing style kml %s :%s", pszUrlTmp,
     831             :                              oKmlErrors.c_str());
     832           0 :                     CPLFree(pszUrlTmp);
     833           0 :                     CPLFree(pszUrl);
     834           0 :                     CPLFree(pszStyleMapId);
     835             : 
     836           0 :                     return nullptr;
     837             :                 }
     838             : 
     839             :                 /***** get the root container *****/
     840             :                 kmldom::KmlFactory *poKmlFactory =
     841           0 :                     kmldom::KmlFactory::GetFactory();
     842           0 :                 ContainerPtr poKmlContainer;
     843           0 :                 if (!(poKmlContainer = MyGetContainerFromRoot(
     844           0 :                           poKmlFactory, std::move(poKmlRoot))))
     845             :                 {
     846           0 :                     CPLFree(pszUrlTmp);
     847           0 :                     CPLFree(pszUrl);
     848           0 :                     CPLFree(pszStyleMapId);
     849             : 
     850           0 :                     return nullptr;
     851             :                 }
     852             : 
     853             :                 /**** parse the styles into the table *****/
     854           0 :                 ParseStyles(AsDocument(poKmlContainer), &poStyleTable);
     855             : 
     856             :                 /***** look for the style we need to map to in the table *****/
     857           0 :                 const char *pszTest = poStyleTable->Find(pszRemoteStyleName);
     858             : 
     859             :                 /***** if found copy it to the table as a new style *****/
     860           0 :                 if (pszTest)
     861           0 :                     poStyleTable->AddStyle(pszStyleMapId, pszTest);
     862             :             }
     863           0 :             CPLFree(pszUrlTmp);
     864             :         }
     865             :     }
     866             : 
     867             :     /***** FIXME Add support here for relative links inside KML. *****/
     868          15 :     CPLFree(pszUrl);
     869          15 :     CPLFree(pszStyleMapId);
     870             : 
     871          15 :     return nullptr;
     872             : }
     873             : 
     874          16 : StyleSelectorPtr StyleFromStyleMap(const StyleMapPtr &poKmlStyleMap,
     875             :                                    OGRStyleTable *poStyleTable)
     876             : {
     877             :     /***** check the config option to see if the    *****/
     878             :     /***** user wants normal or highlighted mapping *****/
     879             :     const char *pszStyleMapKey =
     880          16 :         CPLGetConfigOption("LIBKML_STYLEMAP_KEY", "normal");
     881          32 :     const int nStyleMapKey = EQUAL(pszStyleMapKey, "highlight")
     882          16 :                                  ? STYLESTATE_HIGHLIGHT
     883             :                                  : STYLESTATE_NORMAL;
     884             : 
     885             :     /*****  Loop through the stylemap pairs and look for the "normal" one *****/
     886          17 :     for (size_t i = 0; i < poKmlStyleMap->get_pair_array_size(); ++i)
     887             :     {
     888          17 :         PairPtr myPair = poKmlStyleMap->get_pair_array_at(i);
     889             : 
     890             :         /***** is it the right one of the pair? *****/
     891          17 :         if (myPair->get_key() == nStyleMapKey)
     892             :         {
     893          16 :             if (myPair->has_styleselector())
     894             :                 return StyleFromStyleSelector(myPair->get_styleselector(),
     895           1 :                                               poStyleTable);
     896          15 :             else if (myPair->has_styleurl())
     897             :                 return StyleFromStyleURL(poKmlStyleMap, myPair->get_styleurl(),
     898          15 :                                          poStyleTable);
     899             :         }
     900             :     }
     901             : 
     902           0 :     return nullptr;
     903             : }
     904             : 
     905             : /******************************************************************************
     906             :  Function to parse a style table out of a document.
     907             : ******************************************************************************/
     908             : 
     909         214 : void ParseStyles(DocumentPtr poKmlDocument, OGRStyleTable **poStyleTable)
     910             : {
     911             :     /***** if document is null just bail now *****/
     912         214 :     if (!poKmlDocument)
     913           2 :         return;
     914             : 
     915             :     /***** loop over the Styles *****/
     916         212 :     const size_t nKmlStyles = poKmlDocument->get_styleselector_array_size();
     917             : 
     918             :     /***** Lets first build the style table.    *****/
     919             :     /***** to begin this is just proper styles. *****/
     920         382 :     for (size_t iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++)
     921             :     {
     922             :         StyleSelectorPtr poKmlStyle =
     923         170 :             poKmlDocument->get_styleselector_array_at(iKmlStyle);
     924             : 
     925             :         /***** Everything that is not a style you skip *****/
     926         170 :         if (!poKmlStyle->IsA(kmldom::Type_Style))
     927          16 :             continue;
     928             : 
     929             :         /***** We need to check to see if this is the first style. if it *****/
     930             :         /***** is we will not have a style table and need to create one  *****/
     931             : 
     932         154 :         if (!*poStyleTable)
     933          28 :             *poStyleTable = new OGRStyleTable();
     934             : 
     935         154 :         kml2styletable(*poStyleTable, AsStyle(AsElement(poKmlStyle)));
     936             :     }
     937             : 
     938             :     /***** Now we have to loop back around and get the style maps. We    *****/
     939             :     /***** have to do this a second time since the stylemap might matter *****/
     940             :     /***** and we are just looping reference styles that are farther     *****/
     941             :     /***** down in the file. Order through the XML as it is parsed.      *****/
     942             : 
     943         382 :     for (size_t iKmlStyle = 0; iKmlStyle < nKmlStyles; iKmlStyle++)
     944             :     {
     945             :         StyleSelectorPtr poKmlStyle =
     946         170 :             poKmlDocument->get_styleselector_array_at(iKmlStyle);
     947             : 
     948             :         /***** Everything that is not a stylemap you skip *****/
     949         170 :         if (!poKmlStyle->IsA(kmldom::Type_StyleMap))
     950         154 :             continue;
     951             : 
     952             :         /***** We need to check to see if this is the first style. if it *****/
     953             :         /***** is we will not have a style table and need to create one  *****/
     954          16 :         if (!*poStyleTable)
     955           0 :             *poStyleTable = new OGRStyleTable();
     956             : 
     957             :         /***** copy the style the style map points to since *****/
     958             : 
     959          16 :         char *pszStyleMapId = CPLStrdup(poKmlStyle->get_id().c_str());
     960             :         poKmlStyle =
     961          16 :             StyleFromStyleMap(kmldom::AsStyleMap(poKmlStyle), *poStyleTable);
     962          16 :         if (!poKmlStyle)
     963             :         {
     964          15 :             CPLFree(pszStyleMapId);
     965          15 :             continue;
     966             :         }
     967           1 :         char *pszStyleId = CPLStrdup(poKmlStyle->get_id().c_str());
     968             : 
     969           1 :         kml2styletable(*poStyleTable, AsStyle(AsElement(poKmlStyle)));
     970             : 
     971             :         // Change the name of the new style in the style table
     972             : 
     973           1 :         const char *pszTest = (*poStyleTable)->Find(pszStyleId);
     974             :         // If we found the style we want in the style table we...
     975           1 :         if (pszTest)
     976             :         {
     977           1 :             (*poStyleTable)->AddStyle(pszStyleMapId, pszTest);
     978           1 :             (*poStyleTable)->RemoveStyle(pszStyleId);
     979             :         }
     980           1 :         CPLFree(pszStyleId);
     981           1 :         CPLFree(pszStyleMapId);
     982             :     }
     983             : }
     984             : 
     985             : /******************************************************************************
     986             :  Function to add a style table to a kml container.
     987             : ******************************************************************************/
     988             : 
     989           6 : void styletable2kml(OGRStyleTable *poOgrStyleTable, KmlFactory *poKmlFactory,
     990             :                     ContainerPtr poKmlContainer, char **papszOptions)
     991             : {
     992             :     /***** just return if the styletable is null *****/
     993           6 :     if (!poOgrStyleTable)
     994           2 :         return;
     995             : 
     996           8 :     std::set<CPLString> aoSetNormalStyles;
     997           8 :     std::set<CPLString> aoSetHighlightStyles;
     998           4 :     poOgrStyleTable->ResetStyleStringReading();
     999             : 
    1000             :     // Collect styles that end with _normal or _highlight.
    1001          14 :     while (poOgrStyleTable->GetNextStyle() != nullptr)
    1002             :     {
    1003          10 :         const char *pszStyleName = poOgrStyleTable->GetLastStyleName();
    1004             : 
    1005          10 :         if (strlen(pszStyleName) > strlen("_normal") &&
    1006           6 :             EQUAL(pszStyleName + strlen(pszStyleName) - strlen("_normal"),
    1007             :                   "_normal"))
    1008             :         {
    1009           4 :             CPLString osName(pszStyleName);
    1010           2 :             osName.resize(strlen(pszStyleName) - strlen("_normal"));
    1011           4 :             aoSetNormalStyles.insert(std::move(osName));
    1012             :         }
    1013           8 :         else if (strlen(pszStyleName) > strlen("_highlight") &&
    1014           4 :                  EQUAL(pszStyleName + strlen(pszStyleName) -
    1015             :                            strlen("_highlight"),
    1016             :                        "_highlight"))
    1017             :         {
    1018           4 :             CPLString osName(pszStyleName);
    1019           2 :             osName.resize(strlen(pszStyleName) - strlen("_highlight"));
    1020           2 :             aoSetHighlightStyles.insert(std::move(osName));
    1021             :         }
    1022             :     }
    1023             : 
    1024             :     /***** parse the style table *****/
    1025           4 :     poOgrStyleTable->ResetStyleStringReading();
    1026             : 
    1027           4 :     const char *pszStyleString = nullptr;
    1028          14 :     while ((pszStyleString = poOgrStyleTable->GetNextStyle()) != nullptr)
    1029             :     {
    1030          10 :         const char *pszStyleName = poOgrStyleTable->GetLastStyleName();
    1031             : 
    1032          20 :         if (aoSetNormalStyles.find(pszStyleName) != aoSetNormalStyles.end() &&
    1033          10 :             aoSetHighlightStyles.find(pszStyleName) !=
    1034          10 :                 aoSetHighlightStyles.end())
    1035             :         {
    1036           0 :             continue;
    1037             :         }
    1038             : 
    1039             :         /***** add the style header to the kml *****/
    1040          20 :         StylePtr poKmlStyle = poKmlFactory->CreateStyle();
    1041             : 
    1042          10 :         poKmlStyle->set_id(pszStyleName);
    1043             : 
    1044             :         /***** parse the style string *****/
    1045          10 :         addstylestring2kml(pszStyleString, poKmlStyle, poKmlFactory, nullptr);
    1046             : 
    1047             :         /***** add balloon style *****/
    1048          10 :         const char *pszBalloonStyleBgColor = CSLFetchNameValue(
    1049             :             papszOptions, CPLSPrintf("%s_balloonstyle_bgcolor", pszStyleName));
    1050          10 :         const char *pszBalloonStyleText = CSLFetchNameValue(
    1051             :             papszOptions, CPLSPrintf("%s_balloonstyle_text", pszStyleName));
    1052          10 :         int nR = 0;
    1053          10 :         int nG = 0;
    1054          10 :         int nB = 0;
    1055          10 :         int nA = 0;
    1056          20 :         OGRStylePen oStyleTool;
    1057          11 :         if ((pszBalloonStyleBgColor != nullptr &&
    1058           1 :              oStyleTool.GetRGBFromString(pszBalloonStyleBgColor, nR, nG, nB,
    1059          11 :                                          nA)) ||
    1060             :             pszBalloonStyleText != nullptr)
    1061             :         {
    1062             :             const BalloonStylePtr poKmlBalloonStyle =
    1063           2 :                 poKmlFactory->CreateBalloonStyle();
    1064           2 :             if (pszBalloonStyleBgColor != nullptr &&
    1065           1 :                 oStyleTool.GetRGBFromString(pszBalloonStyleBgColor, nR, nG, nB,
    1066             :                                             nA))
    1067           2 :                 poKmlBalloonStyle->set_bgcolor(
    1068           2 :                     Color32(static_cast<GByte>(nA), static_cast<GByte>(nB),
    1069             :                             static_cast<GByte>(nG), static_cast<GByte>(nR)));
    1070           1 :             if (pszBalloonStyleText != nullptr)
    1071           1 :                 poKmlBalloonStyle->set_text(pszBalloonStyleText);
    1072           1 :             poKmlStyle->set_balloonstyle(poKmlBalloonStyle);
    1073             :         }
    1074             : 
    1075             :         /***** add the style to the container *****/
    1076          10 :         const DocumentPtr poKmlDocument = AsDocument(poKmlContainer);
    1077          10 :         poKmlDocument->add_styleselector(poKmlStyle);
    1078             :     }
    1079             : 
    1080             :     // Find style name that end with _normal and _highlight to create
    1081             :     // a StyleMap from both.
    1082             :     std::set<CPLString>::iterator aoSetNormalStylesIter =
    1083           4 :         aoSetNormalStyles.begin();
    1084           6 :     for (; aoSetNormalStylesIter != aoSetNormalStyles.end();
    1085           2 :          ++aoSetNormalStylesIter)
    1086             :     {
    1087           4 :         CPLString osStyleName(*aoSetNormalStylesIter);
    1088           2 :         if (aoSetHighlightStyles.find(osStyleName) !=
    1089           4 :             aoSetHighlightStyles.end())
    1090             :         {
    1091           4 :             StyleMapPtr poKmlStyleMap = poKmlFactory->CreateStyleMap();
    1092           2 :             poKmlStyleMap->set_id(osStyleName);
    1093             : 
    1094           4 :             PairPtr poKmlPairNormal = poKmlFactory->CreatePair();
    1095           2 :             poKmlPairNormal->set_key(STYLESTATE_NORMAL);
    1096           2 :             poKmlPairNormal->set_styleurl(
    1097             :                 CPLSPrintf("#%s_normal", osStyleName.c_str()));
    1098           2 :             poKmlStyleMap->add_pair(poKmlPairNormal);
    1099             : 
    1100           4 :             PairPtr poKmlPairHighlight = poKmlFactory->CreatePair();
    1101           2 :             poKmlPairHighlight->set_key(STYLESTATE_HIGHLIGHT);
    1102           2 :             poKmlPairHighlight->set_styleurl(
    1103             :                 CPLSPrintf("#%s_highlight", osStyleName.c_str()));
    1104           2 :             poKmlStyleMap->add_pair(poKmlPairHighlight);
    1105             : 
    1106             :             /***** add the style to the container *****/
    1107           2 :             DocumentPtr poKmlDocument = AsDocument(poKmlContainer);
    1108           2 :             poKmlDocument->add_styleselector(poKmlStyleMap);
    1109             :         }
    1110             :     }
    1111             : }
    1112             : 
    1113             : /******************************************************************************
    1114             :  Function to add a ListStyle and select it to a container.
    1115             : ******************************************************************************/
    1116             : 
    1117         216 : void createkmlliststyle(KmlFactory *poKmlFactory, const char *pszBaseName,
    1118             :                         ContainerPtr poKmlLayerContainer,
    1119             :                         DocumentPtr poKmlDocument,
    1120             :                         const CPLString &osListStyleType,
    1121             :                         const CPLString &osListStyleIconHref)
    1122             : {
    1123         216 :     if (!osListStyleType.empty() || !osListStyleIconHref.empty())
    1124             :     {
    1125          16 :         StylePtr poKmlStyle = poKmlFactory->CreateStyle();
    1126             : 
    1127           8 :         const char *pszStyleName = CPLSPrintf(
    1128          16 :             "%s_liststyle", OGRLIBKMLGetSanitizedNCName(pszBaseName).c_str());
    1129           8 :         poKmlStyle->set_id(pszStyleName);
    1130             : 
    1131           8 :         ListStylePtr poKmlListStyle = poKmlFactory->CreateListStyle();
    1132           8 :         poKmlStyle->set_liststyle(poKmlListStyle);
    1133           8 :         if (!osListStyleType.empty())
    1134             :         {
    1135           5 :             if (EQUAL(osListStyleType, "check"))
    1136           1 :                 poKmlListStyle->set_listitemtype(kmldom::LISTITEMTYPE_CHECK);
    1137           4 :             else if (EQUAL(osListStyleType, "radioFolder"))
    1138           1 :                 poKmlListStyle->set_listitemtype(
    1139             :                     kmldom::LISTITEMTYPE_RADIOFOLDER);
    1140           3 :             else if (EQUAL(osListStyleType, "checkOffOnly"))
    1141           1 :                 poKmlListStyle->set_listitemtype(
    1142             :                     kmldom::LISTITEMTYPE_CHECKOFFONLY);
    1143           2 :             else if (EQUAL(osListStyleType, "checkHideChildren"))
    1144           1 :                 poKmlListStyle->set_listitemtype(
    1145             :                     kmldom::LISTITEMTYPE_CHECKHIDECHILDREN);
    1146             :             else
    1147             :             {
    1148           1 :                 CPLError(CE_Warning, CPLE_AppDefined,
    1149             :                          "Invalid value for list style type: %s. "
    1150             :                          "Defaulting to Check",
    1151             :                          osListStyleType.c_str());
    1152           1 :                 poKmlListStyle->set_listitemtype(kmldom::LISTITEMTYPE_CHECK);
    1153             :             }
    1154             :         }
    1155             : 
    1156           8 :         if (!osListStyleIconHref.empty())
    1157             :         {
    1158           6 :             ItemIconPtr poItemIcon = poKmlFactory->CreateItemIcon();
    1159           3 :             poItemIcon->set_href(osListStyleIconHref.c_str());
    1160           3 :             poKmlListStyle->add_itemicon(poItemIcon);
    1161             :         }
    1162             : 
    1163           8 :         poKmlDocument->add_styleselector(poKmlStyle);
    1164           8 :         poKmlLayerContainer->set_styleurl(CPLSPrintf("#%s", pszStyleName));
    1165             :     }
    1166         216 : }

Generated by: LCOV version 1.14