Coverage Report

Created: 2026-02-14 09:00

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