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-05-31 00:00:17 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             :                     *reinterpret_cast<SXFRecordAttributeInfo *>(
     886             :                         psSemanticsdBufBeg);
     887        2291 :                 CPL_LSBPTR16(&(stAttInfo.nCode));
     888        2291 :                 offset += 4;
     889             : 
     890        2291 :                 CPLString oFieldName;
     891        2291 :                 oFieldName.Printf("SC_%d", stAttInfo.nCode);
     892             : 
     893        2291 :                 CPLString oFieldValue;
     894             : 
     895        2291 :                 SXFRecordAttributeType eType =
     896        2291 :                     (SXFRecordAttributeType)stAttInfo.nType;
     897             : 
     898        2291 :                 switch (eType)
     899             :                 {
     900           0 :                     case SXF_RAT_ASCIIZ_DOS:
     901             :                     {
     902           0 :                         unsigned nLen = unsigned(stAttInfo.nScale) + 1;
     903           0 :                         if (nLen > nSemanticsSize ||
     904           0 :                             nSemanticsSize - nLen < offset)
     905             :                         {
     906           0 :                             nSemanticsSize = 0;
     907           0 :                             break;
     908             :                         }
     909           0 :                         char *value = (char *)CPLMalloc(nLen);
     910           0 :                         memcpy(value, psSemanticsdBuf + offset, nLen);
     911           0 :                         value[nLen - 1] = 0;
     912             :                         char *pszRecoded =
     913           0 :                             CPLRecode(value, "CP866", CPL_ENC_UTF8);
     914           0 :                         poFeature->SetField(oFieldName, pszRecoded);
     915           0 :                         CPLFree(pszRecoded);
     916           0 :                         CPLFree(value);
     917             : 
     918           0 :                         offset += stAttInfo.nScale + 1;
     919           0 :                         break;
     920             :                     }
     921           0 :                     case SXF_RAT_ONEBYTE:
     922             :                     {
     923           0 :                         if (offset + sizeof(GByte) > nSemanticsSize)
     924             :                         {
     925           0 :                             nSemanticsSize = 0;
     926           0 :                             break;
     927             :                         }
     928           0 :                         GByte nTmpVal = 0;
     929           0 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     930             :                                sizeof(GByte));
     931           0 :                         nVal = double(nTmpVal) *
     932           0 :                                pow(10.0, (double)stAttInfo.nScale);
     933             : 
     934           0 :                         poFeature->SetField(oFieldName, nVal);
     935           0 :                         offset += 1;
     936           0 :                         break;
     937             :                     }
     938         914 :                     case SXF_RAT_TWOBYTE:
     939             :                     {
     940         914 :                         if (offset + sizeof(GInt16) > nSemanticsSize)
     941             :                         {
     942           0 :                             nSemanticsSize = 0;
     943           0 :                             break;
     944             :                         }
     945         914 :                         GInt16 nTmpVal = 0;
     946         914 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     947             :                                sizeof(GInt16));
     948         914 :                         nVal = double(CPL_LSBWORD16(nTmpVal)) *
     949         914 :                                pow(10.0, (double)stAttInfo.nScale);
     950             : 
     951         914 :                         poFeature->SetField(oFieldName, nVal);
     952         914 :                         offset += 2;
     953         914 :                         break;
     954             :                     }
     955          28 :                     case SXF_RAT_FOURBYTE:
     956             :                     {
     957          28 :                         if (offset + sizeof(GInt32) > nSemanticsSize)
     958             :                         {
     959           0 :                             nSemanticsSize = 0;
     960           0 :                             break;
     961             :                         }
     962          28 :                         GInt32 nTmpVal = 0;
     963          28 :                         memcpy(&nTmpVal, psSemanticsdBuf + offset,
     964             :                                sizeof(GInt32));
     965          28 :                         nVal = double(CPL_LSBWORD32(nTmpVal)) *
     966          28 :                                pow(10.0, (double)stAttInfo.nScale);
     967             : 
     968          28 :                         poFeature->SetField(oFieldName, nVal);
     969          28 :                         offset += 4;
     970          28 :                         break;
     971             :                     }
     972         340 :                     case SXF_RAT_EIGHTBYTE:
     973             :                     {
     974         340 :                         if (offset + sizeof(double) > nSemanticsSize)
     975             :                         {
     976           0 :                             nSemanticsSize = 0;
     977           0 :                             break;
     978             :                         }
     979         340 :                         double dfTmpVal = 0.0;
     980         340 :                         memcpy(&dfTmpVal, psSemanticsdBuf + offset,
     981             :                                sizeof(double));
     982         340 :                         CPL_LSBPTR64(&dfTmpVal);
     983             :                         const double d =
     984         340 :                             dfTmpVal * pow(10.0, (double)stAttInfo.nScale);
     985             : 
     986         340 :                         poFeature->SetField(oFieldName, d);
     987             : 
     988         340 :                         offset += 8;
     989         340 :                         break;
     990             :                     }
     991        1009 :                     case SXF_RAT_ANSI_WIN:
     992             :                     {
     993        1009 :                         unsigned nLen = unsigned(stAttInfo.nScale) + 1;
     994        1009 :                         if (nLen > nSemanticsSize ||
     995        1009 :                             nSemanticsSize - nLen < offset)
     996             :                         {
     997           0 :                             nSemanticsSize = 0;
     998           0 :                             break;
     999             :                         }
    1000        1009 :                         char *value = (char *)CPLMalloc(nLen);
    1001        1009 :                         memcpy(value, psSemanticsdBuf + offset, nLen);
    1002        1009 :                         value[nLen - 1] = 0;
    1003             :                         char *pszRecoded =
    1004        1009 :                             CPLRecode(value, "CP1251", CPL_ENC_UTF8);
    1005        1009 :                         poFeature->SetField(oFieldName, pszRecoded);
    1006        1009 :                         CPLFree(pszRecoded);
    1007        1009 :                         CPLFree(value);
    1008             : 
    1009        1009 :                         offset += nLen;
    1010        1009 :                         break;
    1011             :                     }
    1012           0 :                     case SXF_RAT_UNICODE:
    1013             :                     {
    1014           0 :                         uint64_t nLen64 =
    1015           0 :                             (static_cast<uint64_t>(stAttInfo.nScale) + 1) * 2;
    1016           0 :                         unsigned nLen = static_cast<unsigned>(nLen64);
    1017           0 :                         if (/* nLen < 2 || */ nLen64 > nSemanticsSize ||
    1018           0 :                             nSemanticsSize - nLen < offset)
    1019             :                         {
    1020           0 :                             nSemanticsSize = 0;
    1021           0 :                             break;
    1022             :                         }
    1023           0 :                         char *value = (char *)CPLMalloc(nLen);
    1024           0 :                         memcpy(value, psSemanticsdBuf + offset, nLen - 2);
    1025           0 :                         value[nLen - 1] = 0;
    1026           0 :                         value[nLen - 2] = 0;
    1027           0 :                         char *dst = (char *)CPLMalloc(nLen);
    1028           0 :                         int nCount = 0;
    1029           0 :                         for (int i = 0; (unsigned)i < nLen; i += 2)
    1030             :                         {
    1031           0 :                             unsigned char ucs = value[i];
    1032             : 
    1033           0 :                             if (ucs < 0x80U)
    1034             :                             {
    1035           0 :                                 dst[nCount++] = ucs;
    1036             :                             }
    1037             :                             else
    1038             :                             {
    1039           0 :                                 dst[nCount++] = 0xc0 | (ucs >> 6);
    1040           0 :                                 dst[nCount++] = 0x80 | (ucs & 0x3F);
    1041             :                             }
    1042             :                         }
    1043             : 
    1044           0 :                         poFeature->SetField(oFieldName, dst);
    1045           0 :                         CPLFree(dst);
    1046           0 :                         CPLFree(value);
    1047             : 
    1048           0 :                         offset += nLen;
    1049           0 :                         break;
    1050             :                     }
    1051           0 :                     case SXF_RAT_BIGTEXT:
    1052             :                     {
    1053           0 :                         if (offset + sizeof(GUInt32) > nSemanticsSize)
    1054             :                         {
    1055           0 :                             nSemanticsSize = 0;
    1056           0 :                             break;
    1057             :                         }
    1058           0 :                         GUInt32 scale2 = 0;
    1059           0 :                         memcpy(&scale2, psSemanticsdBuf + offset,
    1060             :                                sizeof(GUInt32));
    1061           0 :                         CPL_LSBPTR32(&scale2);
    1062             :                         /* FIXME add ?: offset += sizeof(GUInt32); */
    1063           0 :                         if (scale2 > nSemanticsSize - 1 ||
    1064           0 :                             nSemanticsSize - (scale2 + 1) < offset)
    1065             :                         {
    1066           0 :                             nSemanticsSize = 0;
    1067           0 :                             break;
    1068             :                         }
    1069             : 
    1070           0 :                         char *value = (char *)CPLMalloc(scale2 + 1);
    1071           0 :                         memcpy(value, psSemanticsdBuf + offset, scale2 + 1);
    1072           0 :                         value[scale2] = 0;
    1073             :                         char *pszRecoded =
    1074           0 :                             CPLRecode(value, CPL_ENC_UTF16, CPL_ENC_UTF8);
    1075           0 :                         poFeature->SetField(oFieldName, pszRecoded);
    1076           0 :                         CPLFree(pszRecoded);
    1077           0 :                         CPLFree(value);
    1078             : 
    1079           0 :                         offset += scale2;
    1080           0 :                         break;
    1081             :                     }
    1082           0 :                     default:
    1083           0 :                         CPLFree(recordCertifBuf);
    1084           0 :                         CPLFree(psSemanticsdBufOrig);
    1085           0 :                         delete poFeature;
    1086           0 :                         return nullptr;
    1087             :                 }
    1088             :             }
    1089             :         }
    1090        1548 :         CPLFree(psSemanticsdBufOrig);
    1091             :     }
    1092             : 
    1093        2377 :     poFeature->SetFID(nFID);
    1094             : 
    1095        2377 :     CPLFree(recordCertifBuf);
    1096             : 
    1097        2377 :     return poFeature;
    1098             : }
    1099             : 
    1100             : /************************************************************************/
    1101             : /*                         TranslatePoint   ()                          */
    1102             : /************************************************************************/
    1103             : 
    1104         323 : OGRFeature *OGRSXFLayer::TranslatePoint(const SXFRecordDescription &certifInfo,
    1105             :                                         const char *psRecordBuf,
    1106             :                                         GUInt32 nBufLen)
    1107             : {
    1108         323 :     double dfX = 1.0;
    1109         323 :     double dfY = 1.0;
    1110         323 :     double dfZ = 0.0;
    1111         323 :     GUInt32 nOffset = 0;
    1112         323 :     GUInt32 nDelta = 0;
    1113             : 
    1114         323 :     if (certifInfo.bDim == 1)
    1115             :     {
    1116             :         nDelta =
    1117           0 :             TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY, &dfZ);
    1118             :     }
    1119             :     else
    1120             :     {
    1121         323 :         nDelta = TranslateXYH(certifInfo, psRecordBuf, nBufLen, &dfX, &dfY);
    1122             :     }
    1123             : 
    1124         323 :     if (nDelta == 0)
    1125           0 :         return nullptr;
    1126         323 :     nOffset += nDelta;
    1127             : 
    1128             :     // OGRFeatureDefn *fd = poFeatureDefn->Clone();
    1129             :     // fd->SetGeomType( wkbMultiPoint );
    1130             :     //   OGRFeature *poFeature = new OGRFeature(fd);
    1131         323 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1132         323 :     OGRMultiPoint *poMPt = new OGRMultiPoint();
    1133             : 
    1134         323 :     poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
    1135             : 
    1136             :     /*---------------------- Reading SubObjects
    1137             :      * --------------------------------*/
    1138             : 
    1139         323 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1140             :     {
    1141           0 :         if (nOffset + 4 > nBufLen)
    1142           0 :             break;
    1143             : 
    1144           0 :         GUInt16 nSubObj = 0;
    1145           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1146           0 :         CPL_LSBPTR16(&nSubObj);
    1147             : 
    1148           0 :         GUInt16 nCoords = 0;
    1149           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1150           0 :         CPL_LSBPTR16(&nCoords);
    1151             : 
    1152           0 :         nOffset += 4;
    1153             : 
    1154           0 :         for (int i = 0; i < nCoords; i++)
    1155             :         {
    1156           0 :             const char *psCoords = psRecordBuf + nOffset;
    1157             : 
    1158           0 :             if (certifInfo.bDim == 1)
    1159             :             {
    1160           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1161             :                                       &dfX, &dfY, &dfZ);
    1162             :             }
    1163             :             else
    1164             :             {
    1165           0 :                 dfZ = 0.0;
    1166           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1167             :                                       &dfX, &dfY);
    1168             :             }
    1169             : 
    1170           0 :             if (nDelta == 0)
    1171           0 :                 break;
    1172           0 :             nOffset += nDelta;
    1173             : 
    1174           0 :             poMPt->addGeometryDirectly(new OGRPoint(dfX, dfY, dfZ));
    1175             :         }
    1176             :     }
    1177             : 
    1178             :     /*****
    1179             :      * TODO :
    1180             :      *          - Translate graphics
    1181             :      *          - Translate 3D vector
    1182             :      */
    1183             : 
    1184         323 :     poFeature->SetGeometryDirectly(poMPt);
    1185             : 
    1186         323 :     return poFeature;
    1187             : }
    1188             : 
    1189             : /************************************************************************/
    1190             : /*                         TranslateLine    ()                          */
    1191             : /************************************************************************/
    1192             : 
    1193         984 : OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription &certifInfo,
    1194             :                                        const char *psRecordBuf, GUInt32 nBufLen)
    1195             : {
    1196         984 :     double dfX = 1.0;
    1197         984 :     double dfY = 1.0;
    1198         984 :     double dfZ = 0.0;
    1199         984 :     GUInt32 nOffset = 0;
    1200             : 
    1201             :     // OGRFeatureDefn *fd = poFeatureDefn->Clone();
    1202             :     // fd->SetGeomType( wkbMultiLineString );
    1203             :     //   OGRFeature *poFeature = new OGRFeature(fd);
    1204             : 
    1205         984 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1206         984 :     OGRMultiLineString *poMLS = new OGRMultiLineString();
    1207             : 
    1208             :     /*---------------------- Reading Primary Line
    1209             :      * --------------------------------*/
    1210             : 
    1211         984 :     OGRLineString *poLS = new OGRLineString();
    1212             : 
    1213       29158 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1214             :     {
    1215       28174 :         const char *psCoords = psRecordBuf + nOffset;
    1216             : 
    1217             :         GInt32 nDelta;
    1218       28174 :         if (certifInfo.bDim == 1)
    1219             :         {
    1220           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1221             :                                   &dfY, &dfZ);
    1222             :         }
    1223             :         else
    1224             :         {
    1225       28174 :             dfZ = 0.0;
    1226       28174 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1227             :                                   &dfY);
    1228             :         }
    1229             : 
    1230       28174 :         if (nDelta == 0)
    1231           0 :             break;
    1232       28174 :         nOffset += nDelta;
    1233             : 
    1234       28174 :         poLS->addPoint(dfX, dfY, dfZ);
    1235             :     }
    1236             : 
    1237         984 :     poMLS->addGeometry(poLS);
    1238             : 
    1239             :     /*---------------------- Reading Sub Lines
    1240             :      * --------------------------------*/
    1241             : 
    1242         984 :     for (GUInt16 count = 0; count < certifInfo.nSubObjectCount; count++)
    1243             :     {
    1244           0 :         poLS->empty();
    1245             : 
    1246           0 :         if (nOffset + 4 > nBufLen)
    1247           0 :             break;
    1248             : 
    1249           0 :         GUInt16 nSubObj = 0;
    1250           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1251           0 :         CPL_LSBPTR16(&nSubObj);
    1252             : 
    1253           0 :         GUInt16 nCoords = 0;
    1254           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1255           0 :         CPL_LSBPTR16(&nCoords);
    1256             : 
    1257           0 :         nOffset += 4;
    1258             : 
    1259           0 :         for (GUInt16 i = 0; i < nCoords; i++)
    1260             :         {
    1261           0 :             const char *psCoords = psRecordBuf + nOffset;
    1262             :             GInt32 nDelta;
    1263           0 :             if (certifInfo.bDim == 1)
    1264             :             {
    1265           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1266             :                                       &dfX, &dfY, &dfZ);
    1267             :             }
    1268             :             else
    1269             :             {
    1270           0 :                 dfZ = 0.0;
    1271           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1272             :                                       &dfX, &dfY);
    1273             :             }
    1274             : 
    1275           0 :             if (nDelta == 0)
    1276           0 :                 break;
    1277           0 :             nOffset += nDelta;
    1278             : 
    1279           0 :             poLS->addPoint(dfX, dfY, dfZ);
    1280             :         }
    1281             : 
    1282           0 :         poMLS->addGeometry(poLS);
    1283             :     }  // for
    1284             : 
    1285         984 :     delete poLS;
    1286         984 :     poFeature->SetGeometryDirectly(poMLS);
    1287             : 
    1288             :     /*****
    1289             :      * TODO :
    1290             :      *          - Translate graphics
    1291             :      *          - Translate 3D vector
    1292             :      */
    1293             : 
    1294         984 :     return poFeature;
    1295             : }
    1296             : 
    1297             : /************************************************************************/
    1298             : /*                       TranslateVetorAngle()                          */
    1299             : /************************************************************************/
    1300             : 
    1301             : OGRFeature *
    1302         420 : OGRSXFLayer::TranslateVetorAngle(const SXFRecordDescription &certifInfo,
    1303             :                                  const char *psRecordBuf, GUInt32 nBufLen)
    1304             : {
    1305         420 :     if (certifInfo.nPointCount != 2)
    1306             :     {
    1307           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    1308             :                  "SXF. The vector object should have 2 points, but not.");
    1309           0 :         return nullptr;
    1310             :     }
    1311             : 
    1312         420 :     GUInt32 nOffset = 0;
    1313             : 
    1314         420 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1315         420 :     OGRPoint *poPT = new OGRPoint();
    1316             : 
    1317             :     /*---------------------- Reading Primary Line
    1318             :      * --------------------------------*/
    1319             : 
    1320         420 :     OGRLineString *poLS = new OGRLineString();
    1321             : 
    1322        1260 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1323             :     {
    1324         840 :         const char *psCoords = psRecordBuf + nOffset;
    1325             : 
    1326         840 :         double dfX = 1.0;
    1327         840 :         double dfY = 1.0;
    1328         840 :         double dfZ = 0.0;
    1329             :         GInt32 nDelta;
    1330         840 :         if (certifInfo.bDim == 1)
    1331             :         {
    1332           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1333             :                                   &dfY, &dfZ);
    1334             :         }
    1335             :         else
    1336             :         {
    1337         840 :             dfZ = 0.0;
    1338         840 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1339             :                                   &dfY);
    1340             :         }
    1341         840 :         if (nDelta == 0)
    1342           0 :             break;
    1343         840 :         nOffset += nDelta;
    1344             : 
    1345         840 :         poLS->addPoint(dfX, dfY, dfZ);
    1346             :     }
    1347             : 
    1348         420 :     poLS->StartPoint(poPT);
    1349             : 
    1350         420 :     OGRPoint *poAngPT = new OGRPoint();
    1351         420 :     poLS->EndPoint(poAngPT);
    1352             : 
    1353         420 :     const double xDiff = poPT->getX() - poAngPT->getX();
    1354         420 :     const double yDiff = poPT->getY() - poAngPT->getY();
    1355         420 :     double dfAngle = atan2(xDiff, yDiff) * TO_DEGREES - 90;
    1356         420 :     if (dfAngle < 0)
    1357         280 :         dfAngle += 360;
    1358             : 
    1359         420 :     poFeature->SetGeometryDirectly(poPT);
    1360         420 :     poFeature->SetField("ANGLE", dfAngle);
    1361             : 
    1362         420 :     delete poAngPT;
    1363         420 :     delete poLS;
    1364             : 
    1365         420 :     return poFeature;
    1366             : }
    1367             : 
    1368             : /************************************************************************/
    1369             : /*                         TranslatePolygon ()                          */
    1370             : /************************************************************************/
    1371             : 
    1372             : OGRFeature *
    1373         510 : OGRSXFLayer::TranslatePolygon(const SXFRecordDescription &certifInfo,
    1374             :                               const char *psRecordBuf, GUInt32 nBufLen)
    1375             : {
    1376         510 :     double dfX = 1.0;
    1377         510 :     double dfY = 1.0;
    1378         510 :     double dfZ = 0.0;
    1379         510 :     GUInt32 nOffset = 0;
    1380         510 :     GUInt32 nDelta = 0;
    1381             : 
    1382         510 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1383         510 :     OGRPolygon *poPoly = new OGRPolygon();
    1384         510 :     OGRLineString *poLS = new OGRLineString();
    1385             : 
    1386             :     /*---------------------- Reading Primary Polygon
    1387             :      * --------------------------------*/
    1388       28991 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1389             :     {
    1390       28481 :         const char *psBuf = psRecordBuf + nOffset;
    1391       28481 :         if (certifInfo.bDim == 1)
    1392             :         {
    1393           0 :             nDelta = TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX,
    1394             :                                   &dfY, &dfZ);
    1395             :         }
    1396             :         else
    1397             :         {
    1398       28481 :             dfZ = 0.0;
    1399             :             nDelta =
    1400       28481 :                 TranslateXYH(certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY);
    1401             :         }
    1402             : 
    1403       28481 :         if (nDelta == 0)
    1404           0 :             break;
    1405       28481 :         nOffset += nDelta;
    1406       28481 :         poLS->addPoint(dfX, dfY, dfZ);
    1407             :     }  // for
    1408             : 
    1409         510 :     OGRLinearRing *poLR = new OGRLinearRing();
    1410         510 :     poLR->addSubLineString(poLS, 0);
    1411             : 
    1412         510 :     poPoly->addRingDirectly(poLR);
    1413             : 
    1414             :     /*---------------------- Reading Sub Lines
    1415             :      * --------------------------------*/
    1416             : 
    1417         542 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1418             :     {
    1419          32 :         poLS->empty();
    1420             : 
    1421          32 :         if (nOffset + 4 > nBufLen)
    1422           0 :             break;
    1423             : 
    1424          32 :         GUInt16 nSubObj = 0;
    1425          32 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1426          32 :         CPL_LSBPTR16(&nSubObj);
    1427             : 
    1428          32 :         GUInt16 nCoords = 0;
    1429          32 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1430          32 :         CPL_LSBPTR16(&nCoords);
    1431             : 
    1432             :         // TODO: Is this really what the buffer size should be?
    1433          32 :         if (nCoords * nDelta != nBufLen - nOffset + 2 - 6)
    1434             :         {
    1435           0 :             CPLError(CE_Warning, CPLE_FileIO,
    1436             :                      "SXF raw feature size incorrect.  "
    1437             :                      "%d %d",
    1438           0 :                      nCoords * nDelta, nBufLen - nOffset + 2 - 6);
    1439             :             // TODO: How best to gracefully exit and report an issue?
    1440             :             // break; or cleanup and return NULL?
    1441             :         }
    1442             : 
    1443          32 :         nOffset += 4;
    1444             : 
    1445         480 :         for (int i = 0; i < nCoords; i++)
    1446             :         {
    1447         448 :             const char *psCoords = psRecordBuf + nOffset;
    1448         448 :             if (certifInfo.bDim == 1)
    1449             :             {
    1450           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1451             :                                       &dfX, &dfY, &dfZ);
    1452             :             }
    1453             :             else
    1454             :             {
    1455         448 :                 dfZ = 0.0;
    1456         448 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1457             :                                       &dfX, &dfY);
    1458             :             }
    1459             : 
    1460         448 :             if (nDelta == 0)
    1461           0 :                 break;
    1462         448 :             nOffset += nDelta;
    1463             : 
    1464         448 :             poLS->addPoint(dfX, dfY, dfZ);
    1465             :         }
    1466             : 
    1467          32 :         poLR = new OGRLinearRing();
    1468          32 :         poLR->addSubLineString(poLS, 0);
    1469             : 
    1470          32 :         poPoly->addRingDirectly(poLR);
    1471             :     }  // for
    1472             : 
    1473         510 :     poFeature->SetGeometryDirectly(poPoly);  // poLS);
    1474         510 :     delete poLS;
    1475             : 
    1476             :     /*****
    1477             :      * TODO :
    1478             :      *          - Translate graphics
    1479             :      *          - Translate 3D vector
    1480             :      */
    1481         510 :     return poFeature;
    1482             : }
    1483             : 
    1484             : /************************************************************************/
    1485             : /*                         TranslateText    ()                          */
    1486             : /************************************************************************/
    1487         140 : OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription &certifInfo,
    1488             :                                        const char *psRecordBuf, GUInt32 nBufLen)
    1489             : {
    1490         140 :     double dfX = 1.0;
    1491         140 :     double dfY = 1.0;
    1492         140 :     double dfZ = 0.0;
    1493         140 :     GUInt32 nOffset = 0;
    1494             : 
    1495         140 :     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    1496         140 :     OGRMultiLineString *poMLS = new OGRMultiLineString();
    1497             : 
    1498             :     /*---------------------- Reading Primary Line
    1499             :      * --------------------------------*/
    1500             : 
    1501         140 :     OGRLineString *poLS = new OGRLineString();
    1502             : 
    1503         420 :     for (GUInt32 count = 0; count < certifInfo.nPointCount; count++)
    1504             :     {
    1505         280 :         const char *psCoords = psRecordBuf + nOffset;
    1506             : 
    1507             :         GUInt32 nDelta;
    1508         280 :         if (certifInfo.bDim == 1)
    1509             :         {
    1510           0 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1511             :                                   &dfY, &dfZ);
    1512             :         }
    1513             :         else
    1514             :         {
    1515         280 :             dfZ = 0.0;
    1516         280 :             nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX,
    1517             :                                   &dfY);
    1518             :         }
    1519             : 
    1520         280 :         if (nDelta == 0)
    1521           0 :             break;
    1522         280 :         nOffset += nDelta;
    1523             : 
    1524         280 :         poLS->addPoint(dfX, dfY, dfZ);
    1525             :     }
    1526             : 
    1527         140 :     poMLS->addGeometry(poLS);
    1528             : 
    1529             :     /*------------------     READING TEXT VALUE
    1530             :      * --------------------------------*/
    1531         280 :     CPLString soText;
    1532             : 
    1533         140 :     if (certifInfo.bHasTextSign)
    1534             :     {
    1535         140 :         if (nOffset + 1 > nBufLen)
    1536           0 :             return poFeature;
    1537         140 :         const char *pszTxt = psRecordBuf + nOffset;
    1538         140 :         GByte nTextL = (GByte)*pszTxt;
    1539         140 :         if (nOffset + 1 + nTextL > nBufLen)
    1540           0 :             return poFeature;
    1541             : 
    1542         140 :         char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
    1543             : 
    1544         140 :         strncpy(pszTextBuf, (pszTxt + 1), nTextL);
    1545         140 :         pszTextBuf[nTextL] = '\0';
    1546             : 
    1547             :         // TODO: Check encoding from sxf
    1548         140 :         char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
    1549         140 :         soText += pszRecoded;
    1550         140 :         CPLFree(pszRecoded);
    1551             : 
    1552         140 :         CPLFree(pszTextBuf);
    1553             : 
    1554         140 :         nOffset += nTextL + 2;
    1555             :     }
    1556             : 
    1557             :     /*---------------------- Reading Sub Lines
    1558             :      * --------------------------------*/
    1559             : 
    1560         140 :     for (int count = 0; count < certifInfo.nSubObjectCount; count++)
    1561             :     {
    1562           0 :         poLS->empty();
    1563             : 
    1564           0 :         if (nOffset + 4 > nBufLen)
    1565           0 :             break;
    1566             : 
    1567           0 :         GUInt16 nSubObj = 0;
    1568           0 :         memcpy(&nSubObj, psRecordBuf + nOffset, 2);
    1569           0 :         CPL_LSBPTR16(&nSubObj);
    1570             : 
    1571           0 :         GUInt16 nCoords = 0;
    1572           0 :         memcpy(&nCoords, psRecordBuf + nOffset + 2, 2);
    1573           0 :         CPL_LSBPTR16(&nCoords);
    1574             : 
    1575           0 :         nOffset += 4;
    1576             : 
    1577           0 :         for (int i = 0; i < nCoords; i++)
    1578             :         {
    1579           0 :             const char *psCoords = psRecordBuf + nOffset;
    1580             :             GUInt32 nDelta;
    1581           0 :             if (certifInfo.bDim == 1)
    1582             :             {
    1583           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1584             :                                       &dfX, &dfY, &dfZ);
    1585             :             }
    1586             :             else
    1587             :             {
    1588           0 :                 dfZ = 0.0;
    1589           0 :                 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset,
    1590             :                                       &dfX, &dfY);
    1591             :             }
    1592             : 
    1593           0 :             if (nDelta == 0)
    1594           0 :                 break;
    1595           0 :             nOffset += nDelta;
    1596             : 
    1597           0 :             poLS->addPoint(dfX, dfY, dfZ);
    1598             :         }
    1599             : 
    1600           0 :         poMLS->addGeometry(poLS);
    1601             : 
    1602           0 :         if (certifInfo.bHasTextSign)
    1603             :         {
    1604           0 :             if (nOffset + 1 > nBufLen)
    1605           0 :                 return poFeature;
    1606           0 :             const char *pszTxt = psRecordBuf + nOffset;
    1607           0 :             GByte nTextL = (GByte)*pszTxt;
    1608           0 :             if (nOffset + 1 + nTextL > nBufLen)
    1609           0 :                 return poFeature;
    1610             : 
    1611           0 :             char *pszTextBuf = (char *)CPLMalloc(nTextL + 1);
    1612             : 
    1613           0 :             strncpy(pszTextBuf, (pszTxt + 1), nTextL);
    1614           0 :             pszTextBuf[nTextL] = '\0';
    1615             : 
    1616             :             // TODO: Check encoding from sxf
    1617           0 :             char *pszRecoded = CPLRecode(pszTextBuf, "CP1251", CPL_ENC_UTF8);
    1618           0 :             soText += " " + CPLString(pszRecoded);
    1619           0 :             CPLFree(pszRecoded);
    1620             : 
    1621           0 :             CPLFree(pszTextBuf);
    1622             : 
    1623           0 :             nOffset += nTextL + 2;
    1624             :         }
    1625             :     }  // for
    1626             : 
    1627         140 :     delete poLS;
    1628         140 :     poFeature->SetGeometryDirectly(poMLS);
    1629             : 
    1630         140 :     poFeature->SetField("TEXT", soText);
    1631         140 :     return poFeature;
    1632             : }
    1633             : 
    1634         297 : const char *OGRSXFLayer::GetFIDColumn()
    1635             : {
    1636         297 :     return sFIDColumn_.c_str();
    1637             : }

Generated by: LCOV version 1.14