LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/selafin - ogrselafinlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 339 647 52.4 %
Date: 2026-01-08 02:20:26 Functions: 14 18 77.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  Selafin importer
       3             :  * Purpose:  Implementation of OGRSelafinLayer class.
       4             :  * Author:   François Hissel, francois.hissel@gmail.com
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2014,  François Hissel <francois.hissel@gmail.com>
       8             :  *
       9             :  * SPDX-License-Identifier: MIT
      10             :  ****************************************************************************/
      11             : 
      12             : #include <cstdlib>
      13             : #include "cpl_conv.h"
      14             : #include "cpl_string.h"
      15             : #include "ogr_p.h"
      16             : #include "io_selafin.h"
      17             : #include "ogr_selafin.h"
      18             : #include "cpl_error.h"
      19             : #include "cpl_quad_tree.h"
      20             : #include "cpl_vsi_virtual.h"
      21             : 
      22             : /************************************************************************/
      23             : /*                           Utilities functions                        */
      24             : /************************************************************************/
      25          74 : static void MoveOverwrite(VSILFILE *fpDest, VSILFILE *fpSource)
      26             : {
      27          74 :     VSIRewindL(fpSource);
      28          74 :     VSIRewindL(fpDest);
      29          74 :     VSIFTruncateL(fpDest, 0);
      30             :     char anBuf[0x10000];
      31         148 :     while (!fpSource->Eof() && !fpSource->Error())
      32             :     {
      33          74 :         size_t nSize = VSIFReadL(anBuf, 1, sizeof(anBuf), fpSource);
      34          74 :         size_t nLeft = nSize;
      35         148 :         while (nLeft > 0)
      36          74 :             nLeft -= VSIFWriteL(anBuf + nSize - nLeft, 1, nLeft, fpDest);
      37             :     }
      38          74 :     VSIFCloseL(fpSource);
      39          74 :     VSIFFlushL(fpDest);
      40          74 : }
      41             : 
      42             : /************************************************************************/
      43             : /*                            OGRSelafinLayer()                         */
      44             : /*       Note that no operation on OGRSelafinLayer is thread-safe       */
      45             : /************************************************************************/
      46             : 
      47          16 : OGRSelafinLayer::OGRSelafinLayer(GDALDataset *poDS, const char *pszLayerNameP,
      48             :                                  int bUpdateP,
      49             :                                  const OGRSpatialReference *poSpatialRefP,
      50             :                                  Selafin::Header *poHeaderP, int nStepNumberP,
      51          16 :                                  SelafinTypeDef eTypeP)
      52          16 :     : m_poDS(poDS), eType(eTypeP), bUpdate(CPL_TO_BOOL(bUpdateP)),
      53             :       nStepNumber(nStepNumberP), poHeader(poHeaderP),
      54             :       poFeatureDefn(
      55          16 :           new OGRFeatureDefn(CPLGetBasenameSafe(pszLayerNameP).c_str())),
      56          32 :       poSpatialRef(nullptr), nCurrentId(-1)
      57             : {
      58             : #ifdef DEBUG_VERBOSE
      59             :     CPLDebug("Selafin", "Opening layer %s", pszLayerNameP);
      60             : #endif
      61          16 :     SetDescription(poFeatureDefn->GetName());
      62          16 :     poFeatureDefn->Reference();
      63          16 :     if (eType == POINTS)
      64           8 :         poFeatureDefn->SetGeomType(wkbPoint);
      65             :     else
      66           8 :         poFeatureDefn->SetGeomType(wkbPolygon);
      67          16 :     if (poSpatialRefP)
      68             :     {
      69           8 :         poSpatialRef = poSpatialRefP->Clone();
      70           8 :         poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
      71             :     }
      72          26 :     for (int i = 0; i < poHeader->nVar; ++i)
      73             :     {
      74          20 :         OGRFieldDefn oFieldDefn(poHeader->papszVariables[i], OFTReal);
      75          10 :         poFeatureDefn->AddFieldDefn(&oFieldDefn);
      76             :     }
      77          16 : }
      78             : 
      79             : /************************************************************************/
      80             : /*                           ~OGRSelafinLayer()                         */
      81             : /************************************************************************/
      82          32 : OGRSelafinLayer::~OGRSelafinLayer()
      83             : {
      84             : #ifdef DEBUG_VERBOSE
      85             :     CPLDebug("Selafin", "Closing layer %s", GetName());
      86             : #endif
      87          16 :     poFeatureDefn->Release();
      88          16 :     if (poSpatialRef)
      89           8 :         poSpatialRef->Release();
      90             :     // poHeader->nRefCount--;
      91             :     // if (poHeader->nRefCount==0) delete poHeader;
      92          32 : }
      93             : 
      94             : /************************************************************************/
      95             : /*                           GetNextFeature()                           */
      96             : /************************************************************************/
      97           1 : OGRFeature *OGRSelafinLayer::GetNextFeature()
      98             : {
      99             :     // CPLDebug("Selafin","GetNextFeature(%li)",nCurrentId+1);
     100             :     while (true)
     101             :     {
     102           1 :         OGRFeature *poFeature = GetFeature(++nCurrentId);
     103           1 :         if (poFeature == nullptr)
     104           0 :             return nullptr;
     105           2 :         if ((m_poFilterGeom == nullptr ||
     106           2 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     107           1 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     108           1 :             return poFeature;
     109           0 :         delete poFeature;
     110           0 :     }
     111             : }
     112             : 
     113             : /************************************************************************/
     114             : /*                            ResetReading()                            */
     115             : /************************************************************************/
     116           1 : void OGRSelafinLayer::ResetReading()
     117             : {
     118             :     // CPLDebug("Selafin","ResetReading()");
     119           1 :     nCurrentId = -1;
     120           1 : }
     121             : 
     122             : /************************************************************************/
     123             : /*                           SetNextByIndex()                           */
     124             : /************************************************************************/
     125           0 : OGRErr OGRSelafinLayer::SetNextByIndex(GIntBig nIndex)
     126             : {
     127             :     // CPLDebug("Selafin","SetNexByIndex(%li)",nIndex);
     128           0 :     if (nIndex < 0 || nIndex >= poHeader->nPoints)
     129           0 :         return OGRERR_FAILURE;
     130           0 :     nCurrentId = nIndex - 1;
     131           0 :     return OGRERR_NONE;
     132             : }
     133             : 
     134             : /************************************************************************/
     135             : /*                           TestCapability()                           */
     136             : /************************************************************************/
     137          14 : int OGRSelafinLayer::TestCapability(const char *pszCap) const
     138             : {
     139             :     // CPLDebug("Selafin","TestCapability(%s)",pszCap);
     140          14 :     if (EQUAL(pszCap, OLCRandomRead))
     141           0 :         return TRUE;
     142          14 :     if (EQUAL(pszCap, OLCSequentialWrite))
     143           1 :         return bUpdate;
     144          13 :     if (EQUAL(pszCap, OLCRandomWrite))
     145           0 :         return bUpdate;
     146          13 :     if (EQUAL(pszCap, OLCFastSpatialFilter))
     147           0 :         return FALSE;
     148          13 :     if (EQUAL(pszCap, OLCFastFeatureCount))
     149           0 :         return TRUE;
     150          13 :     if (EQUAL(pszCap, OLCFastGetExtent))
     151           0 :         return TRUE;
     152          13 :     if (EQUAL(pszCap, OLCFastSetNextByIndex))
     153           0 :         return TRUE;
     154          13 :     if (EQUAL(pszCap, OLCCreateField))
     155           1 :         return bUpdate;
     156          12 :     if (EQUAL(pszCap, OLCCreateGeomField))
     157           0 :         return FALSE;
     158          12 :     if (EQUAL(pszCap, OLCDeleteField))
     159           0 :         return bUpdate;
     160          12 :     if (EQUAL(pszCap, OLCReorderFields))
     161           0 :         return bUpdate;
     162          12 :     if (EQUAL(pszCap, OLCAlterFieldDefn))
     163           0 :         return bUpdate;
     164          12 :     if (EQUAL(pszCap, OLCDeleteFeature))
     165           0 :         return bUpdate;
     166          12 :     if (EQUAL(pszCap, OLCStringsAsUTF8))
     167           0 :         return FALSE;
     168          12 :     if (EQUAL(pszCap, OLCTransactions))
     169           0 :         return FALSE;
     170          12 :     if (EQUAL(pszCap, OLCIgnoreFields))
     171           0 :         return FALSE;
     172          12 :     return FALSE;
     173             : }
     174             : 
     175             : /************************************************************************/
     176             : /*                            GetFeature()                              */
     177             : /************************************************************************/
     178          29 : OGRFeature *OGRSelafinLayer::GetFeature(GIntBig nFID)
     179             : {
     180          29 :     CPLDebug("Selafin", "GetFeature(" CPL_FRMT_GIB ")", nFID);
     181          29 :     if (nFID < 0)
     182           0 :         return nullptr;
     183          29 :     if (eType == POINTS)
     184             :     {
     185          27 :         if (nFID >= poHeader->nPoints)
     186           0 :             return nullptr;
     187          27 :         OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     188          27 :         poFeature->SetGeometryDirectly(new OGRPoint(
     189          27 :             poHeader->paadfCoords[0][nFID], poHeader->paadfCoords[1][nFID]));
     190          27 :         poFeature->SetFID(nFID);
     191          80 :         for (int i = 0; i < poHeader->nVar; ++i)
     192             :         {
     193          53 :             VSIFSeekL(poHeader->fp,
     194          53 :                       poHeader->getPosition(nStepNumber, (int)nFID, i),
     195             :                       SEEK_SET);
     196          53 :             double nData = 0.0;
     197          53 :             if (Selafin::read_float(poHeader->fp, nData) == 1)
     198          53 :                 poFeature->SetField(i, nData);
     199             :         }
     200          27 :         return poFeature;
     201             :     }
     202             :     else
     203             :     {
     204           2 :         if (nFID >= poHeader->nElements)
     205           0 :             return nullptr;
     206             :         double *anData =
     207           2 :             (double *)VSI_MALLOC2_VERBOSE(sizeof(double), poHeader->nVar);
     208           2 :         if (poHeader->nVar > 0 && anData == nullptr)
     209           0 :             return nullptr;
     210           4 :         for (int i = 0; i < poHeader->nVar; ++i)
     211           2 :             anData[i] = 0;
     212           2 :         OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     213           2 :         poFeature->SetFID(nFID);
     214           2 :         OGRPolygon *poPolygon = new OGRPolygon();
     215           2 :         OGRLinearRing *poLinearRing = new OGRLinearRing();
     216          10 :         for (int j = 0; j < poHeader->nPointsPerElement; ++j)
     217             :         {
     218           8 :             int nPointNum =
     219           8 :                 poHeader
     220           8 :                     ->panConnectivity[nFID * poHeader->nPointsPerElement + j] -
     221             :                 1;
     222           8 :             poLinearRing->addPoint(poHeader->paadfCoords[0][nPointNum],
     223           8 :                                    poHeader->paadfCoords[1][nPointNum]);
     224          16 :             for (int i = 0; i < poHeader->nVar; ++i)
     225             :             {
     226           8 :                 VSIFSeekL(poHeader->fp,
     227           8 :                           poHeader->getPosition(nStepNumber, nPointNum, i),
     228             :                           SEEK_SET);
     229           8 :                 double nData = 0.0;
     230           8 :                 if (Selafin::read_float(poHeader->fp, nData) == 1)
     231           8 :                     anData[i] += nData;
     232             :             }
     233             :         }
     234           2 :         poPolygon->addRingDirectly(poLinearRing);
     235           2 :         poPolygon->closeRings();
     236           2 :         poFeature->SetGeometryDirectly(poPolygon);
     237           2 :         if (poHeader->nPointsPerElement)
     238             :         {
     239           4 :             for (int i = 0; i < poHeader->nVar; ++i)
     240           2 :                 poFeature->SetField(i, anData[i] / poHeader->nPointsPerElement);
     241             :         }
     242           2 :         CPLFree(anData);
     243           2 :         return poFeature;
     244             :     }
     245             : }
     246             : 
     247             : /************************************************************************/
     248             : /*                           GetFeatureCount()                          */
     249             : /************************************************************************/
     250           4 : GIntBig OGRSelafinLayer::GetFeatureCount(int bForce)
     251             : {
     252             :     // CPLDebug("Selafin","GetFeatureCount(%i)",bForce);
     253           4 :     if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
     254           4 :         return (eType == POINTS) ? poHeader->nPoints : poHeader->nElements;
     255           0 :     if (!bForce)
     256           0 :         return -1;
     257           0 :     int i = 0;
     258           0 :     int nFeatureCount = 0;
     259           0 :     const int nMax = eType == POINTS ? poHeader->nPoints : poHeader->nElements;
     260           0 :     while (i < nMax)
     261             :     {
     262           0 :         OGRFeature *poFeature = GetFeature(i++);
     263           0 :         if ((m_poFilterGeom == nullptr ||
     264           0 :              FilterGeometry(poFeature->GetGeometryRef())) &&
     265           0 :             (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     266           0 :             ++nFeatureCount;
     267           0 :         delete poFeature;
     268             :     }
     269           0 :     return nFeatureCount;
     270             : }
     271             : 
     272             : /************************************************************************/
     273             : /*                            IGetExtent()                              */
     274             : /************************************************************************/
     275           0 : OGRErr OGRSelafinLayer::IGetExtent(int /* iGeomField*/, OGREnvelope *psExtent,
     276             :                                    bool /* bForce*/)
     277             : {
     278             :     // CPLDebug("Selafin","GetExtent(%i)",bForce);
     279           0 :     if (poHeader->nPoints == 0)
     280           0 :         return OGRERR_NONE;
     281           0 :     CPLRectObj *poObj = poHeader->getBoundingBox();
     282           0 :     psExtent->MinX = poObj->minx;
     283           0 :     psExtent->MaxX = poObj->maxx;
     284           0 :     psExtent->MinY = poObj->miny;
     285           0 :     psExtent->MaxY = poObj->maxy;
     286           0 :     delete poObj;
     287           0 :     return OGRERR_NONE;
     288             : }
     289             : 
     290             : /************************************************************************/
     291             : /*                             ISetFeature()                             */
     292             : /************************************************************************/
     293          25 : OGRErr OGRSelafinLayer::ISetFeature(OGRFeature *poFeature)
     294             : {
     295          25 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     296          25 :     if (poGeom == nullptr)
     297           0 :         return OGRERR_FAILURE;
     298          25 :     if (eType == POINTS)
     299             :     {
     300             :         // If it is a point layer, it is the "easy" case: we change the
     301             :         // coordinates and attributes of the feature and update the file
     302          25 :         if (poGeom->getGeometryType() != wkbPoint)
     303             :         {
     304           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     305             :                      "The new feature should be of the same Point geometry as "
     306             :                      "the existing ones in the layer.");
     307           0 :             return OGRERR_FAILURE;
     308             :         }
     309          25 :         OGRPoint *poPoint = poGeom->toPoint();
     310          25 :         GIntBig nFID = poFeature->GetFID();
     311          25 :         poHeader->paadfCoords[0][nFID] = poPoint->getX();
     312          25 :         poHeader->paadfCoords[1][nFID] = poPoint->getY();
     313          25 :         CPLDebug("Selafin", "SetFeature(" CPL_FRMT_GIB ",%f,%f)", nFID,
     314          25 :                  poHeader->paadfCoords[0][nFID],
     315          25 :                  poHeader->paadfCoords[1][nFID]);
     316          50 :         if (VSIFSeekL(poHeader->fp,
     317          50 :                       88 + 16 + 40 * poHeader->nVar + 48 +
     318          25 :                           ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     319          25 :                           (static_cast<vsi_l_offset>(poHeader->nElements) *
     320          25 :                                poHeader->nPointsPerElement +
     321          25 :                            2) *
     322          25 :                               4 +
     323          25 :                           (poHeader->nPoints + 2) * 4 + 4 + nFID * 4,
     324          25 :                       SEEK_SET) != 0)
     325           0 :             return OGRERR_FAILURE;
     326          25 :         CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     327          25 :                  VSIFTellL(poHeader->fp),
     328          25 :                  poHeader->paadfCoords[0][nFID] - poHeader->adfOrigin[0]);
     329          50 :         if (Selafin::write_float(poHeader->fp, poHeader->paadfCoords[0][nFID] -
     330          25 :                                                    poHeader->adfOrigin[0]) == 0)
     331           0 :             return OGRERR_FAILURE;
     332          50 :         if (VSIFSeekL(poHeader->fp,
     333          50 :                       88 + 16 + 40 * poHeader->nVar + 48 +
     334          25 :                           ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     335          25 :                           (static_cast<vsi_l_offset>(poHeader->nElements) *
     336          25 :                                poHeader->nPointsPerElement +
     337          25 :                            2) *
     338          25 :                               4 +
     339          25 :                           (poHeader->nPoints + 2) * 4 +
     340          25 :                           (poHeader->nPoints + 2) * 4 + 4 + nFID * 4,
     341          25 :                       SEEK_SET) != 0)
     342           0 :             return OGRERR_FAILURE;
     343          25 :         CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     344          25 :                  VSIFTellL(poHeader->fp),
     345          25 :                  poHeader->paadfCoords[1][nFID] - poHeader->adfOrigin[1]);
     346          50 :         if (Selafin::write_float(poHeader->fp, poHeader->paadfCoords[1][nFID] -
     347          25 :                                                    poHeader->adfOrigin[1]) == 0)
     348           0 :             return OGRERR_FAILURE;
     349          75 :         for (int i = 0; i < poHeader->nVar; ++i)
     350             :         {
     351          50 :             double nData = poFeature->GetFieldAsDouble(i);
     352         100 :             if (VSIFSeekL(poHeader->fp,
     353          50 :                           poHeader->getPosition(nStepNumber, (int)nFID, i),
     354          50 :                           SEEK_SET) != 0)
     355           0 :                 return OGRERR_FAILURE;
     356          50 :             if (Selafin::write_float(poHeader->fp, nData) == 0)
     357           0 :                 return OGRERR_FAILURE;
     358             :         }
     359             :     }
     360             :     else
     361             :     {
     362             :         // Else, we have a layer of polygonal elements. Here we consider that
     363             :         // the vertices are moved when we change the geometry (which will also
     364             :         // lead to a modification in the corresponding point layer). The
     365             :         // attributes table can't be changed, because attributes are calculated
     366             :         // from those of the vertices. First we check that the new feature is a
     367             :         // polygon with the right number of vertices
     368           0 :         if (poGeom->getGeometryType() != wkbPolygon)
     369             :         {
     370           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     371             :                      "The new feature should be of the same Polygon geometry "
     372             :                      "as the existing ones in the layer.");
     373           0 :             return OGRERR_FAILURE;
     374             :         }
     375           0 :         OGRLinearRing *poLinearRing = poGeom->toPolygon()->getExteriorRing();
     376           0 :         if (poLinearRing->getNumPoints() != poHeader->nPointsPerElement + 1)
     377             :         {
     378           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     379             :                      "The new feature should have the same number of vertices "
     380             :                      "%d as the existing ones in the layer.",
     381           0 :                      poHeader->nPointsPerElement);
     382           0 :             return OGRERR_FAILURE;
     383             :         }
     384           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     385             :                  "The attributes of elements layer in Selafin files can't be "
     386             :                  "updated.");
     387           0 :         CPLDebug("Selafin", "SetFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",
     388             :                  poFeature->GetFID(), poLinearRing->getX(0),
     389             :                  poLinearRing->getY(0), poLinearRing->getX(1),
     390             :                  poLinearRing->getY(1), poLinearRing->getX(2),
     391             :                  poLinearRing->getY(
     392             :                      2));  //!< This is not safe as we can't be sure there are
     393             :                            //!< at least three vertices in the linear ring, but
     394             :                            //!< we can assume that for a debug mode
     395           0 :         int nFID = static_cast<int>(poFeature->GetFID());
     396             :         // Now we change the coordinates of points in the layer based on the
     397             :         // vertices of the new polygon. We don't look at the order of points and
     398             :         // we assume that it is the same as in the original layer.
     399           0 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     400             :         {
     401           0 :             int nPointId =
     402           0 :                 poHeader
     403           0 :                     ->panConnectivity[nFID * poHeader->nPointsPerElement + i] -
     404             :                 1;
     405           0 :             poHeader->paadfCoords[0][nPointId] = poLinearRing->getX(i);
     406           0 :             poHeader->paadfCoords[1][nPointId] = poLinearRing->getY(i);
     407           0 :             if (VSIFSeekL(
     408           0 :                     poHeader->fp,
     409           0 :                     88 + 16 + 40 * poHeader->nVar + 48 +
     410           0 :                         ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     411           0 :                         (poHeader->nElements * poHeader->nPointsPerElement +
     412           0 :                          2) *
     413           0 :                             4 +
     414           0 :                         (poHeader->nPoints + 2) * 4 + 4 + nPointId * 4,
     415           0 :                     SEEK_SET) != 0)
     416           0 :                 return OGRERR_FAILURE;
     417           0 :             CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     418           0 :                      VSIFTellL(poHeader->fp),
     419           0 :                      poHeader->paadfCoords[0][nPointId] -
     420           0 :                          poHeader->adfOrigin[0]);
     421           0 :             if (Selafin::write_float(poHeader->fp,
     422           0 :                                      poHeader->paadfCoords[0][nPointId] -
     423           0 :                                          poHeader->adfOrigin[0]) == 0)
     424           0 :                 return OGRERR_FAILURE;
     425           0 :             if (VSIFSeekL(
     426           0 :                     poHeader->fp,
     427           0 :                     88 + 16 + 40 * poHeader->nVar + 48 +
     428           0 :                         ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     429           0 :                         (poHeader->nElements * poHeader->nPointsPerElement +
     430           0 :                          2) *
     431           0 :                             4 +
     432           0 :                         (poHeader->nPoints + 2) * 4 +
     433           0 :                         (poHeader->nPoints + 2) * 4 + 4 + nPointId * 4,
     434           0 :                     SEEK_SET) != 0)
     435           0 :                 return OGRERR_FAILURE;
     436           0 :             CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     437           0 :                      VSIFTellL(poHeader->fp),
     438           0 :                      poHeader->paadfCoords[1][nPointId] -
     439           0 :                          poHeader->adfOrigin[1]);
     440           0 :             if (Selafin::write_float(poHeader->fp,
     441           0 :                                      poHeader->paadfCoords[1][nPointId] -
     442           0 :                                          poHeader->adfOrigin[1]) == 0)
     443           0 :                 return OGRERR_FAILURE;
     444             :         }
     445             :     }
     446          25 :     VSIFFlushL(poHeader->fp);
     447          25 :     poHeader->UpdateFileSize();
     448          25 :     return OGRERR_NONE;
     449             : }
     450             : 
     451             : /************************************************************************/
     452             : /*                           ICreateFeature()                            */
     453             : /************************************************************************/
     454          72 : OGRErr OGRSelafinLayer::ICreateFeature(OGRFeature *poFeature)
     455             : {
     456          72 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     457          72 :     if (poGeom == nullptr)
     458           2 :         return OGRERR_FAILURE;
     459          70 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     460           0 :         return OGRERR_FAILURE;
     461          70 :     if (eType == POINTS)
     462             :     {
     463             :         // If it is a point layer, it is the "easy" case: we add a new point
     464             :         // feature and update the file
     465          53 :         if (poGeom->getGeometryType() != wkbPoint)
     466             :         {
     467           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     468             :                      "The new feature should be of the same Point geometry as "
     469             :                      "the existing ones in the layer.");
     470           1 :             return OGRERR_FAILURE;
     471             :         }
     472          52 :         OGRPoint *poPoint = poGeom->toPoint();
     473          52 :         poFeature->SetFID(poHeader->nPoints);
     474          52 :         CPLDebug("Selafin", "CreateFeature(%d,%f,%f)", poHeader->nPoints,
     475             :                  poPoint->getX(), poPoint->getY());
     476             :         // Change the header to add the new feature
     477          52 :         poHeader->addPoint(poPoint->getX(), poPoint->getY());
     478             :     }
     479             :     else
     480             :     {
     481             :         // This is the most difficult case. The user wants to add a polygon
     482             :         // element. First we check that it has the same number of vertices as
     483             :         // the other polygon elements in the file. If there is no other element,
     484             :         // then we define the number of vertices. Every vertex in the layer
     485             :         // should have a corresponding point in the corresponding point layer.
     486             :         // So if we add a polygon element, we also have to add points in the
     487             :         // corresponding layer. The function tries to add as few new points as
     488             :         // possible, reusing already existing points. This is generally what the
     489             :         // user will expect.
     490             : 
     491             :         // First we check that we have the required geometry
     492          17 :         if (poGeom->getGeometryType() != wkbPolygon)
     493             :         {
     494           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     495             :                      "The new feature should be of the same Polygon geometry "
     496             :                      "as the existing ones in the layer.");
     497           0 :             return OGRERR_FAILURE;
     498             :         }
     499             : 
     500             :         // Now we check that we have the right number of vertices, or if this
     501             :         // number was not defined yet (0), we define it at once
     502          17 :         OGRLinearRing *poLinearRing = poGeom->toPolygon()->getExteriorRing();
     503          17 :         poFeature->SetFID(poHeader->nElements);
     504          17 :         CPLDebug("Selafin", "CreateFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",
     505             :                  poFeature->GetFID(), poLinearRing->getX(0),
     506             :                  poLinearRing->getY(0), poLinearRing->getX(1),
     507             :                  poLinearRing->getY(1), poLinearRing->getX(2),
     508             :                  poLinearRing->getY(
     509             :                      2));  //!< This is not safe as we can't be sure there are
     510             :                            //!< at least three vertices in the linear ring, but
     511             :                            //!< we can assume that for a debug mode
     512          17 :         int nNum = poLinearRing->getNumPoints();
     513          17 :         if (poHeader->nPointsPerElement == 0)
     514             :         {
     515           1 :             if (nNum < 4)
     516             :             {
     517           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     518             :                          "The new feature should have at least 3 vertices.");
     519           0 :                 return OGRERR_FAILURE;
     520             :             }
     521           1 :             poHeader->nPointsPerElement = nNum - 1;
     522           1 :             if (poHeader->nElements > 0)
     523             :             {
     524             :                 int *panConnectivity =
     525           0 :                     reinterpret_cast<int *>(VSI_REALLOC_VERBOSE(
     526             :                         poHeader->panConnectivity,
     527             :                         static_cast<size_t>(poHeader->nElements) *
     528             :                             poHeader->nPointsPerElement));
     529           0 :                 if (panConnectivity == nullptr)
     530             :                 {
     531           0 :                     VSIFree(poHeader->panConnectivity);
     532           0 :                     poHeader->panConnectivity = nullptr;
     533           0 :                     return OGRERR_FAILURE;
     534             :                 }
     535           0 :                 poHeader->panConnectivity = panConnectivity;
     536             :             }
     537             :         }
     538             :         else
     539             :         {
     540          16 :             if (poLinearRing->getNumPoints() != poHeader->nPointsPerElement + 1)
     541             :             {
     542           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     543             :                          "The new feature should have the same number of "
     544             :                          "vertices %d as the existing ones in the layer.",
     545           0 :                          poHeader->nPointsPerElement);
     546           0 :                 return OGRERR_FAILURE;
     547             :             }
     548             :         }
     549             : 
     550             :         // Now we look for vertices that are already referenced as points in the
     551             :         // file
     552          17 :         int *anMap = (int *)VSI_MALLOC2_VERBOSE(sizeof(int),
     553             :                                                 poHeader->nPointsPerElement);
     554          17 :         if (anMap == nullptr)
     555             :         {
     556           0 :             return OGRERR_FAILURE;
     557             :         }
     558          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     559          68 :             anMap[i] = -1;
     560          17 :         if (poHeader->nPoints > 0)
     561             :         {
     562          17 :             CPLRectObj *poBB = poHeader->getBoundingBox();
     563             :             double dfMaxDist =
     564          17 :                 (poBB->maxx - poBB->minx) / sqrt((double)(poHeader->nPoints)) /
     565          17 :                 1000.0;  //!< Heuristic approach to estimate a maximum distance
     566             :                          //!< such that two points are considered equal if they
     567             :                          //!< are closer from each other
     568          17 :             dfMaxDist *= dfMaxDist;
     569          17 :             delete poBB;
     570          85 :             for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     571         204 :                 anMap[i] = poHeader->getClosestPoint(
     572          68 :                     poLinearRing->getX(i), poLinearRing->getY(i), dfMaxDist);
     573             :         }
     574             : 
     575             :         // We add new points if needed only
     576          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     577          68 :             if (anMap[i] == -1)
     578             :             {
     579           3 :                 poHeader->addPoint(poLinearRing->getX(i),
     580           3 :                                    poLinearRing->getY(i));
     581           3 :                 anMap[i] = poHeader->nPoints - 1;
     582             :             }
     583             : 
     584             :         // And we update the connectivity table to add the new element
     585          17 :         poHeader->nElements++;
     586          34 :         poHeader->panConnectivity = (int *)CPLRealloc(
     587          17 :             poHeader->panConnectivity,
     588          17 :             sizeof(int) * poHeader->nPointsPerElement * poHeader->nElements);
     589          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     590             :         {
     591          68 :             poHeader->panConnectivity[poHeader->nPointsPerElement *
     592          68 :                                           (poHeader->nElements - 1) +
     593          68 :                                       i] = anMap[i] + 1;
     594             :         }
     595          17 :         poHeader->setUpdated();
     596          17 :         CPLFree(anMap);
     597             :     }
     598             : 
     599             :     // Now comes the real insertion. Since values have to be inserted nearly
     600             :     // everywhere in the file and we don't want to store everything in memory to
     601             :     // overwrite it, we create a new copy of it where we write the new values
     602         138 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     603          69 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     604          69 :     if (fpNew == nullptr)
     605             :     {
     606           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     607             :                  "Failed to open temporary file %s with write access, %s.",
     608           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     609           0 :         return OGRERR_FAILURE;
     610             :     }
     611          69 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     612             :     {
     613           0 :         VSIFCloseL(fpNew);
     614           0 :         VSIUnlink(osTempfile.c_str());
     615           0 :         return OGRERR_FAILURE;
     616             :     }
     617         139 :     for (int i = 0; i < poHeader->nSteps; ++i)
     618             :     {
     619          70 :         int nLen = 0;
     620          70 :         double dfDate = 0.0;
     621          70 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     622          70 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     623          70 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     624          70 :             Selafin::write_integer(fpNew, 4) == 0 ||
     625         210 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     626          70 :             Selafin::write_integer(fpNew, 4) == 0)
     627             :         {
     628           0 :             VSIFCloseL(fpNew);
     629           0 :             VSIUnlink(osTempfile.c_str());
     630           0 :             return OGRERR_FAILURE;
     631             :         }
     632         140 :         for (int j = 0; j < poHeader->nVar; ++j)
     633             :         {
     634          70 :             double *padfValues = nullptr;
     635         140 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     636          70 :                                          poHeader->nFileSize) == -1)
     637             :             {
     638           0 :                 VSIFCloseL(fpNew);
     639           0 :                 VSIUnlink(osTempfile.c_str());
     640           0 :                 return OGRERR_FAILURE;
     641             :             }
     642         140 :             padfValues = (double *)CPLRealloc(
     643          70 :                 padfValues, sizeof(double) * poHeader->nPoints);
     644          70 :             if (padfValues == nullptr)
     645             :             {
     646           0 :                 VSIFCloseL(fpNew);
     647           0 :                 VSIUnlink(osTempfile.c_str());
     648           0 :                 return OGRERR_FAILURE;
     649             :             }
     650          70 :             if (eType == POINTS)
     651         106 :                 padfValues[poHeader->nPoints - 1] =
     652          53 :                     poFeature->GetFieldAsDouble(j);
     653             :             else
     654          17 :                 padfValues[poHeader->nPoints - 1] = 0;
     655         140 :             if (Selafin::write_floatarray(fpNew, padfValues,
     656          70 :                                           poHeader->nPoints) == 0)
     657             :             {
     658           0 :                 CPLFree(padfValues);
     659           0 :                 VSIFCloseL(fpNew);
     660           0 :                 VSIUnlink(osTempfile.c_str());
     661           0 :                 return OGRERR_FAILURE;
     662             :             }
     663          70 :             CPLFree(padfValues);
     664             :         }
     665             :     }
     666             : 
     667             :     // If everything went fine, we overwrite the new file with the content of
     668             :     // the old one. This way, even if something goes bad, we can still recover
     669             :     // the layer. The copy process is format-agnostic.
     670          69 :     MoveOverwrite(poHeader->fp, fpNew);
     671          69 :     VSIUnlink(osTempfile.c_str());
     672          69 :     poHeader->UpdateFileSize();
     673          69 :     return OGRERR_NONE;
     674             : }
     675             : 
     676             : /************************************************************************/
     677             : /*                           CreateField()                              */
     678             : /************************************************************************/
     679           9 : OGRErr OGRSelafinLayer::CreateField(const OGRFieldDefn *poField,
     680             :                                     CPL_UNUSED int bApproxOK)
     681             : {
     682           9 :     CPLDebug("Selafin", "CreateField(%s,%s)", poField->GetNameRef(),
     683             :              OGRFieldDefn::GetFieldTypeName(poField->GetType()));
     684             :     // Test if the field does not exist yet
     685           9 :     if (poFeatureDefn->GetFieldIndex(poField->GetNameRef()) != -1)
     686             :     {
     687             :         // Those two lines are copied from CSV driver, but I am not quite sure
     688             :         // what they actually do
     689           0 :         if (poFeatureDefn->GetGeomFieldIndex(poField->GetNameRef()) != -1)
     690           0 :             return OGRERR_NONE;
     691           0 :         if (poFeatureDefn->GetGeomFieldIndex(
     692           0 :                 CPLSPrintf("geom_%s", poField->GetNameRef())) != -1)
     693           0 :             return OGRERR_NONE;
     694           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     695             :                  "Attempt to create field %s, but a field with this name "
     696             :                  "already exists.",
     697             :                  poField->GetNameRef());
     698           0 :         return OGRERR_FAILURE;
     699             :     }
     700             :     // Test if the field type is legal (only double precision values are
     701             :     // allowed)
     702           9 :     if (poField->GetType() != OFTReal)
     703             :     {
     704           5 :         CPLError(
     705             :             CE_Failure, CPLE_AppDefined,
     706             :             "Attempt to create field of type %s, but this is not supported for "
     707             :             "Selafin files (only double precision fields are allowed).",
     708             :             poField->GetFieldTypeName(poField->GetType()));
     709           5 :         return OGRERR_FAILURE;
     710             :     }
     711           4 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     712           0 :         return OGRERR_FAILURE;
     713             :     // Change the header to add the new field
     714           4 :     poHeader->nVar++;
     715           4 :     poHeader->setUpdated();
     716           8 :     poHeader->papszVariables = (char **)CPLRealloc(
     717           4 :         poHeader->papszVariables, sizeof(char *) * poHeader->nVar);
     718           8 :     poHeader->papszVariables[poHeader->nVar - 1] =
     719           4 :         (char *)VSI_MALLOC2_VERBOSE(sizeof(char), 33);
     720           4 :     strncpy(poHeader->papszVariables[poHeader->nVar - 1], poField->GetNameRef(),
     721             :             32);
     722           4 :     poHeader->papszVariables[poHeader->nVar - 1][32] = 0;
     723           4 :     poFeatureDefn->AddFieldDefn(poField);
     724             : 
     725             :     // Now comes the real insertion. Since values have to be inserted nearly
     726             :     // everywhere in the file and we don't want to store everything in memory to
     727             :     // overwrite it, we create a new copy of it where we write the new values
     728           8 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     729           4 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     730           4 :     if (fpNew == nullptr)
     731             :     {
     732           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     733             :                  "Failed to open temporary file %s with write access, %s.",
     734           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     735           0 :         return OGRERR_FAILURE;
     736             :     }
     737           4 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     738             :     {
     739           0 :         VSIFCloseL(fpNew);
     740           0 :         VSIUnlink(osTempfile.c_str());
     741           0 :         return OGRERR_FAILURE;
     742             :     }
     743           8 :     for (int i = 0; i < poHeader->nSteps; ++i)
     744             :     {
     745           4 :         int nLen = 0;
     746           4 :         double dfDate = 0.0;
     747           4 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     748           4 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     749           4 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     750           4 :             Selafin::write_integer(fpNew, 4) == 0 ||
     751          12 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     752           4 :             Selafin::write_integer(fpNew, 4) == 0)
     753             :         {
     754           0 :             VSIFCloseL(fpNew);
     755           0 :             VSIUnlink(osTempfile.c_str());
     756           0 :             return OGRERR_FAILURE;
     757             :         }
     758           4 :         double *padfValues = nullptr;
     759           5 :         for (int j = 0; j < poHeader->nVar - 1; ++j)
     760             :         {
     761           2 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     762           1 :                                          poHeader->nFileSize) == -1)
     763             :             {
     764           0 :                 VSIFCloseL(fpNew);
     765           0 :                 VSIUnlink(osTempfile.c_str());
     766           0 :                 return OGRERR_FAILURE;
     767             :             }
     768           2 :             if (Selafin::write_floatarray(fpNew, padfValues,
     769           1 :                                           poHeader->nPoints) == 0)
     770             :             {
     771           0 :                 CPLFree(padfValues);
     772           0 :                 VSIFCloseL(fpNew);
     773           0 :                 VSIUnlink(osTempfile.c_str());
     774           0 :                 return OGRERR_FAILURE;
     775             :             }
     776           1 :             CPLFree(padfValues);
     777             :         }
     778           4 :         padfValues =
     779           4 :             (double *)VSI_MALLOC2_VERBOSE(sizeof(double), poHeader->nPoints);
     780          29 :         for (int k = 0; k < poHeader->nPoints; ++k)
     781          25 :             padfValues[k] = 0;
     782           4 :         if (Selafin::write_floatarray(fpNew, padfValues, poHeader->nPoints) ==
     783             :             0)
     784             :         {
     785           0 :             CPLFree(padfValues);
     786           0 :             VSIFCloseL(fpNew);
     787           0 :             VSIUnlink(osTempfile.c_str());
     788           0 :             return OGRERR_FAILURE;
     789             :         }
     790           4 :         CPLFree(padfValues);
     791             :     }
     792           4 :     MoveOverwrite(poHeader->fp, fpNew);
     793           4 :     VSIUnlink(osTempfile.c_str());
     794           4 :     poHeader->UpdateFileSize();
     795           4 :     return OGRERR_NONE;
     796             : }
     797             : 
     798             : /************************************************************************/
     799             : /*                           DeleteField()                              */
     800             : /************************************************************************/
     801           0 : OGRErr OGRSelafinLayer::DeleteField(int iField)
     802             : {
     803           0 :     CPLDebug("Selafin", "DeleteField(%i)", iField);
     804           0 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     805           0 :         return OGRERR_FAILURE;
     806             :     // Change the header to remove the field
     807           0 :     poHeader->nVar--;
     808           0 :     poHeader->setUpdated();
     809           0 :     CPLFree(poHeader->papszVariables[iField]);
     810           0 :     for (int i = iField; i < poHeader->nVar; ++i)
     811           0 :         poHeader->papszVariables[i] = poHeader->papszVariables[i + 1];
     812           0 :     poHeader->papszVariables = (char **)CPLRealloc(
     813           0 :         poHeader->papszVariables, sizeof(char *) * poHeader->nVar);
     814           0 :     poFeatureDefn->DeleteFieldDefn(iField);
     815             : 
     816             :     // Now comes the real deletion. Since values have to be deleted nearly
     817             :     // everywhere in the file and we don't want to store everything in memory to
     818             :     // overwrite it, we create a new copy of it where we write the new values
     819           0 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     820           0 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     821           0 :     if (fpNew == nullptr)
     822             :     {
     823           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     824             :                  "Failed to open temporary file %s with write access, %s.",
     825           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     826           0 :         return OGRERR_FAILURE;
     827             :     }
     828           0 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     829             :     {
     830           0 :         VSIFCloseL(fpNew);
     831           0 :         VSIUnlink(osTempfile.c_str());
     832           0 :         return OGRERR_FAILURE;
     833             :     }
     834           0 :     for (int i = 0; i < poHeader->nSteps; ++i)
     835             :     {
     836           0 :         int nLen = 0;
     837           0 :         double dfDate = 0.0;
     838           0 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     839           0 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     840           0 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     841           0 :             Selafin::write_integer(fpNew, 4) == 0 ||
     842           0 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     843           0 :             Selafin::write_integer(fpNew, 4) == 0)
     844             :         {
     845           0 :             VSIFCloseL(fpNew);
     846           0 :             VSIUnlink(osTempfile.c_str());
     847           0 :             return OGRERR_FAILURE;
     848             :         }
     849           0 :         for (int j = 0; j < poHeader->nVar; ++j)
     850             :         {
     851           0 :             double *padfValues = nullptr;
     852           0 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     853           0 :                                          poHeader->nFileSize) == -1)
     854             :             {
     855           0 :                 VSIFCloseL(fpNew);
     856           0 :                 VSIUnlink(osTempfile.c_str());
     857           0 :                 return OGRERR_FAILURE;
     858             :             }
     859           0 :             if (j != iField)
     860             :             {
     861           0 :                 if (Selafin::write_floatarray(fpNew, padfValues,
     862           0 :                                               poHeader->nPoints) == 0)
     863             :                 {
     864           0 :                     CPLFree(padfValues);
     865           0 :                     VSIFCloseL(fpNew);
     866           0 :                     VSIUnlink(osTempfile.c_str());
     867           0 :                     return OGRERR_FAILURE;
     868             :                 }
     869             :             }
     870           0 :             CPLFree(padfValues);
     871             :         }
     872             :     }
     873           0 :     MoveOverwrite(poHeader->fp, fpNew);
     874           0 :     VSIUnlink(osTempfile.c_str());
     875           0 :     poHeader->UpdateFileSize();
     876           0 :     return OGRERR_NONE;
     877             : }
     878             : 
     879             : /************************************************************************/
     880             : /*                          ReorderFields()                             */
     881             : /************************************************************************/
     882           1 : OGRErr OGRSelafinLayer::ReorderFields(int *panMap)
     883             : {
     884           1 :     CPLDebug("Selafin", "ReorderFields()");
     885           1 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     886           0 :         return OGRERR_FAILURE;
     887             :     // Change the header according to the map
     888             :     char **papszNew =
     889           1 :         (char **)VSI_MALLOC2_VERBOSE(sizeof(char *), poHeader->nVar);
     890           3 :     for (int i = 0; i < poHeader->nVar; ++i)
     891           2 :         papszNew[i] = poHeader->papszVariables[panMap[i]];
     892           1 :     CPLFree(poHeader->papszVariables);
     893           1 :     poHeader->papszVariables = papszNew;
     894           1 :     poFeatureDefn->ReorderFieldDefns(panMap);
     895             : 
     896             :     // Now comes the real change.
     897           2 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     898           1 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     899           1 :     if (fpNew == nullptr)
     900             :     {
     901           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     902             :                  "Failed to open temporary file %s with write access, %s.",
     903           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     904           0 :         return OGRERR_FAILURE;
     905             :     }
     906           1 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     907             :     {
     908           0 :         VSIFCloseL(fpNew);
     909           0 :         VSIUnlink(osTempfile.c_str());
     910           0 :         return OGRERR_FAILURE;
     911             :     }
     912           1 :     double *padfValues = nullptr;
     913           2 :     for (int i = 0; i < poHeader->nSteps; ++i)
     914             :     {
     915           1 :         int nLen = 0;
     916           1 :         double dfDate = 0.0;
     917           1 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     918           1 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     919           1 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     920           1 :             Selafin::write_integer(fpNew, 4) == 0 ||
     921           3 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     922           1 :             Selafin::write_integer(fpNew, 4) == 0)
     923             :         {
     924           0 :             VSIFCloseL(fpNew);
     925           0 :             VSIUnlink(osTempfile.c_str());
     926           0 :             return OGRERR_FAILURE;
     927             :         }
     928           3 :         for (int j = 0; j < poHeader->nVar; ++j)
     929             :         {
     930           2 :             if (VSIFSeekL(poHeader->fp, poHeader->getPosition(i, -1, panMap[j]),
     931           4 :                           SEEK_SET) != 0 ||
     932           2 :                 Selafin::read_floatarray(poHeader->fp, &padfValues,
     933           2 :                                          poHeader->nFileSize) == -1)
     934             :             {
     935           0 :                 VSIFCloseL(fpNew);
     936           0 :                 VSIUnlink(osTempfile.c_str());
     937           0 :                 return OGRERR_FAILURE;
     938             :             }
     939           4 :             if (Selafin::write_floatarray(fpNew, padfValues,
     940           2 :                                           poHeader->nPoints) == 0)
     941             :             {
     942           0 :                 CPLFree(padfValues);
     943           0 :                 VSIFCloseL(fpNew);
     944           0 :                 VSIUnlink(osTempfile.c_str());
     945           0 :                 return OGRERR_FAILURE;
     946             :             }
     947           2 :             CPLFree(padfValues);
     948             :         }
     949             :     }
     950           1 :     MoveOverwrite(poHeader->fp, fpNew);
     951           1 :     VSIUnlink(osTempfile.c_str());
     952           1 :     poHeader->UpdateFileSize();
     953           1 :     return OGRERR_NONE;
     954             : }
     955             : 
     956             : /************************************************************************/
     957             : /*                         AlterFieldDefn()                             */
     958             : /************************************************************************/
     959           1 : OGRErr OGRSelafinLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
     960             :                                        int /* nFlagsIn */)
     961             : {
     962           1 :     CPLDebug("Selafin", "AlterFieldDefn(%i,%s,%s)", iField,
     963             :              poNewFieldDefn->GetNameRef(),
     964             :              OGRFieldDefn::GetFieldTypeName(poNewFieldDefn->GetType()));
     965             :     // Test if the field type is legal (only double precision values are
     966             :     // allowed)
     967           1 :     if (poNewFieldDefn->GetType() != OFTReal)
     968             :     {
     969           0 :         CPLError(
     970             :             CE_Failure, CPLE_AppDefined,
     971             :             "Attempt to update field with type %s, but this is not supported "
     972             :             "for Selafin files (only double precision fields are allowed).",
     973             :             poNewFieldDefn->GetFieldTypeName(poNewFieldDefn->GetType()));
     974           0 :         return OGRERR_FAILURE;
     975             :     }
     976             :     // Since the field type can't change, only the field name is changed. We
     977             :     // change it in the header
     978           1 :     CPLFree(poHeader->papszVariables[iField]);
     979           2 :     poHeader->papszVariables[iField] =
     980           1 :         (char *)VSI_MALLOC2_VERBOSE(sizeof(char), 33);
     981           1 :     strncpy(poHeader->papszVariables[iField], poNewFieldDefn->GetNameRef(), 32);
     982           1 :     poHeader->papszVariables[iField][32] = 0;
     983             :     // And we update the file
     984           1 :     if (VSIFSeekL(poHeader->fp, 88 + 16 + 40 * iField, SEEK_SET) != 0)
     985           0 :         return OGRERR_FAILURE;
     986           1 :     if (Selafin::write_string(poHeader->fp, poHeader->papszVariables[iField],
     987           1 :                               32) == 0)
     988           0 :         return OGRERR_FAILURE;
     989           1 :     VSIFFlushL(poHeader->fp);
     990           1 :     poHeader->UpdateFileSize();
     991           1 :     return OGRERR_NONE;
     992             : }
     993             : 
     994             : /************************************************************************/
     995             : /*                          DeleteFeature()                             */
     996             : /************************************************************************/
     997           0 : OGRErr OGRSelafinLayer::DeleteFeature(GIntBig nFID)
     998             : {
     999           0 :     CPLDebug("Selafin", "DeleteFeature(" CPL_FRMT_GIB ")", nFID);
    1000           0 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
    1001           0 :         return OGRERR_FAILURE;
    1002             :     // Change the header to delete the feature
    1003           0 :     if (eType == POINTS)
    1004           0 :         poHeader->removePoint((int)nFID);
    1005             :     else
    1006             :     {
    1007             :         // For elements layer, we only delete the element and not the vertices
    1008           0 :         poHeader->nElements--;
    1009           0 :         for (int i = (int)nFID; i < poHeader->nElements; ++i)
    1010           0 :             for (int j = 0; j < poHeader->nPointsPerElement; ++j)
    1011           0 :                 poHeader->panConnectivity[poHeader->nPointsPerElement * i + j] =
    1012           0 :                     poHeader->panConnectivity[poHeader->nPointsPerElement *
    1013           0 :                                                   (i + 1) +
    1014           0 :                                               j];
    1015           0 :         poHeader->panConnectivity = (int *)CPLRealloc(
    1016           0 :             poHeader->panConnectivity,
    1017           0 :             sizeof(int) * poHeader->nPointsPerElement * poHeader->nElements);
    1018           0 :         poHeader->setUpdated();
    1019             :     }
    1020             : 
    1021             :     // Now we perform the deletion by creating a new temporary layer
    1022           0 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
    1023           0 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
    1024           0 :     if (fpNew == nullptr)
    1025             :     {
    1026           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1027             :                  "Failed to open temporary file %s with write access, %s.",
    1028           0 :                  osTempfile.c_str(), VSIStrerror(errno));
    1029           0 :         return OGRERR_FAILURE;
    1030             :     }
    1031           0 :     if (Selafin::write_header(fpNew, poHeader) == 0)
    1032             :     {
    1033           0 :         VSIFCloseL(fpNew);
    1034           0 :         VSIUnlink(osTempfile.c_str());
    1035           0 :         return OGRERR_FAILURE;
    1036             :     }
    1037           0 :     for (int i = 0; i < poHeader->nSteps; ++i)
    1038             :     {
    1039           0 :         int nLen = 0;
    1040           0 :         double dfDate = 0.0;
    1041           0 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
    1042           0 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
    1043           0 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
    1044           0 :             Selafin::write_integer(fpNew, 4) == 0 ||
    1045           0 :             Selafin::write_float(fpNew, dfDate) == 0 ||
    1046           0 :             Selafin::write_integer(fpNew, 4) == 0)
    1047             :         {
    1048           0 :             VSIFCloseL(fpNew);
    1049           0 :             VSIUnlink(osTempfile.c_str());
    1050           0 :             return OGRERR_FAILURE;
    1051             :         }
    1052           0 :         for (int j = 0; j < poHeader->nVar; ++j)
    1053             :         {
    1054           0 :             double *padfValues = nullptr;
    1055           0 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
    1056           0 :                                          poHeader->nFileSize) == -1)
    1057             :             {
    1058           0 :                 VSIFCloseL(fpNew);
    1059           0 :                 VSIUnlink(osTempfile.c_str());
    1060           0 :                 return OGRERR_FAILURE;
    1061             :             }
    1062           0 :             if (eType == POINTS)
    1063             :             {
    1064           0 :                 for (int k = (int)nFID; k <= poHeader->nPoints; ++k)
    1065           0 :                     padfValues[k - 1] = padfValues[k];
    1066             :             }
    1067           0 :             if (Selafin::write_floatarray(fpNew, padfValues,
    1068           0 :                                           poHeader->nPoints) == 0)
    1069             :             {
    1070           0 :                 CPLFree(padfValues);
    1071           0 :                 VSIFCloseL(fpNew);
    1072           0 :                 VSIUnlink(osTempfile.c_str());
    1073           0 :                 return OGRERR_FAILURE;
    1074             :             }
    1075           0 :             CPLFree(padfValues);
    1076             :         }
    1077             :     }
    1078             : 
    1079             :     // If everything went fine, we overwrite the new file with the content of
    1080             :     // the old one. This way, even if something goes bad, we can still recover
    1081             :     // the layer. The copy process is format-agnostic.
    1082           0 :     MoveOverwrite(poHeader->fp, fpNew);
    1083           0 :     VSIUnlink(osTempfile.c_str());
    1084           0 :     poHeader->UpdateFileSize();
    1085             : 
    1086           0 :     return OGRERR_NONE;
    1087             : }

Generated by: LCOV version 1.14