LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/sxf - ogrsxflayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 468 835 56.0 %
Date: 2024-11-21 22:18:42 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.14