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