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

Generated by: LCOV version 1.14