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

Generated by: LCOV version 1.14