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

Generated by: LCOV version 1.14