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

Generated by: LCOV version 1.14