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: 2025-01-18 12:42:00 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)
     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             : /*                             GetExtent()                              */
     274             : /************************************************************************/
     275           0 : OGRErr OGRSelafinLayer::GetExtent(OGREnvelope *psExtent, CPL_UNUSED int bForce)
     276             : {
     277             :     // CPLDebug("Selafin","GetExtent(%i)",bForce);
     278           0 :     if (poHeader->nPoints == 0)
     279           0 :         return OGRERR_NONE;
     280           0 :     CPLRectObj *poObj = poHeader->getBoundingBox();
     281           0 :     psExtent->MinX = poObj->minx;
     282           0 :     psExtent->MaxX = poObj->maxx;
     283           0 :     psExtent->MinY = poObj->miny;
     284           0 :     psExtent->MaxY = poObj->maxy;
     285           0 :     delete poObj;
     286           0 :     return OGRERR_NONE;
     287             : }
     288             : 
     289             : /************************************************************************/
     290             : /*                             ISetFeature()                             */
     291             : /************************************************************************/
     292          25 : OGRErr OGRSelafinLayer::ISetFeature(OGRFeature *poFeature)
     293             : {
     294          25 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     295          25 :     if (poGeom == nullptr)
     296           0 :         return OGRERR_FAILURE;
     297          25 :     if (eType == POINTS)
     298             :     {
     299             :         // If it is a point layer, it is the "easy" case: we change the
     300             :         // coordinates and attributes of the feature and update the file
     301          25 :         if (poGeom->getGeometryType() != wkbPoint)
     302             :         {
     303           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     304             :                      "The new feature should be of the same Point geometry as "
     305             :                      "the existing ones in the layer.");
     306           0 :             return OGRERR_FAILURE;
     307             :         }
     308          25 :         OGRPoint *poPoint = poGeom->toPoint();
     309          25 :         GIntBig nFID = poFeature->GetFID();
     310          25 :         poHeader->paadfCoords[0][nFID] = poPoint->getX();
     311          25 :         poHeader->paadfCoords[1][nFID] = poPoint->getY();
     312          25 :         CPLDebug("Selafin", "SetFeature(" CPL_FRMT_GIB ",%f,%f)", nFID,
     313          25 :                  poHeader->paadfCoords[0][nFID],
     314          25 :                  poHeader->paadfCoords[1][nFID]);
     315          50 :         if (VSIFSeekL(
     316          25 :                 poHeader->fp,
     317          50 :                 88 + 16 + 40 * poHeader->nVar + 48 +
     318          25 :                     ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     319          25 :                     (poHeader->nElements * poHeader->nPointsPerElement + 2) *
     320          25 :                         4 +
     321          25 :                     (poHeader->nPoints + 2) * 4 + 4 + nFID * 4,
     322          25 :                 SEEK_SET) != 0)
     323           0 :             return OGRERR_FAILURE;
     324          25 :         CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     325          25 :                  VSIFTellL(poHeader->fp),
     326          25 :                  poHeader->paadfCoords[0][nFID] - poHeader->adfOrigin[0]);
     327          50 :         if (Selafin::write_float(poHeader->fp, poHeader->paadfCoords[0][nFID] -
     328          25 :                                                    poHeader->adfOrigin[0]) == 0)
     329           0 :             return OGRERR_FAILURE;
     330          50 :         if (VSIFSeekL(
     331          25 :                 poHeader->fp,
     332          50 :                 88 + 16 + 40 * poHeader->nVar + 48 +
     333          25 :                     ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     334          25 :                     (poHeader->nElements * poHeader->nPointsPerElement + 2) *
     335          25 :                         4 +
     336          25 :                     (poHeader->nPoints + 2) * 4 + (poHeader->nPoints + 2) * 4 +
     337          25 :                     4 + nFID * 4,
     338          25 :                 SEEK_SET) != 0)
     339           0 :             return OGRERR_FAILURE;
     340          25 :         CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     341          25 :                  VSIFTellL(poHeader->fp),
     342          25 :                  poHeader->paadfCoords[1][nFID] - poHeader->adfOrigin[1]);
     343          50 :         if (Selafin::write_float(poHeader->fp, poHeader->paadfCoords[1][nFID] -
     344          25 :                                                    poHeader->adfOrigin[1]) == 0)
     345           0 :             return OGRERR_FAILURE;
     346          75 :         for (int i = 0; i < poHeader->nVar; ++i)
     347             :         {
     348          50 :             double nData = poFeature->GetFieldAsDouble(i);
     349         100 :             if (VSIFSeekL(poHeader->fp,
     350          50 :                           poHeader->getPosition(nStepNumber, (int)nFID, i),
     351          50 :                           SEEK_SET) != 0)
     352           0 :                 return OGRERR_FAILURE;
     353          50 :             if (Selafin::write_float(poHeader->fp, nData) == 0)
     354           0 :                 return OGRERR_FAILURE;
     355             :         }
     356             :     }
     357             :     else
     358             :     {
     359             :         // Else, we have a layer of polygonal elements. Here we consider that
     360             :         // the vertices are moved when we change the geometry (which will also
     361             :         // lead to a modification in the corresponding point layer). The
     362             :         // attributes table can't be changed, because attributes are calculated
     363             :         // from those of the vertices. First we check that the new feature is a
     364             :         // polygon with the right number of vertices
     365           0 :         if (poGeom->getGeometryType() != wkbPolygon)
     366             :         {
     367           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     368             :                      "The new feature should be of the same Polygon geometry "
     369             :                      "as the existing ones in the layer.");
     370           0 :             return OGRERR_FAILURE;
     371             :         }
     372           0 :         OGRLinearRing *poLinearRing = poGeom->toPolygon()->getExteriorRing();
     373           0 :         if (poLinearRing->getNumPoints() != poHeader->nPointsPerElement + 1)
     374             :         {
     375           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     376             :                      "The new feature should have the same number of vertices "
     377             :                      "%d as the existing ones in the layer.",
     378           0 :                      poHeader->nPointsPerElement);
     379           0 :             return OGRERR_FAILURE;
     380             :         }
     381           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     382             :                  "The attributes of elements layer in Selafin files can't be "
     383             :                  "updated.");
     384           0 :         CPLDebug("Selafin", "SetFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",
     385             :                  poFeature->GetFID(), poLinearRing->getX(0),
     386             :                  poLinearRing->getY(0), poLinearRing->getX(1),
     387             :                  poLinearRing->getY(1), poLinearRing->getX(2),
     388             :                  poLinearRing->getY(
     389             :                      2));  //!< This is not safe as we can't be sure there are
     390             :                            //!< at least three vertices in the linear ring, but
     391             :                            //!< we can assume that for a debug mode
     392           0 :         int nFID = static_cast<int>(poFeature->GetFID());
     393             :         // Now we change the coordinates of points in the layer based on the
     394             :         // vertices of the new polygon. We don't look at the order of points and
     395             :         // we assume that it is the same as in the original layer.
     396           0 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     397             :         {
     398           0 :             int nPointId =
     399           0 :                 poHeader
     400           0 :                     ->panConnectivity[nFID * poHeader->nPointsPerElement + i] -
     401             :                 1;
     402           0 :             poHeader->paadfCoords[0][nPointId] = poLinearRing->getX(i);
     403           0 :             poHeader->paadfCoords[1][nPointId] = poLinearRing->getY(i);
     404           0 :             if (VSIFSeekL(
     405           0 :                     poHeader->fp,
     406           0 :                     88 + 16 + 40 * poHeader->nVar + 48 +
     407           0 :                         ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     408           0 :                         (poHeader->nElements * poHeader->nPointsPerElement +
     409           0 :                          2) *
     410           0 :                             4 +
     411           0 :                         (poHeader->nPoints + 2) * 4 + 4 + nPointId * 4,
     412           0 :                     SEEK_SET) != 0)
     413           0 :                 return OGRERR_FAILURE;
     414           0 :             CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     415           0 :                      VSIFTellL(poHeader->fp),
     416           0 :                      poHeader->paadfCoords[0][nPointId] -
     417           0 :                          poHeader->adfOrigin[0]);
     418           0 :             if (Selafin::write_float(poHeader->fp,
     419           0 :                                      poHeader->paadfCoords[0][nPointId] -
     420           0 :                                          poHeader->adfOrigin[0]) == 0)
     421           0 :                 return OGRERR_FAILURE;
     422           0 :             if (VSIFSeekL(
     423           0 :                     poHeader->fp,
     424           0 :                     88 + 16 + 40 * poHeader->nVar + 48 +
     425           0 :                         ((poHeader->panStartDate != nullptr) ? 32 : 0) + 24 +
     426           0 :                         (poHeader->nElements * poHeader->nPointsPerElement +
     427           0 :                          2) *
     428           0 :                             4 +
     429           0 :                         (poHeader->nPoints + 2) * 4 +
     430           0 :                         (poHeader->nPoints + 2) * 4 + 4 + nPointId * 4,
     431           0 :                     SEEK_SET) != 0)
     432           0 :                 return OGRERR_FAILURE;
     433           0 :             CPLDebug("Selafin", "Write_float(" CPL_FRMT_GUIB ",%f)",
     434           0 :                      VSIFTellL(poHeader->fp),
     435           0 :                      poHeader->paadfCoords[1][nPointId] -
     436           0 :                          poHeader->adfOrigin[1]);
     437           0 :             if (Selafin::write_float(poHeader->fp,
     438           0 :                                      poHeader->paadfCoords[1][nPointId] -
     439           0 :                                          poHeader->adfOrigin[1]) == 0)
     440           0 :                 return OGRERR_FAILURE;
     441             :         }
     442             :     }
     443          25 :     VSIFFlushL(poHeader->fp);
     444          25 :     poHeader->UpdateFileSize();
     445          25 :     return OGRERR_NONE;
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                           ICreateFeature()                            */
     450             : /************************************************************************/
     451          72 : OGRErr OGRSelafinLayer::ICreateFeature(OGRFeature *poFeature)
     452             : {
     453          72 :     OGRGeometry *poGeom = poFeature->GetGeometryRef();
     454          72 :     if (poGeom == nullptr)
     455           2 :         return OGRERR_FAILURE;
     456          70 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     457           0 :         return OGRERR_FAILURE;
     458          70 :     if (eType == POINTS)
     459             :     {
     460             :         // If it is a point layer, it is the "easy" case: we add a new point
     461             :         // feature and update the file
     462          53 :         if (poGeom->getGeometryType() != wkbPoint)
     463             :         {
     464           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     465             :                      "The new feature should be of the same Point geometry as "
     466             :                      "the existing ones in the layer.");
     467           1 :             return OGRERR_FAILURE;
     468             :         }
     469          52 :         OGRPoint *poPoint = poGeom->toPoint();
     470          52 :         poFeature->SetFID(poHeader->nPoints);
     471          52 :         CPLDebug("Selafin", "CreateFeature(%d,%f,%f)", poHeader->nPoints,
     472             :                  poPoint->getX(), poPoint->getY());
     473             :         // Change the header to add the new feature
     474          52 :         poHeader->addPoint(poPoint->getX(), poPoint->getY());
     475             :     }
     476             :     else
     477             :     {
     478             :         // This is the most difficult case. The user wants to add a polygon
     479             :         // element. First we check that it has the same number of vertices as
     480             :         // the other polygon elements in the file. If there is no other element,
     481             :         // then we define the number of vertices. Every vertex in the layer
     482             :         // should have a corresponding point in the corresponding point layer.
     483             :         // So if we add a polygon element, we also have to add points in the
     484             :         // corresponding layer. The function tries to add as few new points as
     485             :         // possible, reusing already existing points. This is generally what the
     486             :         // user will expect.
     487             : 
     488             :         // First we check that we have the required geometry
     489          17 :         if (poGeom->getGeometryType() != wkbPolygon)
     490             :         {
     491           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     492             :                      "The new feature should be of the same Polygon geometry "
     493             :                      "as the existing ones in the layer.");
     494           0 :             return OGRERR_FAILURE;
     495             :         }
     496             : 
     497             :         // Now we check that we have the right number of vertices, or if this
     498             :         // number was not defined yet (0), we define it at once
     499          17 :         OGRLinearRing *poLinearRing = poGeom->toPolygon()->getExteriorRing();
     500          17 :         poFeature->SetFID(poHeader->nElements);
     501          17 :         CPLDebug("Selafin", "CreateFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",
     502             :                  poFeature->GetFID(), poLinearRing->getX(0),
     503             :                  poLinearRing->getY(0), poLinearRing->getX(1),
     504             :                  poLinearRing->getY(1), poLinearRing->getX(2),
     505             :                  poLinearRing->getY(
     506             :                      2));  //!< This is not safe as we can't be sure there are
     507             :                            //!< at least three vertices in the linear ring, but
     508             :                            //!< we can assume that for a debug mode
     509          17 :         int nNum = poLinearRing->getNumPoints();
     510          17 :         if (poHeader->nPointsPerElement == 0)
     511             :         {
     512           1 :             if (nNum < 4)
     513             :             {
     514           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     515             :                          "The new feature should have at least 3 vertices.");
     516           0 :                 return OGRERR_FAILURE;
     517             :             }
     518           1 :             poHeader->nPointsPerElement = nNum - 1;
     519           1 :             if (poHeader->nElements > 0)
     520             :             {
     521             :                 int *panConnectivity =
     522           0 :                     reinterpret_cast<int *>(VSI_REALLOC_VERBOSE(
     523             :                         poHeader->panConnectivity,
     524             :                         static_cast<size_t>(poHeader->nElements) *
     525             :                             poHeader->nPointsPerElement));
     526           0 :                 if (panConnectivity == nullptr)
     527             :                 {
     528           0 :                     VSIFree(poHeader->panConnectivity);
     529           0 :                     poHeader->panConnectivity = nullptr;
     530           0 :                     return OGRERR_FAILURE;
     531             :                 }
     532           0 :                 poHeader->panConnectivity = panConnectivity;
     533             :             }
     534             :         }
     535             :         else
     536             :         {
     537          16 :             if (poLinearRing->getNumPoints() != poHeader->nPointsPerElement + 1)
     538             :             {
     539           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     540             :                          "The new feature should have the same number of "
     541             :                          "vertices %d as the existing ones in the layer.",
     542           0 :                          poHeader->nPointsPerElement);
     543           0 :                 return OGRERR_FAILURE;
     544             :             }
     545             :         }
     546             : 
     547             :         // Now we look for vertices that are already referenced as points in the
     548             :         // file
     549          17 :         int *anMap = (int *)VSI_MALLOC2_VERBOSE(sizeof(int),
     550             :                                                 poHeader->nPointsPerElement);
     551          17 :         if (anMap == nullptr)
     552             :         {
     553           0 :             return OGRERR_FAILURE;
     554             :         }
     555          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     556          68 :             anMap[i] = -1;
     557          17 :         if (poHeader->nPoints > 0)
     558             :         {
     559          17 :             CPLRectObj *poBB = poHeader->getBoundingBox();
     560             :             double dfMaxDist =
     561          17 :                 (poBB->maxx - poBB->minx) / sqrt((double)(poHeader->nPoints)) /
     562          17 :                 1000.0;  //!< Heuristic approach to estimate a maximum distance
     563             :                          //!< such that two points are considered equal if they
     564             :                          //!< are closer from each other
     565          17 :             dfMaxDist *= dfMaxDist;
     566          17 :             delete poBB;
     567          85 :             for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     568         204 :                 anMap[i] = poHeader->getClosestPoint(
     569          68 :                     poLinearRing->getX(i), poLinearRing->getY(i), dfMaxDist);
     570             :         }
     571             : 
     572             :         // We add new points if needed only
     573          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     574          68 :             if (anMap[i] == -1)
     575             :             {
     576           3 :                 poHeader->addPoint(poLinearRing->getX(i),
     577           3 :                                    poLinearRing->getY(i));
     578           3 :                 anMap[i] = poHeader->nPoints - 1;
     579             :             }
     580             : 
     581             :         // And we update the connectivity table to add the new element
     582          17 :         poHeader->nElements++;
     583          34 :         poHeader->panConnectivity = (int *)CPLRealloc(
     584          17 :             poHeader->panConnectivity,
     585          17 :             sizeof(int) * poHeader->nPointsPerElement * poHeader->nElements);
     586          85 :         for (int i = 0; i < poHeader->nPointsPerElement; ++i)
     587             :         {
     588          68 :             poHeader->panConnectivity[poHeader->nPointsPerElement *
     589          68 :                                           (poHeader->nElements - 1) +
     590          68 :                                       i] = anMap[i] + 1;
     591             :         }
     592          17 :         poHeader->setUpdated();
     593          17 :         CPLFree(anMap);
     594             :     }
     595             : 
     596             :     // Now comes the real insertion. Since values have to be inserted nearly
     597             :     // everywhere in the file and we don't want to store everything in memory to
     598             :     // overwrite it, we create a new copy of it where we write the new values
     599         138 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     600          69 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     601          69 :     if (fpNew == nullptr)
     602             :     {
     603           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     604             :                  "Failed to open temporary file %s with write access, %s.",
     605           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     606           0 :         return OGRERR_FAILURE;
     607             :     }
     608          69 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     609             :     {
     610           0 :         VSIFCloseL(fpNew);
     611           0 :         VSIUnlink(osTempfile.c_str());
     612           0 :         return OGRERR_FAILURE;
     613             :     }
     614         139 :     for (int i = 0; i < poHeader->nSteps; ++i)
     615             :     {
     616          70 :         int nLen = 0;
     617          70 :         double dfDate = 0.0;
     618          70 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     619          70 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     620          70 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     621          70 :             Selafin::write_integer(fpNew, 4) == 0 ||
     622         210 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     623          70 :             Selafin::write_integer(fpNew, 4) == 0)
     624             :         {
     625           0 :             VSIFCloseL(fpNew);
     626           0 :             VSIUnlink(osTempfile.c_str());
     627           0 :             return OGRERR_FAILURE;
     628             :         }
     629         140 :         for (int j = 0; j < poHeader->nVar; ++j)
     630             :         {
     631          70 :             double *padfValues = nullptr;
     632         140 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     633          70 :                                          poHeader->nFileSize) == -1)
     634             :             {
     635           0 :                 VSIFCloseL(fpNew);
     636           0 :                 VSIUnlink(osTempfile.c_str());
     637           0 :                 return OGRERR_FAILURE;
     638             :             }
     639         140 :             padfValues = (double *)CPLRealloc(
     640          70 :                 padfValues, sizeof(double) * poHeader->nPoints);
     641          70 :             if (padfValues == nullptr)
     642             :             {
     643           0 :                 VSIFCloseL(fpNew);
     644           0 :                 VSIUnlink(osTempfile.c_str());
     645           0 :                 return OGRERR_FAILURE;
     646             :             }
     647          70 :             if (eType == POINTS)
     648         106 :                 padfValues[poHeader->nPoints - 1] =
     649          53 :                     poFeature->GetFieldAsDouble(j);
     650             :             else
     651          17 :                 padfValues[poHeader->nPoints - 1] = 0;
     652         140 :             if (Selafin::write_floatarray(fpNew, padfValues,
     653          70 :                                           poHeader->nPoints) == 0)
     654             :             {
     655           0 :                 CPLFree(padfValues);
     656           0 :                 VSIFCloseL(fpNew);
     657           0 :                 VSIUnlink(osTempfile.c_str());
     658           0 :                 return OGRERR_FAILURE;
     659             :             }
     660          70 :             CPLFree(padfValues);
     661             :         }
     662             :     }
     663             : 
     664             :     // If everything went fine, we overwrite the new file with the content of
     665             :     // the old one. This way, even if something goes bad, we can still recover
     666             :     // the layer. The copy process is format-agnostic.
     667          69 :     MoveOverwrite(poHeader->fp, fpNew);
     668          69 :     VSIUnlink(osTempfile.c_str());
     669          69 :     poHeader->UpdateFileSize();
     670          69 :     return OGRERR_NONE;
     671             : }
     672             : 
     673             : /************************************************************************/
     674             : /*                           CreateField()                              */
     675             : /************************************************************************/
     676           9 : OGRErr OGRSelafinLayer::CreateField(const OGRFieldDefn *poField,
     677             :                                     CPL_UNUSED int bApproxOK)
     678             : {
     679           9 :     CPLDebug("Selafin", "CreateField(%s,%s)", poField->GetNameRef(),
     680             :              OGRFieldDefn::GetFieldTypeName(poField->GetType()));
     681             :     // Test if the field does not exist yet
     682           9 :     if (poFeatureDefn->GetFieldIndex(poField->GetNameRef()) != -1)
     683             :     {
     684             :         // Those two lines are copied from CSV driver, but I am not quite sure
     685             :         // what they actually do
     686           0 :         if (poFeatureDefn->GetGeomFieldIndex(poField->GetNameRef()) != -1)
     687           0 :             return OGRERR_NONE;
     688           0 :         if (poFeatureDefn->GetGeomFieldIndex(
     689           0 :                 CPLSPrintf("geom_%s", poField->GetNameRef())) != -1)
     690           0 :             return OGRERR_NONE;
     691           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     692             :                  "Attempt to create field %s, but a field with this name "
     693             :                  "already exists.",
     694             :                  poField->GetNameRef());
     695           0 :         return OGRERR_FAILURE;
     696             :     }
     697             :     // Test if the field type is legal (only double precision values are
     698             :     // allowed)
     699           9 :     if (poField->GetType() != OFTReal)
     700             :     {
     701           5 :         CPLError(
     702             :             CE_Failure, CPLE_AppDefined,
     703             :             "Attempt to create field of type %s, but this is not supported for "
     704             :             "Selafin files (only double precision fields are allowed).",
     705             :             poField->GetFieldTypeName(poField->GetType()));
     706           5 :         return OGRERR_FAILURE;
     707             :     }
     708           4 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     709           0 :         return OGRERR_FAILURE;
     710             :     // Change the header to add the new field
     711           4 :     poHeader->nVar++;
     712           4 :     poHeader->setUpdated();
     713           8 :     poHeader->papszVariables = (char **)CPLRealloc(
     714           4 :         poHeader->papszVariables, sizeof(char *) * poHeader->nVar);
     715           8 :     poHeader->papszVariables[poHeader->nVar - 1] =
     716           4 :         (char *)VSI_MALLOC2_VERBOSE(sizeof(char), 33);
     717           4 :     strncpy(poHeader->papszVariables[poHeader->nVar - 1], poField->GetNameRef(),
     718             :             32);
     719           4 :     poHeader->papszVariables[poHeader->nVar - 1][32] = 0;
     720           4 :     poFeatureDefn->AddFieldDefn(poField);
     721             : 
     722             :     // Now comes the real insertion. Since values have to be inserted nearly
     723             :     // everywhere in the file and we don't want to store everything in memory to
     724             :     // overwrite it, we create a new copy of it where we write the new values
     725           8 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     726           4 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     727           4 :     if (fpNew == nullptr)
     728             :     {
     729           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     730             :                  "Failed to open temporary file %s with write access, %s.",
     731           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     732           0 :         return OGRERR_FAILURE;
     733             :     }
     734           4 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     735             :     {
     736           0 :         VSIFCloseL(fpNew);
     737           0 :         VSIUnlink(osTempfile.c_str());
     738           0 :         return OGRERR_FAILURE;
     739             :     }
     740           8 :     for (int i = 0; i < poHeader->nSteps; ++i)
     741             :     {
     742           4 :         int nLen = 0;
     743           4 :         double dfDate = 0.0;
     744           4 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     745           4 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     746           4 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     747           4 :             Selafin::write_integer(fpNew, 4) == 0 ||
     748          12 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     749           4 :             Selafin::write_integer(fpNew, 4) == 0)
     750             :         {
     751           0 :             VSIFCloseL(fpNew);
     752           0 :             VSIUnlink(osTempfile.c_str());
     753           0 :             return OGRERR_FAILURE;
     754             :         }
     755           4 :         double *padfValues = nullptr;
     756           5 :         for (int j = 0; j < poHeader->nVar - 1; ++j)
     757             :         {
     758           2 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     759           1 :                                          poHeader->nFileSize) == -1)
     760             :             {
     761           0 :                 VSIFCloseL(fpNew);
     762           0 :                 VSIUnlink(osTempfile.c_str());
     763           0 :                 return OGRERR_FAILURE;
     764             :             }
     765           2 :             if (Selafin::write_floatarray(fpNew, padfValues,
     766           1 :                                           poHeader->nPoints) == 0)
     767             :             {
     768           0 :                 CPLFree(padfValues);
     769           0 :                 VSIFCloseL(fpNew);
     770           0 :                 VSIUnlink(osTempfile.c_str());
     771           0 :                 return OGRERR_FAILURE;
     772             :             }
     773           1 :             CPLFree(padfValues);
     774             :         }
     775           4 :         padfValues =
     776           4 :             (double *)VSI_MALLOC2_VERBOSE(sizeof(double), poHeader->nPoints);
     777          29 :         for (int k = 0; k < poHeader->nPoints; ++k)
     778          25 :             padfValues[k] = 0;
     779           4 :         if (Selafin::write_floatarray(fpNew, padfValues, poHeader->nPoints) ==
     780             :             0)
     781             :         {
     782           0 :             CPLFree(padfValues);
     783           0 :             VSIFCloseL(fpNew);
     784           0 :             VSIUnlink(osTempfile.c_str());
     785           0 :             return OGRERR_FAILURE;
     786             :         }
     787           4 :         CPLFree(padfValues);
     788             :     }
     789           4 :     MoveOverwrite(poHeader->fp, fpNew);
     790           4 :     VSIUnlink(osTempfile.c_str());
     791           4 :     poHeader->UpdateFileSize();
     792           4 :     return OGRERR_NONE;
     793             : }
     794             : 
     795             : /************************************************************************/
     796             : /*                           DeleteField()                              */
     797             : /************************************************************************/
     798           0 : OGRErr OGRSelafinLayer::DeleteField(int iField)
     799             : {
     800           0 :     CPLDebug("Selafin", "DeleteField(%i)", iField);
     801           0 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     802           0 :         return OGRERR_FAILURE;
     803             :     // Change the header to remove the field
     804           0 :     poHeader->nVar--;
     805           0 :     poHeader->setUpdated();
     806           0 :     CPLFree(poHeader->papszVariables[iField]);
     807           0 :     for (int i = iField; i < poHeader->nVar; ++i)
     808           0 :         poHeader->papszVariables[i] = poHeader->papszVariables[i + 1];
     809           0 :     poHeader->papszVariables = (char **)CPLRealloc(
     810           0 :         poHeader->papszVariables, sizeof(char *) * poHeader->nVar);
     811           0 :     poFeatureDefn->DeleteFieldDefn(iField);
     812             : 
     813             :     // Now comes the real deletion. Since values have to be deleted nearly
     814             :     // everywhere in the file and we don't want to store everything in memory to
     815             :     // overwrite it, we create a new copy of it where we write the new values
     816           0 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     817           0 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     818           0 :     if (fpNew == nullptr)
     819             :     {
     820           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     821             :                  "Failed to open temporary file %s with write access, %s.",
     822           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     823           0 :         return OGRERR_FAILURE;
     824             :     }
     825           0 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     826             :     {
     827           0 :         VSIFCloseL(fpNew);
     828           0 :         VSIUnlink(osTempfile.c_str());
     829           0 :         return OGRERR_FAILURE;
     830             :     }
     831           0 :     for (int i = 0; i < poHeader->nSteps; ++i)
     832             :     {
     833           0 :         int nLen = 0;
     834           0 :         double dfDate = 0.0;
     835           0 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     836           0 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     837           0 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     838           0 :             Selafin::write_integer(fpNew, 4) == 0 ||
     839           0 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     840           0 :             Selafin::write_integer(fpNew, 4) == 0)
     841             :         {
     842           0 :             VSIFCloseL(fpNew);
     843           0 :             VSIUnlink(osTempfile.c_str());
     844           0 :             return OGRERR_FAILURE;
     845             :         }
     846           0 :         for (int j = 0; j < poHeader->nVar; ++j)
     847             :         {
     848           0 :             double *padfValues = nullptr;
     849           0 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
     850           0 :                                          poHeader->nFileSize) == -1)
     851             :             {
     852           0 :                 VSIFCloseL(fpNew);
     853           0 :                 VSIUnlink(osTempfile.c_str());
     854           0 :                 return OGRERR_FAILURE;
     855             :             }
     856           0 :             if (j != iField)
     857             :             {
     858           0 :                 if (Selafin::write_floatarray(fpNew, padfValues,
     859           0 :                                               poHeader->nPoints) == 0)
     860             :                 {
     861           0 :                     CPLFree(padfValues);
     862           0 :                     VSIFCloseL(fpNew);
     863           0 :                     VSIUnlink(osTempfile.c_str());
     864           0 :                     return OGRERR_FAILURE;
     865             :                 }
     866             :             }
     867           0 :             CPLFree(padfValues);
     868             :         }
     869             :     }
     870           0 :     MoveOverwrite(poHeader->fp, fpNew);
     871           0 :     VSIUnlink(osTempfile.c_str());
     872           0 :     poHeader->UpdateFileSize();
     873           0 :     return OGRERR_NONE;
     874             : }
     875             : 
     876             : /************************************************************************/
     877             : /*                          ReorderFields()                             */
     878             : /************************************************************************/
     879           1 : OGRErr OGRSelafinLayer::ReorderFields(int *panMap)
     880             : {
     881           1 :     CPLDebug("Selafin", "ReorderFields()");
     882           1 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     883           0 :         return OGRERR_FAILURE;
     884             :     // Change the header according to the map
     885             :     char **papszNew =
     886           1 :         (char **)VSI_MALLOC2_VERBOSE(sizeof(char *), poHeader->nVar);
     887           3 :     for (int i = 0; i < poHeader->nVar; ++i)
     888           2 :         papszNew[i] = poHeader->papszVariables[panMap[i]];
     889           1 :     CPLFree(poHeader->papszVariables);
     890           1 :     poHeader->papszVariables = papszNew;
     891           1 :     poFeatureDefn->ReorderFieldDefns(panMap);
     892             : 
     893             :     // Now comes the real change.
     894           2 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
     895           1 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
     896           1 :     if (fpNew == nullptr)
     897             :     {
     898           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     899             :                  "Failed to open temporary file %s with write access, %s.",
     900           0 :                  osTempfile.c_str(), VSIStrerror(errno));
     901           0 :         return OGRERR_FAILURE;
     902             :     }
     903           1 :     if (Selafin::write_header(fpNew, poHeader) == 0)
     904             :     {
     905           0 :         VSIFCloseL(fpNew);
     906           0 :         VSIUnlink(osTempfile.c_str());
     907           0 :         return OGRERR_FAILURE;
     908             :     }
     909           1 :     double *padfValues = nullptr;
     910           2 :     for (int i = 0; i < poHeader->nSteps; ++i)
     911             :     {
     912           1 :         int nLen = 0;
     913           1 :         double dfDate = 0.0;
     914           1 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     915           1 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
     916           1 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
     917           1 :             Selafin::write_integer(fpNew, 4) == 0 ||
     918           3 :             Selafin::write_float(fpNew, dfDate) == 0 ||
     919           1 :             Selafin::write_integer(fpNew, 4) == 0)
     920             :         {
     921           0 :             VSIFCloseL(fpNew);
     922           0 :             VSIUnlink(osTempfile.c_str());
     923           0 :             return OGRERR_FAILURE;
     924             :         }
     925           3 :         for (int j = 0; j < poHeader->nVar; ++j)
     926             :         {
     927           2 :             if (VSIFSeekL(poHeader->fp, poHeader->getPosition(i, -1, panMap[j]),
     928           4 :                           SEEK_SET) != 0 ||
     929           2 :                 Selafin::read_floatarray(poHeader->fp, &padfValues,
     930           2 :                                          poHeader->nFileSize) == -1)
     931             :             {
     932           0 :                 VSIFCloseL(fpNew);
     933           0 :                 VSIUnlink(osTempfile.c_str());
     934           0 :                 return OGRERR_FAILURE;
     935             :             }
     936           4 :             if (Selafin::write_floatarray(fpNew, padfValues,
     937           2 :                                           poHeader->nPoints) == 0)
     938             :             {
     939           0 :                 CPLFree(padfValues);
     940           0 :                 VSIFCloseL(fpNew);
     941           0 :                 VSIUnlink(osTempfile.c_str());
     942           0 :                 return OGRERR_FAILURE;
     943             :             }
     944           2 :             CPLFree(padfValues);
     945             :         }
     946             :     }
     947           1 :     MoveOverwrite(poHeader->fp, fpNew);
     948           1 :     VSIUnlink(osTempfile.c_str());
     949           1 :     poHeader->UpdateFileSize();
     950           1 :     return OGRERR_NONE;
     951             : }
     952             : 
     953             : /************************************************************************/
     954             : /*                         AlterFieldDefn()                             */
     955             : /************************************************************************/
     956           1 : OGRErr OGRSelafinLayer::AlterFieldDefn(int iField, OGRFieldDefn *poNewFieldDefn,
     957             :                                        int /* nFlagsIn */)
     958             : {
     959           1 :     CPLDebug("Selafin", "AlterFieldDefn(%i,%s,%s)", iField,
     960             :              poNewFieldDefn->GetNameRef(),
     961             :              OGRFieldDefn::GetFieldTypeName(poNewFieldDefn->GetType()));
     962             :     // Test if the field type is legal (only double precision values are
     963             :     // allowed)
     964           1 :     if (poNewFieldDefn->GetType() != OFTReal)
     965             :     {
     966           0 :         CPLError(
     967             :             CE_Failure, CPLE_AppDefined,
     968             :             "Attempt to update field with type %s, but this is not supported "
     969             :             "for Selafin files (only double precision fields are allowed).",
     970             :             poNewFieldDefn->GetFieldTypeName(poNewFieldDefn->GetType()));
     971           0 :         return OGRERR_FAILURE;
     972             :     }
     973             :     // Since the field type can't change, only the field name is changed. We
     974             :     // change it in the header
     975           1 :     CPLFree(poHeader->papszVariables[iField]);
     976           2 :     poHeader->papszVariables[iField] =
     977           1 :         (char *)VSI_MALLOC2_VERBOSE(sizeof(char), 33);
     978           1 :     strncpy(poHeader->papszVariables[iField], poNewFieldDefn->GetNameRef(), 32);
     979           1 :     poHeader->papszVariables[iField][32] = 0;
     980             :     // And we update the file
     981           1 :     if (VSIFSeekL(poHeader->fp, 88 + 16 + 40 * iField, SEEK_SET) != 0)
     982           0 :         return OGRERR_FAILURE;
     983           1 :     if (Selafin::write_string(poHeader->fp, poHeader->papszVariables[iField],
     984           1 :                               32) == 0)
     985           0 :         return OGRERR_FAILURE;
     986           1 :     VSIFFlushL(poHeader->fp);
     987           1 :     poHeader->UpdateFileSize();
     988           1 :     return OGRERR_NONE;
     989             : }
     990             : 
     991             : /************************************************************************/
     992             : /*                          DeleteFeature()                             */
     993             : /************************************************************************/
     994           0 : OGRErr OGRSelafinLayer::DeleteFeature(GIntBig nFID)
     995             : {
     996           0 :     CPLDebug("Selafin", "DeleteFeature(" CPL_FRMT_GIB ")", nFID);
     997           0 :     if (VSIFSeekL(poHeader->fp, poHeader->getPosition(0), SEEK_SET) != 0)
     998           0 :         return OGRERR_FAILURE;
     999             :     // Change the header to delete the feature
    1000           0 :     if (eType == POINTS)
    1001           0 :         poHeader->removePoint((int)nFID);
    1002             :     else
    1003             :     {
    1004             :         // For elements layer, we only delete the element and not the vertices
    1005           0 :         poHeader->nElements--;
    1006           0 :         for (int i = (int)nFID; i < poHeader->nElements; ++i)
    1007           0 :             for (int j = 0; j < poHeader->nPointsPerElement; ++j)
    1008           0 :                 poHeader->panConnectivity[poHeader->nPointsPerElement * i + j] =
    1009           0 :                     poHeader->panConnectivity[poHeader->nPointsPerElement *
    1010           0 :                                                   (i + 1) +
    1011           0 :                                               j];
    1012           0 :         poHeader->panConnectivity = (int *)CPLRealloc(
    1013           0 :             poHeader->panConnectivity,
    1014           0 :             sizeof(int) * poHeader->nPointsPerElement * poHeader->nElements);
    1015           0 :         poHeader->setUpdated();
    1016             :     }
    1017             : 
    1018             :     // Now we perform the deletion by creating a new temporary layer
    1019           0 :     const std::string osTempfile = CPLGenerateTempFilenameSafe(nullptr);
    1020           0 :     VSILFILE *fpNew = VSIFOpenL(osTempfile.c_str(), "wb+");
    1021           0 :     if (fpNew == nullptr)
    1022             :     {
    1023           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
    1024             :                  "Failed to open temporary file %s with write access, %s.",
    1025           0 :                  osTempfile.c_str(), VSIStrerror(errno));
    1026           0 :         return OGRERR_FAILURE;
    1027             :     }
    1028           0 :     if (Selafin::write_header(fpNew, poHeader) == 0)
    1029             :     {
    1030           0 :         VSIFCloseL(fpNew);
    1031           0 :         VSIUnlink(osTempfile.c_str());
    1032           0 :         return OGRERR_FAILURE;
    1033             :     }
    1034           0 :     for (int i = 0; i < poHeader->nSteps; ++i)
    1035             :     {
    1036           0 :         int nLen = 0;
    1037           0 :         double dfDate = 0.0;
    1038           0 :         if (Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
    1039           0 :             Selafin::read_float(poHeader->fp, dfDate) == 0 ||
    1040           0 :             Selafin::read_integer(poHeader->fp, nLen, true) == 0 ||
    1041           0 :             Selafin::write_integer(fpNew, 4) == 0 ||
    1042           0 :             Selafin::write_float(fpNew, dfDate) == 0 ||
    1043           0 :             Selafin::write_integer(fpNew, 4) == 0)
    1044             :         {
    1045           0 :             VSIFCloseL(fpNew);
    1046           0 :             VSIUnlink(osTempfile.c_str());
    1047           0 :             return OGRERR_FAILURE;
    1048             :         }
    1049           0 :         for (int j = 0; j < poHeader->nVar; ++j)
    1050             :         {
    1051           0 :             double *padfValues = nullptr;
    1052           0 :             if (Selafin::read_floatarray(poHeader->fp, &padfValues,
    1053           0 :                                          poHeader->nFileSize) == -1)
    1054             :             {
    1055           0 :                 VSIFCloseL(fpNew);
    1056           0 :                 VSIUnlink(osTempfile.c_str());
    1057           0 :                 return OGRERR_FAILURE;
    1058             :             }
    1059           0 :             if (eType == POINTS)
    1060             :             {
    1061           0 :                 for (int k = (int)nFID; k <= poHeader->nPoints; ++k)
    1062           0 :                     padfValues[k - 1] = padfValues[k];
    1063             :             }
    1064           0 :             if (Selafin::write_floatarray(fpNew, padfValues,
    1065           0 :                                           poHeader->nPoints) == 0)
    1066             :             {
    1067           0 :                 CPLFree(padfValues);
    1068           0 :                 VSIFCloseL(fpNew);
    1069           0 :                 VSIUnlink(osTempfile.c_str());
    1070           0 :                 return OGRERR_FAILURE;
    1071             :             }
    1072           0 :             CPLFree(padfValues);
    1073             :         }
    1074             :     }
    1075             : 
    1076             :     // If everything went fine, we overwrite the new file with the content of
    1077             :     // the old one. This way, even if something goes bad, we can still recover
    1078             :     // the layer. The copy process is format-agnostic.
    1079           0 :     MoveOverwrite(poHeader->fp, fpNew);
    1080           0 :     VSIUnlink(osTempfile.c_str());
    1081           0 :     poHeader->UpdateFileSize();
    1082             : 
    1083           0 :     return OGRERR_NONE;
    1084             : }

Generated by: LCOV version 1.14