LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sxf - ogrsxfdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 365 619 59.0 %
Date: 2024-04-27 17:22:41 Functions: 15 15 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SXF Translator
       4             :  * Purpose:  Definition of classes for OGR SXF Datasource.
       5             :  * Author:   Ben Ahmed Daho Ali, bidandou(at)yahoo(dot)fr
       6             :  *           Dmitry Baryshnikov, polimax@mail.ru
       7             :  *           Alexandr Lisovenko, alexander.lisovenko@gmail.com
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2011, Ben Ahmed Daho Ali
      11             :  * Copyright (c) 2013, NextGIS
      12             :  * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
      13             :  * Copyright (c) 2019, NextGIS, <info@nextgis.com>
      14             :  *
      15             :  * Permission is hereby granted, free of charge, to any person obtaining a
      16             :  * copy of this software and associated documentation files (the "Software"),
      17             :  * to deal in the Software without restriction, including without limitation
      18             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      19             :  * and/or sell copies of the Software, and to permit persons to whom the
      20             :  * Software is furnished to do so, subject to the following conditions:
      21             :  *
      22             :  * The above copyright notice and this permission notice shall be included
      23             :  * in all copies or substantial portions of the Software.
      24             :  *
      25             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      26             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      27             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      28             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      29             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      30             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      31             :  * DEALINGS IN THE SOFTWARE.
      32             :  ****************************************************************************/
      33             : 
      34             : #include "cpl_conv.h"
      35             : #include "ogr_sxf.h"
      36             : #include "cpl_string.h"
      37             : #include "cpl_multiproc.h"
      38             : 
      39             : #include <math.h>
      40             : #include <map>
      41             : #include <string>
      42             : 
      43             : // EPSG code range http://gis.stackexchange.com/a/18676/9904
      44             : constexpr int MIN_EPSG = 1000;
      45             : constexpr int MAX_EPSG = 32768;
      46             : 
      47             : /************************************************************************/
      48             : /*                         OGRSXFDataSource()                           */
      49             : /************************************************************************/
      50             : 
      51           6 : OGRSXFDataSource::OGRSXFDataSource()
      52             : {
      53           6 :     memset(&oSXFPassport.informationFlags, 0,
      54             :            sizeof(oSXFPassport.informationFlags));
      55           6 : }
      56             : 
      57             : /************************************************************************/
      58             : /*                          ~OGRSXFDataSource()                         */
      59             : /************************************************************************/
      60             : 
      61          12 : OGRSXFDataSource::~OGRSXFDataSource()
      62             : 
      63             : {
      64           6 :     m_apoLayers.clear();
      65             : 
      66           6 :     if (nullptr != oSXFPassport.stMapDescription.pSpatRef)
      67             :     {
      68           5 :         oSXFPassport.stMapDescription.pSpatRef->Release();
      69             :     }
      70             : 
      71           6 :     CloseFile();
      72             : 
      73           6 :     if (hIOMutex != nullptr)
      74             :     {
      75           1 :         CPLDestroyMutex(hIOMutex);
      76           1 :         hIOMutex = nullptr;
      77             :     }
      78          12 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                     CloseFile()                                      */
      82             : /************************************************************************/
      83           6 : void OGRSXFDataSource::CloseFile()
      84             : {
      85           6 :     if (nullptr != fpSXF)
      86             :     {
      87           5 :         VSIFCloseL(fpSXF);
      88           5 :         fpSXF = nullptr;
      89             :     }
      90           6 : }
      91             : 
      92             : /************************************************************************/
      93             : /*                           TestCapability()                           */
      94             : /************************************************************************/
      95             : 
      96          39 : int OGRSXFDataSource::TestCapability(const char *pszCap)
      97             : {
      98          39 :     if (EQUAL(pszCap, ODsCZGeometries))
      99          18 :         return true;
     100             : 
     101          21 :     return false;
     102             : }
     103             : 
     104             : /************************************************************************/
     105             : /*                              GetLayer()                              */
     106             : /************************************************************************/
     107             : 
     108         942 : OGRLayer *OGRSXFDataSource::GetLayer(int iLayer)
     109             : 
     110             : {
     111         942 :     if (iLayer < 0 || iLayer >= GetLayerCount())
     112           2 :         return nullptr;
     113             :     else
     114         940 :         return m_apoLayers[iLayer].get();
     115             : }
     116             : 
     117             : /************************************************************************/
     118             : /*                                Open()                                */
     119             : /************************************************************************/
     120             : 
     121           6 : int OGRSXFDataSource::Open(const char *pszFilename, bool bUpdateIn,
     122             :                            const char *const *papszOpenOpts)
     123             : {
     124           6 :     if (bUpdateIn)
     125             :     {
     126           1 :         return FALSE;
     127             :     }
     128             : 
     129           5 :     pszName = pszFilename;
     130             : 
     131           5 :     fpSXF = VSIFOpenL(pszName, "rb");
     132           5 :     if (fpSXF == nullptr)
     133             :     {
     134           0 :         CPLError(CE_Warning, CPLE_OpenFailed, "SXF open file %s failed",
     135             :                  pszFilename);
     136           0 :         return FALSE;
     137             :     }
     138             : 
     139             :     // read header
     140           5 :     const int nFileHeaderSize = sizeof(SXFHeader);
     141             :     SXFHeader stSXFFileHeader;
     142             :     const size_t nObjectsRead =
     143           5 :         VSIFReadL(&stSXFFileHeader, nFileHeaderSize, 1, fpSXF);
     144             : 
     145           5 :     if (nObjectsRead != 1)
     146             :     {
     147           0 :         CPLError(CE_Failure, CPLE_None, "SXF head read failed");
     148           0 :         CloseFile();
     149           0 :         return FALSE;
     150             :     }
     151           5 :     CPL_LSBPTR32(&(stSXFFileHeader.nHeaderLength));
     152           5 :     CPL_LSBPTR32(&(stSXFFileHeader.nCheckSum));
     153             : 
     154             :     // check version
     155           5 :     oSXFPassport.version = 0;
     156           5 :     if (stSXFFileHeader.nHeaderLength > 256)  // if size == 400 then version >=
     157             :                                               // 4
     158             :     {
     159           5 :         oSXFPassport.version = stSXFFileHeader.nFormatVersion[2];
     160             :     }
     161             :     else
     162             :     {
     163           0 :         oSXFPassport.version = stSXFFileHeader.nFormatVersion[1];
     164             :     }
     165             : 
     166           5 :     if (oSXFPassport.version < 3)
     167             :     {
     168           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     169             :                  "SXF File version not supported");
     170           0 :         CloseFile();
     171           0 :         return FALSE;
     172             :     }
     173             : 
     174             :     // read description
     175           5 :     if (ReadSXFDescription(fpSXF, oSXFPassport) != OGRERR_NONE)
     176             :     {
     177           0 :         CPLError(CE_Failure, CPLE_NotSupported, "SXF. Wrong description.");
     178           0 :         CloseFile();
     179           0 :         return FALSE;
     180             :     }
     181             : 
     182             :     // read flags
     183           5 :     if (ReadSXFInformationFlags(fpSXF, oSXFPassport) != OGRERR_NONE)
     184             :     {
     185           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     186             :                  "SXF. Wrong state of the data.");
     187           0 :         CloseFile();
     188           0 :         return FALSE;
     189             :     }
     190             : 
     191           5 :     if (oSXFPassport.version == 3 &&
     192           0 :         oSXFPassport.informationFlags.bProjectionDataCompliance == false)
     193             :     {
     194           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     195             :                  "SXF. Data does not correspond to the projection.");
     196           0 :         CloseFile();
     197           0 :         return FALSE;
     198             :     }
     199             : 
     200             :     // read spatial data
     201           5 :     if (ReadSXFMapDescription(fpSXF, oSXFPassport, papszOpenOpts) !=
     202             :         OGRERR_NONE)
     203             :     {
     204           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     205             :                  "SXF. Wrong state of the data.");
     206           0 :         CloseFile();
     207           0 :         return FALSE;
     208             :     }
     209             : 
     210           5 :     if (oSXFPassport.informationFlags.bRealCoordinatesCompliance == false)
     211             :     {
     212           5 :         CPLError(CE_Warning, CPLE_NotSupported,
     213             :                  "SXF. Given material may be rotated in the conditional system "
     214             :                  "of coordinates");
     215             :     }
     216             : 
     217             :     /*---------------- TRY READ THE RSC FILE HEADER  -----------------------*/
     218             : 
     219           5 :     CPLString soRSCRileName;
     220             :     const char *pszRSCRileName =
     221           5 :         CSLFetchNameValueDef(papszOpenOpts, "SXF_RSC_FILENAME",
     222             :                              CPLGetConfigOption("SXF_RSC_FILENAME", ""));
     223          10 :     if (pszRSCRileName != nullptr &&
     224           5 :         CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
     225             :     {
     226           1 :         soRSCRileName = pszRSCRileName;
     227             :     }
     228             : 
     229           5 :     if (soRSCRileName.empty())
     230             :     {
     231           4 :         pszRSCRileName = CPLResetExtension(pszFilename, "rsc");
     232           4 :         if (CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
     233             :         {
     234           0 :             soRSCRileName = pszRSCRileName;
     235             :         }
     236             :     }
     237             : 
     238           5 :     if (soRSCRileName.empty())
     239             :     {
     240           4 :         pszRSCRileName = CPLResetExtension(pszFilename, "RSC");
     241           4 :         if (CPLCheckForFile((char *)pszRSCRileName, nullptr) == TRUE)
     242             :         {
     243           0 :             soRSCRileName = pszRSCRileName;
     244             :         }
     245             :     }
     246             : 
     247             :     // 1. Create layers from RSC file or create default set of layers from
     248             :     // gdal_data/default.rsc.
     249             : 
     250           5 :     if (soRSCRileName.empty())
     251             :     {
     252           4 :         pszRSCRileName = CPLFindFile("gdal", "default.rsc");
     253           4 :         if (nullptr != pszRSCRileName)
     254             :         {
     255           4 :             soRSCRileName = pszRSCRileName;
     256             :         }
     257             :         else
     258             :         {
     259           0 :             CPLDebug("OGRSXFDataSource", "Default RSC file not found");
     260             :         }
     261             :     }
     262             : 
     263           5 :     if (soRSCRileName.empty())
     264             :     {
     265           0 :         CPLError(CE_Warning, CPLE_None, "RSC file for %s not exist",
     266             :                  pszFilename);
     267             :     }
     268             :     else
     269             :     {
     270           5 :         VSILFILE *fpRSC = VSIFOpenL(soRSCRileName, "rb");
     271           5 :         if (fpRSC == nullptr)
     272             :         {
     273           0 :             CPLError(CE_Warning, CPLE_OpenFailed, "RSC file %s open failed",
     274             :                      soRSCRileName.c_str());
     275             :         }
     276             :         else
     277             :         {
     278           5 :             CPLDebug("OGRSXFDataSource", "RSC Filename: %s",
     279             :                      soRSCRileName.c_str());
     280           5 :             CreateLayers(fpRSC, papszOpenOpts);
     281           5 :             VSIFCloseL(fpRSC);
     282             :         }
     283             :     }
     284             : 
     285           5 :     if (m_apoLayers.empty())  // create default set of layers
     286             :     {
     287           1 :         CreateLayers();
     288             :     }
     289             : 
     290           5 :     FillLayers();
     291             : 
     292           5 :     return TRUE;
     293             : }
     294             : 
     295           5 : OGRErr OGRSXFDataSource::ReadSXFDescription(VSILFILE *fpSXFIn,
     296             :                                             SXFPassport &passport)
     297             : {
     298             :     // int nObjectsRead = 0;
     299             : 
     300           5 :     if (passport.version == 3)
     301             :     {
     302             :         // 78
     303             :         GByte buff[62];
     304           0 :         /* nObjectsRead = */ VSIFReadL(&buff, 62, 1, fpSXFIn);
     305           0 :         char date[3] = {0};
     306             : 
     307             :         // read year
     308           0 :         memcpy(date, buff, 2);
     309           0 :         passport.dtCrateDate.nYear = static_cast<GUInt16>(atoi(date));
     310           0 :         if (passport.dtCrateDate.nYear < 50)
     311           0 :             passport.dtCrateDate.nYear += 2000;
     312             :         else
     313           0 :             passport.dtCrateDate.nYear += 1900;
     314             : 
     315           0 :         memcpy(date, buff + 2, 2);
     316             : 
     317           0 :         passport.dtCrateDate.nMonth = static_cast<GUInt16>(atoi(date));
     318             : 
     319           0 :         memcpy(date, buff + 4, 2);
     320             : 
     321           0 :         passport.dtCrateDate.nDay = static_cast<GUInt16>(atoi(date));
     322             : 
     323           0 :         char szName[26] = {0};
     324           0 :         memcpy(szName, buff + 8, 24);
     325           0 :         szName[sizeof(szName) - 1] = '\0';
     326             :         char *pszRecoded =
     327           0 :             CPLRecode(szName, "CP1251", CPL_ENC_UTF8);  // szName + 2
     328             :         passport.sMapSheet =
     329           0 :             pszRecoded;  // TODO: check the encoding in SXF created in Linux
     330           0 :         CPLFree(pszRecoded);
     331             : 
     332           0 :         memcpy(&passport.nScale, buff + 32, 4);
     333           0 :         CPL_LSBPTR32(&passport.nScale);
     334             : 
     335           0 :         memcpy(szName, buff + 36, 26);
     336           0 :         szName[sizeof(szName) - 1] = '\0';
     337           0 :         pszRecoded = CPLRecode(szName, "CP866", CPL_ENC_UTF8);
     338             :         passport.sMapSheetName =
     339           0 :             pszRecoded;  // TODO: check the encoding in SXF created in Linux
     340           0 :         CPLFree(pszRecoded);
     341             :     }
     342           5 :     else if (passport.version == 4)
     343             :     {
     344             :         // 96
     345             :         GByte buff[80];
     346           5 :         /* nObjectsRead = */ VSIFReadL(&buff, 80, 1, fpSXFIn);
     347           5 :         char date[5] = {0};
     348             : 
     349             :         // read year
     350           5 :         memcpy(date, buff, 4);
     351           5 :         passport.dtCrateDate.nYear = static_cast<GUInt16>(atoi(date));
     352             : 
     353           5 :         memcpy(date, buff + 4, 2);
     354           5 :         memset(date + 2, 0, 3);
     355             : 
     356           5 :         passport.dtCrateDate.nMonth = static_cast<GUInt16>(atoi(date));
     357             : 
     358           5 :         memcpy(date, buff + 6, 2);
     359             : 
     360           5 :         passport.dtCrateDate.nDay = static_cast<GUInt16>(atoi(date));
     361             : 
     362           5 :         char szName[32] = {0};
     363           5 :         memcpy(szName, buff + 12, 32);
     364           5 :         szName[sizeof(szName) - 1] = '\0';
     365             :         char *pszRecoded =
     366           5 :             CPLRecode(szName, "CP1251", CPL_ENC_UTF8);  // szName + 2
     367             :         passport.sMapSheet =
     368           5 :             pszRecoded;  // TODO: check the encoding in SXF created in Linux
     369           5 :         CPLFree(pszRecoded);
     370             : 
     371           5 :         memcpy(&passport.nScale, buff + 44, 4);
     372           5 :         CPL_LSBPTR32(&passport.nScale);
     373             : 
     374           5 :         memcpy(szName, buff + 48, 32);
     375           5 :         szName[sizeof(szName) - 1] = '\0';
     376           5 :         pszRecoded = CPLRecode(szName, "CP1251", CPL_ENC_UTF8);
     377             :         passport.sMapSheetName =
     378           5 :             pszRecoded;  // TODO: check the encoding in SXF created in Linux
     379           5 :         CPLFree(pszRecoded);
     380             :     }
     381             : 
     382           5 :     SetMetadataItem("SHEET", passport.sMapSheet);
     383           5 :     SetMetadataItem("SHEET_NAME", passport.sMapSheetName);
     384           5 :     SetMetadataItem("SHEET_CREATE_DATE",
     385           5 :                     CPLSPrintf("%.2u-%.2u-%.4u", passport.dtCrateDate.nDay,
     386           5 :                                passport.dtCrateDate.nMonth,
     387           5 :                                passport.dtCrateDate.nYear));
     388           5 :     SetMetadataItem("SXF_VERSION", CPLSPrintf("%u", passport.version));
     389           5 :     SetMetadataItem("SCALE", CPLSPrintf("1 : %u", passport.nScale));
     390             : 
     391           5 :     return OGRERR_NONE;
     392             : }
     393             : 
     394           5 : OGRErr OGRSXFDataSource::ReadSXFInformationFlags(VSILFILE *fpSXFIn,
     395             :                                                  SXFPassport &passport)
     396             : {
     397             :     // int nObjectsRead = 0;
     398             :     GByte val[4];
     399           5 :     /* nObjectsRead = */ VSIFReadL(&val, 4, 1, fpSXFIn);
     400             : 
     401           5 :     if (!(CHECK_BIT(val[0], 0) && CHECK_BIT(val[0], 1)))  // xxxxxx11
     402             :     {
     403           0 :         return OGRERR_UNSUPPORTED_OPERATION;
     404             :     }
     405             : 
     406           5 :     if (CHECK_BIT(val[0], 2))  // xxxxx0xx or xxxxx1xx
     407             :     {
     408           5 :         passport.informationFlags.bProjectionDataCompliance = true;
     409             :     }
     410             :     else
     411             :     {
     412           0 :         passport.informationFlags.bProjectionDataCompliance = false;
     413             :     }
     414             : 
     415           5 :     if (CHECK_BIT(val[0], 4))
     416             :     {
     417           0 :         passport.informationFlags.bRealCoordinatesCompliance = true;
     418             :     }
     419             :     else
     420             :     {
     421           5 :         passport.informationFlags.bRealCoordinatesCompliance = false;
     422             :     }
     423             : 
     424           5 :     if (CHECK_BIT(val[0], 6))
     425             :     {
     426           0 :         passport.informationFlags.stCodingType = SXF_SEM_TXT;
     427             :     }
     428             :     else
     429             :     {
     430           5 :         if (CHECK_BIT(val[0], 5))
     431             :         {
     432           0 :             passport.informationFlags.stCodingType = SXF_SEM_HEX;
     433             :         }
     434             :         else
     435             :         {
     436           5 :             passport.informationFlags.stCodingType = SXF_SEM_DEC;
     437             :         }
     438             :     }
     439             : 
     440           5 :     if (CHECK_BIT(val[0], 7))
     441             :     {
     442           0 :         passport.informationFlags.stGenType = SXF_GT_LARGE_SCALE;
     443             :     }
     444             :     else
     445             :     {
     446           5 :         passport.informationFlags.stGenType = SXF_GT_SMALL_SCALE;
     447             :     }
     448             : 
     449             :     // version specific
     450             : 
     451           5 :     if (passport.version == 3)
     452             :     {
     453             :         // degrees are ints * 100 000 000
     454             :         // meters are ints / 10
     455           0 :         passport.informationFlags.stEnc = SXF_ENC_DOS;
     456           0 :         passport.informationFlags.stCoordAcc = SXF_COORD_ACC_DM;
     457           0 :         passport.informationFlags.bSort = false;
     458             :     }
     459           5 :     else if (passport.version == 4)
     460             :     {
     461           5 :         if (val[1] <= SXF_ENC_LAST)
     462             :         {
     463           5 :             passport.informationFlags.stEnc =
     464           5 :                 static_cast<SXFTextEncoding>(val[1]);
     465             :         }
     466             :         else
     467             :         {
     468           0 :             CPLDebug("SXF",
     469             :                      "Invalid passport.informationFlags.stEnc = %d. "
     470             :                      "Defaulting to SXF_ENC_DOS",
     471           0 :                      val[1]);
     472           0 :             passport.informationFlags.stEnc = SXF_ENC_DOS;
     473             :         }
     474             : 
     475           5 :         if (val[2] <= SXF_COORD_ACC_LAST)
     476             :         {
     477           5 :             passport.informationFlags.stCoordAcc =
     478           5 :                 static_cast<SXFCoordinatesAccuracy>(val[2]);
     479             :         }
     480             :         else
     481             :         {
     482           0 :             CPLDebug("SXF",
     483             :                      "Invalid passport.informationFlags.stCoordAcc = %d. "
     484             :                      "Defaulting to SXF_COORD_ACC_UNDEFINED",
     485           0 :                      val[1]);
     486           0 :             passport.informationFlags.stCoordAcc = SXF_COORD_ACC_UNDEFINED;
     487             :         }
     488             : 
     489           5 :         if (CHECK_BIT(val[3], 0))
     490             :         {
     491           0 :             passport.informationFlags.bSort = true;
     492             :         }
     493             :         else
     494             :         {
     495           5 :             passport.informationFlags.bSort = false;
     496             :         }
     497             :     }
     498             : 
     499           5 :     return OGRERR_NONE;
     500             : }
     501             : 
     502           5 : void OGRSXFDataSource::SetVertCS(const long iVCS, SXFPassport &passport,
     503             :                                  const char *const *papszOpenOpts)
     504             : {
     505             :     const char *pszSetVertCS =
     506           5 :         CSLFetchNameValueDef(papszOpenOpts, "SXF_SET_VERTCS",
     507             :                              CPLGetConfigOption("SXF_SET_VERTCS", "NO"));
     508           5 :     if (!CPLTestBool(pszSetVertCS))
     509           5 :         return;
     510             : 
     511           0 :     passport.stMapDescription.pSpatRef->importVertCSFromPanorama(
     512             :         static_cast<int>(iVCS));
     513             : }
     514             : 
     515           5 : OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE *fpSXFIn,
     516             :                                                SXFPassport &passport,
     517             :                                                const char *const *papszOpenOpts)
     518             : {
     519             :     // int nObjectsRead = 0;
     520           5 :     passport.stMapDescription.Env.MaxX = -100000000;
     521           5 :     passport.stMapDescription.Env.MinX = 100000000;
     522           5 :     passport.stMapDescription.Env.MaxY = -100000000;
     523           5 :     passport.stMapDescription.Env.MinY = 100000000;
     524             : 
     525           5 :     bool bIsX = true;  // passport.informationFlags.bRealCoordinatesCompliance;
     526             :                        // //if real coordinates we need to swap x & y
     527             : 
     528             :     // version specific
     529           5 :     if (passport.version == 3)
     530             :     {
     531             :         short nNoObjClass, nNoSemClass;
     532           0 :         if (VSIFReadL(&nNoObjClass, 2, 1, fpSXFIn) != 1)
     533           0 :             return OGRERR_FAILURE;
     534           0 :         if (VSIFReadL(&nNoSemClass, 2, 1, fpSXFIn) != 1)
     535           0 :             return OGRERR_FAILURE;
     536             :         GByte byMask[8];
     537           0 :         if (VSIFReadL(&byMask, 8, 1, fpSXFIn) != 1)
     538           0 :             return OGRERR_FAILURE;
     539             : 
     540             :         int nCorners[8];
     541             : 
     542             :         // get projected corner coords
     543           0 :         if (VSIFReadL(&nCorners, 32, 1, fpSXFIn) != 1)
     544           0 :             return OGRERR_FAILURE;
     545             : 
     546           0 :         for (int i = 0; i < 8; i++)
     547             :         {
     548           0 :             CPL_LSBPTR32(&nCorners[i]);
     549           0 :             passport.stMapDescription.stProjCoords[i] =
     550           0 :                 double(nCorners[i]) / 10.0;
     551           0 :             if (bIsX)  // X
     552             :             {
     553           0 :                 if (passport.stMapDescription.Env.MaxY <
     554           0 :                     passport.stMapDescription.stProjCoords[i])
     555           0 :                     passport.stMapDescription.Env.MaxY =
     556           0 :                         passport.stMapDescription.stProjCoords[i];
     557           0 :                 if (passport.stMapDescription.Env.MinY >
     558           0 :                     passport.stMapDescription.stProjCoords[i])
     559           0 :                     passport.stMapDescription.Env.MinY =
     560           0 :                         passport.stMapDescription.stProjCoords[i];
     561             :             }
     562             :             else
     563             :             {
     564           0 :                 if (passport.stMapDescription.Env.MaxX <
     565           0 :                     passport.stMapDescription.stProjCoords[i])
     566           0 :                     passport.stMapDescription.Env.MaxX =
     567           0 :                         passport.stMapDescription.stProjCoords[i];
     568           0 :                 if (passport.stMapDescription.Env.MinX >
     569           0 :                     passport.stMapDescription.stProjCoords[i])
     570           0 :                     passport.stMapDescription.Env.MinX =
     571           0 :                         passport.stMapDescription.stProjCoords[i];
     572             :             }
     573           0 :             bIsX = !bIsX;
     574             :         }
     575             :         // get geographic corner coords
     576           0 :         if (VSIFReadL(&nCorners, 32, 1, fpSXFIn) != 1)
     577           0 :             return OGRERR_FAILURE;
     578             : 
     579           0 :         for (int i = 0; i < 8; i++)
     580             :         {
     581           0 :             CPL_LSBPTR32(&nCorners[i]);
     582           0 :             passport.stMapDescription.stGeoCoords[i] =
     583           0 :                 double(nCorners[i]) *
     584             :                 0.00000057295779513082;  // from radians to degree * 100 000 000
     585             :         }
     586             :     }
     587           5 :     else if (passport.version == 4)
     588             :     {
     589           5 :         int nEPSG = 0;
     590           5 :         if (VSIFReadL(&nEPSG, 4, 1, fpSXFIn) != 1)
     591           0 :             return OGRERR_FAILURE;
     592           5 :         CPL_LSBPTR32(&nEPSG);
     593             : 
     594           5 :         if (nEPSG >= MIN_EPSG &&
     595           0 :             nEPSG <= MAX_EPSG)  // TODO: check epsg valid range
     596             :         {
     597           0 :             passport.stMapDescription.pSpatRef = new OGRSpatialReference();
     598           0 :             passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
     599             :         }
     600             : 
     601             :         double dfCorners[8];
     602           5 :         if (VSIFReadL(&dfCorners, 64, 1, fpSXFIn) != 1)
     603           0 :             return OGRERR_FAILURE;
     604             : 
     605          45 :         for (int i = 0; i < 8; i++)
     606             :         {
     607          40 :             CPL_LSBPTR64(&dfCorners[i]);
     608          40 :             passport.stMapDescription.stProjCoords[i] = dfCorners[i];
     609          40 :             if (bIsX)  // X
     610             :             {
     611          20 :                 if (passport.stMapDescription.Env.MaxY <
     612          20 :                     passport.stMapDescription.stProjCoords[i])
     613          10 :                     passport.stMapDescription.Env.MaxY =
     614          10 :                         passport.stMapDescription.stProjCoords[i];
     615          20 :                 if (passport.stMapDescription.Env.MinY >
     616          20 :                     passport.stMapDescription.stProjCoords[i])
     617          10 :                     passport.stMapDescription.Env.MinY =
     618          10 :                         passport.stMapDescription.stProjCoords[i];
     619             :             }
     620             :             else
     621             :             {
     622          20 :                 if (passport.stMapDescription.Env.MaxX <
     623          20 :                     passport.stMapDescription.stProjCoords[i])
     624          15 :                     passport.stMapDescription.Env.MaxX =
     625          15 :                         passport.stMapDescription.stProjCoords[i];
     626          20 :                 if (passport.stMapDescription.Env.MinX >
     627          20 :                     passport.stMapDescription.stProjCoords[i])
     628           5 :                     passport.stMapDescription.Env.MinX =
     629           5 :                         passport.stMapDescription.stProjCoords[i];
     630             :             }
     631          40 :             bIsX = !bIsX;
     632             :         }
     633             :         // get geographic corner coords
     634           5 :         if (VSIFReadL(&dfCorners, 64, 1, fpSXFIn) != 1)
     635           0 :             return OGRERR_FAILURE;
     636             : 
     637          45 :         for (int i = 0; i < 8; i++)
     638             :         {
     639          40 :             CPL_LSBPTR64(&dfCorners[i]);
     640          40 :             passport.stMapDescription.stGeoCoords[i] =
     641          40 :                 dfCorners[i] * TO_DEGREES;  // to degree
     642             :         }
     643             :     }
     644             : 
     645           5 :     if (nullptr != passport.stMapDescription.pSpatRef)
     646             :     {
     647           0 :         return OGRERR_NONE;
     648             :     }
     649             : 
     650           5 :     GByte anData[8] = {0};
     651           5 :     if (VSIFReadL(&anData, 8, 1, fpSXFIn) != 1)
     652           0 :         return OGRERR_FAILURE;
     653           5 :     long iEllips = anData[0];
     654           5 :     long iVCS = anData[1];
     655           5 :     long iProjSys = anData[2];
     656             :     /* long iDatum = anData[3]; Unused. */
     657           5 :     double dfProjScale = 1;
     658             : 
     659           5 :     double adfPrjParams[8] = {0};
     660             : 
     661           5 :     if (passport.version == 3)
     662             :     {
     663           0 :         switch (anData[4])
     664             :         {
     665           0 :             case 1:
     666           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DECIMETRE;
     667           0 :                 break;
     668           0 :             case 2:
     669           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_CENTIMETRE;
     670           0 :                 break;
     671           0 :             case 3:
     672           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_MILLIMETRE;
     673           0 :                 break;
     674           0 :             case 130:
     675           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_RADIAN;
     676           0 :                 break;
     677           0 :             case 129:
     678           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DEGREE;
     679           0 :                 break;
     680           0 :             default:
     681           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_METRE;
     682           0 :                 break;
     683             :         }
     684             : 
     685           0 :         VSIFSeekL(fpSXFIn, 212, SEEK_SET);
     686             : 
     687             :         struct _buff
     688             :         {
     689             :             GUInt32 nRes;
     690             :             GInt16 anFrame[8];
     691             :             // cppcheck-suppress unusedStructMember
     692             :             GUInt32 nFrameCode;
     693             :         } buff;
     694             : 
     695           0 :         if (VSIFReadL(&buff, 20, 1, fpSXFIn) != 1)
     696           0 :             return OGRERR_FAILURE;
     697           0 :         CPL_LSBPTR32(&buff.nRes);
     698           0 :         CPL_LSBPTR32(&buff.nFrameCode);
     699           0 :         passport.stMapDescription.nResolution = buff.nRes;  // resolution
     700             : 
     701           0 :         for (int i = 0; i < 8; i++)
     702             :         {
     703           0 :             CPL_LSBPTR16(&(buff.anFrame[i]));
     704           0 :             passport.stMapDescription.stFrameCoords[i] = buff.anFrame[i];
     705             :         }
     706             : 
     707             :         int anParams[5];
     708           0 :         if (VSIFReadL(&anParams, 20, 1, fpSXFIn) != 1)
     709           0 :             return OGRERR_FAILURE;
     710           0 :         for (int i = 0; i < 5; i++)
     711             :         {
     712           0 :             CPL_LSBPTR32(&anParams[i]);
     713             :         }
     714             : 
     715           0 :         if (anParams[0] != -1)
     716           0 :             dfProjScale = double(anParams[0]) / 100000000.0;
     717             : 
     718           0 :         if (anParams[2] != -1)
     719           0 :             passport.stMapDescription.dfXOr =
     720           0 :                 double(anParams[2]) / 100000000.0 * TO_DEGREES;
     721             :         else
     722           0 :             passport.stMapDescription.dfXOr = 0;
     723             : 
     724           0 :         if (anParams[3] != -1)
     725           0 :             passport.stMapDescription.dfYOr =
     726           0 :                 double(anParams[2]) / 100000000.0 * TO_DEGREES;
     727             :         else
     728           0 :             passport.stMapDescription.dfYOr = 0;
     729             : 
     730           0 :         passport.stMapDescription.dfFalseNorthing = 0;
     731           0 :         passport.stMapDescription.dfFalseEasting = 0;
     732             : 
     733             :         // adfPrjParams[0] = double(anParams[0]) / 100000000.0; // to radians
     734             :         // adfPrjParams[1] = double(anParams[1]) / 100000000.0;
     735             :         // adfPrjParams[2] = double(anParams[2]) / 100000000.0;
     736             :         // adfPrjParams[3] = double(anParams[3]) / 100000000.0;
     737           0 :         adfPrjParams[4] = dfProjScale;  //?
     738             :         // adfPrjParams[5] = 0;//?
     739             :         // adfPrjParams[6] = 0;//?
     740             :         // adfPrjParams[7] = 0;// importFromPanorama calc it by itself
     741             :     }
     742           5 :     else if (passport.version == 4)
     743             :     {
     744           5 :         switch (anData[4])
     745             :         {
     746           0 :             case 64:
     747           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_RADIAN;
     748           0 :                 break;
     749           0 :             case 65:
     750           0 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_DEGREE;
     751           0 :                 break;
     752           5 :             default:
     753           5 :                 passport.stMapDescription.eUnitInPlan = SXF_COORD_MU_METRE;
     754           5 :                 break;
     755             :         }
     756             : 
     757           5 :         VSIFSeekL(fpSXFIn, 312, SEEK_SET);
     758             :         GUInt32 buff[10];
     759           5 :         if (VSIFReadL(&buff, 40, 1, fpSXFIn) != 1)
     760           0 :             return OGRERR_FAILURE;
     761          55 :         for (int i = 0; i < 10; i++)
     762             :         {
     763          50 :             CPL_LSBPTR32(&buff[i]);
     764             :         }
     765             : 
     766           5 :         passport.stMapDescription.nResolution = buff[0];  // resolution
     767          45 :         for (int i = 0; i < 8; i++)
     768          40 :             passport.stMapDescription.stFrameCoords[i] = buff[1 + i];
     769             : 
     770           5 :         double adfParams[6] = {};
     771           5 :         if (VSIFReadL(&adfParams, 48, 1, fpSXFIn) != 1)
     772           0 :             return OGRERR_FAILURE;
     773          35 :         for (int i = 0; i < 6; i++)
     774             :         {
     775          30 :             CPL_LSBPTR64(&adfParams[i]);
     776             :         }
     777             : 
     778           5 :         if (adfParams[1] != -1)
     779           5 :             dfProjScale = adfParams[1];
     780           5 :         passport.stMapDescription.dfXOr = adfParams[2] * TO_DEGREES;
     781           5 :         passport.stMapDescription.dfYOr = adfParams[3] * TO_DEGREES;
     782           5 :         passport.stMapDescription.dfFalseNorthing = adfParams[4];
     783           5 :         passport.stMapDescription.dfFalseEasting = adfParams[5];
     784             : 
     785             :         // adfPrjParams[0] = adfParams[0]; // to radians
     786             :         // adfPrjParams[1] = adfParams[1];
     787             :         // adfPrjParams[2] = adfParams[2];
     788             :         // adfPrjParams[3] = adfParams[3];
     789           5 :         adfPrjParams[4] = dfProjScale;  //?
     790             :         // adfPrjParams[5] = adfParams[4];
     791             :         // adfPrjParams[6] = adfParams[5];
     792             :         // adfPrjParams[7] = 0;// importFromPanorama calc it by itself
     793             :     }
     794             : 
     795           5 :     passport.stMapDescription.dfScale = passport.nScale;
     796             : 
     797           5 :     if (passport.stMapDescription.nResolution == 0)
     798             :     {
     799           0 :         return OGRERR_FAILURE;
     800             :     }
     801           5 :     const double dfCoeff = double(passport.stMapDescription.dfScale) /
     802           5 :                            passport.stMapDescription.nResolution;
     803           5 :     passport.stMapDescription.bIsRealCoordinates =
     804           5 :         passport.informationFlags.bRealCoordinatesCompliance;
     805           5 :     passport.stMapDescription.stCoordAcc = passport.informationFlags.stCoordAcc;
     806             : 
     807           5 :     if (!passport.stMapDescription.bIsRealCoordinates)
     808             :     {
     809           5 :         if (passport.stMapDescription.stFrameCoords[0] == 0 &&
     810           5 :             passport.stMapDescription.stFrameCoords[1] == 0 &&
     811           5 :             passport.stMapDescription.stFrameCoords[2] == 0 &&
     812           5 :             passport.stMapDescription.stFrameCoords[3] == 0 &&
     813           5 :             passport.stMapDescription.stFrameCoords[4] == 0 &&
     814           5 :             passport.stMapDescription.stFrameCoords[5] == 0 &&
     815           5 :             passport.stMapDescription.stFrameCoords[6] == 0 &&
     816           5 :             passport.stMapDescription.stFrameCoords[7] == 0)
     817             :         {
     818           5 :             passport.stMapDescription.bIsRealCoordinates = true;
     819             :         }
     820             :         else
     821             :         {
     822             :             // origin
     823           0 :             passport.stMapDescription.dfXOr =
     824           0 :                 passport.stMapDescription.stProjCoords[1] -
     825           0 :                 passport.stMapDescription.stFrameCoords[1] * dfCoeff;
     826           0 :             passport.stMapDescription.dfYOr =
     827           0 :                 passport.stMapDescription.stProjCoords[0] -
     828           0 :                 passport.stMapDescription.stFrameCoords[0] * dfCoeff;
     829             :         }
     830             :     }
     831             : 
     832             :     // normalize some coordintatessystems
     833           5 :     if ((iEllips == 1 || iEllips == 0) &&
     834             :         iProjSys == 1)  // Pulkovo 1942 / Gauss-Kruger
     835             :     {
     836           5 :         double dfCenterLongEnv =
     837           5 :             passport.stMapDescription.stGeoCoords[1] +
     838           5 :             fabs(passport.stMapDescription.stGeoCoords[5] -
     839           5 :                  passport.stMapDescription.stGeoCoords[1]) /
     840             :                 2;
     841             : 
     842           5 :         int nZoneEnv = (int)((dfCenterLongEnv + 3.0) / 6.0 + 0.5);
     843             : 
     844           5 :         if (nZoneEnv > 1 && nZoneEnv < 33)
     845             :         {
     846           5 :             int nEPSG = 28400 + nZoneEnv;
     847           5 :             passport.stMapDescription.pSpatRef = new OGRSpatialReference();
     848           5 :             passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     849             :                 OAMS_TRADITIONAL_GIS_ORDER);
     850             :             OGRErr eErr =
     851           5 :                 passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
     852           5 :             SetVertCS(iVCS, passport, papszOpenOpts);
     853           5 :             return eErr;
     854             :         }
     855             :         else
     856             :         {
     857           0 :             adfPrjParams[7] = nZoneEnv;
     858             : 
     859           0 :             if (adfPrjParams[5] == 0)  // False Easting
     860             :             {
     861           0 :                 if (passport.stMapDescription.Env.MaxX < 500000)
     862           0 :                     adfPrjParams[5] = 500000;
     863             :                 else
     864             :                 {
     865           0 :                     if (nZoneEnv >= -60 && nZoneEnv <= 60)
     866           0 :                         adfPrjParams[5] = nZoneEnv * 1000000 + 500000;
     867             :                     else
     868             :                     {
     869           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
     870             :                                  "Wrong nZoneEnv = %d value", nZoneEnv);
     871           0 :                         return OGRERR_FAILURE;
     872             :                     }
     873             :                 }
     874             :             }
     875           0 :         }
     876             :     }
     877           0 :     else if (iEllips == 9 && iProjSys == 17)  // WGS84 / UTM
     878             :     {
     879           0 :         double dfCenterLongEnv =
     880           0 :             passport.stMapDescription.stGeoCoords[1] +
     881           0 :             fabs(passport.stMapDescription.stGeoCoords[5] -
     882           0 :                  passport.stMapDescription.stGeoCoords[1]) /
     883             :                 2;
     884           0 :         int nZoneEnv = (int)(30 + (dfCenterLongEnv + 3.0) / 6.0 + 0.5);
     885           0 :         bool bNorth = passport.stMapDescription.stGeoCoords[6] +
     886           0 :                           (passport.stMapDescription.stGeoCoords[2] -
     887           0 :                            passport.stMapDescription.stGeoCoords[6]) /
     888             :                               2 <
     889             :                       0;
     890           0 :         int nEPSG = 0;
     891           0 :         if (bNorth)
     892             :         {
     893           0 :             nEPSG = 32600 + nZoneEnv;
     894             :         }
     895             :         else
     896             :         {
     897           0 :             nEPSG = 32700 + nZoneEnv;
     898             :         }
     899           0 :         passport.stMapDescription.pSpatRef = new OGRSpatialReference();
     900           0 :         passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     901             :             OAMS_TRADITIONAL_GIS_ORDER);
     902           0 :         OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(nEPSG);
     903           0 :         SetVertCS(iVCS, passport, papszOpenOpts);
     904           0 :         return eErr;
     905             :     }
     906           0 :     else if (iEllips == 45 && iProjSys == 35)  // Mercator 3857 on sphere wgs84
     907             :     {
     908           0 :         passport.stMapDescription.pSpatRef = new OGRSpatialReference(
     909             :             "PROJCS[\"WGS 84 / Pseudo-Mercator\",GEOGCS[\"WGS "
     910             :             "84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS "
     911             :             "84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],"
     912             :             "AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY["
     913             :             "\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY["
     914             :             "\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]],PROJECTION["
     915             :             "\"Mercator_1SP\"],PARAMETER[\"central_meridian\",0],PARAMETER["
     916             :             "\"scale_factor\",1],PARAMETER[\"false_easting\",0],PARAMETER["
     917             :             "\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\","
     918             :             "\"9001\"]],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH],EXTENSION[\"PROJ4\","
     919             :             "\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 "
     920             :             "+x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  "
     921           0 :             "+no_defs\"],AUTHORITY[\"EPSG\",\"3857\"]]");
     922           0 :         passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     923             :             OAMS_TRADITIONAL_GIS_ORDER);
     924           0 :         OGRErr eErr =
     925             :             OGRERR_NONE;  // passport.stMapDescription.pSpatRef->importFromEPSG(3857);
     926           0 :         SetVertCS(iVCS, passport, papszOpenOpts);
     927           0 :         return eErr;
     928             :     }
     929           0 :     else if (iEllips == 9 && iProjSys == 35)  // Mercator 3395 on ellips wgs84
     930             :     {
     931           0 :         passport.stMapDescription.pSpatRef = new OGRSpatialReference();
     932           0 :         passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     933             :             OAMS_TRADITIONAL_GIS_ORDER);
     934           0 :         OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(3395);
     935           0 :         SetVertCS(iVCS, passport, papszOpenOpts);
     936           0 :         return eErr;
     937             :     }
     938           0 :     else if (iEllips == 9 && iProjSys == 34)  // Miller 54003 on sphere wgs84
     939             :     {
     940           0 :         passport.stMapDescription.pSpatRef = new OGRSpatialReference(
     941             :             "PROJCS[\"World_Miller_Cylindrical\",GEOGCS[\"GCS_GLOBE\", "
     942             :             "DATUM[\"GLOBE\", SPHEROID[\"GLOBE\", 6367444.6571, "
     943             :             "0.0]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0."
     944             :             "017453292519943295]],PROJECTION[\"Miller_Cylindrical\"],PARAMETER["
     945             :             "\"False_Easting\",0],PARAMETER[\"False_Northing\",0],PARAMETER["
     946             :             "\"Central_Meridian\",0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\","
     947           0 :             "\"54003\"]]");
     948           0 :         passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     949             :             OAMS_TRADITIONAL_GIS_ORDER);
     950           0 :         OGRErr eErr =
     951             :             OGRERR_NONE;  // passport.stMapDescription.pSpatRef->importFromEPSG(3395);
     952             :         // OGRErr eErr =
     953             :         // passport.stMapDescription.pSpatRef->importFromEPSG(54003);
     954             : 
     955           0 :         SetVertCS(iVCS, passport, papszOpenOpts);
     956           0 :         return eErr;
     957             :     }
     958           0 :     else if (iEllips == 9 && iProjSys == 33 &&
     959           0 :              passport.stMapDescription.eUnitInPlan == SXF_COORD_MU_DEGREE)
     960             :     {
     961           0 :         passport.stMapDescription.pSpatRef =
     962           0 :             new OGRSpatialReference(SRS_WKT_WGS84_LAT_LONG);
     963           0 :         passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     964             :             OAMS_TRADITIONAL_GIS_ORDER);
     965           0 :         OGRErr eErr = OGRERR_NONE;
     966           0 :         SetVertCS(iVCS, passport, papszOpenOpts);
     967           0 :         return eErr;
     968             :     }
     969             : 
     970             :     // TODO: Need to normalize more SRS:
     971             :     // PAN_PROJ_WAG1
     972             :     // PAN_PROJ_MERCAT
     973             :     // PAN_PROJ_PS
     974             :     // PAN_PROJ_POLYC
     975             :     // PAN_PROJ_EC
     976             :     // PAN_PROJ_LCC
     977             :     // PAN_PROJ_STEREO
     978             :     // PAN_PROJ_AE
     979             :     // PAN_PROJ_GNOMON
     980             :     // PAN_PROJ_MOLL
     981             :     // PAN_PROJ_LAEA
     982             :     // PAN_PROJ_EQC
     983             :     // PAN_PROJ_CEA
     984             :     // PAN_PROJ_IMWP
     985             :     //
     986             : 
     987           0 :     passport.stMapDescription.pSpatRef = new OGRSpatialReference();
     988           0 :     passport.stMapDescription.pSpatRef->SetAxisMappingStrategy(
     989             :         OAMS_TRADITIONAL_GIS_ORDER);
     990           0 :     OGRErr eErr = passport.stMapDescription.pSpatRef->importFromPanorama(
     991           0 :         anData[2], anData[3], anData[0], adfPrjParams);
     992           0 :     SetVertCS(iVCS, passport, papszOpenOpts);
     993           0 :     return eErr;
     994             : }
     995             : 
     996           5 : void OGRSXFDataSource::FillLayers()
     997             : {
     998           5 :     CPLDebug("SXF", "Create layers");
     999             : 
    1000             :     // 2. Read all records (only classify code and offset) and add this to
    1001             :     // correspondence layer
    1002           5 :     int nObjectsRead = 0;
    1003           5 :     vsi_l_offset nOffset = 0;
    1004             : 
    1005             :     // get record count
    1006           5 :     GUInt32 nRecordCountMax = 0;
    1007           5 :     if (oSXFPassport.version == 3)
    1008             :     {
    1009           0 :         VSIFSeekL(fpSXF, 288, SEEK_SET);
    1010           0 :         nObjectsRead =
    1011           0 :             static_cast<int>(VSIFReadL(&nRecordCountMax, 4, 1, fpSXF));
    1012           0 :         nOffset = 300;
    1013           0 :         CPL_LSBPTR32(&nRecordCountMax);
    1014             :     }
    1015           5 :     else if (oSXFPassport.version == 4)
    1016             :     {
    1017           5 :         VSIFSeekL(fpSXF, 440, SEEK_SET);
    1018           5 :         nObjectsRead =
    1019           5 :             static_cast<int>(VSIFReadL(&nRecordCountMax, 4, 1, fpSXF));
    1020           5 :         nOffset = 452;
    1021           5 :         CPL_LSBPTR32(&nRecordCountMax);
    1022             :     }
    1023             :     /* else nOffset and nObjectsRead will be 0 */
    1024             : 
    1025           5 :     if (nObjectsRead != 1)
    1026             :     {
    1027           0 :         CPLError(CE_Failure, CPLE_FileIO, "Get record count failed");
    1028           0 :         return;
    1029             :     }
    1030             : 
    1031           5 :     VSIFSeekL(fpSXF, nOffset, SEEK_SET);
    1032             : 
    1033         395 :     for (GUInt32 nFID = 0; nFID < nRecordCountMax; nFID++)
    1034             :     {
    1035             :         GInt32 buff[6];
    1036         390 :         nObjectsRead = static_cast<int>(VSIFReadL(&buff, 24, 1, fpSXF));
    1037        2730 :         for (int i = 0; i < 6; i++)
    1038             :         {
    1039        2340 :             CPL_LSBPTR32(&buff[i]);
    1040             :         }
    1041             : 
    1042         390 :         if (nObjectsRead != 1 || buff[0] != IDSXFOBJ)
    1043             :         {
    1044           0 :             CPLError(CE_Failure, CPLE_FileIO, "Read record %d failed", nFID);
    1045           0 :             return;
    1046             :         }
    1047             : 
    1048         390 :         bool bHasSemantic = CHECK_BIT(buff[5], 9);
    1049         390 :         if (bHasSemantic)  // check has attributes
    1050             :         {
    1051             :             // we have already 24 byte read
    1052         250 :             vsi_l_offset nOffsetSemantic = 8 + buff[2];
    1053         250 :             VSIFSeekL(fpSXF, nOffsetSemantic, SEEK_CUR);
    1054             :         }
    1055             : 
    1056         390 :         int nSemanticSize = buff[1] - 32 - buff[2];
    1057         390 :         if (nSemanticSize < 0)
    1058             :         {
    1059           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid value");
    1060           0 :             break;
    1061             :         }
    1062             : 
    1063        4643 :         for (const auto &poLayer : m_apoLayers)
    1064             :         {
    1065        4643 :             if (poLayer->AddRecord(nFID, buff[3], nOffset, bHasSemantic,
    1066        4643 :                                    nSemanticSize) == TRUE)
    1067             :             {
    1068         390 :                 break;
    1069             :             }
    1070             :         }
    1071         390 :         nOffset += buff[1];
    1072         390 :         VSIFSeekL(fpSXF, nOffset, SEEK_SET);
    1073             :     }
    1074             :     // 3. delete empty layers
    1075          87 :     for (size_t i = 0; i < m_apoLayers.size(); /* increment in loop */)
    1076             :     {
    1077          82 :         OGRSXFLayer *pOGRSXFLayer = m_apoLayers[i].get();
    1078          82 :         if (pOGRSXFLayer->GetFeatureCount() == 0)
    1079             :         {
    1080          44 :             m_apoLayers.erase(m_apoLayers.begin() + i);
    1081             :         }
    1082             :         else
    1083             :         {
    1084          38 :             pOGRSXFLayer->ResetReading();
    1085          38 :             ++i;
    1086             :         }
    1087             :     }
    1088             : }
    1089             : 
    1090        2140 : OGRSXFLayer *OGRSXFDataSource::GetLayerById(GByte nID)
    1091             : {
    1092       18820 :     for (const auto &poLayer : m_apoLayers)
    1093             :     {
    1094       18820 :         if (poLayer->GetId() == nID)
    1095             :         {
    1096        2140 :             return poLayer.get();
    1097             :         }
    1098             :     }
    1099           0 :     return nullptr;
    1100             : }
    1101             : 
    1102           1 : void OGRSXFDataSource::CreateLayers()
    1103             : {
    1104             :     // default layers set
    1105           1 :     m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
    1106           2 :         fpSXF, &hIOMutex, static_cast<GByte>(0), CPLString("SYSTEM"),
    1107           2 :         oSXFPassport.version, oSXFPassport.stMapDescription));
    1108           1 :     auto pLayer = m_apoLayers.back().get();
    1109             : 
    1110             :     // default codes
    1111          15 :     for (unsigned int i = 1000000001; i < 1000000015; i++)
    1112             :     {
    1113          14 :         pLayer->AddClassifyCode(i);
    1114             :     }
    1115           1 :     pLayer->AddClassifyCode(91000000);
    1116             : 
    1117           1 :     m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
    1118           2 :         fpSXF, &hIOMutex, static_cast<GByte>(255), CPLString("Not_Classified"),
    1119           2 :         oSXFPassport.version, oSXFPassport.stMapDescription));
    1120           1 : }
    1121             : 
    1122           5 : void OGRSXFDataSource::CreateLayers(VSILFILE *fpRSC,
    1123             :                                     const char *const *papszOpenOpts)
    1124             : {
    1125             : 
    1126             :     RSCHeader stRSCFileHeader;
    1127             :     int nObjectsRead = static_cast<int>(
    1128           5 :         VSIFReadL(&stRSCFileHeader, sizeof(stRSCFileHeader), 1, fpRSC));
    1129             : 
    1130           5 :     if (nObjectsRead != 1)
    1131             :     {
    1132           1 :         CPLError(CE_Warning, CPLE_None, "RSC head read failed");
    1133           1 :         return;
    1134             :     }
    1135             : 
    1136           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nFileLength));
    1137           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nVersion));
    1138           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nEncoding));
    1139           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nFileState));
    1140           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nFileModState));
    1141           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nLang));
    1142           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nNextID));
    1143           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nScale));
    1144             : 
    1145             : #define SWAP_SECTION(x)                                                        \
    1146             :     CPL_LSBPTR32(&(x.nOffset));                                                \
    1147             :     CPL_LSBPTR32(&(x.nLength));                                                \
    1148             :     CPL_LSBPTR32(&(x.nRecordCount));
    1149             : 
    1150           4 :     SWAP_SECTION(stRSCFileHeader.Objects);
    1151           4 :     SWAP_SECTION(stRSCFileHeader.Semantic);
    1152           4 :     SWAP_SECTION(stRSCFileHeader.ClassifySemantic);
    1153           4 :     SWAP_SECTION(stRSCFileHeader.Defaults);
    1154           4 :     SWAP_SECTION(stRSCFileHeader.Semantics);
    1155           4 :     SWAP_SECTION(stRSCFileHeader.Layers);
    1156           4 :     SWAP_SECTION(stRSCFileHeader.Limits);
    1157           4 :     SWAP_SECTION(stRSCFileHeader.Parameters);
    1158           4 :     SWAP_SECTION(stRSCFileHeader.Print);
    1159           4 :     SWAP_SECTION(stRSCFileHeader.Palettes);
    1160           4 :     SWAP_SECTION(stRSCFileHeader.Fonts);
    1161           4 :     SWAP_SECTION(stRSCFileHeader.Libs);
    1162           4 :     SWAP_SECTION(stRSCFileHeader.ImageParams);
    1163           4 :     SWAP_SECTION(stRSCFileHeader.Tables);
    1164           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nFontEnc));
    1165           4 :     CPL_LSBPTR32(&(stRSCFileHeader.nColorsInPalette));
    1166             : 
    1167             :     GByte szLayersID[4];
    1168             : 
    1169             :     struct _layer
    1170             :     {
    1171             :         GUInt32 nLength;
    1172             :         char szName[32];
    1173             :         char szShortName[16];
    1174             :         GByte nNo;
    1175             :         // cppcheck-suppress unusedStructMember
    1176             :         GByte nPos;
    1177             :         // cppcheck-suppress unusedStructMember
    1178             :         GUInt16 nSemanticCount;
    1179             :     };
    1180             : 
    1181           4 :     VSIFSeekL(fpRSC, stRSCFileHeader.Layers.nOffset - sizeof(szLayersID),
    1182             :               SEEK_SET);
    1183           4 :     VSIFReadL(&szLayersID, sizeof(szLayersID), 1, fpRSC);
    1184           4 :     vsi_l_offset nOffset = stRSCFileHeader.Layers.nOffset;
    1185             :     _layer LAYER;
    1186             : 
    1187          80 :     for (GUInt32 i = 0; i < stRSCFileHeader.Layers.nRecordCount; ++i)
    1188             :     {
    1189          76 :         VSIFReadL(&LAYER, sizeof(LAYER), 1, fpRSC);
    1190          76 :         CPL_LSBPTR32(&(LAYER.nLength));
    1191          76 :         CPL_LSBPTR16(&(LAYER.nSemanticCount));
    1192          76 :         bool bLayerFullName = CPLTestBool(CSLFetchNameValueDef(
    1193             :             papszOpenOpts, "SXF_LAYER_FULLNAME",
    1194             :             CPLGetConfigOption("SXF_LAYER_FULLNAME", "NO")));
    1195          76 :         char *pszRecoded = nullptr;
    1196          76 :         if (bLayerFullName)
    1197             :         {
    1198          19 :             if (LAYER.szName[0] == 0)
    1199           0 :                 pszRecoded = CPLStrdup("Unnamed");
    1200          19 :             else if (stRSCFileHeader.nFontEnc == 125)
    1201           0 :                 pszRecoded = CPLRecode(LAYER.szName, "KOI8-R", CPL_ENC_UTF8);
    1202          19 :             else if (stRSCFileHeader.nFontEnc == 126)
    1203          19 :                 pszRecoded = CPLRecode(LAYER.szName, "CP1251", CPL_ENC_UTF8);
    1204             :             else
    1205           0 :                 pszRecoded = CPLStrdup(LAYER.szName);
    1206             : 
    1207          19 :             m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
    1208          38 :                 fpSXF, &hIOMutex, LAYER.nNo, CPLString(pszRecoded),
    1209          38 :                 oSXFPassport.version, oSXFPassport.stMapDescription));
    1210             :         }
    1211             :         else
    1212             :         {
    1213          57 :             if (LAYER.szShortName[0] == 0)
    1214           0 :                 pszRecoded = CPLStrdup("Unnamed");
    1215          57 :             else if (stRSCFileHeader.nFontEnc == 125)
    1216             :                 pszRecoded =
    1217           0 :                     CPLRecode(LAYER.szShortName, "KOI8-R", CPL_ENC_UTF8);
    1218          57 :             else if (stRSCFileHeader.nFontEnc == 126)
    1219             :                 pszRecoded =
    1220          57 :                     CPLRecode(LAYER.szShortName, "CP1251", CPL_ENC_UTF8);
    1221             :             else
    1222           0 :                 pszRecoded = CPLStrdup(LAYER.szShortName);
    1223             : 
    1224          57 :             m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
    1225         114 :                 fpSXF, &hIOMutex, LAYER.nNo, CPLString(pszRecoded),
    1226         114 :                 oSXFPassport.version, oSXFPassport.stMapDescription));
    1227             :         }
    1228          76 :         CPLFree(pszRecoded);
    1229             : 
    1230          76 :         nOffset += LAYER.nLength;
    1231          76 :         VSIFSeekL(fpRSC, nOffset, SEEK_SET);
    1232             :     }
    1233             : 
    1234           4 :     m_apoLayers.emplace_back(std::make_unique<OGRSXFLayer>(
    1235           8 :         fpSXF, &hIOMutex, static_cast<GByte>(255), CPLString("Not_Classified"),
    1236           8 :         oSXFPassport.version, oSXFPassport.stMapDescription));
    1237             : 
    1238             :     char szObjectsID[4];
    1239             : 
    1240             :     struct _object
    1241             :     {
    1242             :         unsigned nLength;
    1243             :         unsigned nClassifyCode;
    1244             :         // cppcheck-suppress unusedStructMember
    1245             :         unsigned nObjectNumber;
    1246             :         // cppcheck-suppress unusedStructMember
    1247             :         unsigned nObjectCode;
    1248             :         char szShortName[32];
    1249             :         char szName[32];
    1250             :         // cppcheck-suppress unusedStructMember
    1251             :         char szGeomType;
    1252             :         char szLayernNo;
    1253             :         // cppcheck-suppress unusedStructMember
    1254             :         char szUnimportantSeg[14];
    1255             :     };
    1256             : 
    1257           4 :     VSIFSeekL(fpRSC, stRSCFileHeader.Objects.nOffset - sizeof(szObjectsID),
    1258             :               SEEK_SET);
    1259           4 :     VSIFReadL(&szObjectsID, sizeof(szObjectsID), 1, fpRSC);
    1260           4 :     nOffset = stRSCFileHeader.Objects.nOffset;
    1261             :     _object OBJECT;
    1262             : 
    1263        2144 :     for (GUInt32 i = 0; i < stRSCFileHeader.Objects.nRecordCount; ++i)
    1264             :     {
    1265        2140 :         VSIFReadL(&OBJECT, sizeof(_object), 1, fpRSC);
    1266        2140 :         CPL_LSBPTR32(&(OBJECT.nLength));
    1267        2140 :         CPL_LSBPTR32(&(OBJECT.nClassifyCode));
    1268        2140 :         CPL_LSBPTR32(&(OBJECT.nObjectNumber));
    1269        2140 :         CPL_LSBPTR32(&(OBJECT.nObjectCode));
    1270             : 
    1271        2140 :         OGRSXFLayer *pLayer = GetLayerById(OBJECT.szLayernNo);
    1272        2140 :         if (nullptr != pLayer)
    1273             :         {
    1274        2140 :             char *pszRecoded = nullptr;
    1275        2140 :             if (OBJECT.szName[0] == 0)
    1276           0 :                 pszRecoded = CPLStrdup("Unnamed");
    1277        2140 :             else if (stRSCFileHeader.nFontEnc == 125)
    1278           0 :                 pszRecoded = CPLRecode(OBJECT.szName, "KOI8-R", CPL_ENC_UTF8);
    1279        2140 :             else if (stRSCFileHeader.nFontEnc == 126)
    1280        2140 :                 pszRecoded = CPLRecode(OBJECT.szName, "CP1251", CPL_ENC_UTF8);
    1281             :             else
    1282             :                 pszRecoded =
    1283           0 :                     CPLStrdup(OBJECT.szName);  // already in  CPL_ENC_UTF8
    1284             : 
    1285        2140 :             pLayer->AddClassifyCode(OBJECT.nClassifyCode, pszRecoded);
    1286             :             // printf("%d;%s\n", OBJECT.nClassifyCode, OBJECT.szName);
    1287        2140 :             CPLFree(pszRecoded);
    1288             :         }
    1289             : 
    1290        2140 :         nOffset += OBJECT.nLength;
    1291        2140 :         VSIFSeekL(fpRSC, nOffset, SEEK_SET);
    1292             :     }
    1293             : }

Generated by: LCOV version 1.14