LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sxf - ogrsxflayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 468 835 56.0 %
Date: 2025-02-20 10:14:44 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  SXF Translator
       4             :  * Purpose:  Definition of classes for OGR SXF Layers.
       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             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  ****************************************************************************/
      16             : 
      17             : #include "ogr_sxf.h"
      18             : #include "cpl_conv.h"
      19             : #include "cpl_string.h"
      20             : #include "ogr_p.h"
      21             : #include "ogr_srs_api.h"
      22             : #include "cpl_multiproc.h"
      23             : 
      24             : /************************************************************************/
      25             : /*                        OGRSXFLayer()                                 */
      26             : /************************************************************************/
      27             : 
      28          82 : OGRSXFLayer::OGRSXFLayer(VSILFILE *fp, CPLMutex **hIOMutex, GByte nID,
      29             :                          const char *pszLayerName, int nVer,
      30          82 :                          const SXFMapDescription &sxfMapDesc)
      31          82 :     : OGRLayer(), poFeatureDefn(new OGRFeatureDefn(pszLayerName)), fpSXF(fp),
      32             :       nLayerID(nID), stSXFMapDescription(sxfMapDesc), m_nSXFFormatVer(nVer),
      33             :       sFIDColumn_("ogc_fid"), m_hIOMutex(hIOMutex),
      34          82 :       m_dfCoeff(sxfMapDesc.nResolution == 0
      35           0 :                     ? 0.0
      36         164 :                     : sxfMapDesc.dfScale / sxfMapDesc.nResolution)
      37             : {
      38          82 :     stSXFMapDescription.pSpatRef->Reference();
      39          82 :     oNextIt = mnRecordDesc.begin();
      40          82 :     SetDescription(poFeatureDefn->GetName());
      41          82 :     poFeatureDefn->Reference();
      42             : 
      43          82 :     poFeatureDefn->SetGeomType(wkbUnknown);
      44          82 :     if (poFeatureDefn->GetGeomFieldCount() != 0)
      45          82 :         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(
      46          82 :             stSXFMapDescription.pSpatRef);
      47             : 
      48         164 :     OGRFieldDefn oFIDField(sFIDColumn_, OFTInteger);
      49          82 :     poFeatureDefn->AddFieldDefn(&oFIDField);
      50             : 
      51         164 :     OGRFieldDefn oClCodeField("CLCODE", OFTInteger);
      52          82 :     oClCodeField.SetWidth(10);
      53          82 :     poFeatureDefn->AddFieldDefn(&oClCodeField);
      54             : 
      55         164 :     OGRFieldDefn oClNameField("CLNAME", OFTString);
      56          82 :     oClNameField.SetWidth(32);
      57          82 :     poFeatureDefn->AddFieldDefn(&oClNameField);
      58             : 
      59         164 :     OGRFieldDefn oNumField("OBJECTNUMB", OFTInteger);
      60          82 :     oNumField.SetWidth(10);
      61          82 :     poFeatureDefn->AddFieldDefn(&oNumField);
      62             : 
      63         164 :     OGRFieldDefn oAngField("ANGLE", OFTReal);
      64          82 :     poFeatureDefn->AddFieldDefn(&oAngField);
      65             : 
      66         164 :     OGRFieldDefn oTextField("TEXT", OFTString);
      67          82 :     oTextField.SetWidth(255);
      68          82 :     poFeatureDefn->AddFieldDefn(&oTextField);
      69          82 : }
      70             : 
      71             : /************************************************************************/
      72             : /*                         ~OGRSXFLayer()                               */
      73             : /************************************************************************/
      74             : 
      75         164 : OGRSXFLayer::~OGRSXFLayer()
      76             : {
      77          82 :     stSXFMapDescription.pSpatRef->Release();
      78          82 :     poFeatureDefn->Release();
      79         164 : }
      80             : 
      81             : /************************************************************************/
      82             : /*                AddClassifyCode(unsigned nClassCode)                  */
      83             : /* Add layer supported classify codes. Only records with this code can  */
      84             : /* be in layer                                                          */
      85             : /************************************************************************/
      86             : 
      87        2155 : void OGRSXFLayer::AddClassifyCode(unsigned nClassCode, const char *szName)
      88             : {
      89        2155 :     if (szName != nullptr)
      90             :     {
      91        2140 :         mnClassificators[nClassCode] = CPLString(szName);
      92             :     }
      93             :     else
      94             :     {
      95          15 :         mnClassificators[nClassCode] = CPLString().Printf("%d", nClassCode);
      96             :     }
      97        2155 : }
      98             : 
      99             : /************************************************************************/
     100             : /*                           AddRecord()                                */
     101             : /************************************************************************/
     102             : 
     103        4643 : bool OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode,
     104             :                             vsi_l_offset nOffset, bool bHasSemantic,
     105             :                             size_t nSemanticsSize)
     106             : {
     107        9085 :     if (mnClassificators.find(nClassCode) != mnClassificators.end() ||
     108        4442 :         EQUAL(GetName(), "Not_Classified"))
     109             :     {
     110         390 :         mnRecordDesc[nFID] = nOffset;
     111             :         // Add additional semantics (attribute fields).
     112         390 :         if (bHasSemantic)
     113             :         {
     114         250 :             size_t offset = 0;
     115             : 
     116         610 :             while (offset < nSemanticsSize)
     117             :             {
     118             :                 SXFRecordAttributeInfo stAttrInfo;
     119         360 :                 bool bAddField = false;
     120         360 :                 size_t nCurrOff = 0;
     121             :                 int nReadObj =
     122         360 :                     static_cast<int>(VSIFReadL(&stAttrInfo, 4, 1, fpSXF));
     123         360 :                 if (nReadObj == 1)
     124             :                 {
     125         360 :                     CPL_LSBPTR16(&(stAttrInfo.nCode));
     126         720 :                     CPLString oFieldName;
     127         360 :                     if (snAttributeCodes.find(stAttrInfo.nCode) ==
     128         720 :                         snAttributeCodes.end())
     129             :                     {
     130         142 :                         bAddField = true;
     131         142 :                         snAttributeCodes.insert(stAttrInfo.nCode);
     132         142 :                         oFieldName.Printf("SC_%d", stAttrInfo.nCode);
     133             :                     }
     134             : 
     135         360 :                     SXFRecordAttributeType eType =
     136         360 :                         (SXFRecordAttributeType)stAttrInfo.nType;
     137             : 
     138         360 :                     offset += 4;
     139             : 
     140         360 :                     switch (eType)  // TODO: set field type form RSC as here
     141             :                                     // sometimes we have the codes and string
     142             :                                     // values can be get from RSC by this code
     143             :                     {
     144           0 :                         case SXF_RAT_ASCIIZ_DOS:
     145             :                         {
     146           0 :                             if (bAddField)
     147             :                             {
     148           0 :                                 OGRFieldDefn oField(oFieldName, OFTString);
     149           0 :                                 oField.SetWidth(255);
     150           0 :                                 poFeatureDefn->AddFieldDefn(&oField);
     151             :                             }
     152           0 :                             offset += stAttrInfo.nScale + 1;
     153           0 :                             nCurrOff = stAttrInfo.nScale + 1;
     154           0 :                             break;
     155             :                         }
     156           0 :                         case SXF_RAT_ONEBYTE:
     157             :                         {
     158           0 :                             if (bAddField)
     159             :                             {
     160           0 :                                 OGRFieldDefn oField(oFieldName, OFTReal);
     161           0 :                                 poFeatureDefn->AddFieldDefn(&oField);
     162             :                             }
     163           0 :                             offset += 1;
     164           0 :                             nCurrOff = 1;
     165           0 :                             break;
     166             :                         }
     167         140 :                         case SXF_RAT_TWOBYTE:
     168             :                         {
     169         140 :                             if (bAddField)
     170             :                             {
     171         164 :                                 OGRFieldDefn oField(oFieldName, OFTReal);
     172          82 :                                 poFeatureDefn->AddFieldDefn(&oField);
     173             :                             }
     174         140 :                             offset += 2;
     175         140 :                             nCurrOff = 2;
     176         140 :                             break;
     177             :                         }
     178           5 :                         case SXF_RAT_FOURBYTE:
     179             :                         {
     180           5 :                             if (bAddField)
     181             :                             {
     182           0 :                                 OGRFieldDefn oField(oFieldName, OFTReal);
     183           0 :                                 poFeatureDefn->AddFieldDefn(&oField);
     184             :                             }
     185           5 :                             offset += 4;
     186           5 :                             nCurrOff = 4;
     187           5 :                             break;
     188             :                         }
     189          50 :                         case SXF_RAT_EIGHTBYTE:
     190             :                         {
     191          50 :                             if (bAddField)
     192             :                             {
     193          56 :                                 OGRFieldDefn oField(oFieldName, OFTReal);
     194          28 :                                 poFeatureDefn->AddFieldDefn(&oField);
     195             :                             }
     196          50 :                             offset += 8;
     197          50 :                             nCurrOff = 8;
     198          50 :                             break;
     199             :                         }
     200         165 :                         case SXF_RAT_ANSI_WIN:
     201             :                         {
     202         165 :                             if (bAddField)
     203             :                             {
     204          64 :                                 OGRFieldDefn oField(oFieldName, OFTString);
     205          32 :                                 oField.SetWidth(255);
     206          32 :                                 poFeatureDefn->AddFieldDefn(&oField);
     207             :                             }
     208         165 :                             unsigned nLen = unsigned(stAttrInfo.nScale) + 1;
     209         165 :                             offset += nLen;
     210         165 :                             nCurrOff = nLen;
     211         165 :                             break;
     212             :                         }
     213           0 :                         case SXF_RAT_UNICODE:
     214             :                         {
     215           0 :                             if (bAddField)
     216             :                             {
     217           0 :                                 OGRFieldDefn oField(oFieldName, OFTString);
     218           0 :                                 oField.SetWidth(255);
     219           0 :                                 poFeatureDefn->AddFieldDefn(&oField);
     220             :                             }
     221           0 :                             unsigned nLen =
     222           0 :                                 (unsigned(stAttrInfo.nScale) + 1) * 2;
     223           0 :                             offset += nLen;
     224           0 :                             nCurrOff = nLen;
     225           0 :                             break;
     226             :                         }
     227           0 :                         case SXF_RAT_BIGTEXT:
     228             :                         {
     229           0 :                             if (bAddField)
     230             :                             {
     231           0 :                                 OGRFieldDefn oField(oFieldName, OFTString);
     232           0 :                                 oField.SetWidth(1024);
     233           0 :                                 poFeatureDefn->AddFieldDefn(&oField);
     234             :                             }
     235           0 :                             GUInt32 scale2 = 0;
     236           0 :                             VSIFReadL(&scale2, sizeof(GUInt32), 1, fpSXF);
     237           0 :                             CPL_LSBPTR32(&scale2);
     238             : 
     239           0 :                             offset += scale2;
     240           0 :                             nCurrOff = scale2;
     241           0 :                             break;
     242             :                         }
     243           0 :                         default:
     244           0 :                             break;
     245             :                     }
     246             :                 }
     247         360 :                 if (nCurrOff == 0)
     248           0 :                     break;
     249         360 :                 VSIFSeekL(fpSXF, nCurrOff, SEEK_CUR);
     250             :             }
     251             :         }
     252         390 :         return true;
     253             :     }
     254             : 
     255        4253 :     return false;
     256             : }
     257             : 
     258             : /************************************************************************/
     259             : /*                           SetNextByIndex()                           */
     260             : /************************************************************************/
     261             : 
     262          28 : OGRErr OGRSXFLayer::SetNextByIndex(GIntBig nIndex)
     263             : {
     264          28 :     if (nIndex < 0 || nIndex > (long)mnRecordDesc.size())
     265          18 :         return OGRERR_FAILURE;
     266             : 
     267          10 :     oNextIt = mnRecordDesc.begin();
     268          10 :     std::advance(oNextIt, static_cast<size_t>(nIndex));
     269             : 
     270          10 :     return OGRERR_NONE;
     271             : }
     272             : 
     273             : /************************************************************************/
     274             : /*                             GetFeature()                             */
     275             : /************************************************************************/
     276             : 
     277          60 : OGRFeature *OGRSXFLayer::GetFeature(GIntBig nFID)
     278             : {
     279          60 :     const auto IT = mnRecordDesc.find(static_cast<long>(nFID));
     280          60 :     if (IT != mnRecordDesc.end())
     281             :     {
     282          33 :         VSIFSeekL(fpSXF, IT->second, SEEK_SET);
     283          33 :         OGRFeature *poFeature = GetNextRawFeature(IT->first);
     284          66 :         if (poFeature != nullptr && poFeature->GetGeometryRef() != nullptr &&
     285          33 :             GetSpatialRef() != nullptr)
     286             :         {
     287          66 :             poFeature->GetGeometryRef()->assignSpatialReference(
     288          33 :                 GetSpatialRef());
     289             :         }
     290          33 :         return poFeature;
     291             :     }
     292             : 
     293          27 :     return nullptr;
     294             : }
     295             : 
     296             : /************************************************************************/
     297             : /*                           GetSpatialRef()                            */
     298             : /************************************************************************/
     299             : 
     300        2925 : OGRSpatialReference *OGRSXFLayer::GetSpatialRef()
     301             : {
     302        2925 :     return stSXFMapDescription.pSpatRef;
     303             : }
     304             : 
     305             : /************************************************************************/
     306             : /*                            IGetExtent()                              */
     307             : /************************************************************************/
     308             : 
     309          36 : OGRErr OGRSXFLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     310             :                                bool bForce)
     311             : {
     312          36 :     if (bForce)
     313             :     {
     314          36 :         return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     315             :     }
     316             :     else
     317             :     {
     318           0 :         psExtent->MinX = stSXFMapDescription.Env.MinX;
     319           0 :         psExtent->MaxX = stSXFMapDescription.Env.MaxX;
     320           0 :         psExtent->MinY = stSXFMapDescription.Env.MinY;
     321           0 :         psExtent->MaxY = stSXFMapDescription.Env.MaxY;
     322             : 
     323           0 :         return OGRERR_NONE;
     324             :     }
     325             : }
     326             : 
     327             : /************************************************************************/
     328             : /*                          GetFeatureCount()                           */
     329             : /************************************************************************/
     330             : 
     331         208 : GIntBig OGRSXFLayer::GetFeatureCount(int bForce)
     332             : {
     333         208 :     if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
     334         154 :         return static_cast<int>(mnRecordDesc.size());
     335             :     else
     336          54 :         return OGRLayer::GetFeatureCount(bForce);
     337             : }
     338             : 
     339             : /************************************************************************/
     340             : /*                            ResetReading()                            */
     341             : /************************************************************************/
     342             : 
     343         858 : void OGRSXFLayer::ResetReading()
     344             : 
     345             : {
     346         858 :     oNextIt = mnRecordDesc.begin();
     347         858 : }
     348             : 
     349             : /************************************************************************/
     350             : /*                           GetNextFeature()                           */
     351             : /************************************************************************/
     352             : 
     353        1686 : OGRFeature *OGRSXFLayer::GetNextFeature()
     354             : {
     355        3372 :     CPLMutexHolderD(m_hIOMutex);
     356        2605 :     while (oNextIt != mnRecordDesc.end())
     357             :     {
     358        2344 :         VSIFSeekL(fpSXF, oNextIt->second, SEEK_SET);
     359        2344 :         OGRFeature *poFeature = GetNextRawFeature(oNextIt->first);
     360             : 
     361        2344 :         ++oNextIt;
     362             : 
     363        2344 :         if (poFeature == nullptr)
     364           0 :             continue;
     365             : 
     366        5546 :         if ((m_poFilterGeom == nullptr ||
     367        4125 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     368        1781 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     369             :         {
     370        2850 :             if (poFeature->GetGeometryRef() != nullptr &&
     371        1425 :                 GetSpatialRef() != nullptr)
     372             :             {
     373        2850 :                 poFeature->GetGeometryRef()->assignSpatialReference(
     374        1425 :                     GetSpatialRef());
     375             :             }
     376             : 
     377        1425 :             return poFeature;
     378             :         }
     379             : 
     380         919 :         delete poFeature;
     381             :     }
     382         261 :     return nullptr;
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                           TestCapability()                           */
     387             : /************************************************************************/
     388             : 
     389         324 : int OGRSXFLayer::TestCapability(const char *pszCap)
     390             : 
     391             : {
     392         765 :     if (EQUAL(pszCap, OLCStringsAsUTF8) &&
     393         441 :         CPLCanRecode("test", "CP1251", CPL_ENC_UTF8) &&
     394         117 :         CPLCanRecode("test", "KOI8-R", CPL_ENC_UTF8))
     395         117 :         return TRUE;
     396         207 :     else if (EQUAL(pszCap, OLCRandomRead))
     397           0 :         return TRUE;
     398         207 :     else if (EQUAL(pszCap, OLCFastFeatureCount))
     399           0 :         return TRUE;
     400         207 :     else if (EQUAL(pszCap, OLCFastGetExtent))
     401          18 :         return TRUE;
     402         189 :     else if (EQUAL(pszCap, OLCFastSetNextByIndex))
     403           0 :         return TRUE;
     404         189 :     else if (EQUAL(pszCap, OLCZGeometries))
     405          27 :         return TRUE;
     406             : 
     407         162 :     return FALSE;
     408             : }
     409             : 
     410             : /************************************************************************/
     411             : /*                                TranslateXYH()                        */
     412             : /************************************************************************/
     413             : /****
     414             :  * TODO : Take into account information given in the passport
     415             :  * like unit of measurement, type and dimensions (integer, float, double) of
     416             :  * coordinate, the vector format, etc.
     417             :  */
     418             : 
     419       58546 : GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription &certifInfo,
     420             :                                   const char *psBuff, GUInt32 nBufLen,
     421             :                                   double *dfX, double *dfY, double *dfH)
     422             : {
     423             :     // Xp, Yp(м) = Xo, Yo(м) + (Xd, Yd / R * S), (1)
     424             : 
     425       58546 :     int offset = 0;
     426       58546 :     switch (certifInfo.eValType)
     427             :     {
     428           0 :         case SXF_VT_SHORT:
     429             :         {
     430           0 :             if (nBufLen < 4)
     431           0 :                 return 0;
     432           0 :             GInt16 x = 0;
     433           0 :             GInt16 y = 0;
     434           0 :             memcpy(&y, psBuff, 2);
     435           0 :             CPL_LSBPTR16(&y);
     436           0 :             memcpy(&x, psBuff + 2, 2);
     437           0 :             CPL_LSBPTR16(&x);
     438             : 
     439           0 :             if (stSXFMapDescription.bIsRealCoordinates)
     440             :             {
     441           0 :                 *dfX = (double)x;
     442           0 :                 *dfY = (double)y;
     443             :             }
     444             :             else
     445             :             {
     446           0 :                 if (m_nSXFFormatVer == 3)
     447             :                 {
     448           0 :                     *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
     449           0 :                     *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
     450             :                 }
     451           0 :                 else if (m_nSXFFormatVer == 4)
     452             :                 {
     453             :                     // TODO: check on real data
     454           0 :                     *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
     455           0 :                     *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
     456             :                 }
     457             :             }
     458             : 
     459           0 :             offset += 4;
     460             : 
     461           0 :             if (dfH != nullptr)
     462             :             {
     463           0 :                 if (nBufLen < 4 + 4)
     464           0 :                     return 0;
     465           0 :                 float h = 0.0f;
     466           0 :                 memcpy(&h, psBuff + 4, 4);  // H always in float
     467           0 :                 CPL_LSBPTR32(&h);
     468           0 :                 *dfH = (double)h;
     469             : 
     470           0 :                 offset += 4;
     471             :             }
     472             :         }
     473           0 :         break;
     474           0 :         case SXF_VT_FLOAT:
     475             :         {
     476           0 :             if (nBufLen < 8)
     477           0 :                 return 0;
     478           0 :             float y = 0.0f;
     479           0 :             memcpy(&y, psBuff, 4);
     480           0 :             CPL_LSBPTR32(&y);
     481           0 :             float x = 0.0f;
     482           0 :             memcpy(&x, psBuff + 4, 4);
     483           0 :             CPL_LSBPTR32(&x);
     484             : 
     485           0 :             if (stSXFMapDescription.bIsRealCoordinates)
     486             :             {
     487           0 :                 *dfX = (double)x;
     488           0 :                 *dfY = (double)y;
     489             :             }
     490             :             else
     491             :             {
     492           0 :                 *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
     493           0 :                 *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
     494             :             }
     495             : 
     496           0 :             offset += 8;
     497             : 
     498           0 :             if (dfH != nullptr)
     499             :             {
     500           0 :                 if (nBufLen < 8 + 4)
     501           0 :                     return 0;
     502           0 :                 float h = 0.0f;
     503           0 :                 memcpy(&h, psBuff + 8, 4);  // H always in float
     504           0 :                 CPL_LSBPTR32(&h);
     505           0 :                 *dfH = (double)h;
     506             : 
     507           0 :                 offset += 4;
     508             :             }
     509             :         }
     510           0 :         break;
     511           0 :         case SXF_VT_INT:
     512             :         {
     513           0 :             if (nBufLen < 8)
     514           0 :                 return 0;
     515             :             GInt32 x, y;
     516           0 :             memcpy(&y, psBuff, 4);
     517           0 :             CPL_LSBPTR32(&y);
     518           0 :             memcpy(&x, psBuff + 4, 4);
     519           0 :             CPL_LSBPTR32(&x);
     520             : 
     521           0 :             if (stSXFMapDescription.bIsRealCoordinates)
     522             :             {
     523           0 :                 *dfX = (double)x;
     524           0 :                 *dfY = (double)y;
     525             :             }
     526             :             else
     527             :             {
     528             :                 // TODO: check on real data
     529           0 :                 if (m_nSXFFormatVer == 3)
     530             :                 {
     531           0 :                     *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
     532           0 :                     *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
     533             :                 }
     534           0 :                 else if (m_nSXFFormatVer == 4)
     535             :                 {
     536           0 :                     *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
     537           0 :                     *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
     538             :                 }
     539             :             }
     540           0 :             offset += 8;
     541             : 
     542           0 :             if (dfH != nullptr)
     543             :             {
     544           0 :                 if (nBufLen < 8 + 4)
     545           0 :                     return 0;
     546           0 :                 float h = 0.0f;
     547           0 :                 memcpy(&h, psBuff + 8, 4);  // H always in float
     548           0 :                 CPL_LSBPTR32(&h);
     549           0 :                 *dfH = (double)h;
     550             : 
     551           0 :                 offset += 4;
     552             :             }
     553             :         }
     554           0 :         break;
     555       58546 :         case SXF_VT_DOUBLE:
     556             :         {
     557       58546 :             if (nBufLen < 16)
     558           0 :                 return 0;
     559       58546 :             double x = 0.0;
     560       58546 :             double y = 0.0;
     561       58546 :             memcpy(&y, psBuff, 8);
     562       58546 :             CPL_LSBPTR64(&y);
     563       58546 :             memcpy(&x, psBuff + 8, 8);
     564       58546 :             CPL_LSBPTR64(&x);
     565             : 
     566       58546 :             if (stSXFMapDescription.bIsRealCoordinates)
     567             :             {
     568       58546 :                 *dfX = x;
     569       58546 :                 *dfY = y;
     570             :             }
     571             :             else
     572             :             {
     573           0 :                 *dfX = stSXFMapDescription.dfXOr + x * m_dfCoeff;
     574           0 :                 *dfY = stSXFMapDescription.dfYOr + y * m_dfCoeff;
     575             :             }
     576             : 
     577       58546 :             offset += 16;
     578             : 
     579       58546 :             if (dfH != nullptr)
     580             :             {
     581           0 :                 if (nBufLen < 16 + 8)
     582           0 :                     return 0;
     583           0 :                 double h = 0.0;
     584           0 :                 memcpy(&h, psBuff + 16, 8);  // H in double
     585           0 :                 CPL_LSBPTR64(&h);
     586           0 :                 *dfH = (double)h;
     587             : 
     588           0 :                 offset += 8;
     589             :             }
     590             :         }
     591       58546 :         break;
     592             :     };
     593             : 
     594       58546 :     return offset;
     595             : }
     596             : 
     597             : /************************************************************************/
     598             : /*                         GetNextRawFeature()                          */
     599             : /************************************************************************/
     600             : 
     601        2377 : OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
     602             : {
     603             :     SXFRecordHeader stRecordHeader;
     604             :     int nObjectRead = static_cast<int>(
     605        2377 :         VSIFReadL(&stRecordHeader, sizeof(SXFRecordHeader), 1, fpSXF));
     606             : 
     607        2377 :     if (nObjectRead != 1)
     608             :     {
     609           0 :         CPLError(CE_Failure, CPLE_FileIO, "SXF. Read record failed.");
     610           0 :         return nullptr;
     611             :     }
     612        2377 :     CPL_LSBPTR32(&(stRecordHeader.nID));
     613        2377 :     if (stRecordHeader.nID != IDSXFOBJ)
     614             :     {
     615           0 :         CPLError(CE_Failure, CPLE_FileIO, "SXF. Read record failed.");
     616           0 :         return nullptr;
     617             :     }
     618        2377 :     CPL_LSBPTR32(&(stRecordHeader.nFullLength));
     619        2377 :     CPL_LSBPTR32(&(stRecordHeader.nGeometryLength));
     620        2377 :     CPL_LSBPTR32(&(stRecordHeader.nClassifyCode));
     621        2377 :     CPL_LSBPTR16(&(stRecordHeader.anGroup[0]));
     622        2377 :     CPL_LSBPTR16(&(stRecordHeader.anGroup[1]));
     623        2377 :     CPL_LSBPTR32(&(stRecordHeader.nPointCount));
     624        2377 :     CPL_LSBPTR16(&(stRecordHeader.nSubObjectCount));
     625        2377 :     CPL_LSBPTR16(&(stRecordHeader.nPointCountSmall));
     626             : 
     627        2377 :     SXFGeometryType eGeomType = SXF_GT_Unknown;
     628        2377 :     GByte code = 0;
     629             : 
     630        2377 :     if (m_nSXFFormatVer == 3)
     631             :     {
     632           0 :         if (CHECK_BIT(stRecordHeader.nRef[2], 3))
     633             :         {
     634           0 :             if (CHECK_BIT(stRecordHeader.nRef[2], 4))
     635             :             {
     636           0 :                 code = 0x22;
     637           0 :                 stRecordHeader.nSubObjectCount = 0;
     638             :             }
     639             :             else
     640             :             {
     641           0 :                 code = 0x21;
     642           0 :                 stRecordHeader.nSubObjectCount = 0;
     643             :             }
     644             :         }
     645             :         else
     646             :         {
     647           0 :             code = stRecordHeader.nRef[0] & 3;  // get first 2 bits
     648             :         }
     649             :     }
     650        2377 :     else if (m_nSXFFormatVer == 4)
     651             :     {
     652        2377 :         if (CHECK_BIT(stRecordHeader.nRef[2], 5))
     653             :         {
     654           0 :             stRecordHeader.nSubObjectCount = 0;
     655             :         }
     656             : 
     657             :         // check if vector
     658        2377 :         code = stRecordHeader.nRef[0] & 15;  // get first 4 bits
     659        2377 :         if (code == 0x04)                    // xxxx0100
     660             :         {
     661         420 :             code = 0x21;
     662         420 :             stRecordHeader.nSubObjectCount = 0;
     663             :             // if (CHECK_BIT(stRecordHeader.nRef[2], 5))
     664             :             //{
     665             :             //     code = 0x22;
     666             :             //     stRecordHeader.nSubObjectCount = 0;
     667             :             // }
     668             :             // else
     669             :             //{
     670             :             //     code = 0x21;
     671             :             //     stRecordHeader.nSubObjectCount = 0;
     672             :             // }
     673             :             // if (CHECK_BIT(stRecordHeader.nRef[2], 4))
     674             :             //{
     675             :             // }
     676             :             // else
     677             :             //{
     678             :             // }
     679             :         }
     680             :     }
     681             : 
     682        2377 :     if (code == 0x00)  // xxxx0000
     683         984 :         eGeomType = SXF_GT_Line;
     684        1393 :     else if (code == 0x01)  // xxxx0001
     685         510 :         eGeomType = SXF_GT_Polygon;
     686         883 :     else if (code == 0x02)  // xxxx0010
     687         323 :         eGeomType = SXF_GT_Point;
     688         560 :     else if (code == 0x03)  // xxxx0011
     689         140 :         eGeomType = SXF_GT_Text;
     690             : #ifdef not_possible_given_above_code /* see below code too if re-enabling this \
     691             :                                       */
     692             :     // beginning 4.0
     693             :     else if (code == 0x04)  // xxxx0100
     694             :     {
     695             :         CPLError(CE_Warning, CPLE_NotSupported, "SXF. Not support type.");
     696             :         eGeomType = SXF_GT_Vector;
     697             :     }
     698             : #endif
     699         420 :     else if (code == 0x05)  // xxxx0101
     700           0 :         eGeomType = SXF_GT_TextTemplate;
     701         420 :     else if (code == 0x21)
     702         420 :         eGeomType = SXF_GT_VectorAngle;
     703           0 :     else if (code == 0x22)
     704           0 :         eGeomType = SXF_GT_VectorScaled;
     705             : 
     706        2377 :     bool bHasAttributes = CHECK_BIT(stRecordHeader.nRef[1], 1);
     707        2377 :     bool bHasRefVector = CHECK_BIT(stRecordHeader.nRef[1], 3);
     708        2377 :     if (bHasRefVector == true)
     709           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     710             :                  "SXF. Parsing the vector of the tying not support.");
     711             : 
     712             :     SXFRecordDescription stCertInfo;
     713        2377 :     if (stRecordHeader.nPointCountSmall == 65535)
     714             :     {
     715           0 :         stCertInfo.nPointCount = stRecordHeader.nPointCount;
     716             :     }
     717             :     else
     718             :     {
     719        2377 :         stCertInfo.nPointCount = stRecordHeader.nPointCountSmall;
     720             :     }
     721        2377 :     stCertInfo.nSubObjectCount = stRecordHeader.nSubObjectCount;
     722             : 
     723        2377 :     bool bFloatType(false), bBigType(false);
     724        2377 :     bool b3D(true);
     725        2377 :     if (m_nSXFFormatVer == 3)
     726             :     {
     727           0 :         b3D = CHECK_BIT(stRecordHeader.nRef[2], 1);
     728           0 :         bFloatType = CHECK_BIT(stRecordHeader.nRef[2], 2);
     729           0 :         bBigType = CHECK_BIT(stRecordHeader.nRef[1], 2);
     730           0 :         stCertInfo.bHasTextSign = CHECK_BIT(stRecordHeader.nRef[2], 5);
     731             :     }
     732        2377 :     else if (m_nSXFFormatVer == 4)
     733             :     {
     734        2377 :         b3D = CHECK_BIT(stRecordHeader.nRef[2], 1);
     735        2377 :         bFloatType = CHECK_BIT(stRecordHeader.nRef[2], 2);
     736        2377 :         bBigType = CHECK_BIT(stRecordHeader.nRef[1], 2);
     737        2377 :         stCertInfo.bHasTextSign = CHECK_BIT(stRecordHeader.nRef[2], 3);
     738             :     }
     739             :     // Else trouble.
     740             : 
     741        2377 :     if (b3D)  // xxxxxx1x
     742           0 :         stCertInfo.bDim = 1;
     743             :     else
     744        2377 :         stCertInfo.bDim = 0;
     745             : 
     746        2377 :     if (bFloatType)
     747             :     {
     748        2377 :         if (bBigType)
     749             :         {
     750        2377 :             stCertInfo.eValType = SXF_VT_DOUBLE;
     751             :         }
     752             :         else
     753             :         {
     754           0 :             stCertInfo.eValType = SXF_VT_FLOAT;
     755             :         }
     756             :     }
     757             :     else
     758             :     {
     759           0 :         if (bBigType)
     760             :         {
     761           0 :             stCertInfo.eValType = SXF_VT_INT;
     762             :         }
     763             :         else
     764             :         {
     765           0 :             stCertInfo.eValType = SXF_VT_SHORT;
     766             :         }
     767             :     }
     768             : 
     769        2377 :     stCertInfo.bFormat = CHECK_BIT(stRecordHeader.nRef[2], 0);
     770        2377 :     stCertInfo.eGeomType = eGeomType;
     771             : 
     772        2377 :     OGRFeature *poFeature = nullptr;
     773        2377 :     if (stRecordHeader.nGeometryLength > 100 * 1024 * 1024)
     774           0 :         return nullptr;
     775             :     char *recordCertifBuf =
     776        2377 :         (char *)VSI_MALLOC_VERBOSE(stRecordHeader.nGeometryLength);
     777        2377 :     if (recordCertifBuf == nullptr)
     778           0 :         return nullptr;
     779        2377 :     nObjectRead = static_cast<int>(
     780        2377 :         VSIFReadL(recordCertifBuf, stRecordHeader.nGeometryLength, 1, fpSXF));
     781        2377 :     if (nObjectRead != 1)
     782             :     {
     783           0 :         CPLError(CE_Failure, CPLE_FileIO, "SXF. Read geometry failed.");
     784           0 :         CPLFree(recordCertifBuf);
     785           0 :         return nullptr;
     786             :     }
     787             : 
     788        2377 :     if (eGeomType == SXF_GT_Point)
     789         323 :         poFeature = TranslatePoint(stCertInfo, recordCertifBuf,
     790             :                                    stRecordHeader.nGeometryLength);
     791        2054 :     else if (eGeomType == SXF_GT_Line || eGeomType == SXF_GT_VectorScaled)
     792         984 :         poFeature = TranslateLine(stCertInfo, recordCertifBuf,
     793             :                                   stRecordHeader.nGeometryLength);
     794        1070 :     else if (eGeomType == SXF_GT_Polygon)
     795         510 :         poFeature = TranslatePolygon(stCertInfo, recordCertifBuf,
     796             :                                      stRecordHeader.nGeometryLength);
     797         560 :     else if (eGeomType == SXF_GT_Text)
     798         140 :         poFeature = TranslateText(stCertInfo, recordCertifBuf,
     799             :                                   stRecordHeader.nGeometryLength);
     800         420 :     else if (eGeomType == SXF_GT_VectorAngle)
     801             :     {
     802         420 :         poFeature = TranslateVetorAngle(stCertInfo, recordCertifBuf,
     803             :                                         stRecordHeader.nGeometryLength);
     804             :     }
     805             : #ifdef not_possible_given_above_code
     806             :     else if (eGeomType == SXF_GT_Vector)
     807             :     {
     808             :         CPLError(CE_Warning, CPLE_NotSupported,
     809             :                  "SXF. Geometry type Vector do not support.");
     810             :         CPLFree(recordCertifBuf);
     811             :         return NULL;
     812             :     }
     813             : #endif
     814           0 :     else if (eGeomType == SXF_GT_TextTemplate)  // TODO realize this
     815             :     {
     816           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     817             :                  "SXF. Geometry type Text Template do not support.");
     818           0 :         CPLFree(recordCertifBuf);
     819           0 :         return nullptr;
     820             :     }
     821             :     else
     822             :     {
     823           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     824             :                  "SXF. Unsupported geometry type.");
     825           0 :         CPLFree(recordCertifBuf);
     826           0 :         return nullptr;
     827             :     }
     828             : 
     829        2377 :     if (poFeature == nullptr)
     830             :     {
     831           0 :         CPLFree(recordCertifBuf);
     832           0 :         return nullptr;
     833             :     }
     834             : 
     835        2377 :     poFeature->SetField(sFIDColumn_, (int)nFID);
     836             : 
     837        2377 :     poFeature->SetField("CLCODE", (int)stRecordHeader.nClassifyCode);
     838             : 
     839        4754 :     CPLString szName = mnClassificators[stRecordHeader.nClassifyCode];
     840             : 
     841        2377 :     if (szName.empty())
     842             :     {
     843         813 :         szName.Printf("%d", stRecordHeader.nClassifyCode);
     844             :     }
     845        2377 :     poFeature->SetField("CLNAME", szName);
     846             : 
     847        2377 :     poFeature->SetField("OBJECTNUMB", stRecordHeader.nSubObjectCount);
     848             : 
     849        2377 :     if (bHasAttributes)
     850             :     {
     851        1548 :         if (stRecordHeader.nFullLength < 32 ||
     852        1548 :             stRecordHeader.nGeometryLength > stRecordHeader.nFullLength - 32)
     853             :         {
     854           0 :             CPLFree(recordCertifBuf);
     855           0 :             delete poFeature;
     856           0 :             return nullptr;
     857             :         }
     858        1548 :         size_t nSemanticsSize =
     859        1548 :             stRecordHeader.nFullLength - 32 - stRecordHeader.nGeometryLength;
     860        1548 :         if (nSemanticsSize > 1024 * 1024)
     861             :         {
     862           0 :             CPLFree(recordCertifBuf);
     863           0 :             delete poFeature;
     864           0 :             return nullptr;
     865             :         }
     866        1548 :         char *psSemanticsdBuf = (char *)VSI_MALLOC_VERBOSE(nSemanticsSize);
     867        1548 :         if (psSemanticsdBuf == nullptr)
     868             :         {
     869           0 :             CPLFree(recordCertifBuf);
     870           0 :             delete poFeature;
     871           0 :             return nullptr;
     872             :         }
     873        1548 :         char *psSemanticsdBufOrig = psSemanticsdBuf;
     874        1548 :         nObjectRead = static_cast<int>(
     875        1548 :             VSIFReadL(psSemanticsdBuf, nSemanticsSize, 1, fpSXF));
     876        1548 :         if (nObjectRead == 1)
     877             :         {
     878        1548 :             size_t offset = 0;
     879        1548 :             double nVal = 0;
     880             : 
     881        3839 :             while (offset + sizeof(SXFRecordAttributeInfo) < nSemanticsSize)
     882             :             {
     883        2291 :                 char *psSemanticsdBufBeg = psSemanticsdBuf + offset;
     884        2291 :                 SXFRecordAttributeInfo stAttInfo =
     885             :                     *(SXFRecordAttributeInfo *)psSemanticsdBufBeg;
     886        2291 :                 CPL_LSBPTR16(&(stAttInfo.nCode));
     887        2291 :                 offset += 4;
     888             : 
     889        2291 :                 CPLString oFieldName;
     890        2291 :                 oFieldName.Printf("SC_%d", stAttInfo.nCode);
     891             : 
     892        2291 :                 CPLString oFieldValue;
     893             : 
     894        2291 :                 SXFRecordAttributeType eType =
     895        2291 :                     (SXFRecordAttributeType)stAttInfo.nType;
     896             : 
     897        2291 :                 switch (eType)
     898             :                 {
     899           0 :                     case SXF_RAT_ASCIIZ_DOS:
     900             :                     {
     901           0 :                         unsigned nLen = unsigned(stAttInfo.nScale) + 1;
     902           0 :                         if (nLen > nSemanticsSize ||
     903           0 :                             nSemanticsSize - nLen < offset)
     904             :                         {
     905           0 :                             nSemanticsSize = 0;
     906           0 :                             break;
     907             :                         }
     908           0 :                         char *value = (char *)CPLMalloc(nLen);
     909           0 :                         memcpy(value, psSemanticsdBuf + offset, nLen);
     910           0 :                         value[nLen - 1] = 0;
     911             :                         char *pszRecoded =
     912           0 :                             CPLRecode(value, "CP866", CPL_ENC_UTF8);
     913           0 :                         poFeature->SetField(oFieldName, pszRecoded);
     914           0 :                         CPLFree(pszRecoded);
     915           0 :                         CPLFree(value);
     916             : 
     917           0 :                         offset += stAttInfo.nScale + 1;
     918           0 :                         break;
     919             :                     }
     920           0 :                     case SXF_RAT_ONEBYTE:
     921             :                     {
     922           0 :                         if (offset + sizeof(GByte) > nSemanticsSize)
     923             :                         {
     924           0 :                             nSemanticsSize = 0;
     925           0 :                             break;
     926             :                         }
     927           0 :                         GByte nTmpVal = 0;
     928           0 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     929             :                                sizeof(GByte));
     930           0 :                         nVal = double(nTmpVal) *
     931           0 :                                pow(10.0, (double)stAttInfo.nScale);
     932             : 
     933           0 :                         poFeature->SetField(oFieldName, nVal);
     934           0 :                         offset += 1;
     935           0 :                         break;
     936             :                     }
     937         914 :                     case SXF_RAT_TWOBYTE:
     938             :                     {
     939         914 :                         if (offset + sizeof(GInt16) > nSemanticsSize)
     940             :                         {
     941           0 :                             nSemanticsSize = 0;
     942           0 :                             break;
     943             :                         }
     944         914 :                         GInt16 nTmpVal = 0;
     945         914 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     946             :                                sizeof(GInt16));
     947         914 :                         nVal = double(CPL_LSBWORD16(nTmpVal)) *
     948         914 :                                pow(10.0, (double)stAttInfo.nScale);
     949             : 
     950         914 :                         poFeature->SetField(oFieldName, nVal);
     951         914 :                         offset += 2;
     952         914 :                         break;
     953             :                     }
     954          28 :                     case SXF_RAT_FOURBYTE:
     955             :                     {
     956          28 :                         if (offset + sizeof(GInt32) > nSemanticsSize)
     957             :                         {
     958           0 :                             nSemanticsSize = 0;
     959           0 :                             break;
     960             :                         }
     961          28 :                         GInt32 nTmpVal = 0;
     962          28 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     963             :                                sizeof(GInt32));
     964          28 :                         nVal = double(CPL_LSBWORD32(nTmpVal)) *
     965          28 :                                pow(10.0, (double)stAttInfo.nScale);
     966             : 
     967          28 :                         poFeature->SetField(oFieldName, nVal);
     968          28 :                         offset += 4;
     969          28 :                         break;
     970             :                     }
     971         340 :                     case SXF_RAT_EIGHTBYTE:
     972             :                     {
     973         340 :                         if (offset + sizeof(double) > nSemanticsSize)
     974             :                         {
     975           0 :                             nSemanticsSize = 0;
     976           0 :                             break;
     977             :                         }
     978         340 :                         double dfTmpVal = 0.0;
     979         340 :                         memcpy(&dfTmpVal, psSemanticsdBuf + offset,
     980             :                                sizeof(double));
     981         340 :                         CPL_LSBPTR64(&dfTmpVal);
     982             :                         const double d =
     983         340 :                             dfTmpVal * pow(10.0, (double)stAttInfo.nScale);
     984             : 
     985         340 :                         poFeature->SetField(oFieldName, d);
     986             : 
     987         340 :                         offset += 8;
     988         340 :                         break;
     989             :                     }
     990        1009 :                     case SXF_RAT_ANSI_WIN:
     991             :                     {
     992        1009 :                         unsigned nLen = unsigned(stAttInfo.nScale) + 1;
     993        1009 :                         if (nLen > nSemanticsSize ||
     994        1009 :                             nSemanticsSize - nLen < offset)
     995             :                         {
     996           0 :                             nSemanticsSize = 0;
     997           0 :                             break;
     998             :                         }
     999        1009 :                         char *value = (char *)CPLMalloc(nLen);
    1000        1009 :                         memcpy(value, psSemanticsdBuf + offset, nLen);
    1001        1009 :                         value[nLen - 1] = 0;
    1002             :                         char *pszRecoded =
    1003        1009 :                             CPLRecode(value, "CP1251", CPL_ENC_UTF8);
    1004        1009 :                         poFeature->SetField(oFieldName, pszRecoded);
    1005        1009 :                         CPLFree(pszRecoded);
    1006        1009 :                         CPLFree(value);
    1007             : 
    1008        1009 :                         offset += nLen;
    1009        1009 :                         break;
    1010             :                     }
    1011           0 :                     case SXF_RAT_UNICODE:
    1012             :                     {
    1013           0 :                         uint64_t nLen64 =
    1014           0 :                             (static_cast<uint64_t>(stAttInfo.nScale) + 1) * 2;
    1015           0 :                         unsigned nLen = static_cast<unsigned>(nLen64);
    1016           0 :                         if (/* nLen < 2 || */ nLen64 > nSemanticsSize ||
    1017           0 :                             nSemanticsSize - nLen < offset)
    1018             :                         {
    1019           0 :                             nSemanticsSize = 0;
    1020           0 :                             break;
    1021             :                         }
    1022           0 :                         char *value = (char *)CPLMalloc(nLen);
    1023           0 :                         memcpy(value, psSemanticsdBuf + offset, nLen - 2);
    1024           0 :                         value[nLen - 1] = 0;
    1025           0 :                         value[nLen - 2] = 0;
    1026           0 :                         char *dst = (char *)CPLMalloc(nLen);
    1027           0 :                         int nCount = 0;
    1028           0 :                         for (int i = 0; (unsigned)i < nLen; i += 2)
    1029             :                         {
    1030           0 :                             unsigned char ucs = value[i];
    1031             : 
    1032           0 :                             if (ucs < 0x80U)
    1033             :                             {
    1034           0 :                                 dst[nCount++] = ucs;
    1035             :                             }
    1036             :                             else
    1037             :                             {
    1038           0 :                                 dst[nCount++] = 0xc0 | (ucs >> 6);
    1039           0 :                                 dst[nCount++] = 0x80 | (ucs & 0x3F);
    1040             :                             }
    1041             :                         }
    1042             : 
    1043           0 :                         poFeature->SetField(oFieldName, dst);
    1044           0 :                         CPLFree(dst);
    1045           0 :                         CPLFree(value);
    1046             : 
    1047           0 :                         offset += nLen;
    1048           0 :                         break;
    1049             :                     }
    1050           0 :                     case SXF_RAT_BIGTEXT:
    1051             :                     {
    1052           0 :                         if (offset + sizeof(GUInt32) > nSemanticsSize)
    1053             :                         {
    1054           0 :                             nSemanticsSize = 0;
    1055           0 :                             break;
    1056             :                         }
    1057           0 :                         GUInt32 scale2 = 0;
    1058           0 :                         memcpy(&scale2, psSemanticsdBuf + offset,
    1059             :                                sizeof(GUInt32));
    1060           0 :                         CPL_LSBPTR32(&scale2);
    1061             :                         /* FIXME add ?: offset += sizeof(GUInt32); */
    1062           0 :                         if (scale2 > nSemanticsSize - 1 ||
    1063           0 :                             nSemanticsSize - (scale2 + 1) < offset)
    1064             :                         {
    1065           0 :                             nSemanticsSize = 0;
    1066           0 :                             break;
    1067             :                         }
    1068             : 
    1069           0 :                         char *value = (char *)CPLMalloc(scale2 + 1);
    1070           0 :                         memcpy(value, psSemanticsdBuf + offset, scale2 + 1);
    1071           0 :                         value[scale2] = 0;
    1072             :                         char *pszRecoded =
    1073           0 :                             CPLRecode(value, CPL_ENC_UTF16, CPL_ENC_UTF8);
    1074           0 :                         poFeature->SetField(oFieldName, pszRecoded);
    1075           0 :                         CPLFree(pszRecoded);
    1076           0 :                         CPLFree(value);
    1077             : 
    1078           0 :                         offset += scale2;
    1079           0 :                         break;
    1080             :                     }
    1081           0 :                     default:
    1082           0 :                         CPLFree(recordCertifBuf);
    1083           0 :                         CPLFree(psSemanticsdBufOrig);
    1084           0 :                         delete poFeature;
    1085           0 :                         return nullptr;
    1086             :                 }
    1087             :             }
    1088             :         }
    1089        1548 :         CPLFree(psSemanticsdBufOrig);
    1090             :     }
    1091             : 
    1092        2377 :     poFeature->SetFID(nFID);
    1093             : 
    1094        2377 :     CPLFree(recordCertifBuf);
    1095             : 
    1096        2377 :     return poFeature;
    1097             : }
    1098             : 
    1099             : /************************************************************************/
    1100             : /*                         TranslatePoint   ()                          */
    1101             : /************************************************************************/
    1102             : 
    1103         323 : OGRFeature *OGRSXFLayer::TranslatePoint(const SXFRecordDescription &certifInfo,
    1104             :                                         const char *psRecordBuf,
    1105             :                                         GUInt32 nBufLen)
    1106             : {
    1107         323 :     double dfX = 1.0;
    1108         323 :     double dfY = 1.0;
    1109         323 :     double dfZ = 0.0;
    1110         323 :     GUInt32 nOffset = 0;
    1111         323 :     GUInt32 nDelta = 0;
    1112             : 
    1113         323 :     if (certifInfo.bDim == 1)
    1114             :     {
    1115             :         nDelta =
    1116           0 :             TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY, &dfZ);
    1117             :     }
    1118             :     else
    1119             :     {
    1120         323 :         nDelta = TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY);
    1121             :     }
    1122             : 
    1123         323 :     if (nDelta == 0)
    1124           0 :         return nullptr;
    1125         323 :     nOffset += nDelta;
    1126             : 
    1127             :     // OGRFeatureDefn *fd = poFeatureDefn->Clone();
    1128             :     // fd->SetGeomType( wkbMultiPoint );
    1129             :     //   OGRFeature *poFeature = new OGRFeature(fd);
    1130         323 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1131         323 :     OGRMultiPoint *poMPt = new OGRMultiPoint();
    1132             : 
    1133         323 :     poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
    1134             : 
    1135             :     /*---------------------- Reading SubObjects
    1136             :      * --------------------------------*/
    1137             : 
    1138         323 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1139             :     {
    1140           0 :         if (nOffset + 4 > nBufLen)
    1141           0 :             break;
    1142             : 
    1143           0 :         GUInt16 nSubObj = 0;
    1144           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1145           0 :         CPL_LSBPTR16(&nSubObj);
    1146             : 
    1147           0 :         GUInt16 nCoords = 0;
    1148           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1149           0 :         CPL_LSBPTR16(&nCoords);
    1150             : 
    1151           0 :         nOffset += 4;
    1152             : 
    1153           0 :         for (int i = 0; i < nCoords; i++)
    1154             :         {
    1155           0 :             const char *psCoords = psRecordBuf + nOffset;
    1156             : 
    1157           0 :             if (certifInfo.bDim == 1)
    1158             :             {
    1159           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1160             :                                       &dfX, &dfY, &dfZ);
    1161             :             }
    1162             :             else
    1163             :             {
    1164           0 :                 dfZ = 0.0;
    1165           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1166             :                                       &dfX, &dfY);
    1167             :             }
    1168             : 
    1169           0 :             if (nDelta == 0)
    1170           0 :                 break;
    1171           0 :             nOffset += nDelta;
    1172             : 
    1173           0 :             poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
    1174             :         }
    1175             :     }
    1176             : 
    1177             :     /*****
    1178             :      * TODO :
    1179             :      *          - Translate graphics
    1180             :      *          - Translate 3D vector
    1181             :      */
    1182             : 
    1183         323 :     poFeature->SetGeometryDirectly(poMPt);
    1184             : 
    1185         323 :     return poFeature;
    1186             : }
    1187             : 
    1188             : /************************************************************************/
    1189             : /*                         TranslateLine    ()                          */
    1190             : /************************************************************************/
    1191             : 
    1192         984 : OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription &certifInfo,
    1193             :                                        const char *psRecordBuf, GUInt32 nBufLen)
    1194             : {
    1195         984 :     double dfX = 1.0;
    1196         984 :     double dfY = 1.0;
    1197         984 :     double dfZ = 0.0;
    1198         984 :     GUInt32 nOffset = 0;
    1199             : 
    1200             :     // OGRFeatureDefn *fd = poFeatureDefn->Clone();
    1201             :     // fd->SetGeomType( wkbMultiLineString );
    1202             :     //   OGRFeature *poFeature = new OGRFeature(fd);
    1203             : 
    1204         984 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1205         984 :     OGRMultiLineString *poMLS = new OGRMultiLineString();
    1206             : 
    1207             :     /*---------------------- Reading Primary Line
    1208             :      * --------------------------------*/
    1209             : 
    1210         984 :     OGRLineString *poLS = new OGRLineString();
    1211             : 
    1212       29158 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1213             :     {
    1214       28174 :         const char *psCoords = psRecordBuf + nOffset;
    1215             : 
    1216             :         GInt32 nDelta;
    1217       28174 :         if (certifInfo.bDim == 1)
    1218             :         {
    1219           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1220             :                                   &dfY, &dfZ);
    1221             :         }
    1222             :         else
    1223             :         {
    1224       28174 :             dfZ = 0.0;
    1225       28174 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1226             :                                   &dfY);
    1227             :         }
    1228             : 
    1229       28174 :         if (nDelta == 0)
    1230           0 :             break;
    1231       28174 :         nOffset += nDelta;
    1232             : 
    1233       28174 :         poLS->addPoint(dfX, dfY, dfZ);
    1234             :     }
    1235             : 
    1236         984 :     poMLS->addGeometry(poLS);
    1237             : 
    1238             :     /*---------------------- Reading Sub Lines
    1239             :      * --------------------------------*/
    1240             : 
    1241         984 :     for (GUInt16 count = 0; count < certifInfo.nSubObjectCount; count++)
    1242             :     {
    1243           0 :         poLS->empty();
    1244             : 
    1245           0 :         if (nOffset + 4 > nBufLen)
    1246           0 :             break;
    1247             : 
    1248           0 :         GUInt16 nSubObj = 0;
    1249           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1250           0 :         CPL_LSBPTR16(&nSubObj);
    1251             : 
    1252           0 :         GUInt16 nCoords = 0;
    1253           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1254           0 :         CPL_LSBPTR16(&nCoords);
    1255             : 
    1256           0 :         nOffset += 4;
    1257             : 
    1258           0 :         for (GUInt16 i = 0; i < nCoords; i++)
    1259             :         {
    1260           0 :             const char *psCoords = psRecordBuf + nOffset;
    1261             :             GInt32 nDelta;
    1262           0 :             if (certifInfo.bDim == 1)
    1263             :             {
    1264           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1265             :                                       &dfX, &dfY, &dfZ);
    1266             :             }
    1267             :             else
    1268             :             {
    1269           0 :                 dfZ = 0.0;
    1270           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1271             :                                       &dfX, &dfY);
    1272             :             }
    1273             : 
    1274           0 :             if (nDelta == 0)
    1275           0 :                 break;
    1276           0 :             nOffset += nDelta;
    1277             : 
    1278           0 :             poLS->addPoint(dfX, dfY, dfZ);
    1279             :         }
    1280             : 
    1281           0 :         poMLS->addGeometry(poLS);
    1282             :     }  // for
    1283             : 
    1284         984 :     delete poLS;
    1285         984 :     poFeature->SetGeometryDirectly(poMLS);
    1286             : 
    1287             :     /*****
    1288             :      * TODO :
    1289             :      *          - Translate graphics
    1290             :      *          - Translate 3D vector
    1291             :      */
    1292             : 
    1293         984 :     return poFeature;
    1294             : }
    1295             : 
    1296             : /************************************************************************/
    1297             : /*                       TranslateVetorAngle()                          */
    1298             : /************************************************************************/
    1299             : 
    1300             : OGRFeature *
    1301         420 : OGRSXFLayer::TranslateVetorAngle(const SXFRecordDescription &certifInfo,
    1302             :                                  const char *psRecordBuf, GUInt32 nBufLen)
    1303             : {
    1304         420 :     if (certifInfo.nPointCount != 2)
    1305             :     {
    1306           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1307             :                  "SXF. The vector object should have 2 points, but not.");
    1308           0 :         return nullptr;
    1309             :     }
    1310             : 
    1311         420 :     GUInt32 nOffset = 0;
    1312             : 
    1313         420 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1314         420 :     OGRPoint *poPT = new OGRPoint();
    1315             : 
    1316             :     /*---------------------- Reading Primary Line
    1317             :      * --------------------------------*/
    1318             : 
    1319         420 :     OGRLineString *poLS = new OGRLineString();
    1320             : 
    1321        1260 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1322             :     {
    1323         840 :         const char *psCoords = psRecordBuf + nOffset;
    1324             : 
    1325         840 :         double dfX = 1.0;
    1326         840 :         double dfY = 1.0;
    1327         840 :         double dfZ = 0.0;
    1328             :         GInt32 nDelta;
    1329         840 :         if (certifInfo.bDim == 1)
    1330             :         {
    1331           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1332             :                                   &dfY, &dfZ);
    1333             :         }
    1334             :         else
    1335             :         {
    1336         840 :             dfZ = 0.0;
    1337         840 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1338             :                                   &dfY);
    1339             :         }
    1340         840 :         if (nDelta == 0)
    1341           0 :             break;
    1342         840 :         nOffset += nDelta;
    1343             : 
    1344         840 :         poLS->addPoint(dfX, dfY, dfZ);
    1345             :     }
    1346             : 
    1347         420 :     poLS->StartPoint(poPT);
    1348             : 
    1349         420 :     OGRPoint *poAngPT = new OGRPoint();
    1350         420 :     poLS->EndPoint(poAngPT);
    1351             : 
    1352         420 :     const double xDiff = poPT->getX() - poAngPT->getX();
    1353         420 :     const double yDiff = poPT->getY() - poAngPT->getY();
    1354         420 :     double dfAngle = atan2(xDiff, yDiff) * TO_DEGREES - 90;
    1355         420 :     if (dfAngle < 0)
    1356         280 :         dfAngle += 360;
    1357             : 
    1358         420 :     poFeature->SetGeometryDirectly(poPT);
    1359         420 :     poFeature->SetField("ANGLE", dfAngle);
    1360             : 
    1361         420 :     delete poAngPT;
    1362         420 :     delete poLS;
    1363             : 
    1364         420 :     return poFeature;
    1365             : }
    1366             : 
    1367             : /************************************************************************/
    1368             : /*                         TranslatePolygon ()                          */
    1369             : /************************************************************************/
    1370             : 
    1371             : OGRFeature *
    1372         510 : OGRSXFLayer::TranslatePolygon(const SXFRecordDescription &certifInfo,
    1373             :                               const char *psRecordBuf, GUInt32 nBufLen)
    1374             : {
    1375         510 :     double dfX = 1.0;
    1376         510 :     double dfY = 1.0;
    1377         510 :     double dfZ = 0.0;
    1378         510 :     GUInt32 nOffset = 0;
    1379         510 :     GUInt32 nDelta = 0;
    1380             : 
    1381         510 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1382         510 :     OGRPolygon *poPoly = new OGRPolygon();
    1383         510 :     OGRLineString *poLS = new OGRLineString();
    1384             : 
    1385             :     /*---------------------- Reading Primary Polygon
    1386             :      * --------------------------------*/
    1387       28991 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1388             :     {
    1389       28481 :         const char *psBuf = psRecordBuf + nOffset;
    1390       28481 :         if (certifInfo.bDim == 1)
    1391             :         {
    1392           0 :             nDelta = TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX,
    1393             :                                   &dfY, &dfZ);
    1394             :         }
    1395             :         else
    1396             :         {
    1397       28481 :             dfZ = 0.0;
    1398             :             nDelta =
    1399       28481 :                 TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY);
    1400             :         }
    1401             : 
    1402       28481 :         if (nDelta == 0)
    1403           0 :             break;
    1404       28481 :         nOffset += nDelta;
    1405       28481 :         poLS->addPoint(dfX, dfY, dfZ);
    1406             :     }  // for
    1407             : 
    1408         510 :     OGRLinearRing *poLR = new OGRLinearRing();
    1409         510 :     poLR->addSubLineString(poLS, 0);
    1410             : 
    1411         510 :     poPoly->addRingDirectly(poLR);
    1412             : 
    1413             :     /*---------------------- Reading Sub Lines
    1414             :      * --------------------------------*/
    1415             : 
    1416         542 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1417             :     {
    1418          32 :         poLS->empty();
    1419             : 
    1420          32 :         if (nOffset + 4 > nBufLen)
    1421           0 :             break;
    1422             : 
    1423          32 :         GUInt16 nSubObj = 0;
    1424          32 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1425          32 :         CPL_LSBPTR16(&nSubObj);
    1426             : 
    1427          32 :         GUInt16 nCoords = 0;
    1428          32 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1429          32 :         CPL_LSBPTR16(&nCoords);
    1430             : 
    1431             :         // TODO: Is this really what the buffer size should be?
    1432          32 :         if (nCoords * nDelta != nBufLen - nOffset + 2 - 6)
    1433             :         {
    1434           0 :             CPLError(CE_Warning, CPLE_FileIO,
    1435             :                      "SXF raw feature size incorrect.  "
    1436             :                      "%d %d",
    1437           0 :                      nCoords * nDelta, nBufLen - nOffset + 2 - 6);
    1438             :             // TODO: How best to gracefully exit and report an issue?
    1439             :             // break; or cleanup and return NULL?
    1440             :         }
    1441             : 
    1442          32 :         nOffset += 4;
    1443             : 
    1444         480 :         for (int i = 0; i < nCoords; i++)
    1445             :         {
    1446         448 :             const char *psCoords = psRecordBuf + nOffset;
    1447         448 :             if (certifInfo.bDim == 1)
    1448             :             {
    1449           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1450             :                                       &dfX, &dfY, &dfZ);
    1451             :             }
    1452             :             else
    1453             :             {
    1454         448 :                 dfZ = 0.0;
    1455         448 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1456             :                                       &dfX, &dfY);
    1457             :             }
    1458             : 
    1459         448 :             if (nDelta == 0)
    1460           0 :                 break;
    1461         448 :             nOffset += nDelta;
    1462             : 
    1463         448 :             poLS->addPoint(dfX, dfY, dfZ);
    1464             :         }
    1465             : 
    1466          32 :         poLR = new OGRLinearRing();
    1467          32 :         poLR->addSubLineString(poLS, 0);
    1468             : 
    1469          32 :         poPoly->addRingDirectly(poLR);
    1470             :     }  // for
    1471             : 
    1472         510 :     poFeature->SetGeometryDirectly(poPoly);  // poLS);
    1473         510 :     delete poLS;
    1474             : 
    1475             :     /*****
    1476             :      * TODO :
    1477             :      *          - Translate graphics
    1478             :      *          - Translate 3D vector
    1479             :      */
    1480         510 :     return poFeature;
    1481             : }
    1482             : 
    1483             : /************************************************************************/
    1484             : /*                         TranslateText    ()                          */
    1485             : /************************************************************************/
    1486         140 : OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription &certifInfo,
    1487             :                                        const char *psRecordBuf, GUInt32 nBufLen)
    1488             : {
    1489         140 :     double dfX = 1.0;
    1490         140 :     double dfY = 1.0;
    1491         140 :     double dfZ = 0.0;
    1492         140 :     GUInt32 nOffset = 0;
    1493             : 
    1494         140 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1495         140 :     OGRMultiLineString *poMLS = new OGRMultiLineString();
    1496             : 
    1497             :     /*---------------------- Reading Primary Line
    1498             :      * --------------------------------*/
    1499             : 
    1500         140 :     OGRLineString *poLS = new OGRLineString();
    1501             : 
    1502         420 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1503             :     {
    1504         280 :         const char *psCoords = psRecordBuf + nOffset;
    1505             : 
    1506             :         GUInt32 nDelta;
    1507         280 :         if (certifInfo.bDim == 1)
    1508             :         {
    1509           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1510             :                                   &dfY, &dfZ);
    1511             :         }
    1512             :         else
    1513             :         {
    1514         280 :             dfZ = 0.0;
    1515         280 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1516             :                                   &dfY);
    1517             :         }
    1518             : 
    1519         280 :         if (nDelta == 0)
    1520           0 :             break;
    1521         280 :         nOffset += nDelta;
    1522             : 
    1523         280 :         poLS->addPoint(dfX, dfY, dfZ);
    1524             :     }
    1525             : 
    1526         140 :     poMLS->addGeometry(poLS);
    1527             : 
    1528             :     /*------------------     READING TEXT VALUE
    1529             :      * --------------------------------*/
    1530         280 :     CPLString soText;
    1531             : 
    1532         140 :     if (certifInfo.bHasTextSign)
    1533             :     {
    1534         140 :         if (nOffset + 1 > nBufLen)
    1535           0 :             return poFeature;
    1536         140 :         const char *pszTxt = psRecordBuf + nOffset;
    1537         140 :         GByte nTextL = (GByte)*pszTxt;
    1538         140 :         if (nOffset + 1 + nTextL > nBufLen)
    1539           0 :             return poFeature;
    1540             : 
    1541         140 :         char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
    1542             : 
    1543         140 :         strncpy(pszTextBuf, (pszTxt + 1), nTextL);
    1544         140 :         pszTextBuf[nTextL] = '\0';
    1545             : 
    1546             :         // TODO: Check encoding from sxf
    1547         140 :         char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
    1548         140 :         soText += pszRecoded;
    1549         140 :         CPLFree(pszRecoded);
    1550             : 
    1551         140 :         CPLFree(pszTextBuf);
    1552             : 
    1553         140 :         nOffset += nTextL + 2;
    1554             :     }
    1555             : 
    1556             :     /*---------------------- Reading Sub Lines
    1557             :      * --------------------------------*/
    1558             : 
    1559         140 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1560             :     {
    1561           0 :         poLS->empty();
    1562             : 
    1563           0 :         if (nOffset + 4 > nBufLen)
    1564           0 :             break;
    1565             : 
    1566           0 :         GUInt16 nSubObj = 0;
    1567           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1568           0 :         CPL_LSBPTR16(&nSubObj);
    1569             : 
    1570           0 :         GUInt16 nCoords = 0;
    1571           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1572           0 :         CPL_LSBPTR16(&nCoords);
    1573             : 
    1574           0 :         nOffset += 4;
    1575             : 
    1576           0 :         for (int i = 0; i < nCoords; i++)
    1577             :         {
    1578           0 :             const char *psCoords = psRecordBuf + nOffset;
    1579             :             GUInt32 nDelta;
    1580           0 :             if (certifInfo.bDim == 1)
    1581             :             {
    1582           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1583             :                                       &dfX, &dfY, &dfZ);
    1584             :             }
    1585             :             else
    1586             :             {
    1587           0 :                 dfZ = 0.0;
    1588           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1589             :                                       &dfX, &dfY);
    1590             :             }
    1591             : 
    1592           0 :             if (nDelta == 0)
    1593           0 :                 break;
    1594           0 :             nOffset += nDelta;
    1595             : 
    1596           0 :             poLS->addPoint(dfX, dfY, dfZ);
    1597             :         }
    1598             : 
    1599           0 :         poMLS->addGeometry(poLS);
    1600             : 
    1601           0 :         if (certifInfo.bHasTextSign)
    1602             :         {
    1603           0 :             if (nOffset + 1 > nBufLen)
    1604           0 :                 return poFeature;
    1605           0 :             const char *pszTxt = psRecordBuf + nOffset;
    1606           0 :             GByte nTextL = (GByte)*pszTxt;
    1607           0 :             if (nOffset + 1 + nTextL > nBufLen)
    1608           0 :                 return poFeature;
    1609             : 
    1610           0 :             char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
    1611             : 
    1612           0 :             strncpy(pszTextBuf, (pszTxt + 1), nTextL);
    1613           0 :             pszTextBuf[nTextL] = '\0';
    1614             : 
    1615             :             // TODO: Check encoding from sxf
    1616           0 :             char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
    1617           0 :             soText += " " + CPLString(pszRecoded);
    1618           0 :             CPLFree(pszRecoded);
    1619             : 
    1620           0 :             CPLFree(pszTextBuf);
    1621             : 
    1622           0 :             nOffset += nTextL + 2;
    1623             :         }
    1624             :     }  // for
    1625             : 
    1626         140 :     delete poLS;
    1627         140 :     poFeature->SetGeometryDirectly(poMLS);
    1628             : 
    1629         140 :     poFeature->SetField("TEXT", soText);
    1630         140 :     return poFeature;
    1631             : }
    1632             : 
    1633         297 : const char *OGRSXFLayer::GetFIDColumn()
    1634             : {
    1635         297 :     return sFIDColumn_.c_str();
    1636             : }

Generated by: LCOV version 1.14