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

Generated by: LCOV version 1.14