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

Generated by: LCOV version 1.14