LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/edigeo - ogredigeodatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 822 0.0 %
Date: 2025-09-10 17:48:50 Functions: 0 24 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  EDIGEO Translator
       4             :  * Purpose:  Implements OGREDIGEODataSource class
       5             :  * Author:   Even Rouault, even dot rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "ogr_edigeo.h"
      14             : #include "cpl_conv.h"
      15             : #include "cpl_string.h"
      16             : 
      17             : /************************************************************************/
      18             : /*                        OGREDIGEODataSource()                         */
      19             : /************************************************************************/
      20             : 
      21           0 : OGREDIGEODataSource::OGREDIGEODataSource()
      22             :     : fpTHF(nullptr), papoLayers(nullptr), nLayers(0), poSRS(nullptr),
      23             :       bExtentValid(FALSE), dfMinX(0), dfMinY(0), dfMaxX(0), dfMaxY(0),
      24             :       bRecodeToUTF8(
      25           0 :           CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_RECODE_TO_UTF8", "YES"))),
      26             :       bHasUTF8ContentOnly(TRUE), iATR(-1), iDI3(-1), iDI4(-1), iHEI(-1),
      27             :       iFON(-1), iATR_VAL(-1), iANGLE(-1), iSIZE(-1), iOBJ_LNK(-1),
      28             :       iOBJ_LNK_LAYER(-1),
      29             :       // coverity[tainted_data]
      30             :       dfSizeFactor(
      31           0 :           CPLAtof(CPLGetConfigOption("OGR_EDIGEO_FONT_SIZE_FACTOR", "2"))),
      32           0 :       bIncludeFontFamily(CPLTestBool(
      33           0 :           CPLGetConfigOption("OGR_EDIGEO_INCLUDE_FONT_FAMILY", "YES")))
      34             : {
      35           0 :     if (dfSizeFactor <= 0 || dfSizeFactor >= 100)
      36           0 :         dfSizeFactor = 2;
      37           0 : }
      38             : 
      39             : /************************************************************************/
      40             : /*                      ~OGREDIGEODataSource()                          */
      41             : /************************************************************************/
      42             : 
      43           0 : OGREDIGEODataSource::~OGREDIGEODataSource()
      44             : 
      45             : {
      46           0 :     for (int i = 0; i < nLayers; i++)
      47           0 :         delete papoLayers[i];
      48           0 :     CPLFree(papoLayers);
      49             : 
      50           0 :     if (fpTHF)
      51           0 :         VSIFCloseL(fpTHF);
      52             : 
      53           0 :     if (poSRS)
      54           0 :         poSRS->Release();
      55           0 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                              GetLayer()                              */
      59             : /************************************************************************/
      60             : 
      61           0 : const OGRLayer *OGREDIGEODataSource::GetLayer(int iLayer) const
      62             : 
      63             : {
      64           0 :     ReadEDIGEO();
      65           0 :     if (iLayer < 0 || iLayer >= nLayers)
      66           0 :         return nullptr;
      67             :     else
      68           0 :         return papoLayers[iLayer];
      69             : }
      70             : 
      71             : /************************************************************************/
      72             : /*                         GetLayerCount()                              */
      73             : /************************************************************************/
      74             : 
      75           0 : int OGREDIGEODataSource::GetLayerCount() const
      76             : {
      77           0 :     ReadEDIGEO();
      78           0 :     return nLayers;
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                              ReadTHF()                               */
      83             : /************************************************************************/
      84             : 
      85           0 : int OGREDIGEODataSource::ReadTHF(VSILFILE *fp) const
      86             : {
      87           0 :     const char *pszLine = nullptr;
      88           0 :     while ((pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr)
      89             :     {
      90           0 :         if (strlen(pszLine) < 8 || pszLine[7] != ':')
      91           0 :             continue;
      92             : 
      93             :         /* Cf Z 52000 tableau 56 for field list*/
      94             : 
      95           0 :         if (STARTS_WITH(pszLine, "LONSA"))
      96             :         {
      97           0 :             if (!osLON.empty())
      98             :             {
      99           0 :                 CPLDebug("EDIGEO", "We only handle one lot per THF file");
     100           0 :                 break;
     101             :             }
     102           0 :             osLON = pszLine + 8;
     103             :         }
     104           0 :         else if (STARTS_WITH(pszLine, "GNNSA"))
     105           0 :             osGNN = pszLine + 8;
     106           0 :         else if (STARTS_WITH(pszLine, "GONSA"))
     107           0 :             osGON = pszLine + 8;
     108           0 :         else if (STARTS_WITH(pszLine, "QANSA"))
     109           0 :             osQAN = pszLine + 8;
     110           0 :         else if (STARTS_WITH(pszLine, "DINSA"))
     111           0 :             osDIN = pszLine + 8;
     112           0 :         else if (STARTS_WITH(pszLine, "SCNSA"))
     113           0 :             osSCN = pszLine + 8;
     114           0 :         else if (STARTS_WITH(pszLine, "GDNSA"))
     115           0 :             aosGDN.push_back(pszLine + 8);
     116             :     }
     117           0 :     if (osLON.empty())
     118             :     {
     119           0 :         CPLDebug("EDIGEO", "LON field missing");
     120           0 :         return 0;
     121             :     }
     122           0 :     if (osGON.empty())
     123             :     {
     124           0 :         CPLDebug("EDIGEO", "GON field missing");
     125           0 :         return 0;
     126             :     }
     127           0 :     if (osDIN.empty())
     128             :     {
     129           0 :         CPLDebug("EDIGEO", "DIN field missing");
     130           0 :         return 0;
     131             :     }
     132           0 :     if (osSCN.empty())
     133             :     {
     134           0 :         CPLDebug("EDIGEO", "SCN field missing");
     135           0 :         return FALSE;
     136             :     }
     137             : 
     138           0 :     CPLDebug("EDIGEO", "LON = %s", osLON.c_str());
     139           0 :     CPLDebug("EDIGEO", "GNN = %s", osGNN.c_str());
     140           0 :     CPLDebug("EDIGEO", "GON = %s", osGON.c_str());
     141           0 :     CPLDebug("EDIGEO", "QAN = %s", osQAN.c_str());
     142           0 :     CPLDebug("EDIGEO", "DIN = %s", osDIN.c_str());
     143           0 :     CPLDebug("EDIGEO", "SCN = %s", osSCN.c_str());
     144           0 :     for (int i = 0; i < (int)aosGDN.size(); i++)
     145           0 :         CPLDebug("EDIGEO", "GDN[%d] = %s", i, aosGDN[i].c_str());
     146             : 
     147           0 :     return TRUE;
     148             : }
     149             : 
     150             : /************************************************************************/
     151             : /*                             OpenFile()                               */
     152             : /************************************************************************/
     153             : 
     154           0 : VSILFILE *OGREDIGEODataSource::OpenFile(const char *pszType,
     155             :                                         const CPLString &osExt) const
     156             : {
     157           0 :     CPLString osTmp = osLON + pszType;
     158           0 :     CPLString osFilename = CPLFormCIFilenameSafe(
     159           0 :         CPLGetPathSafe(GetDescription()).c_str(), osTmp.c_str(), osExt.c_str());
     160           0 :     VSILFILE *fp = VSIFOpenL(osFilename, "rb");
     161           0 :     if (fp == nullptr)
     162             :     {
     163           0 :         const CPLString osExtLower = CPLString(osExt).tolower();
     164             :         const CPLString osFilename2 =
     165           0 :             CPLFormCIFilenameSafe(CPLGetPathSafe(GetDescription()).c_str(),
     166           0 :                                   osTmp.c_str(), osExtLower.c_str());
     167           0 :         fp = VSIFOpenL(osFilename2, "rb");
     168           0 :         if (fp == nullptr)
     169             :         {
     170           0 :             CPLDebug("EDIGEO", "Cannot open %s", osFilename.c_str());
     171             :         }
     172             :     }
     173           0 :     return fp;
     174             : }
     175             : 
     176             : /************************************************************************/
     177             : /*                              ReadGEO()                               */
     178             : /************************************************************************/
     179             : 
     180           0 : int OGREDIGEODataSource::ReadGEO() const
     181             : {
     182           0 :     VSILFILE *fp = OpenFile(osGON, "GEO");
     183           0 :     if (fp == nullptr)
     184           0 :         return FALSE;
     185             : 
     186           0 :     const char *pszLine = nullptr;
     187           0 :     while ((pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr)
     188             :     {
     189           0 :         if (strlen(pszLine) < 8 || pszLine[7] != ':')
     190           0 :             continue;
     191             : 
     192           0 :         if (STARTS_WITH(pszLine, "RELSA"))
     193             :         {
     194           0 :             osREL = pszLine + 8;
     195           0 :             CPLDebug("EDIGEO", "REL = %s", osREL.c_str());
     196           0 :             break;
     197             :         }
     198             :     }
     199             : 
     200           0 :     VSIFCloseL(fp);
     201             : 
     202           0 :     if (osREL.empty())
     203             :     {
     204           0 :         CPLDebug("EDIGEO", "REL field missing");
     205           0 :         return FALSE;
     206             :     }
     207             : 
     208             :     /* All the SRS names mentioned in B.8.2.3 and B.8.3.1 are in the IGN file */
     209           0 :     poSRS = new OGRSpatialReference();
     210           0 :     poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     211           0 :     CPLString osProj4Str = "+init=IGNF:" + osREL;
     212           0 :     if (poSRS->SetFromUserInput(osProj4Str.c_str()) != OGRERR_NONE)
     213             :     {
     214             :         /* Hard code a few common cases */
     215           0 :         if (osREL == "LAMB1")
     216           0 :             poSRS->importFromProj4(
     217             :                 "+proj=lcc +lat_1=49.5 +lat_0=49.5 +lon_0=0 +k_0=0.99987734 "
     218             :                 "+x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 "
     219             :                 "+nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
     220           0 :         else if (osREL == "LAMB2")
     221           0 :             poSRS->importFromProj4(
     222             :                 "+proj=lcc +lat_1=46.8 +lat_0=46.8 +lon_0=0 +k_0=0.99987742 "
     223             :                 "+x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 "
     224             :                 "+nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
     225           0 :         else if (osREL == "LAMB3")
     226           0 :             poSRS->importFromProj4(
     227             :                 "+proj=lcc +lat_1=44.1 +lat_0=44.1 +lon_0=0 +k_0=0.9998775 "
     228             :                 "+x_0=600000 +y_0=200000 +a=6378249.2 +b=6356514.999978254 "
     229             :                 "+nadgrids=ntf_r93.gsb,null +pm=paris +units=m +no_defs");
     230           0 :         else if (osREL == "LAMB4")
     231           0 :             poSRS->importFromProj4(
     232             :                 "+proj=lcc +lat_1=42.165 +lat_0=42.165 +lon_0=0 "
     233             :                 "+k_0=0.99994471 +x_0=234.358 +y_0=185861.369 +a=6378249.2 "
     234             :                 "+b=6356514.999978254 +nadgrids=ntf_r93.gsb,null +pm=paris "
     235             :                 "+units=m +no_defs");
     236           0 :         else if (osREL == "LAMB93")
     237           0 :             poSRS->importFromProj4(
     238             :                 "+proj=lcc +lat_1=44 +lat_2=49 +lat_0=46.5 +lon_0=3 "
     239             :                 "+x_0=700000 +y_0=6600000 +ellps=GRS81 +towgs84=0,0,0,0,0,0,0 "
     240             :                 "+units=m +no_defs");
     241             :         else
     242             :         {
     243           0 :             CPLDebug("EDIGEO",
     244             :                      "Cannot resolve %s SRS. Check that the IGNF file is in "
     245             :                      "the directory of PROJ.4 resource files",
     246             :                      osREL.c_str());
     247           0 :             delete poSRS;
     248           0 :             poSRS = nullptr;
     249             :         }
     250             :     }
     251             : 
     252           0 :     return TRUE;
     253             : }
     254             : 
     255             : /************************************************************************/
     256             : /*                              ReadGEN()                               */
     257             : /************************************************************************/
     258             : 
     259           0 : int OGREDIGEODataSource::ReadGEN() const
     260             : {
     261           0 :     VSILFILE *fp = OpenFile(osGNN, "GEN");
     262           0 :     if (fp == nullptr)
     263           0 :         return FALSE;
     264             : 
     265           0 :     const char *pszLine = nullptr;
     266           0 :     CPLString osCM1;
     267           0 :     CPLString osCM2;
     268           0 :     while ((pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr)
     269             :     {
     270           0 :         if (strlen(pszLine) < 8 || pszLine[7] != ':')
     271           0 :             continue;
     272             : 
     273           0 :         if (STARTS_WITH(pszLine, "CM1CC"))
     274             :         {
     275           0 :             osCM1 = pszLine + 8;
     276             :         }
     277           0 :         else if (STARTS_WITH(pszLine, "CM2CC"))
     278             :         {
     279           0 :             osCM2 = pszLine + 8;
     280             :         }
     281             :     }
     282             : 
     283           0 :     VSIFCloseL(fp);
     284             : 
     285           0 :     if (osCM1.empty() || osCM2.empty())
     286           0 :         return FALSE;
     287             : 
     288           0 :     char **papszTokens1 = CSLTokenizeString2(osCM1.c_str(), ";", 0);
     289           0 :     char **papszTokens2 = CSLTokenizeString2(osCM2.c_str(), ";", 0);
     290           0 :     if (CSLCount(papszTokens1) == 2 && CSLCount(papszTokens2) == 2)
     291             :     {
     292           0 :         bExtentValid = TRUE;
     293           0 :         dfMinX = CPLAtof(papszTokens1[0]);
     294           0 :         dfMinY = CPLAtof(papszTokens1[1]);
     295           0 :         dfMaxX = CPLAtof(papszTokens2[0]);
     296           0 :         dfMaxY = CPLAtof(papszTokens2[1]);
     297             :     }
     298           0 :     CSLDestroy(papszTokens1);
     299           0 :     CSLDestroy(papszTokens2);
     300             : 
     301           0 :     return bExtentValid;
     302             : }
     303             : 
     304             : /************************************************************************/
     305             : /*                              ReadDIC()                               */
     306             : /************************************************************************/
     307             : 
     308           0 : int OGREDIGEODataSource::ReadDIC() const
     309             : {
     310           0 :     VSILFILE *fp = OpenFile(osDIN, "DIC");
     311           0 :     if (fp == nullptr)
     312           0 :         return FALSE;
     313             : 
     314           0 :     const char *pszLine = nullptr;
     315           0 :     CPLString osRTY;
     316           0 :     CPLString osRID;
     317           0 :     CPLString osLAB;
     318           0 :     CPLString osTYP;
     319             :     while (true)
     320             :     {
     321           0 :         pszLine = CPLReadLine2L(fp, 81, nullptr);
     322           0 :         if (pszLine != nullptr)
     323             :         {
     324           0 :             if (strlen(pszLine) < 8 || pszLine[7] != ':')
     325           0 :                 continue;
     326             :         }
     327             : 
     328           0 :         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
     329             :         {
     330           0 :             if (osRTY == "DID")
     331             :             {
     332             :                 // CPLDebug("EDIGEO", "Object %s = %s",
     333             :                 //          osRID.c_str(), osLAB.c_str());
     334           0 :                 mapObjects[osRID] = osLAB;
     335             :             }
     336           0 :             else if (osRTY == "DIA")
     337             :             {
     338             :                 // CPLDebug("EDIGEO", "Attribute %s = %s, %s",
     339             :                 //          osRID.c_str(), osLAB.c_str(), osTYP.c_str());
     340           0 :                 OGREDIGEOAttributeDef sAttributeDef;
     341           0 :                 sAttributeDef.osLAB = osLAB;
     342           0 :                 sAttributeDef.osTYP = osTYP;
     343           0 :                 mapAttributes[osRID] = std::move(sAttributeDef);
     344             :             }
     345             :         }
     346             : 
     347           0 :         if (pszLine == nullptr)
     348           0 :             break;
     349             : 
     350           0 :         if (STARTS_WITH(pszLine, "RTYSA"))
     351             :         {
     352           0 :             osRTY = pszLine + 8;
     353           0 :             osRID = "";
     354           0 :             osLAB = "";
     355           0 :             osTYP = "";
     356             :         }
     357           0 :         else if (STARTS_WITH(pszLine, "RIDSA"))
     358           0 :             osRID = pszLine + 8;
     359           0 :         else if (STARTS_WITH(pszLine, "LABSA"))
     360           0 :             osLAB = pszLine + 8;
     361           0 :         else if (STARTS_WITH(pszLine, "TYPSA"))
     362           0 :             osTYP = pszLine + 8;
     363           0 :     }
     364             : 
     365           0 :     VSIFCloseL(fp);
     366             : 
     367           0 :     return TRUE;
     368             : }
     369             : 
     370             : /************************************************************************/
     371             : /*                              ReadSCD()                               */
     372             : /************************************************************************/
     373             : 
     374           0 : int OGREDIGEODataSource::ReadSCD() const
     375             : {
     376           0 :     VSILFILE *fp = OpenFile(osSCN, "SCD");
     377           0 :     if (fp == nullptr)
     378           0 :         return FALSE;
     379             : 
     380           0 :     const char *pszLine = nullptr;
     381           0 :     CPLString osRTY, osRID, osNameRID, osKND;
     382           0 :     strListType aosAttrRID;
     383           0 :     int nWidth = 0;
     384             :     while (true)
     385             :     {
     386           0 :         pszLine = CPLReadLine2L(fp, 81, nullptr);
     387           0 :         if (pszLine != nullptr)
     388             :         {
     389           0 :             if (strlen(pszLine) < 8 || pszLine[7] != ':')
     390           0 :                 continue;
     391             :         }
     392             : 
     393           0 :         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
     394             :         {
     395           0 :             if (osRTY == "OBJ")
     396             :             {
     397           0 :                 if (mapObjects.find(osNameRID) == mapObjects.end())
     398             :                 {
     399           0 :                     CPLDebug("EDIGEO", "Cannot find object %s",
     400             :                              osNameRID.c_str());
     401             :                 }
     402             :                 else
     403             :                 {
     404           0 :                     OGREDIGEOObjectDescriptor objDesc;
     405           0 :                     objDesc.osRID = osRID;
     406           0 :                     objDesc.osNameRID = osNameRID;
     407           0 :                     objDesc.osKND = osKND;
     408           0 :                     objDesc.aosAttrRID = aosAttrRID;
     409             :                     /*CPLDebug("EDIGEO", "Object %s = %s, %s, %d attributes",
     410             :                             osRID.c_str(), osNameRID.c_str(), osKND.c_str(),
     411             :                             (int)aosAttrRID.size());*/
     412             : 
     413           0 :                     aoObjList.push_back(std::move(objDesc));
     414             :                 }
     415             :             }
     416           0 :             else if (osRTY == "ATT")
     417             :             {
     418           0 :                 if (mapAttributes.find(osNameRID) == mapAttributes.end())
     419             :                 {
     420           0 :                     CPLDebug("EDIGEO", "Cannot find attribute %s",
     421             :                              osNameRID.c_str());
     422             :                 }
     423             :                 else
     424             :                 {
     425           0 :                     OGREDIGEOAttributeDescriptor attDesc;
     426           0 :                     attDesc.osRID = osRID;
     427           0 :                     attDesc.osNameRID = osNameRID;
     428           0 :                     attDesc.nWidth = nWidth;
     429             :                     /*CPLDebug("EDIGEO", "Attribute %s = %s, %d",
     430             :                             osRID.c_str(), osNameRID.c_str(), nWidth);*/
     431             : 
     432           0 :                     mapAttributesSCD[osRID] = std::move(attDesc);
     433             :                 }
     434             :             }
     435             :         }
     436             : 
     437           0 :         if (pszLine == nullptr)
     438           0 :             break;
     439           0 :         if (STARTS_WITH(pszLine, "RTYSA"))
     440             :         {
     441           0 :             osRTY = pszLine + 8;
     442           0 :             osRID = "";
     443           0 :             osNameRID = "";
     444           0 :             osKND = "";
     445           0 :             aosAttrRID.resize(0);
     446           0 :             nWidth = 0;
     447             :         }
     448           0 :         else if (STARTS_WITH(pszLine, "RIDSA"))
     449           0 :             osRID = pszLine + 8;
     450           0 :         else if (STARTS_WITH(pszLine, "DIPCP"))
     451             :         {
     452           0 :             const char *pszDIP = pszLine + 8;
     453           0 :             char **papszTokens = CSLTokenizeString2(pszDIP, ";", 0);
     454           0 :             if (CSLCount(papszTokens) == 4)
     455             :             {
     456           0 :                 osNameRID = papszTokens[3];
     457             :             }
     458           0 :             CSLDestroy(papszTokens);
     459             :         }
     460           0 :         else if (STARTS_WITH(pszLine, "KNDSA"))
     461           0 :             osKND = pszLine + 8;
     462           0 :         else if (STARTS_WITH(pszLine, "AAPCP"))
     463             :         {
     464           0 :             const char *pszAAP = pszLine + 8;
     465           0 :             char **papszTokens = CSLTokenizeString2(pszAAP, ";", 0);
     466           0 :             if (CSLCount(papszTokens) == 4)
     467             :             {
     468           0 :                 const char *pszAttRID = papszTokens[3];
     469           0 :                 aosAttrRID.push_back(pszAttRID);
     470             :             }
     471           0 :             CSLDestroy(papszTokens);
     472             :         }
     473           0 :         else if (STARTS_WITH(pszLine, "CANSN"))
     474           0 :             nWidth = atoi(pszLine + 8);
     475           0 :     }
     476             : 
     477           0 :     VSIFCloseL(fp);
     478             : 
     479           0 :     return TRUE;
     480             : }
     481             : 
     482             : /************************************************************************/
     483             : /*                              ReadQAL()                               */
     484             : /************************************************************************/
     485             : 
     486           0 : int OGREDIGEODataSource::ReadQAL() const
     487             : {
     488           0 :     VSILFILE *fp = OpenFile(osQAN, "QAL");
     489           0 :     if (fp == nullptr)
     490           0 :         return FALSE;
     491             : 
     492           0 :     const char *pszLine = nullptr;
     493           0 :     CPLString osRTY;
     494           0 :     CPLString osRID;
     495           0 :     int nODA = 0;
     496           0 :     int nUDA = 0;
     497             :     while (true)
     498             :     {
     499           0 :         pszLine = CPLReadLine2L(fp, 81, nullptr);
     500           0 :         if (pszLine != nullptr)
     501             :         {
     502           0 :             if (strlen(pszLine) < 8 || pszLine[7] != ':')
     503           0 :                 continue;
     504             :         }
     505             : 
     506           0 :         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
     507             :         {
     508           0 :             if (osRTY == "QUP")
     509             :             {
     510           0 :                 mapQAL[osRID] = intintType(nODA, nUDA);
     511             :             }
     512           0 :             if (pszLine == nullptr)
     513           0 :                 break;
     514           0 :             osRTY = pszLine + 8;
     515           0 :             osRID = "";
     516           0 :             nODA = 0;
     517           0 :             nUDA = 0;
     518             :         }
     519           0 :         else if (STARTS_WITH(pszLine, "RIDSA"))
     520           0 :             osRID = pszLine + 8;
     521           0 :         else if (STARTS_WITH(pszLine, "ODASD"))
     522           0 :             nODA = atoi(pszLine + 8);
     523           0 :         else if (STARTS_WITH(pszLine, "UDASD"))
     524           0 :             nUDA = atoi(pszLine + 8);
     525             :     }
     526             : 
     527           0 :     VSIFCloseL(fp);
     528             : 
     529           0 :     return TRUE;
     530             : }
     531             : 
     532             : /************************************************************************/
     533             : /*                       CreateLayerFromObjectDesc()                    */
     534             : /************************************************************************/
     535             : 
     536           0 : int OGREDIGEODataSource::CreateLayerFromObjectDesc(
     537             :     const OGREDIGEOObjectDescriptor &objDesc) const
     538             : {
     539           0 :     OGRwkbGeometryType eType = wkbUnknown;
     540           0 :     if (objDesc.osKND == "ARE")
     541           0 :         eType = wkbPolygon;
     542           0 :     else if (objDesc.osKND == "LIN")
     543           0 :         eType = wkbLineString;
     544           0 :     else if (objDesc.osKND == "PCT")
     545           0 :         eType = wkbPoint;
     546             :     else
     547             :     {
     548           0 :         CPLDebug("EDIGEO", "Unknown KND : %s", objDesc.osKND.c_str());
     549           0 :         return FALSE;
     550             :     }
     551             : 
     552           0 :     const char *pszLayerName = objDesc.osRID.c_str();
     553             :     // mapObjects.find(objDesc.osNameRID)->second.c_str();
     554             :     OGREDIGEOLayer *poLayer = new OGREDIGEOLayer(
     555           0 :         const_cast<OGREDIGEODataSource *>(this), pszLayerName, eType, poSRS);
     556             : 
     557           0 :     poLayer->AddFieldDefn("OBJECT_RID", OFTString, "");
     558             : 
     559           0 :     for (int j = 0; j < (int)objDesc.aosAttrRID.size(); j++)
     560             :     {
     561             :         std::map<CPLString, OGREDIGEOAttributeDescriptor>::iterator it =
     562           0 :             mapAttributesSCD.find(objDesc.aosAttrRID[j]);
     563           0 :         if (it != mapAttributesSCD.end())
     564             :         {
     565           0 :             const OGREDIGEOAttributeDescriptor &attrDesc = it->second;
     566             :             const OGREDIGEOAttributeDef &attrDef =
     567           0 :                 mapAttributes[attrDesc.osNameRID];
     568           0 :             OGRFieldType eFieldType = OFTString;
     569           0 :             if (attrDef.osTYP == "R" || attrDef.osTYP == "E")
     570           0 :                 eFieldType = OFTReal;
     571           0 :             else if (attrDef.osTYP == "I" || attrDef.osTYP == "N")
     572           0 :                 eFieldType = OFTInteger;
     573             : 
     574           0 :             poLayer->AddFieldDefn(attrDef.osLAB, eFieldType,
     575           0 :                                   objDesc.aosAttrRID[j]);
     576             :         }
     577             :     }
     578             : 
     579           0 :     if (strcmp(poLayer->GetName(), "ID_S_OBJ_Z_1_2_2") == 0)
     580             :     {
     581           0 :         OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
     582             : 
     583           0 :         iATR = poFDefn->GetFieldIndex("ATR");
     584           0 :         iDI3 = poFDefn->GetFieldIndex("DI3");
     585           0 :         iDI4 = poFDefn->GetFieldIndex("DI4");
     586           0 :         iHEI = poFDefn->GetFieldIndex("HEI");
     587           0 :         iFON = poFDefn->GetFieldIndex("FON");
     588             : 
     589           0 :         poLayer->AddFieldDefn("OGR_OBJ_LNK", OFTString, "");
     590           0 :         iOBJ_LNK = poFDefn->GetFieldIndex("OGR_OBJ_LNK");
     591             : 
     592           0 :         poLayer->AddFieldDefn("OGR_OBJ_LNK_LAYER", OFTString, "");
     593           0 :         iOBJ_LNK_LAYER = poFDefn->GetFieldIndex("OGR_OBJ_LNK_LAYER");
     594             : 
     595           0 :         poLayer->AddFieldDefn("OGR_ATR_VAL", OFTString, "");
     596           0 :         iATR_VAL = poFDefn->GetFieldIndex("OGR_ATR_VAL");
     597             : 
     598           0 :         poLayer->AddFieldDefn("OGR_ANGLE", OFTReal, "");
     599           0 :         iANGLE = poFDefn->GetFieldIndex("OGR_ANGLE");
     600             : 
     601           0 :         poLayer->AddFieldDefn("OGR_FONT_SIZE", OFTReal, "");
     602           0 :         iSIZE = poFDefn->GetFieldIndex("OGR_FONT_SIZE");
     603             :     }
     604           0 :     else if (!mapQAL.empty())
     605             :     {
     606           0 :         poLayer->AddFieldDefn("CREAT_DATE", OFTInteger, "");
     607           0 :         poLayer->AddFieldDefn("UPDATE_DATE", OFTInteger, "");
     608             :     }
     609             : 
     610           0 :     mapLayer[objDesc.osRID] = poLayer;
     611             : 
     612           0 :     papoLayers =
     613           0 :         (OGRLayer **)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer *));
     614           0 :     papoLayers[nLayers] = poLayer;
     615           0 :     nLayers++;
     616             : 
     617           0 :     return TRUE;
     618             : }
     619             : 
     620             : /************************************************************************/
     621             : /*                              ReadVEC()                               */
     622             : /************************************************************************/
     623             : 
     624           0 : int OGREDIGEODataSource::ReadVEC(const char *pszVECName) const
     625             : {
     626           0 :     VSILFILE *fp = OpenFile(pszVECName, "VEC");
     627           0 :     if (fp == nullptr)
     628           0 :         return FALSE;
     629             : 
     630           0 :     const char *pszLine = nullptr;
     631           0 :     CPLString osRTY, osRID;
     632           0 :     xyPairListType aXY;
     633           0 :     CPLString osLnkStartType, osLnkStartName, osLnkEndType, osLnkEndName;
     634           0 :     strListType osLnkEndNameList;
     635           0 :     CPLString osAttId;
     636           0 :     std::vector<strstrType> aosAttIdVal;
     637           0 :     CPLString osSCP;
     638           0 :     CPLString osQUP_RID;
     639           0 :     int bIso8859_1 = FALSE;
     640             : 
     641             :     while (true)
     642             :     {
     643           0 :         pszLine = CPLReadLine2L(fp, 81, nullptr);
     644           0 :     skip_read_next_line:
     645           0 :         if (pszLine != nullptr)
     646             :         {
     647           0 :             if (strlen(pszLine) < 8 || pszLine[7] != ':')
     648           0 :                 continue;
     649             :         }
     650             : 
     651           0 :         if (pszLine == nullptr || STARTS_WITH(pszLine, "RTYSA"))
     652             :         {
     653           0 :             if (osRTY == "PAR")
     654             :             {
     655           0 :                 if (aXY.size() < 2)
     656           0 :                     CPLDebug("EDIGEO", "Error: ARC %s has not enough points",
     657             :                              osRID.c_str());
     658             :                 else
     659           0 :                     mapPAR[osRID] = aXY;
     660             :             }
     661           0 :             else if (osRTY == "LNK")
     662             :             {
     663           0 :                 if (osLnkStartType == "PAR" && osLnkEndType == "PFE")
     664             :                 {
     665             :                     /*CPLDebug("EDIGEO", "PFE[%s] -> PAR[%s]",
     666             :                              osLnkEndName.c_str(), osLnkStartName.c_str());*/
     667           0 :                     if (mapPFE_PAR.find(osLnkEndName) == mapPFE_PAR.end())
     668           0 :                         mapPFE_PAR[osLnkEndName].push_back(osLnkStartName);
     669             :                     else
     670             :                     {
     671           0 :                         int bAlreadyExists = FALSE;
     672           0 :                         strListType &osPARList = mapPFE_PAR[osLnkEndName];
     673           0 :                         for (int j = 0; j < (int)osPARList.size(); j++)
     674             :                         {
     675           0 :                             if (osPARList[j] == osLnkStartName)
     676           0 :                                 bAlreadyExists = TRUE;
     677             :                         }
     678           0 :                         if (!bAlreadyExists)
     679           0 :                             osPARList.push_back(osLnkStartName);
     680             :                     }
     681             :                 }
     682           0 :                 else if (osLnkStartType == "FEA" && osLnkEndType == "PFE")
     683             :                 {
     684             :                     /*CPLDebug("EDIGEO", "FEA[%s] -> PFE[%s]",
     685             :                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
     686           0 :                     listFEA_PFE.push_back(
     687           0 :                         std::pair(osLnkStartName, osLnkEndNameList));
     688             :                 }
     689           0 :                 else if (osLnkStartType == "FEA" && osLnkEndType == "PAR")
     690             :                 {
     691             :                     /*CPLDebug("EDIGEO", "FEA[%s] -> PAR[%s]",
     692             :                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
     693           0 :                     listFEA_PAR.push_back(
     694           0 :                         std::pair(osLnkStartName, osLnkEndNameList));
     695             :                 }
     696           0 :                 else if (osLnkStartType == "FEA" && osLnkEndType == "PNO")
     697             :                 {
     698             :                     /*CPLDebug("EDIGEO", "FEA[%s] -> PNO[%s]",
     699             :                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
     700           0 :                     listFEA_PNO.push_back(
     701           0 :                         strstrType(osLnkStartName, osLnkEndName));
     702             :                 }
     703           0 :                 else if (osLnkStartType == "FEA" && osLnkEndType == "FEA")
     704             :                 {
     705             :                     /*CPLDebug("EDIGEO", "FEA[%s] -> FEA[%s]",
     706             :                              osLnkStartName.c_str(), osLnkEndName.c_str());*/
     707           0 :                     if (osSCP == "IS_S_REL_IWW")
     708           0 :                         mapFEA_FEA[osLnkStartName] = osLnkEndName;
     709             :                 }
     710           0 :                 else if (osLnkStartType == "PAR" && osLnkEndType == "PNO")
     711             :                 {
     712             :                 }
     713             :                 else
     714             :                 {
     715           0 :                     CPLDebug("EDIGEO", "Unhandled LNK(%s) %s=%s --> %s=%s",
     716             :                              osRID.c_str(), osLnkStartType.c_str(),
     717             :                              osLnkStartName.c_str(), osLnkEndType.c_str(),
     718             :                              osLnkEndName.c_str());
     719             :                 }
     720             :             }
     721           0 :             else if (osRTY == "FEA")
     722             :             {
     723           0 :                 OGREDIGEOFEADesc feaDesc;
     724           0 :                 feaDesc.aosAttIdVal = aosAttIdVal;
     725           0 :                 feaDesc.osSCP = osSCP;
     726           0 :                 feaDesc.osQUP_RID = osQUP_RID;
     727           0 :                 mapFEA[osRID] = std::move(feaDesc);
     728             :             }
     729           0 :             else if (osRTY == "PNO")
     730             :             {
     731           0 :                 if (aXY.size() == 1)
     732             :                 {
     733             :                     /*CPLDebug("EDIGEO", "PNO[%s] = %f, %f",
     734             :                              osRID.c_str(), aXY[0].first, aXY[0].second);*/
     735           0 :                     mapPNO[osRID] = aXY[0];
     736             :                 }
     737             :             }
     738           0 :             if (pszLine == nullptr)
     739           0 :                 break;
     740           0 :             osRTY = pszLine + 8;
     741           0 :             osRID = "";
     742           0 :             aXY.resize(0);
     743           0 :             osLnkStartType = "";
     744           0 :             osLnkStartName = "";
     745           0 :             osLnkEndType = "";
     746           0 :             osLnkEndName = "";
     747           0 :             osAttId = "";
     748           0 :             aosAttIdVal.resize(0);
     749           0 :             osLnkEndNameList.resize(0);
     750           0 :             osSCP = "";
     751           0 :             osQUP_RID = "";
     752           0 :             bIso8859_1 = FALSE;
     753             :         }
     754           0 :         else if (STARTS_WITH(pszLine, "RIDSA"))
     755           0 :             osRID = pszLine + 8;
     756           0 :         else if (STARTS_WITH(pszLine, "CORCC"))
     757             :         {
     758           0 :             const char *pszY = strchr(pszLine + 8, ';');
     759           0 :             if (pszY)
     760             :             {
     761           0 :                 double dfX = CPLAtof(pszLine + 8);
     762           0 :                 double dfY = CPLAtof(pszY + 1);
     763           0 :                 aXY.push_back(xyPairType(dfX, dfY));
     764             :             }
     765             :         }
     766           0 :         else if (STARTS_WITH(pszLine, "FTPCP"))
     767             :         {
     768           0 :             char **papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
     769           0 :             if (CSLCount(papszTokens) == 4)
     770             :             {
     771           0 :                 if (osLnkStartType.empty())
     772             :                 {
     773           0 :                     osLnkStartType = papszTokens[2];
     774           0 :                     osLnkStartName = papszTokens[3];
     775             :                 }
     776             :                 else
     777             :                 {
     778           0 :                     osLnkEndType = papszTokens[2];
     779           0 :                     osLnkEndName = papszTokens[3];
     780           0 :                     osLnkEndNameList.push_back(osLnkEndName);
     781             :                 }
     782             :             }
     783           0 :             CSLDestroy(papszTokens);
     784             :         }
     785           0 :         else if (STARTS_WITH(pszLine, "SCPCP"))
     786             :         {
     787           0 :             char **papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
     788           0 :             if (CSLCount(papszTokens) == 4)
     789             :             {
     790           0 :                 if (osRTY == "LNK")
     791             :                 {
     792           0 :                     if (strcmp(papszTokens[2], "ASS") == 0)
     793           0 :                         osSCP = papszTokens[3];
     794             :                 }
     795           0 :                 else if (strcmp(papszTokens[2], "OBJ") == 0)
     796           0 :                     osSCP = papszTokens[3];
     797             :             }
     798           0 :             CSLDestroy(papszTokens);
     799             :         }
     800           0 :         else if (STARTS_WITH(pszLine, "ATPCP"))
     801             :         {
     802           0 :             char **papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
     803           0 :             if (CSLCount(papszTokens) == 4)
     804             :             {
     805           0 :                 if (strcmp(papszTokens[2], "ATT") == 0)
     806           0 :                     osAttId = papszTokens[3];
     807             :             }
     808           0 :             CSLDestroy(papszTokens);
     809             :         }
     810           0 :         else if (strcmp(pszLine, "TEXT 06:8859-1") == 0)
     811             :         {
     812           0 :             bIso8859_1 = TRUE;
     813             :         }
     814           0 :         else if (STARTS_WITH(pszLine, "ATVS"))
     815             :         {
     816           0 :             CPLString osAttVal = pszLine + 8;
     817             :             while (true)
     818             :             {
     819           0 :                 pszLine = CPLReadLine2L(fp, 81, nullptr);
     820           0 :                 if (pszLine != nullptr && strlen(pszLine) >= 8 &&
     821           0 :                     pszLine[7] == ':' && STARTS_WITH(pszLine, "NEXT "))
     822             :                 {
     823           0 :                     osAttVal += pszLine + 8;
     824             :                 }
     825             :                 else
     826             :                 {
     827             :                     break;
     828             :                 }
     829             :             }
     830           0 :             if (bIso8859_1 && bRecodeToUTF8)
     831             :             {
     832           0 :                 char *pszNewVal = CPLRecode(osAttVal.c_str(), CPL_ENC_ISO8859_1,
     833             :                                             CPL_ENC_UTF8);
     834           0 :                 osAttVal = pszNewVal;
     835           0 :                 CPLFree(pszNewVal);
     836             :             }
     837           0 :             else if (bHasUTF8ContentOnly)
     838             :             {
     839           0 :                 bHasUTF8ContentOnly = CPLIsUTF8(osAttVal.c_str(), -1);
     840             :             }
     841           0 :             if (!osAttId.empty())
     842           0 :                 aosAttIdVal.push_back(strstrType(osAttId, osAttVal));
     843           0 :             osAttId = "";
     844           0 :             bIso8859_1 = FALSE;
     845           0 :             goto skip_read_next_line;
     846             :         }
     847           0 :         else if (STARTS_WITH(pszLine, "ATVCP"))
     848             :         {
     849           0 :             char **papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
     850           0 :             if (CSLCount(papszTokens) == 4)
     851             :             {
     852           0 :                 if (strcmp(papszTokens[2], "ATT") == 0)
     853             :                 {
     854           0 :                     CPLString osAttVal = papszTokens[3];
     855           0 :                     if (!osAttId.empty())
     856           0 :                         aosAttIdVal.push_back(strstrType(osAttId, osAttVal));
     857           0 :                     osAttId = "";
     858             :                 }
     859             :             }
     860           0 :             CSLDestroy(papszTokens);
     861             :         }
     862           0 :         else if (STARTS_WITH(pszLine, "QAPCP"))
     863             :         {
     864           0 :             char **papszTokens = CSLTokenizeString2(pszLine + 8, ";", 0);
     865           0 :             if (CSLCount(papszTokens) == 4)
     866             :             {
     867           0 :                 if (strcmp(papszTokens[2], "QUP") == 0)
     868             :                 {
     869           0 :                     osQUP_RID = papszTokens[3];
     870             :                 }
     871             :             }
     872           0 :             CSLDestroy(papszTokens);
     873             :         }
     874           0 :     }
     875             : 
     876           0 :     VSIFCloseL(fp);
     877             : 
     878           0 :     return TRUE;
     879             : }
     880             : 
     881             : /************************************************************************/
     882             : /*                        CreateFeature()                               */
     883             : /************************************************************************/
     884             : 
     885           0 : OGRFeature *OGREDIGEODataSource::CreateFeature(const CPLString &osFEA) const
     886             : {
     887             :     const std::map<CPLString, OGREDIGEOFEADesc>::iterator itFEA =
     888           0 :         mapFEA.find(osFEA);
     889           0 :     if (itFEA == mapFEA.end())
     890             :     {
     891           0 :         CPLDebug("EDIGEO", "ERROR: Cannot find FEA %s", osFEA.c_str());
     892           0 :         return nullptr;
     893             :     }
     894             : 
     895           0 :     const OGREDIGEOFEADesc &fea = itFEA->second;
     896             :     const std::map<CPLString, OGREDIGEOLayer *>::iterator itLyr =
     897           0 :         mapLayer.find(fea.osSCP);
     898           0 :     if (itLyr != mapLayer.end())
     899             :     {
     900           0 :         OGREDIGEOLayer *poLayer = itLyr->second;
     901             : 
     902           0 :         OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
     903           0 :         poFeature->SetField(0, itFEA->first.c_str());
     904           0 :         for (int i = 0; i < (int)fea.aosAttIdVal.size(); i++)
     905             :         {
     906           0 :             const CPLString &id = fea.aosAttIdVal[i].first;
     907           0 :             const CPLString &val = fea.aosAttIdVal[i].second;
     908           0 :             int iIndex = poLayer->GetAttributeIndex(id);
     909           0 :             if (iIndex != -1)
     910           0 :                 poFeature->SetField(iIndex, val.c_str());
     911             :             else
     912           0 :                 CPLDebug("EDIGEO", "ERROR: Cannot find attribute %s",
     913             :                          id.c_str());
     914             :         }
     915             : 
     916           0 :         if (strcmp(poLayer->GetName(), "ID_S_OBJ_Z_1_2_2") != 0 &&
     917           0 :             !mapQAL.empty() && !fea.osQUP_RID.empty())
     918             :         {
     919             :             const std::map<CPLString, intintType>::iterator itQAL =
     920           0 :                 mapQAL.find(fea.osQUP_RID);
     921           0 :             if (itQAL != mapQAL.end())
     922             :             {
     923           0 :                 const intintType &creationUpdateDate = itQAL->second;
     924           0 :                 if (creationUpdateDate.first != 0)
     925           0 :                     poFeature->SetField("CREAT_DATE", creationUpdateDate.first);
     926           0 :                 if (creationUpdateDate.second != 0)
     927           0 :                     poFeature->SetField("UPDATE_DATE",
     928           0 :                                         creationUpdateDate.second);
     929             :             }
     930             :         }
     931             : 
     932           0 :         poLayer->AddFeature(poFeature);
     933             : 
     934           0 :         return poFeature;
     935             :     }
     936             :     else
     937             :     {
     938           0 :         CPLDebug("EDIGEO", "ERROR: Cannot find layer %s", fea.osSCP.c_str());
     939           0 :         return nullptr;
     940             :     }
     941             : }
     942             : 
     943             : /************************************************************************/
     944             : /*                             SetStyle()                               */
     945             : /************************************************************************/
     946             : 
     947           0 : int OGREDIGEODataSource::SetStyle(const CPLString &osFEA,
     948             :                                   OGRFeature *poFeature) const
     949             : {
     950             :     /* EDIGEO PCI specific */
     951             :     /* See EDIGeO_PCI.pdf, chapter 3 "Principes généraux de */
     952             :     /* positionnement de la toponymie. */
     953           0 :     const char *pszATR = nullptr;
     954           0 :     if (strcmp(poFeature->GetDefnRef()->GetName(), "ID_S_OBJ_Z_1_2_2") == 0 &&
     955           0 :         iATR != -1 && (pszATR = poFeature->GetFieldAsString(iATR)) != nullptr)
     956             :     {
     957           0 :         const CPLString osATR = pszATR;
     958             :         std::map<CPLString, CPLString>::iterator itFEA_FEA =
     959           0 :             mapFEA_FEA.find(osFEA);
     960           0 :         if (itFEA_FEA != mapFEA_FEA.end())
     961             :         {
     962           0 :             const CPLString &osOBJ_LNK = itFEA_FEA->second;
     963             :             std::map<CPLString, OGREDIGEOFEADesc>::iterator itFEA_LNK =
     964           0 :                 mapFEA.find(osOBJ_LNK);
     965           0 :             if (itFEA_LNK != mapFEA.end())
     966             :             {
     967           0 :                 const OGREDIGEOFEADesc &fea_lnk = itFEA_LNK->second;
     968           0 :                 for (int j = 0; j < (int)fea_lnk.aosAttIdVal.size(); j++)
     969             :                 {
     970           0 :                     if (fea_lnk.aosAttIdVal[j].first == osATR)
     971             :                     {
     972           0 :                         double dfAngle = 0;
     973           0 :                         if (iDI3 != -1 && iDI4 != -1)
     974             :                         {
     975             :                             double dfBaseVectorX =
     976           0 :                                 poFeature->GetFieldAsDouble(iDI3);
     977             :                             double dfBaseVectorY =
     978           0 :                                 poFeature->GetFieldAsDouble(iDI4);
     979           0 :                             dfAngle = atan2(dfBaseVectorY, dfBaseVectorX) /
     980             :                                       M_PI * 180;
     981           0 :                             if (dfAngle < 0)
     982           0 :                                 dfAngle += 360;
     983             :                         }
     984           0 :                         double dfSize = 1;
     985           0 :                         if (iHEI != -1)
     986           0 :                             dfSize = poFeature->GetFieldAsDouble(iHEI);
     987           0 :                         if (dfSize <= 0 || dfSize >= 100)
     988           0 :                             dfSize = 1;
     989           0 :                         const char *pszFontFamily = nullptr;
     990           0 :                         if (iFON != -1)
     991           0 :                             pszFontFamily = poFeature->GetFieldAsString(iFON);
     992             : 
     993           0 :                         CPLString osStyle("LABEL(t:\"");
     994           0 :                         osStyle += fea_lnk.aosAttIdVal[j].second;
     995           0 :                         osStyle += "\"";
     996           0 :                         if (dfAngle != 0)
     997             :                         {
     998           0 :                             osStyle += ",a:";
     999           0 :                             osStyle += CPLString().Printf("%.1f", dfAngle);
    1000             :                         }
    1001           0 :                         if (pszFontFamily != nullptr && bIncludeFontFamily)
    1002             :                         {
    1003           0 :                             osStyle += ",f:\"";
    1004           0 :                             osStyle += pszFontFamily;
    1005           0 :                             osStyle += "\"";
    1006             :                         }
    1007           0 :                         osStyle += ",s:";
    1008           0 :                         osStyle += CPLString().Printf("%.1f", dfSize);
    1009           0 :                         osStyle += ",c:#000000)";
    1010           0 :                         poFeature->SetStyleString(osStyle);
    1011             : 
    1012           0 :                         poFeature->SetField(iATR_VAL,
    1013           0 :                                             fea_lnk.aosAttIdVal[j].second);
    1014           0 :                         poFeature->SetField(iANGLE, dfAngle);
    1015           0 :                         poFeature->SetField(iSIZE, dfSize * dfSizeFactor);
    1016           0 :                         poFeature->SetField(iOBJ_LNK, osOBJ_LNK);
    1017           0 :                         poFeature->SetField(iOBJ_LNK_LAYER, fea_lnk.osSCP);
    1018             : 
    1019           0 :                         setLayersWithLabels.insert(fea_lnk.osSCP);
    1020             : 
    1021           0 :                         break;
    1022             :                     }
    1023             :                 }
    1024             :             }
    1025             :         }
    1026             :     }
    1027             : 
    1028           0 :     return TRUE;
    1029             : }
    1030             : 
    1031             : /************************************************************************/
    1032             : /*                           BuildPoints()                              */
    1033             : /************************************************************************/
    1034             : 
    1035           0 : int OGREDIGEODataSource::BuildPoints() const
    1036             : {
    1037           0 :     for (int i = 0; i < (int)listFEA_PNO.size(); i++)
    1038             :     {
    1039           0 :         const CPLString &osFEA = listFEA_PNO[i].first;
    1040           0 :         const CPLString &osPNO = listFEA_PNO[i].second;
    1041             :         const std::map<CPLString, xyPairType>::iterator itPNO =
    1042           0 :             mapPNO.find(osPNO);
    1043           0 :         if (itPNO == mapPNO.end())
    1044             :         {
    1045           0 :             CPLDebug("EDIGEO", "Cannot find PNO %s", osPNO.c_str());
    1046             :         }
    1047             :         else
    1048             :         {
    1049           0 :             OGRFeature *poFeature = CreateFeature(osFEA);
    1050           0 :             if (poFeature)
    1051             :             {
    1052           0 :                 const xyPairType &pno = itPNO->second;
    1053           0 :                 OGRPoint *poPoint = new OGRPoint(pno.first, pno.second);
    1054           0 :                 if (poSRS)
    1055           0 :                     poPoint->assignSpatialReference(poSRS);
    1056           0 :                 poFeature->SetGeometryDirectly(poPoint);
    1057             : 
    1058           0 :                 SetStyle(osFEA, poFeature);
    1059             :             }
    1060             :         }
    1061             :     }
    1062             : 
    1063           0 :     return TRUE;
    1064             : }
    1065             : 
    1066             : /************************************************************************/
    1067             : /*                        BuildLineStrings()                            */
    1068             : /************************************************************************/
    1069             : 
    1070           0 : int OGREDIGEODataSource::BuildLineStrings() const
    1071             : {
    1072             :     int i, iter;
    1073             : 
    1074           0 :     for (iter = 0; iter < (int)listFEA_PAR.size(); iter++)
    1075             :     {
    1076           0 :         const CPLString &osFEA = listFEA_PAR[iter].first;
    1077           0 :         const strListType &aosPAR = listFEA_PAR[iter].second;
    1078           0 :         OGRFeature *poFeature = CreateFeature(osFEA);
    1079           0 :         if (poFeature)
    1080             :         {
    1081           0 :             OGRGeometry *poGeom = nullptr;
    1082           0 :             OGRMultiLineString *poMulti = nullptr;
    1083           0 :             for (int k = 0; k < (int)aosPAR.size(); k++)
    1084             :             {
    1085             :                 const std::map<CPLString, xyPairListType>::iterator itPAR =
    1086           0 :                     mapPAR.find(aosPAR[k]);
    1087           0 :                 if (itPAR != mapPAR.end())
    1088             :                 {
    1089           0 :                     const xyPairListType &arc = itPAR->second;
    1090             : 
    1091           0 :                     OGRLineString *poLS = new OGRLineString();
    1092           0 :                     poLS->setNumPoints((int)arc.size());
    1093           0 :                     for (i = 0; i < (int)arc.size(); i++)
    1094             :                     {
    1095           0 :                         poLS->setPoint(i, arc[i].first, arc[i].second);
    1096             :                     }
    1097             : 
    1098           0 :                     if (poGeom != nullptr)
    1099             :                     {
    1100           0 :                         if (poMulti == nullptr)
    1101             :                         {
    1102           0 :                             poMulti = new OGRMultiLineString();
    1103           0 :                             poMulti->addGeometryDirectly(poGeom);
    1104           0 :                             poGeom = poMulti;
    1105             :                         }
    1106           0 :                         poMulti->addGeometryDirectly(poLS);
    1107             :                     }
    1108             :                     else
    1109           0 :                         poGeom = poLS;
    1110             :                 }
    1111             :                 else
    1112           0 :                     CPLDebug("EDIGEO", "ERROR: Cannot find ARC %s",
    1113           0 :                              aosPAR[k].c_str());
    1114             :             }
    1115           0 :             if (poGeom != nullptr)
    1116             :             {
    1117           0 :                 poGeom->assignSpatialReference(poSRS);
    1118           0 :                 poFeature->SetGeometryDirectly(poGeom);
    1119             :             }
    1120             :         }
    1121             :     }
    1122             : 
    1123           0 :     return TRUE;
    1124             : }
    1125             : 
    1126             : /************************************************************************/
    1127             : /*                           BuildPolygon()                             */
    1128             : /************************************************************************/
    1129             : 
    1130           0 : int OGREDIGEODataSource::BuildPolygon(const CPLString &osFEA,
    1131             :                                       const strListType &aosPFE) const
    1132             : {
    1133           0 :     std::vector<xyPairListType> aoXYList;
    1134             : 
    1135           0 :     for (int k = 0; k < (int)aosPFE.size(); k++)
    1136             :     {
    1137             :         const std::map<CPLString, strListType>::iterator itPFE_PAR =
    1138           0 :             mapPFE_PAR.find(aosPFE[k]);
    1139           0 :         if (itPFE_PAR == mapPFE_PAR.end())
    1140             :         {
    1141           0 :             CPLDebug("EDIGEO", "ERROR: Cannot find PFE %s", aosPFE[k].c_str());
    1142           0 :             return FALSE;
    1143             :         }
    1144             : 
    1145           0 :         const strListType &aosPARList = itPFE_PAR->second;
    1146             : 
    1147             :         /* --------------------------------------------------------------------
    1148             :          */
    1149             :         /*      Resolve arc ids to arc coordinate lists. */
    1150             :         /* --------------------------------------------------------------------
    1151             :          */
    1152           0 :         std::vector<const xyPairListType *> aoPARPtrList;
    1153           0 :         for (int i = 0; i < (int)aosPARList.size(); i++)
    1154             :         {
    1155             :             const std::map<CPLString, xyPairListType>::iterator itPAR =
    1156           0 :                 mapPAR.find(aosPARList[i]);
    1157           0 :             if (itPAR != mapPAR.end())
    1158           0 :                 aoPARPtrList.push_back(&(itPAR->second));
    1159             :             else
    1160           0 :                 CPLDebug("EDIGEO", "ERROR: Cannot find ARC %s",
    1161           0 :                          aosPARList[i].c_str());
    1162             :         }
    1163             : 
    1164           0 :         if (aoPARPtrList.empty())
    1165           0 :             return FALSE;
    1166             : 
    1167             :         /* --------------------------------------------------------------------
    1168             :          */
    1169             :         /*      Now try to chain all arcs together. */
    1170             :         /* --------------------------------------------------------------------
    1171             :          */
    1172             : 
    1173           0 :         for (int j = 0; j < (int)aoPARPtrList.size(); j++)
    1174             :         {
    1175           0 :             if (aoPARPtrList[j] == nullptr)
    1176           0 :                 continue;
    1177           0 :             const xyPairListType &sFirstRing = *(aoPARPtrList[j]);
    1178           0 :             const xyPairType *psNext = &(sFirstRing.back());
    1179             : 
    1180           0 :             xyPairListType aoXY;
    1181           0 :             for (int i = 0; i < (int)sFirstRing.size(); i++)
    1182           0 :                 aoXY.push_back(sFirstRing[i]);
    1183           0 :             aoPARPtrList[j] = nullptr;
    1184             : 
    1185           0 :             int nIter = 1;
    1186           0 :             while (aoXY.back() != aoXY[0] && nIter < (int)aoPARPtrList.size())
    1187             :             {
    1188           0 :                 bool bFound = false;
    1189           0 :                 bool bReverseSecond = false;
    1190           0 :                 int i = 0;  // Used after for.
    1191           0 :                 for (; i < (int)aoPARPtrList.size(); i++)
    1192             :                 {
    1193           0 :                     if (aoPARPtrList[i] != nullptr)
    1194             :                     {
    1195           0 :                         const xyPairListType &sSecondRing = *(aoPARPtrList[i]);
    1196           0 :                         if (*psNext == sSecondRing[0])
    1197             :                         {
    1198           0 :                             bFound = true;
    1199           0 :                             bReverseSecond = false;
    1200           0 :                             break;
    1201             :                         }
    1202           0 :                         else if (*psNext == sSecondRing.back())
    1203             :                         {
    1204           0 :                             bFound = true;
    1205           0 :                             bReverseSecond = true;
    1206           0 :                             break;
    1207             :                         }
    1208             :                     }
    1209             :                 }
    1210             : 
    1211           0 :                 if (!bFound)
    1212             :                 {
    1213           0 :                     CPLDebug("EDIGEO", "Cannot find ring for FEA %s / PFE %s",
    1214           0 :                              osFEA.c_str(), aosPFE[k].c_str());
    1215           0 :                     break;
    1216             :                 }
    1217             :                 else
    1218             :                 {
    1219           0 :                     const xyPairListType &secondRing = *(aoPARPtrList[i]);
    1220           0 :                     aoPARPtrList[i] = nullptr;
    1221           0 :                     if (!bReverseSecond)
    1222             :                     {
    1223           0 :                         for (i = 1; i < (int)secondRing.size(); i++)
    1224           0 :                             aoXY.push_back(secondRing[i]);
    1225           0 :                         psNext = &secondRing.back();
    1226             :                     }
    1227             :                     else
    1228             :                     {
    1229           0 :                         for (i = 1; i < (int)secondRing.size(); i++)
    1230           0 :                             aoXY.push_back(
    1231           0 :                                 secondRing[secondRing.size() - 1 - i]);
    1232           0 :                         psNext = &secondRing[0];
    1233             :                     }
    1234             :                 }
    1235             : 
    1236           0 :                 nIter++;
    1237             :             }
    1238             : 
    1239           0 :             aoXYList.push_back(std::move(aoXY));
    1240             :         }
    1241             :     }
    1242             : 
    1243             :     /* -------------------------------------------------------------------- */
    1244             :     /*      Create feature.                                                 */
    1245             :     /* -------------------------------------------------------------------- */
    1246           0 :     OGRFeature *poFeature = CreateFeature(osFEA);
    1247           0 :     if (poFeature)
    1248             :     {
    1249           0 :         std::vector<OGRGeometry *> aosPolygons;
    1250           0 :         for (int j = 0; j < (int)aoXYList.size(); j++)
    1251             :         {
    1252           0 :             const xyPairListType &aoXY = aoXYList[j];
    1253           0 :             OGRLinearRing *poLS = new OGRLinearRing();
    1254           0 :             poLS->setNumPoints((int)aoXY.size());
    1255           0 :             for (int i = 0; i < (int)aoXY.size(); i++)
    1256           0 :                 poLS->setPoint(i, aoXY[i].first, aoXY[i].second);
    1257           0 :             poLS->closeRings();
    1258           0 :             OGRPolygon *poPolygon = new OGRPolygon();
    1259           0 :             poPolygon->addRingDirectly(poLS);
    1260           0 :             aosPolygons.push_back(poPolygon);
    1261             :         }
    1262             : 
    1263           0 :         int bIsValidGeometry = FALSE;
    1264           0 :         OGRGeometry *poGeom = OGRGeometryFactory::organizePolygons(
    1265           0 :             &aosPolygons[0], (int)aosPolygons.size(), &bIsValidGeometry,
    1266             :             nullptr);
    1267           0 :         if (poGeom)
    1268             :         {
    1269           0 :             if (poSRS)
    1270           0 :                 poGeom->assignSpatialReference(poSRS);
    1271           0 :             poFeature->SetGeometryDirectly(poGeom);
    1272             :         }
    1273             :     }
    1274           0 :     return TRUE;
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                          BuildPolygons()                             */
    1279             : /************************************************************************/
    1280             : 
    1281           0 : int OGREDIGEODataSource::BuildPolygons() const
    1282             : {
    1283           0 :     for (int iter = 0; iter < (int)listFEA_PFE.size(); iter++)
    1284             :     {
    1285           0 :         const CPLString &osFEA = listFEA_PFE[iter].first;
    1286           0 :         const strListType &aosPFE = listFEA_PFE[iter].second;
    1287           0 :         BuildPolygon(osFEA, aosPFE);
    1288             :     }
    1289             : 
    1290           0 :     return TRUE;
    1291             : }
    1292             : 
    1293             : /************************************************************************/
    1294             : /*                  OGREDIGEOSortForQGIS()                              */
    1295             : /************************************************************************/
    1296             : 
    1297           0 : static int OGREDIGEOSortForQGIS(const void *a, const void *b)
    1298             : {
    1299           0 :     OGREDIGEOLayer *poLayerA = *((OGREDIGEOLayer **)a);
    1300           0 :     OGREDIGEOLayer *poLayerB = *((OGREDIGEOLayer **)b);
    1301             :     int nTypeA, nTypeB;
    1302           0 :     switch (poLayerA->GetLayerDefn()->GetGeomType())
    1303             :     {
    1304           0 :         case wkbPoint:
    1305           0 :             nTypeA = 1;
    1306           0 :             break;
    1307           0 :         case wkbLineString:
    1308           0 :             nTypeA = 2;
    1309           0 :             break;
    1310           0 :         case wkbPolygon:
    1311           0 :             nTypeA = 3;
    1312           0 :             break;
    1313           0 :         default:
    1314           0 :             nTypeA = 4;
    1315           0 :             break;
    1316             :     }
    1317           0 :     switch (poLayerB->GetLayerDefn()->GetGeomType())
    1318             :     {
    1319           0 :         case wkbPoint:
    1320           0 :             nTypeB = 1;
    1321           0 :             break;
    1322           0 :         case wkbLineString:
    1323           0 :             nTypeB = 2;
    1324           0 :             break;
    1325           0 :         case wkbPolygon:
    1326           0 :             nTypeB = 3;
    1327           0 :             break;
    1328           0 :         default:
    1329           0 :             nTypeB = 4;
    1330           0 :             break;
    1331             :     }
    1332           0 :     if (nTypeA == nTypeB)
    1333             :     {
    1334           0 :         int nCmp = strcmp(poLayerA->GetName(), poLayerB->GetName());
    1335           0 :         if (nCmp == 0)
    1336           0 :             return 0;
    1337             : 
    1338             :         static const char *const apszPolyOrder[] = {
    1339             :             "COMMUNE_id",  "LIEUDIT_id",  "SECTION_id", "SUBDSECT_id",
    1340             :             "SUBDFISC_id", "PARCELLE_id", "BATIMENT_id"};
    1341           0 :         for (int i = 0; i < (int)(sizeof(apszPolyOrder) / sizeof(char *)); i++)
    1342             :         {
    1343           0 :             if (strcmp(poLayerA->GetName(), apszPolyOrder[i]) == 0)
    1344           0 :                 return -1;
    1345           0 :             if (strcmp(poLayerB->GetName(), apszPolyOrder[i]) == 0)
    1346           0 :                 return 1;
    1347             :         }
    1348           0 :         return nCmp;
    1349             :     }
    1350             :     else
    1351           0 :         return nTypeB - nTypeA;
    1352             : }
    1353             : 
    1354             : /************************************************************************/
    1355             : /*                                Open()                                */
    1356             : /************************************************************************/
    1357             : 
    1358           0 : int OGREDIGEODataSource::Open(const char *pszFilename)
    1359             : 
    1360             : {
    1361           0 :     fpTHF = VSIFOpenL(pszFilename, "rb");
    1362           0 :     if (fpTHF == nullptr)
    1363           0 :         return FALSE;
    1364             : 
    1365           0 :     const char *pszLine = nullptr;
    1366           0 :     int i = 0;
    1367           0 :     bool bIsEDIGEO = false;
    1368           0 :     while (i < 100 && (pszLine = CPLReadLine2L(fpTHF, 81, nullptr)) != nullptr)
    1369             :     {
    1370           0 :         if (strcmp(pszLine, "RTYSA03:GTS") == 0)
    1371             :         {
    1372           0 :             bIsEDIGEO = true;
    1373           0 :             break;
    1374             :         }
    1375           0 :         i++;
    1376             :     }
    1377             : 
    1378           0 :     if (!bIsEDIGEO)
    1379             :     {
    1380           0 :         VSIFCloseL(fpTHF);
    1381           0 :         fpTHF = nullptr;
    1382           0 :         return FALSE;
    1383             :     }
    1384             : 
    1385           0 :     return TRUE;
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : /*                           ReadEDIGEO()                               */
    1390             : /************************************************************************/
    1391             : 
    1392           0 : void OGREDIGEODataSource::ReadEDIGEO() const
    1393             : {
    1394           0 :     std::lock_guard oLock(m_oMutex);
    1395           0 :     if (bHasReadEDIGEO)
    1396           0 :         return;
    1397             : 
    1398           0 :     bHasReadEDIGEO = TRUE;
    1399             : 
    1400             :     /* -------------------------------------------------------------------- */
    1401             :     /*      Read .THF file                                                  */
    1402             :     /* -------------------------------------------------------------------- */
    1403           0 :     VSIFSeekL(fpTHF, 0, SEEK_SET);
    1404           0 :     if (!ReadTHF(fpTHF))
    1405             :     {
    1406           0 :         VSIFCloseL(fpTHF);
    1407           0 :         fpTHF = nullptr;
    1408           0 :         return;
    1409             :     }
    1410           0 :     VSIFCloseL(fpTHF);
    1411           0 :     fpTHF = nullptr;
    1412             : 
    1413             :     /* -------------------------------------------------------------------- */
    1414             :     /*      Read .GEO file                                                  */
    1415             :     /* -------------------------------------------------------------------- */
    1416           0 :     if (!ReadGEO())
    1417           0 :         return;
    1418             : 
    1419             :     /* -------------------------------------------------------------------- */
    1420             :     /*      Read .GEN file                                                  */
    1421             :     /* -------------------------------------------------------------------- */
    1422           0 :     if (!osGNN.empty())
    1423           0 :         ReadGEN();
    1424             : 
    1425             :     /* -------------------------------------------------------------------- */
    1426             :     /*      Read .DIC file                                                  */
    1427             :     /* -------------------------------------------------------------------- */
    1428           0 :     if (!ReadDIC())
    1429           0 :         return;
    1430             : 
    1431             :     /* -------------------------------------------------------------------- */
    1432             :     /*      Read .SCD file                                                  */
    1433             :     /* -------------------------------------------------------------------- */
    1434           0 :     if (!ReadSCD())
    1435           0 :         return;
    1436             : 
    1437             :     /* -------------------------------------------------------------------- */
    1438             :     /*      Read .QAL file                                                  */
    1439             :     /* -------------------------------------------------------------------- */
    1440           0 :     if (!osQAN.empty())
    1441           0 :         ReadQAL();
    1442             : 
    1443             :     /* -------------------------------------------------------------------- */
    1444             :     /*      Create layers from SCD definitions                              */
    1445             :     /* -------------------------------------------------------------------- */
    1446           0 :     for (int i = 0; i < (int)aoObjList.size(); i++)
    1447             :     {
    1448           0 :         CreateLayerFromObjectDesc(aoObjList[i]);
    1449             :     }
    1450             : 
    1451             :     /* -------------------------------------------------------------------- */
    1452             :     /*      Read .VEC files and create features                             */
    1453             :     /* -------------------------------------------------------------------- */
    1454           0 :     for (int i = 0; i < (int)aosGDN.size(); i++)
    1455             :     {
    1456           0 :         ReadVEC(aosGDN[i]);
    1457             : 
    1458           0 :         BuildPoints();
    1459           0 :         BuildLineStrings();
    1460           0 :         BuildPolygons();
    1461             : 
    1462           0 :         mapPNO.clear();
    1463           0 :         mapPAR.clear();
    1464           0 :         mapFEA.clear();
    1465           0 :         mapPFE_PAR.clear();
    1466           0 :         listFEA_PFE.clear();
    1467           0 :         listFEA_PAR.clear();
    1468           0 :         listFEA_PNO.clear();
    1469           0 :         mapFEA_FEA.clear();
    1470             :     }
    1471             : 
    1472           0 :     mapObjects.clear();
    1473           0 :     mapAttributes.clear();
    1474           0 :     mapAttributesSCD.clear();
    1475           0 :     mapQAL.clear();
    1476             : 
    1477             :     /* -------------------------------------------------------------------- */
    1478             :     /*      Delete empty layers                                             */
    1479             :     /* -------------------------------------------------------------------- */
    1480           0 :     for (int i = 0; i < nLayers; /*nothing*/)
    1481             :     {
    1482           0 :         if (papoLayers[i]->GetFeatureCount(TRUE) == 0)
    1483             :         {
    1484           0 :             delete papoLayers[i];
    1485           0 :             if (i < nLayers - 1)
    1486           0 :                 memmove(papoLayers + i, papoLayers + i + 1,
    1487           0 :                         (nLayers - i - 1) * sizeof(OGREDIGEOLayer *));
    1488           0 :             nLayers--;
    1489             :         }
    1490             :         else
    1491           0 :             i++;
    1492             :     }
    1493             : 
    1494             :     /* -------------------------------------------------------------------- */
    1495             :     /*      When added from QGIS, the layers must be ordered from           */
    1496             :     /*      bottom (Polygon) to top (Point) to get nice visual effect       */
    1497             :     /* -------------------------------------------------------------------- */
    1498           0 :     if (CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_SORT_FOR_QGIS", "YES")))
    1499           0 :         qsort(papoLayers, nLayers, sizeof(OGREDIGEOLayer *),
    1500             :               OGREDIGEOSortForQGIS);
    1501             : 
    1502             :     /* -------------------------------------------------------------------- */
    1503             :     /*      Create a label layer for each feature layer                     */
    1504             :     /* -------------------------------------------------------------------- */
    1505           0 :     if (CPLTestBool(
    1506             :             CPLGetConfigOption("OGR_EDIGEO_CREATE_LABEL_LAYERS", "YES")))
    1507           0 :         CreateLabelLayers();
    1508             : 
    1509           0 :     return;
    1510             : }
    1511             : 
    1512             : /************************************************************************/
    1513             : /*                         CreateLabelLayers()                          */
    1514             : /************************************************************************/
    1515             : 
    1516           0 : void OGREDIGEODataSource::CreateLabelLayers() const
    1517             : {
    1518           0 :     OGRLayer *poLayer = const_cast<OGREDIGEODataSource *>(this)->GetLayerByName(
    1519           0 :         "ID_S_OBJ_Z_1_2_2");
    1520           0 :     if (poLayer == nullptr)
    1521           0 :         return;
    1522             : 
    1523           0 :     std::map<CPLString, OGREDIGEOLayer *> mapLayerNameToLayer;
    1524             : 
    1525           0 :     OGRFeature *poFeature = nullptr;
    1526           0 :     OGRFeatureDefn *poFeatureDefn = poLayer->GetLayerDefn();
    1527           0 :     while ((poFeature = poLayer->GetNextFeature()) != nullptr)
    1528             :     {
    1529             :         const char *pszBelongingLayerName =
    1530           0 :             poFeature->GetFieldAsString(iOBJ_LNK_LAYER);
    1531           0 :         if (pszBelongingLayerName)
    1532             :         {
    1533           0 :             CPLString osBelongingLayerName = pszBelongingLayerName;
    1534             :             std::map<CPLString, OGREDIGEOLayer *>::iterator it =
    1535           0 :                 mapLayerNameToLayer.find(osBelongingLayerName);
    1536           0 :             OGREDIGEOLayer *poLabelLayer = nullptr;
    1537             : 
    1538           0 :             if (it == mapLayerNameToLayer.end())
    1539             :             {
    1540             :                 /* Create label layer if it does not already exist */
    1541           0 :                 CPLString osLayerLabelName = osBelongingLayerName + "_LABEL";
    1542           0 :                 poLabelLayer = new OGREDIGEOLayer(
    1543             :                     const_cast<OGREDIGEODataSource *>(this),
    1544           0 :                     osLayerLabelName.c_str(), wkbPoint, poSRS);
    1545             :                 OGRFeatureDefn *poLabelFeatureDefn =
    1546           0 :                     poLabelLayer->GetLayerDefn();
    1547           0 :                 for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
    1548           0 :                     poLabelFeatureDefn->AddFieldDefn(
    1549           0 :                         poFeatureDefn->GetFieldDefn(i));
    1550           0 :                 mapLayerNameToLayer[osBelongingLayerName] = poLabelLayer;
    1551             : 
    1552           0 :                 papoLayers = (OGRLayer **)CPLRealloc(
    1553           0 :                     papoLayers, (nLayers + 1) * sizeof(OGRLayer *));
    1554           0 :                 papoLayers[nLayers] = poLabelLayer;
    1555           0 :                 nLayers++;
    1556             :             }
    1557             :             else
    1558             :             {
    1559           0 :                 poLabelLayer = mapLayerNameToLayer[osBelongingLayerName];
    1560             :             }
    1561             : 
    1562             :             OGRFeature *poNewFeature =
    1563           0 :                 new OGRFeature(poLabelLayer->GetLayerDefn());
    1564           0 :             poNewFeature->SetFrom(poFeature);
    1565           0 :             poLabelLayer->AddFeature(poNewFeature);
    1566             :         }
    1567           0 :         delete poFeature;
    1568             :     }
    1569             : 
    1570           0 :     poLayer->ResetReading();
    1571             : }

Generated by: LCOV version 1.14