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

Generated by: LCOV version 1.14