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