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 819 0.0 %
Date: 2024-11-21 22:18:42 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             :           CPLGetConfigOption("OGR_EDIGEO_INCLUDE_FONT_FAMILY", "YES"))),
      34           0 :       bHasReadEDIGEO(FALSE)
      35             : {
      36           0 :     if (dfSizeFactor <= 0 || dfSizeFactor >= 100)
      37           0 :         dfSizeFactor = 2;
      38           0 : }
      39             : 
      40             : /************************************************************************/
      41             : /*                      ~OGREDIGEODataSource()                          */
      42             : /************************************************************************/
      43             : 
      44           0 : OGREDIGEODataSource::~OGREDIGEODataSource()
      45             : 
      46             : {
      47           0 :     for (int i = 0; i < nLayers; i++)
      48           0 :         delete papoLayers[i];
      49           0 :     CPLFree(papoLayers);
      50             : 
      51           0 :     if (fpTHF)
      52           0 :         VSIFCloseL(fpTHF);
      53             : 
      54           0 :     if (poSRS)
      55           0 :         poSRS->Release();
      56           0 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                              GetLayer()                              */
      60             : /************************************************************************/
      61             : 
      62           0 : OGRLayer *OGREDIGEODataSource::GetLayer(int iLayer)
      63             : 
      64             : {
      65           0 :     ReadEDIGEO();
      66           0 :     if (iLayer < 0 || iLayer >= nLayers)
      67           0 :         return nullptr;
      68             :     else
      69           0 :         return papoLayers[iLayer];
      70             : }
      71             : 
      72             : /************************************************************************/
      73             : /*                         GetLayerCount()                              */
      74             : /************************************************************************/
      75             : 
      76           0 : int OGREDIGEODataSource::GetLayerCount()
      77             : {
      78           0 :     ReadEDIGEO();
      79           0 :     return nLayers;
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                              ReadTHF()                               */
      84             : /************************************************************************/
      85             : 
      86           0 : int OGREDIGEODataSource::ReadTHF(VSILFILE *fp)
      87             : {
      88           0 :     const char *pszLine = nullptr;
      89           0 :     while ((pszLine = CPLReadLine2L(fp, 81, nullptr)) != nullptr)
      90             :     {
      91           0 :         if (strlen(pszLine) < 8 || pszLine[7] != ':')
      92           0 :             continue;
      93             : 
      94             :         /* Cf Z 52000 tableau 56 for field list*/
      95             : 
      96           0 :         if (STARTS_WITH(pszLine, "LONSA"))
      97             :         {
      98           0 :             if (!osLON.empty())
      99             :             {
     100           0 :                 CPLDebug("EDIGEO", "We only handle one lot per THF file");
     101           0 :                 break;
     102             :             }
     103           0 :             osLON = pszLine + 8;
     104             :         }
     105           0 :         else if (STARTS_WITH(pszLine, "GNNSA"))
     106           0 :             osGNN = pszLine + 8;
     107           0 :         else if (STARTS_WITH(pszLine, "GONSA"))
     108           0 :             osGON = pszLine + 8;
     109           0 :         else if (STARTS_WITH(pszLine, "QANSA"))
     110           0 :             osQAN = pszLine + 8;
     111           0 :         else if (STARTS_WITH(pszLine, "DINSA"))
     112           0 :             osDIN = pszLine + 8;
     113           0 :         else if (STARTS_WITH(pszLine, "SCNSA"))
     114           0 :             osSCN = pszLine + 8;
     115           0 :         else if (STARTS_WITH(pszLine, "GDNSA"))
     116           0 :             aosGDN.push_back(pszLine + 8);
     117             :     }
     118           0 :     if (osLON.empty())
     119             :     {
     120           0 :         CPLDebug("EDIGEO", "LON field missing");
     121           0 :         return 0;
     122             :     }
     123           0 :     if (osGON.empty())
     124             :     {
     125           0 :         CPLDebug("EDIGEO", "GON field missing");
     126           0 :         return 0;
     127             :     }
     128           0 :     if (osDIN.empty())
     129             :     {
     130           0 :         CPLDebug("EDIGEO", "DIN field missing");
     131           0 :         return 0;
     132             :     }
     133           0 :     if (osSCN.empty())
     134             :     {
     135           0 :         CPLDebug("EDIGEO", "SCN field missing");
     136           0 :         return FALSE;
     137             :     }
     138             : 
     139           0 :     CPLDebug("EDIGEO", "LON = %s", osLON.c_str());
     140           0 :     CPLDebug("EDIGEO", "GNN = %s", osGNN.c_str());
     141           0 :     CPLDebug("EDIGEO", "GON = %s", osGON.c_str());
     142           0 :     CPLDebug("EDIGEO", "QAN = %s", osQAN.c_str());
     143           0 :     CPLDebug("EDIGEO", "DIN = %s", osDIN.c_str());
     144           0 :     CPLDebug("EDIGEO", "SCN = %s", osSCN.c_str());
     145           0 :     for (int i = 0; i < (int)aosGDN.size(); i++)
     146           0 :         CPLDebug("EDIGEO", "GDN[%d] = %s", i, aosGDN[i].c_str());
     147             : 
     148           0 :     return TRUE;
     149             : }
     150             : 
     151             : /************************************************************************/
     152             : /*                             OpenFile()                               */
     153             : /************************************************************************/
     154             : 
     155           0 : VSILFILE *OGREDIGEODataSource::OpenFile(const char *pszType,
     156             :                                         const CPLString &osExt)
     157             : {
     158           0 :     CPLString osTmp = osLON + pszType;
     159           0 :     CPLString osFilename = CPLFormCIFilename(CPLGetPath(GetDescription()),
     160           0 :                                              osTmp.c_str(), osExt.c_str());
     161           0 :     VSILFILE *fp = VSIFOpenL(osFilename, "rb");
     162           0 :     if (fp == nullptr)
     163             :     {
     164           0 :         const CPLString osExtLower = CPLString(osExt).tolower();
     165             :         const CPLString osFilename2 = CPLFormCIFilename(
     166           0 :             CPLGetPath(GetDescription()), 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()
     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()
     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()
     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()
     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(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()
     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)
     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 =
     555           0 :         new OGREDIGEOLayer(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)
     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)
     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, OGRFeature *poFeature)
     948             : {
     949             :     /* EDIGEO PCI specific */
     950             :     /* See EDIGeO_PCI.pdf, chapter 3 "Principes généraux de */
     951             :     /* positionnement de la toponymie. */
     952           0 :     const char *pszATR = nullptr;
     953           0 :     if (strcmp(poFeature->GetDefnRef()->GetName(), "ID_S_OBJ_Z_1_2_2") == 0 &&
     954           0 :         iATR != -1 && (pszATR = poFeature->GetFieldAsString(iATR)) != nullptr)
     955             :     {
     956           0 :         const CPLString osATR = pszATR;
     957             :         std::map<CPLString, CPLString>::iterator itFEA_FEA =
     958           0 :             mapFEA_FEA.find(osFEA);
     959           0 :         if (itFEA_FEA != mapFEA_FEA.end())
     960             :         {
     961           0 :             const CPLString &osOBJ_LNK = itFEA_FEA->second;
     962             :             std::map<CPLString, OGREDIGEOFEADesc>::iterator itFEA_LNK =
     963           0 :                 mapFEA.find(osOBJ_LNK);
     964           0 :             if (itFEA_LNK != mapFEA.end())
     965             :             {
     966           0 :                 const OGREDIGEOFEADesc &fea_lnk = itFEA_LNK->second;
     967           0 :                 for (int j = 0; j < (int)fea_lnk.aosAttIdVal.size(); j++)
     968             :                 {
     969           0 :                     if (fea_lnk.aosAttIdVal[j].first == osATR)
     970             :                     {
     971           0 :                         double dfAngle = 0;
     972           0 :                         if (iDI3 != -1 && iDI4 != -1)
     973             :                         {
     974             :                             double dfBaseVectorX =
     975           0 :                                 poFeature->GetFieldAsDouble(iDI3);
     976             :                             double dfBaseVectorY =
     977           0 :                                 poFeature->GetFieldAsDouble(iDI4);
     978           0 :                             dfAngle = atan2(dfBaseVectorY, dfBaseVectorX) /
     979             :                                       M_PI * 180;
     980           0 :                             if (dfAngle < 0)
     981           0 :                                 dfAngle += 360;
     982             :                         }
     983           0 :                         double dfSize = 1;
     984           0 :                         if (iHEI != -1)
     985           0 :                             dfSize = poFeature->GetFieldAsDouble(iHEI);
     986           0 :                         if (dfSize <= 0 || dfSize >= 100)
     987           0 :                             dfSize = 1;
     988           0 :                         const char *pszFontFamily = nullptr;
     989           0 :                         if (iFON != -1)
     990           0 :                             pszFontFamily = poFeature->GetFieldAsString(iFON);
     991             : 
     992           0 :                         CPLString osStyle("LABEL(t:\"");
     993           0 :                         osStyle += fea_lnk.aosAttIdVal[j].second;
     994           0 :                         osStyle += "\"";
     995           0 :                         if (dfAngle != 0)
     996             :                         {
     997           0 :                             osStyle += ",a:";
     998           0 :                             osStyle += CPLString().Printf("%.1f", dfAngle);
     999             :                         }
    1000           0 :                         if (pszFontFamily != nullptr && bIncludeFontFamily)
    1001             :                         {
    1002           0 :                             osStyle += ",f:\"";
    1003           0 :                             osStyle += pszFontFamily;
    1004           0 :                             osStyle += "\"";
    1005             :                         }
    1006           0 :                         osStyle += ",s:";
    1007           0 :                         osStyle += CPLString().Printf("%.1f", dfSize);
    1008           0 :                         osStyle += ",c:#000000)";
    1009           0 :                         poFeature->SetStyleString(osStyle);
    1010             : 
    1011           0 :                         poFeature->SetField(iATR_VAL,
    1012           0 :                                             fea_lnk.aosAttIdVal[j].second);
    1013           0 :                         poFeature->SetField(iANGLE, dfAngle);
    1014           0 :                         poFeature->SetField(iSIZE, dfSize * dfSizeFactor);
    1015           0 :                         poFeature->SetField(iOBJ_LNK, osOBJ_LNK);
    1016           0 :                         poFeature->SetField(iOBJ_LNK_LAYER, fea_lnk.osSCP);
    1017             : 
    1018           0 :                         setLayersWithLabels.insert(fea_lnk.osSCP);
    1019             : 
    1020           0 :                         break;
    1021             :                     }
    1022             :                 }
    1023             :             }
    1024             :         }
    1025             :     }
    1026             : 
    1027           0 :     return TRUE;
    1028             : }
    1029             : 
    1030             : /************************************************************************/
    1031             : /*                           BuildPoints()                              */
    1032             : /************************************************************************/
    1033             : 
    1034           0 : int OGREDIGEODataSource::BuildPoints()
    1035             : {
    1036           0 :     for (int i = 0; i < (int)listFEA_PNO.size(); i++)
    1037             :     {
    1038           0 :         const CPLString &osFEA = listFEA_PNO[i].first;
    1039           0 :         const CPLString &osPNO = listFEA_PNO[i].second;
    1040             :         const std::map<CPLString, xyPairType>::iterator itPNO =
    1041           0 :             mapPNO.find(osPNO);
    1042           0 :         if (itPNO == mapPNO.end())
    1043             :         {
    1044           0 :             CPLDebug("EDIGEO", "Cannot find PNO %s", osPNO.c_str());
    1045             :         }
    1046             :         else
    1047             :         {
    1048           0 :             OGRFeature *poFeature = CreateFeature(osFEA);
    1049           0 :             if (poFeature)
    1050             :             {
    1051           0 :                 const xyPairType &pno = itPNO->second;
    1052           0 :                 OGRPoint *poPoint = new OGRPoint(pno.first, pno.second);
    1053           0 :                 if (poSRS)
    1054           0 :                     poPoint->assignSpatialReference(poSRS);
    1055           0 :                 poFeature->SetGeometryDirectly(poPoint);
    1056             : 
    1057           0 :                 SetStyle(osFEA, poFeature);
    1058             :             }
    1059             :         }
    1060             :     }
    1061             : 
    1062           0 :     return TRUE;
    1063             : }
    1064             : 
    1065             : /************************************************************************/
    1066             : /*                        BuildLineStrings()                            */
    1067             : /************************************************************************/
    1068             : 
    1069           0 : int OGREDIGEODataSource::BuildLineStrings()
    1070             : {
    1071             :     int i, iter;
    1072             : 
    1073           0 :     for (iter = 0; iter < (int)listFEA_PAR.size(); iter++)
    1074             :     {
    1075           0 :         const CPLString &osFEA = listFEA_PAR[iter].first;
    1076           0 :         const strListType &aosPAR = listFEA_PAR[iter].second;
    1077           0 :         OGRFeature *poFeature = CreateFeature(osFEA);
    1078           0 :         if (poFeature)
    1079             :         {
    1080           0 :             OGRGeometry *poGeom = nullptr;
    1081           0 :             OGRMultiLineString *poMulti = nullptr;
    1082           0 :             for (int k = 0; k < (int)aosPAR.size(); k++)
    1083             :             {
    1084             :                 const std::map<CPLString, xyPairListType>::iterator itPAR =
    1085           0 :                     mapPAR.find(aosPAR[k]);
    1086           0 :                 if (itPAR != mapPAR.end())
    1087             :                 {
    1088           0 :                     const xyPairListType &arc = itPAR->second;
    1089             : 
    1090           0 :                     OGRLineString *poLS = new OGRLineString();
    1091           0 :                     poLS->setNumPoints((int)arc.size());
    1092           0 :                     for (i = 0; i < (int)arc.size(); i++)
    1093             :                     {
    1094           0 :                         poLS->setPoint(i, arc[i].first, arc[i].second);
    1095             :                     }
    1096             : 
    1097           0 :                     if (poGeom != nullptr)
    1098             :                     {
    1099           0 :                         if (poMulti == nullptr)
    1100             :                         {
    1101           0 :                             poMulti = new OGRMultiLineString();
    1102           0 :                             poMulti->addGeometryDirectly(poGeom);
    1103           0 :                             poGeom = poMulti;
    1104             :                         }
    1105           0 :                         poMulti->addGeometryDirectly(poLS);
    1106             :                     }
    1107             :                     else
    1108           0 :                         poGeom = poLS;
    1109             :                 }
    1110             :                 else
    1111           0 :                     CPLDebug("EDIGEO", "ERROR: Cannot find ARC %s",
    1112           0 :                              aosPAR[k].c_str());
    1113             :             }
    1114           0 :             if (poGeom != nullptr)
    1115             :             {
    1116           0 :                 poGeom->assignSpatialReference(poSRS);
    1117           0 :                 poFeature->SetGeometryDirectly(poGeom);
    1118             :             }
    1119             :         }
    1120             :     }
    1121             : 
    1122           0 :     return TRUE;
    1123             : }
    1124             : 
    1125             : /************************************************************************/
    1126             : /*                           BuildPolygon()                             */
    1127             : /************************************************************************/
    1128             : 
    1129           0 : int OGREDIGEODataSource::BuildPolygon(const CPLString &osFEA,
    1130             :                                       const strListType &aosPFE)
    1131             : {
    1132           0 :     std::vector<xyPairListType> aoXYList;
    1133             : 
    1134           0 :     for (int k = 0; k < (int)aosPFE.size(); k++)
    1135             :     {
    1136             :         const std::map<CPLString, strListType>::iterator itPFE_PAR =
    1137           0 :             mapPFE_PAR.find(aosPFE[k]);
    1138           0 :         if (itPFE_PAR == mapPFE_PAR.end())
    1139             :         {
    1140           0 :             CPLDebug("EDIGEO", "ERROR: Cannot find PFE %s", aosPFE[k].c_str());
    1141           0 :             return FALSE;
    1142             :         }
    1143             : 
    1144           0 :         const strListType &aosPARList = itPFE_PAR->second;
    1145             : 
    1146             :         /* --------------------------------------------------------------------
    1147             :          */
    1148             :         /*      Resolve arc ids to arc coordinate lists. */
    1149             :         /* --------------------------------------------------------------------
    1150             :          */
    1151           0 :         std::vector<const xyPairListType *> aoPARPtrList;
    1152           0 :         for (int i = 0; i < (int)aosPARList.size(); i++)
    1153             :         {
    1154             :             const std::map<CPLString, xyPairListType>::iterator itPAR =
    1155           0 :                 mapPAR.find(aosPARList[i]);
    1156           0 :             if (itPAR != mapPAR.end())
    1157           0 :                 aoPARPtrList.push_back(&(itPAR->second));
    1158             :             else
    1159           0 :                 CPLDebug("EDIGEO", "ERROR: Cannot find ARC %s",
    1160           0 :                          aosPARList[i].c_str());
    1161             :         }
    1162             : 
    1163           0 :         if (aoPARPtrList.empty())
    1164           0 :             return FALSE;
    1165             : 
    1166             :         /* --------------------------------------------------------------------
    1167             :          */
    1168             :         /*      Now try to chain all arcs together. */
    1169             :         /* --------------------------------------------------------------------
    1170             :          */
    1171             : 
    1172           0 :         for (int j = 0; j < (int)aoPARPtrList.size(); j++)
    1173             :         {
    1174           0 :             if (aoPARPtrList[j] == nullptr)
    1175           0 :                 continue;
    1176           0 :             const xyPairListType &sFirstRing = *(aoPARPtrList[j]);
    1177           0 :             const xyPairType *psNext = &(sFirstRing.back());
    1178             : 
    1179           0 :             xyPairListType aoXY;
    1180           0 :             for (int i = 0; i < (int)sFirstRing.size(); i++)
    1181           0 :                 aoXY.push_back(sFirstRing[i]);
    1182           0 :             aoPARPtrList[j] = nullptr;
    1183             : 
    1184           0 :             int nIter = 1;
    1185           0 :             while (aoXY.back() != aoXY[0] && nIter < (int)aoPARPtrList.size())
    1186             :             {
    1187           0 :                 bool bFound = false;
    1188           0 :                 bool bReverseSecond = false;
    1189           0 :                 int i = 0;  // Used after for.
    1190           0 :                 for (; i < (int)aoPARPtrList.size(); i++)
    1191             :                 {
    1192           0 :                     if (aoPARPtrList[i] != nullptr)
    1193             :                     {
    1194           0 :                         const xyPairListType &sSecondRing = *(aoPARPtrList[i]);
    1195           0 :                         if (*psNext == sSecondRing[0])
    1196             :                         {
    1197           0 :                             bFound = true;
    1198           0 :                             bReverseSecond = false;
    1199           0 :                             break;
    1200             :                         }
    1201           0 :                         else if (*psNext == sSecondRing.back())
    1202             :                         {
    1203           0 :                             bFound = true;
    1204           0 :                             bReverseSecond = true;
    1205           0 :                             break;
    1206             :                         }
    1207             :                     }
    1208             :                 }
    1209             : 
    1210           0 :                 if (!bFound)
    1211             :                 {
    1212           0 :                     CPLDebug("EDIGEO", "Cannot find ring for FEA %s / PFE %s",
    1213           0 :                              osFEA.c_str(), aosPFE[k].c_str());
    1214           0 :                     break;
    1215             :                 }
    1216             :                 else
    1217             :                 {
    1218           0 :                     const xyPairListType &secondRing = *(aoPARPtrList[i]);
    1219           0 :                     aoPARPtrList[i] = nullptr;
    1220           0 :                     if (!bReverseSecond)
    1221             :                     {
    1222           0 :                         for (i = 1; i < (int)secondRing.size(); i++)
    1223           0 :                             aoXY.push_back(secondRing[i]);
    1224           0 :                         psNext = &secondRing.back();
    1225             :                     }
    1226             :                     else
    1227             :                     {
    1228           0 :                         for (i = 1; i < (int)secondRing.size(); i++)
    1229           0 :                             aoXY.push_back(
    1230           0 :                                 secondRing[secondRing.size() - 1 - i]);
    1231           0 :                         psNext = &secondRing[0];
    1232             :                     }
    1233             :                 }
    1234             : 
    1235           0 :                 nIter++;
    1236             :             }
    1237             : 
    1238           0 :             aoXYList.push_back(aoXY);
    1239             :         }
    1240             :     }
    1241             : 
    1242             :     /* -------------------------------------------------------------------- */
    1243             :     /*      Create feature.                                                 */
    1244             :     /* -------------------------------------------------------------------- */
    1245           0 :     OGRFeature *poFeature = CreateFeature(osFEA);
    1246           0 :     if (poFeature)
    1247             :     {
    1248           0 :         std::vector<OGRGeometry *> aosPolygons;
    1249           0 :         for (int j = 0; j < (int)aoXYList.size(); j++)
    1250             :         {
    1251           0 :             const xyPairListType &aoXY = aoXYList[j];
    1252           0 :             OGRLinearRing *poLS = new OGRLinearRing();
    1253           0 :             poLS->setNumPoints((int)aoXY.size());
    1254           0 :             for (int i = 0; i < (int)aoXY.size(); i++)
    1255           0 :                 poLS->setPoint(i, aoXY[i].first, aoXY[i].second);
    1256           0 :             poLS->closeRings();
    1257           0 :             OGRPolygon *poPolygon = new OGRPolygon();
    1258           0 :             poPolygon->addRingDirectly(poLS);
    1259           0 :             aosPolygons.push_back(poPolygon);
    1260             :         }
    1261             : 
    1262           0 :         int bIsValidGeometry = FALSE;
    1263           0 :         OGRGeometry *poGeom = OGRGeometryFactory::organizePolygons(
    1264           0 :             &aosPolygons[0], (int)aosPolygons.size(), &bIsValidGeometry,
    1265             :             nullptr);
    1266           0 :         if (poGeom)
    1267             :         {
    1268           0 :             if (poSRS)
    1269           0 :                 poGeom->assignSpatialReference(poSRS);
    1270           0 :             poFeature->SetGeometryDirectly(poGeom);
    1271             :         }
    1272             :     }
    1273           0 :     return TRUE;
    1274             : }
    1275             : 
    1276             : /************************************************************************/
    1277             : /*                          BuildPolygons()                             */
    1278             : /************************************************************************/
    1279             : 
    1280           0 : int OGREDIGEODataSource::BuildPolygons()
    1281             : {
    1282           0 :     for (int iter = 0; iter < (int)listFEA_PFE.size(); iter++)
    1283             :     {
    1284           0 :         const CPLString &osFEA = listFEA_PFE[iter].first;
    1285           0 :         const strListType &aosPFE = listFEA_PFE[iter].second;
    1286           0 :         BuildPolygon(osFEA, aosPFE);
    1287             :     }
    1288             : 
    1289           0 :     return TRUE;
    1290             : }
    1291             : 
    1292             : /************************************************************************/
    1293             : /*                  OGREDIGEOSortForQGIS()                              */
    1294             : /************************************************************************/
    1295             : 
    1296           0 : static int OGREDIGEOSortForQGIS(const void *a, const void *b)
    1297             : {
    1298           0 :     OGREDIGEOLayer *poLayerA = *((OGREDIGEOLayer **)a);
    1299           0 :     OGREDIGEOLayer *poLayerB = *((OGREDIGEOLayer **)b);
    1300             :     int nTypeA, nTypeB;
    1301           0 :     switch (poLayerA->GetLayerDefn()->GetGeomType())
    1302             :     {
    1303           0 :         case wkbPoint:
    1304           0 :             nTypeA = 1;
    1305           0 :             break;
    1306           0 :         case wkbLineString:
    1307           0 :             nTypeA = 2;
    1308           0 :             break;
    1309           0 :         case wkbPolygon:
    1310           0 :             nTypeA = 3;
    1311           0 :             break;
    1312           0 :         default:
    1313           0 :             nTypeA = 4;
    1314           0 :             break;
    1315             :     }
    1316           0 :     switch (poLayerB->GetLayerDefn()->GetGeomType())
    1317             :     {
    1318           0 :         case wkbPoint:
    1319           0 :             nTypeB = 1;
    1320           0 :             break;
    1321           0 :         case wkbLineString:
    1322           0 :             nTypeB = 2;
    1323           0 :             break;
    1324           0 :         case wkbPolygon:
    1325           0 :             nTypeB = 3;
    1326           0 :             break;
    1327           0 :         default:
    1328           0 :             nTypeB = 4;
    1329           0 :             break;
    1330             :     }
    1331           0 :     if (nTypeA == nTypeB)
    1332             :     {
    1333           0 :         int nCmp = strcmp(poLayerA->GetName(), poLayerB->GetName());
    1334           0 :         if (nCmp == 0)
    1335           0 :             return 0;
    1336             : 
    1337             :         static const char *const apszPolyOrder[] = {
    1338             :             "COMMUNE_id",  "LIEUDIT_id",  "SECTION_id", "SUBDSECT_id",
    1339             :             "SUBDFISC_id", "PARCELLE_id", "BATIMENT_id"};
    1340           0 :         for (int i = 0; i < (int)(sizeof(apszPolyOrder) / sizeof(char *)); i++)
    1341             :         {
    1342           0 :             if (strcmp(poLayerA->GetName(), apszPolyOrder[i]) == 0)
    1343           0 :                 return -1;
    1344           0 :             if (strcmp(poLayerB->GetName(), apszPolyOrder[i]) == 0)
    1345           0 :                 return 1;
    1346             :         }
    1347           0 :         return nCmp;
    1348             :     }
    1349             :     else
    1350           0 :         return nTypeB - nTypeA;
    1351             : }
    1352             : 
    1353             : /************************************************************************/
    1354             : /*                                Open()                                */
    1355             : /************************************************************************/
    1356             : 
    1357           0 : int OGREDIGEODataSource::Open(const char *pszFilename)
    1358             : 
    1359             : {
    1360           0 :     fpTHF = VSIFOpenL(pszFilename, "rb");
    1361           0 :     if (fpTHF == nullptr)
    1362           0 :         return FALSE;
    1363             : 
    1364           0 :     const char *pszLine = nullptr;
    1365           0 :     int i = 0;
    1366           0 :     bool bIsEDIGEO = false;
    1367           0 :     while (i < 100 && (pszLine = CPLReadLine2L(fpTHF, 81, nullptr)) != nullptr)
    1368             :     {
    1369           0 :         if (strcmp(pszLine, "RTYSA03:GTS") == 0)
    1370             :         {
    1371           0 :             bIsEDIGEO = true;
    1372           0 :             break;
    1373             :         }
    1374           0 :         i++;
    1375             :     }
    1376             : 
    1377           0 :     if (!bIsEDIGEO)
    1378             :     {
    1379           0 :         VSIFCloseL(fpTHF);
    1380           0 :         fpTHF = nullptr;
    1381           0 :         return FALSE;
    1382             :     }
    1383             : 
    1384           0 :     return TRUE;
    1385             : }
    1386             : 
    1387             : /************************************************************************/
    1388             : /*                           ReadEDIGEO()                               */
    1389             : /************************************************************************/
    1390             : 
    1391           0 : void OGREDIGEODataSource::ReadEDIGEO()
    1392             : {
    1393           0 :     if (bHasReadEDIGEO)
    1394           0 :         return;
    1395             : 
    1396           0 :     bHasReadEDIGEO = TRUE;
    1397             : 
    1398             :     /* -------------------------------------------------------------------- */
    1399             :     /*      Read .THF file                                                  */
    1400             :     /* -------------------------------------------------------------------- */
    1401           0 :     VSIFSeekL(fpTHF, 0, SEEK_SET);
    1402           0 :     if (!ReadTHF(fpTHF))
    1403             :     {
    1404           0 :         VSIFCloseL(fpTHF);
    1405           0 :         fpTHF = nullptr;
    1406           0 :         return;
    1407             :     }
    1408           0 :     VSIFCloseL(fpTHF);
    1409           0 :     fpTHF = nullptr;
    1410             : 
    1411             :     /* -------------------------------------------------------------------- */
    1412             :     /*      Read .GEO file                                                  */
    1413             :     /* -------------------------------------------------------------------- */
    1414           0 :     if (!ReadGEO())
    1415           0 :         return;
    1416             : 
    1417             :     /* -------------------------------------------------------------------- */
    1418             :     /*      Read .GEN file                                                  */
    1419             :     /* -------------------------------------------------------------------- */
    1420           0 :     if (!osGNN.empty())
    1421           0 :         ReadGEN();
    1422             : 
    1423             :     /* -------------------------------------------------------------------- */
    1424             :     /*      Read .DIC file                                                  */
    1425             :     /* -------------------------------------------------------------------- */
    1426           0 :     if (!ReadDIC())
    1427           0 :         return;
    1428             : 
    1429             :     /* -------------------------------------------------------------------- */
    1430             :     /*      Read .SCD file                                                  */
    1431             :     /* -------------------------------------------------------------------- */
    1432           0 :     if (!ReadSCD())
    1433           0 :         return;
    1434             : 
    1435             :     /* -------------------------------------------------------------------- */
    1436             :     /*      Read .QAL file                                                  */
    1437             :     /* -------------------------------------------------------------------- */
    1438           0 :     if (!osQAN.empty())
    1439           0 :         ReadQAL();
    1440             : 
    1441             :     /* -------------------------------------------------------------------- */
    1442             :     /*      Create layers from SCD definitions                              */
    1443             :     /* -------------------------------------------------------------------- */
    1444           0 :     for (int i = 0; i < (int)aoObjList.size(); i++)
    1445             :     {
    1446           0 :         CreateLayerFromObjectDesc(aoObjList[i]);
    1447             :     }
    1448             : 
    1449             :     /* -------------------------------------------------------------------- */
    1450             :     /*      Read .VEC files and create features                             */
    1451             :     /* -------------------------------------------------------------------- */
    1452           0 :     for (int i = 0; i < (int)aosGDN.size(); i++)
    1453             :     {
    1454           0 :         ReadVEC(aosGDN[i]);
    1455             : 
    1456           0 :         BuildPoints();
    1457           0 :         BuildLineStrings();
    1458           0 :         BuildPolygons();
    1459             : 
    1460           0 :         mapPNO.clear();
    1461           0 :         mapPAR.clear();
    1462           0 :         mapFEA.clear();
    1463           0 :         mapPFE_PAR.clear();
    1464           0 :         listFEA_PFE.clear();
    1465           0 :         listFEA_PAR.clear();
    1466           0 :         listFEA_PNO.clear();
    1467           0 :         mapFEA_FEA.clear();
    1468             :     }
    1469             : 
    1470           0 :     mapObjects.clear();
    1471           0 :     mapAttributes.clear();
    1472           0 :     mapAttributesSCD.clear();
    1473           0 :     mapQAL.clear();
    1474             : 
    1475             :     /* -------------------------------------------------------------------- */
    1476             :     /*      Delete empty layers                                             */
    1477             :     /* -------------------------------------------------------------------- */
    1478           0 :     for (int i = 0; i < nLayers; /*nothing*/)
    1479             :     {
    1480           0 :         if (papoLayers[i]->GetFeatureCount(TRUE) == 0)
    1481             :         {
    1482           0 :             delete papoLayers[i];
    1483           0 :             if (i < nLayers - 1)
    1484           0 :                 memmove(papoLayers + i, papoLayers + i + 1,
    1485           0 :                         (nLayers - i - 1) * sizeof(OGREDIGEOLayer *));
    1486           0 :             nLayers--;
    1487             :         }
    1488             :         else
    1489           0 :             i++;
    1490             :     }
    1491             : 
    1492             :     /* -------------------------------------------------------------------- */
    1493             :     /*      When added from QGIS, the layers must be ordered from           */
    1494             :     /*      bottom (Polygon) to top (Point) to get nice visual effect       */
    1495             :     /* -------------------------------------------------------------------- */
    1496           0 :     if (CPLTestBool(CPLGetConfigOption("OGR_EDIGEO_SORT_FOR_QGIS", "YES")))
    1497           0 :         qsort(papoLayers, nLayers, sizeof(OGREDIGEOLayer *),
    1498             :               OGREDIGEOSortForQGIS);
    1499             : 
    1500             :     /* -------------------------------------------------------------------- */
    1501             :     /*      Create a label layer for each feature layer                     */
    1502             :     /* -------------------------------------------------------------------- */
    1503           0 :     if (CPLTestBool(
    1504             :             CPLGetConfigOption("OGR_EDIGEO_CREATE_LABEL_LAYERS", "YES")))
    1505           0 :         CreateLabelLayers();
    1506             : 
    1507           0 :     return;
    1508             : }
    1509             : 
    1510             : /************************************************************************/
    1511             : /*                         CreateLabelLayers()                          */
    1512             : /************************************************************************/
    1513             : 
    1514           0 : void OGREDIGEODataSource::CreateLabelLayers()
    1515             : {
    1516           0 :     OGRLayer *poLayer = GetLayerByName("ID_S_OBJ_Z_1_2_2");
    1517           0 :     if (poLayer == nullptr)
    1518           0 :         return;
    1519             : 
    1520           0 :     std::map<CPLString, OGREDIGEOLayer *> mapLayerNameToLayer;
    1521             : 
    1522           0 :     OGRFeature *poFeature = nullptr;
    1523           0 :     OGRFeatureDefn *poFeatureDefn = poLayer->GetLayerDefn();
    1524           0 :     while ((poFeature = poLayer->GetNextFeature()) != nullptr)
    1525             :     {
    1526             :         const char *pszBelongingLayerName =
    1527           0 :             poFeature->GetFieldAsString(iOBJ_LNK_LAYER);
    1528           0 :         if (pszBelongingLayerName)
    1529             :         {
    1530           0 :             CPLString osBelongingLayerName = pszBelongingLayerName;
    1531             :             std::map<CPLString, OGREDIGEOLayer *>::iterator it =
    1532           0 :                 mapLayerNameToLayer.find(osBelongingLayerName);
    1533           0 :             OGREDIGEOLayer *poLabelLayer = nullptr;
    1534             : 
    1535           0 :             if (it == mapLayerNameToLayer.end())
    1536             :             {
    1537             :                 /* Create label layer if it does not already exist */
    1538           0 :                 CPLString osLayerLabelName = osBelongingLayerName + "_LABEL";
    1539           0 :                 poLabelLayer = new OGREDIGEOLayer(
    1540           0 :                     this, osLayerLabelName.c_str(), wkbPoint, poSRS);
    1541             :                 OGRFeatureDefn *poLabelFeatureDefn =
    1542           0 :                     poLabelLayer->GetLayerDefn();
    1543           0 :                 for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
    1544           0 :                     poLabelFeatureDefn->AddFieldDefn(
    1545           0 :                         poFeatureDefn->GetFieldDefn(i));
    1546           0 :                 mapLayerNameToLayer[osBelongingLayerName] = poLabelLayer;
    1547             : 
    1548           0 :                 papoLayers = (OGRLayer **)CPLRealloc(
    1549           0 :                     papoLayers, (nLayers + 1) * sizeof(OGRLayer *));
    1550           0 :                 papoLayers[nLayers] = poLabelLayer;
    1551           0 :                 nLayers++;
    1552             :             }
    1553             :             else
    1554             :             {
    1555           0 :                 poLabelLayer = mapLayerNameToLayer[osBelongingLayerName];
    1556             :             }
    1557             : 
    1558             :             OGRFeature *poNewFeature =
    1559           0 :                 new OGRFeature(poLabelLayer->GetLayerDefn());
    1560           0 :             poNewFeature->SetFrom(poFeature);
    1561           0 :             poLabelLayer->AddFeature(poNewFeature);
    1562             :         }
    1563           0 :         delete poFeature;
    1564             :     }
    1565             : 
    1566           0 :     poLayer->ResetReading();
    1567             : }

Generated by: LCOV version 1.14