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