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