Line data Source code
1 : /******************************************************************************
2 : * Project: Selafin importer
3 : * Purpose: Implementation of functions for reading records in Selafin files
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 "io_selafin.h"
29 : #include "cpl_vsi.h"
30 : #include "cpl_conv.h"
31 : #include "cpl_port.h"
32 : #include "cpl_error.h"
33 : #include "cpl_quad_tree.h"
34 :
35 : namespace Selafin
36 : {
37 :
38 : const char SELAFIN_ERROR_MESSAGE[] = "Error when reading Selafin file\n";
39 :
40 : struct Point
41 : {
42 : int nIndex;
43 : const Header *poHeader;
44 : };
45 :
46 300 : static void GetBoundsFunc(const void *hFeature, CPLRectObj *poBounds)
47 : {
48 300 : const Point *poPoint = (const Point *)hFeature;
49 300 : poBounds->minx = poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
50 300 : poBounds->maxx = poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
51 300 : poBounds->miny = poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
52 300 : poBounds->maxy = poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
53 300 : }
54 :
55 25 : static int DumpFeatures(void *pElt, void * /* pUserData */)
56 : {
57 25 : Point *poPoint = (Point *)pElt;
58 25 : delete poPoint;
59 25 : return TRUE;
60 : }
61 :
62 : /****************************************************************/
63 : /* Header */
64 : /****************************************************************/
65 21 : Header::Header()
66 : : nHeaderSize(0), nStepSize(0), nMinxIndex(-1), nMaxxIndex(-1),
67 : nMinyIndex(-1), nMaxyIndex(-1), bTreeUpdateNeeded(true), nFileSize(0),
68 : fp(nullptr), pszFilename(nullptr), pszTitle(nullptr), nVar(0),
69 : papszVariables(nullptr), nPoints(0), nElements(0), nPointsPerElement(0),
70 : panConnectivity(nullptr), poTree(nullptr), panBorder(nullptr),
71 21 : panStartDate(nullptr), nSteps(0), nEpsg(0)
72 : {
73 21 : paadfCoords[0] = nullptr;
74 21 : paadfCoords[1] = nullptr;
75 168 : for (size_t i = 0; i < 7; ++i)
76 147 : anUnused[i] = 0;
77 21 : adfOrigin[0] = 0.0;
78 21 : adfOrigin[1] = 0.0;
79 21 : }
80 :
81 42 : Header::~Header()
82 : {
83 21 : CPLFree(pszFilename);
84 21 : CPLFree(pszTitle);
85 21 : if (papszVariables != nullptr)
86 : {
87 13 : for (int i = 0; i < nVar; ++i)
88 7 : CPLFree(papszVariables[i]);
89 6 : CPLFree(papszVariables);
90 : }
91 21 : CPLFree(panConnectivity);
92 21 : CPLFree(panBorder);
93 21 : if (poTree != nullptr)
94 : {
95 1 : CPLQuadTreeForeach(poTree, DumpFeatures, nullptr);
96 1 : CPLQuadTreeDestroy(poTree);
97 : }
98 21 : CPLFree(panStartDate);
99 63 : for (size_t i = 0; i < 2; ++i)
100 42 : CPLFree(paadfCoords[i]);
101 21 : if (fp != nullptr)
102 21 : VSIFCloseL(fp);
103 21 : }
104 :
105 97 : void Header::setUpdated()
106 : {
107 194 : nHeaderSize = 88 + 16 + nVar * 40 + 12 * 4 +
108 97 : ((panStartDate == nullptr) ? 0 : 32) + 24 +
109 97 : (nElements * nPointsPerElement + 2) * 4 + (nPoints + 2) * 12;
110 97 : nStepSize = 12 + nVar * (nPoints + 2) * 4;
111 97 : }
112 :
113 224 : int Header::getPosition(int nStep, int nFeature, int nAttribute) const
114 : {
115 113 : int a = (nFeature != -1 || nAttribute != -1)
116 337 : ? (12 + nAttribute * (nPoints + 2) * 4 + 4 + nFeature * 4)
117 : : 0;
118 224 : int b = nStep * nStepSize;
119 224 : return nHeaderSize + b + a;
120 : }
121 :
122 18 : CPLRectObj *Header::getBoundingBox() const
123 : {
124 18 : CPLRectObj *poBox = new CPLRectObj;
125 18 : poBox->minx = paadfCoords[0][nMinxIndex];
126 18 : poBox->maxx = paadfCoords[0][nMaxxIndex];
127 18 : poBox->miny = paadfCoords[1][nMinyIndex];
128 18 : poBox->maxy = paadfCoords[1][nMaxyIndex];
129 18 : return poBox;
130 : }
131 :
132 21 : void Header::updateBoundingBox()
133 : {
134 21 : if (nPoints > 0)
135 : {
136 3 : nMinxIndex = 0;
137 52 : for (int i = 1; i < nPoints; ++i)
138 49 : if (paadfCoords[0][i] < paadfCoords[0][nMinxIndex])
139 0 : nMinxIndex = i;
140 3 : nMaxxIndex = 0;
141 52 : for (int i = 1; i < nPoints; ++i)
142 49 : if (paadfCoords[0][i] > paadfCoords[0][nMaxxIndex])
143 8 : nMaxxIndex = i;
144 3 : nMinyIndex = 0;
145 52 : for (int i = 1; i < nPoints; ++i)
146 49 : if (paadfCoords[1][i] < paadfCoords[1][nMinyIndex])
147 0 : nMinyIndex = i;
148 3 : nMaxyIndex = 0;
149 52 : for (int i = 1; i < nPoints; ++i)
150 49 : if (paadfCoords[1][i] > paadfCoords[1][nMaxyIndex])
151 8 : nMaxyIndex = i;
152 : }
153 21 : }
154 :
155 68 : int Header::getClosestPoint(const double &dfx, const double &dfy,
156 : const double &dfMax)
157 : {
158 : // If there is no quad-tree of the points, build it now
159 68 : if (bTreeUpdateNeeded)
160 : {
161 1 : if (poTree != nullptr)
162 : {
163 0 : CPLQuadTreeForeach(poTree, DumpFeatures, nullptr);
164 0 : CPLQuadTreeDestroy(poTree);
165 : }
166 : }
167 68 : if (bTreeUpdateNeeded || poTree == nullptr)
168 : {
169 1 : bTreeUpdateNeeded = false;
170 1 : CPLRectObj *poBB = getBoundingBox();
171 1 : poTree = CPLQuadTreeCreate(poBB, GetBoundsFunc);
172 1 : delete poBB;
173 1 : CPLQuadTreeSetBucketCapacity(poTree, 2);
174 26 : for (int i = 0; i < nPoints; ++i)
175 : {
176 25 : Point *poPoint = new Point;
177 25 : poPoint->poHeader = this;
178 25 : poPoint->nIndex = i;
179 25 : CPLQuadTreeInsert(poTree, (void *)poPoint);
180 : }
181 : }
182 : // Now we can look for the nearest neighbour using this tree
183 68 : int nIndex = -1;
184 : CPLRectObj poObj;
185 68 : poObj.minx = dfx - dfMax;
186 68 : poObj.maxx = dfx + dfMax;
187 68 : poObj.miny = dfy - dfMax;
188 68 : poObj.maxy = dfy + dfMax;
189 68 : int nFeatureCount = 0;
190 68 : void **phResults = CPLQuadTreeSearch(poTree, &poObj, &nFeatureCount);
191 68 : if (nFeatureCount <= 0)
192 3 : return -1;
193 65 : double dfMin = dfMax * dfMax;
194 130 : for (int i = 0; i < nFeatureCount; ++i)
195 : {
196 65 : Point *poPoint = (Point *)(phResults[i]);
197 65 : double dfa = dfx - poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
198 65 : dfa *= dfa;
199 65 : if (dfa >= dfMin)
200 0 : continue;
201 65 : const double dfb =
202 65 : dfy - poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
203 65 : const double dfc = dfa + dfb * dfb;
204 65 : if (dfc < dfMin)
205 : {
206 65 : dfMin = dfc;
207 65 : nIndex = poPoint->nIndex;
208 : }
209 : }
210 65 : CPLFree(phResults);
211 65 : return nIndex;
212 : }
213 :
214 55 : void Header::addPoint(const double &dfx, const double &dfy)
215 : {
216 : // We add the point to all the tables
217 55 : nPoints++;
218 165 : for (size_t i = 0; i < 2; ++i)
219 110 : paadfCoords[i] =
220 110 : (double *)CPLRealloc(paadfCoords[i], sizeof(double) * nPoints);
221 55 : paadfCoords[0][nPoints - 1] = dfx;
222 55 : paadfCoords[1][nPoints - 1] = dfy;
223 55 : panBorder = (int *)CPLRealloc(panBorder, sizeof(int) * nPoints);
224 55 : panBorder[nPoints - 1] = 0;
225 : // We update the bounding box
226 55 : if (nMinxIndex == -1 || dfx < paadfCoords[0][nMinxIndex])
227 3 : nMinxIndex = nPoints - 1;
228 55 : if (nMaxxIndex == -1 || dfx > paadfCoords[0][nMaxxIndex])
229 12 : nMaxxIndex = nPoints - 1;
230 55 : if (nMinyIndex == -1 || dfy < paadfCoords[1][nMinyIndex])
231 3 : nMinyIndex = nPoints - 1;
232 55 : if (nMaxyIndex == -1 || dfy > paadfCoords[1][nMaxyIndex])
233 12 : nMaxyIndex = nPoints - 1;
234 : // We update some parameters of the header
235 55 : bTreeUpdateNeeded = true;
236 55 : setUpdated();
237 55 : }
238 :
239 0 : void Header::removePoint(int nIndex)
240 : {
241 : // We remove the point from all the tables
242 0 : nPoints--;
243 0 : for (size_t i = 0; i < 2; ++i)
244 : {
245 0 : for (int j = nIndex; j < nPoints; ++j)
246 0 : paadfCoords[i][j] = paadfCoords[i][j + 1];
247 0 : paadfCoords[i] =
248 0 : (double *)CPLRealloc(paadfCoords[i], sizeof(double) * nPoints);
249 : }
250 0 : for (int j = nIndex; j < nPoints; ++j)
251 0 : panBorder[j] = panBorder[j + 1];
252 0 : panBorder = (int *)CPLRealloc(panBorder, sizeof(int) * nPoints);
253 :
254 : // We must also remove all the elements referencing the deleted feature,
255 : // otherwise the file will not be consistent any inter
256 0 : int nOldElements = nElements;
257 0 : for (int i = 0; i < nElements; ++i)
258 : {
259 0 : bool bReferencing = false;
260 0 : int *panTemp = panConnectivity + i * nPointsPerElement;
261 0 : for (int j = 0; j < nPointsPerElement; ++j)
262 0 : bReferencing |= (panTemp[j] == nIndex + 1);
263 0 : if (bReferencing)
264 : {
265 0 : nElements--;
266 0 : for (int j = i; j < nElements; ++j)
267 0 : for (int k = 0; k < nPointsPerElement; ++k)
268 0 : panConnectivity[j * nPointsPerElement + k] =
269 0 : panConnectivity[(j + 1) * nPointsPerElement + k];
270 0 : --i;
271 : }
272 : }
273 0 : if (nOldElements != nElements)
274 0 : panConnectivity = (int *)CPLRealloc(
275 0 : panConnectivity, sizeof(int) * nElements * nPointsPerElement);
276 :
277 : // Now we update the bounding box if needed
278 0 : if (nPoints == 0)
279 : {
280 0 : nMinxIndex = -1;
281 0 : nMaxxIndex = -1;
282 0 : nMinyIndex = -1;
283 0 : nMaxyIndex = -1;
284 : }
285 : else
286 : {
287 0 : if (nIndex == nMinxIndex)
288 : {
289 0 : nMinxIndex = 0;
290 0 : for (int i = 1; i < nPoints; ++i)
291 0 : if (paadfCoords[0][i] < paadfCoords[0][nMinxIndex])
292 0 : nMinxIndex = i;
293 : }
294 0 : if (nIndex == nMaxxIndex)
295 : {
296 0 : nMaxxIndex = 0;
297 0 : for (int i = 1; i < nPoints; ++i)
298 0 : if (paadfCoords[0][i] > paadfCoords[0][nMaxxIndex])
299 0 : nMaxxIndex = i;
300 : }
301 0 : if (nIndex == nMinyIndex)
302 : {
303 0 : nMinyIndex = 0;
304 0 : for (int i = 1; i < nPoints; ++i)
305 0 : if (paadfCoords[1][i] < paadfCoords[1][nMinyIndex])
306 0 : nMinyIndex = i;
307 : }
308 0 : if (nIndex == nMaxyIndex)
309 : {
310 0 : nMaxyIndex = 0;
311 0 : for (int i = 1; i < nPoints; ++i)
312 0 : if (paadfCoords[1][i] > paadfCoords[1][nMaxyIndex])
313 0 : nMaxyIndex = i;
314 : }
315 : }
316 :
317 : // We update some parameters of the header
318 0 : bTreeUpdateNeeded = true;
319 0 : setUpdated();
320 0 : }
321 :
322 : #ifdef notdef
323 : /****************************************************************/
324 : /* TimeStep */
325 : /****************************************************************/
326 : TimeStep::TimeStep(int nRecordsP, int nFieldsP) : nFields(nFieldsP)
327 : {
328 : papadfData = (double **)VSI_MALLOC2_VERBOSE(sizeof(double *), nFieldsP);
329 : for (int i = 0; i < nFieldsP; ++i)
330 : papadfData[i] =
331 : (double *)VSI_MALLOC2_VERBOSE(sizeof(double), nRecordsP);
332 : }
333 :
334 : TimeStep::~TimeStep()
335 : {
336 : for (int i = 0; i < nFields; ++i)
337 : CPLFree(papadfData[i]);
338 : CPLFree(papadfData);
339 : }
340 :
341 : /****************************************************************/
342 : /* TimeStepList */
343 : /****************************************************************/
344 : TimeStepList::~TimeStepList()
345 : {
346 : TimeStepList *poFirst = this;
347 : while (poFirst != 0)
348 : {
349 : TimeStepList *poTmp = poFirst->poNext;
350 : delete poFirst->poStep;
351 : delete poFirst;
352 : poFirst = poTmp;
353 : }
354 : }
355 : #endif
356 :
357 : /****************************************************************/
358 : /* General functions */
359 : /****************************************************************/
360 783 : int read_integer(VSILFILE *fp, int &nData, bool bDiscard)
361 : {
362 : unsigned char anb[4];
363 783 : if (VSIFReadL(anb, 1, 4, fp) < 4)
364 : {
365 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
366 0 : return 0;
367 : };
368 783 : if (!bDiscard)
369 : {
370 633 : memcpy(&nData, anb, 4);
371 633 : CPL_MSBPTR32(&nData);
372 : }
373 783 : return 1;
374 : }
375 :
376 5157 : int write_integer(VSILFILE *fp, int nData)
377 : {
378 : unsigned char anb[4];
379 5157 : CPL_MSBPTR32(&nData);
380 5157 : memcpy(anb, &nData, 4);
381 5157 : if (VSIFWriteL(anb, 1, 4, fp) < 4)
382 : {
383 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
384 0 : return 0;
385 : };
386 5157 : return 1;
387 : }
388 :
389 24 : int read_string(VSILFILE *fp, char *&pszData, vsi_l_offset nFileSize,
390 : bool bDiscard)
391 : {
392 24 : int nLength = 0;
393 24 : read_integer(fp, nLength);
394 24 : if (nLength <= 0 || nLength == INT_MAX ||
395 24 : static_cast<unsigned>(nLength) > nFileSize)
396 : {
397 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
398 0 : return 0;
399 : }
400 24 : if (bDiscard)
401 : {
402 0 : if (VSIFSeekL(fp, nLength + 4, SEEK_CUR) != 0)
403 : {
404 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
405 0 : return 0;
406 : }
407 : }
408 : else
409 : {
410 24 : pszData = (char *)VSI_MALLOC_VERBOSE(nLength + 1);
411 24 : if (pszData == nullptr)
412 : {
413 0 : return 0;
414 : }
415 24 : if ((int)VSIFReadL(pszData, 1, nLength, fp) < (int)nLength)
416 : {
417 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
418 0 : VSIFree(pszData);
419 0 : pszData = nullptr;
420 0 : return 0;
421 : }
422 24 : pszData[nLength] = 0;
423 24 : if (VSIFSeekL(fp, 4, SEEK_CUR) != 0)
424 : {
425 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
426 0 : VSIFree(pszData);
427 0 : pszData = nullptr;
428 0 : return 0;
429 : }
430 : }
431 24 : return nLength;
432 : }
433 :
434 169 : int write_string(VSILFILE *fp, char *pszData, size_t nLength)
435 : {
436 169 : if (nLength == 0)
437 0 : nLength = strlen(pszData);
438 169 : if (write_integer(fp, static_cast<int>(nLength)) == 0)
439 0 : return 0;
440 169 : if (VSIFWriteL(pszData, 1, nLength, fp) < nLength)
441 : {
442 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
443 0 : return 0;
444 : }
445 169 : if (write_integer(fp, static_cast<int>(nLength)) == 0)
446 0 : return 0;
447 169 : return 1;
448 : }
449 :
450 105 : int read_intarray(VSILFILE *fp, int *&panData, vsi_l_offset nFileSize,
451 : bool bDiscard)
452 : {
453 105 : int nLength = 0;
454 105 : read_integer(fp, nLength);
455 105 : panData = nullptr;
456 105 : if (nLength < 0 || static_cast<unsigned>(nLength) / 4 > nFileSize)
457 : {
458 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
459 0 : return -1;
460 : }
461 105 : if (bDiscard)
462 : {
463 0 : if (VSIFSeekL(fp, nLength + 4, SEEK_CUR) != 0)
464 : {
465 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
466 0 : return -1;
467 : }
468 : }
469 : else
470 : {
471 105 : if (nLength == 0)
472 39 : panData = nullptr;
473 : else
474 : {
475 66 : panData = (int *)VSI_MALLOC2_VERBOSE(nLength / 4, sizeof(int));
476 66 : if (panData == nullptr)
477 0 : return -1;
478 : }
479 493 : for (int i = 0; i < nLength / 4; ++i)
480 388 : if (read_integer(fp, panData[i]) == 0)
481 : {
482 0 : CPLFree(panData);
483 0 : panData = nullptr;
484 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
485 0 : return -1;
486 : }
487 105 : if (VSIFSeekL(fp, 4, SEEK_CUR) != 0)
488 : {
489 0 : CPLFree(panData);
490 0 : panData = nullptr;
491 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
492 0 : return -1;
493 : }
494 : }
495 105 : return nLength / 4;
496 : }
497 :
498 460 : int write_intarray(VSILFILE *fp, int *panData, size_t nLength)
499 : {
500 460 : if (write_integer(fp, static_cast<int>(nLength * 4)) == 0)
501 0 : return 0;
502 3675 : for (size_t i = 0; i < nLength; ++i)
503 : {
504 3215 : if (write_integer(fp, panData[i]) == 0)
505 : {
506 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
507 0 : return 0;
508 : }
509 : }
510 460 : if (write_integer(fp, static_cast<int>(nLength * 4)) == 0)
511 0 : return 0;
512 460 : return 1;
513 : }
514 :
515 1353 : int read_float(VSILFILE *fp, double &dfData, bool bDiscard)
516 : {
517 1353 : float dfVal = 0.0;
518 1353 : if (VSIFReadL(&dfVal, 1, 4, fp) < 4)
519 : {
520 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
521 0 : return 0;
522 : };
523 1353 : if (!bDiscard)
524 : {
525 1353 : CPL_MSBPTR32(&dfVal);
526 1353 : dfData = dfVal;
527 : }
528 1353 : return 1;
529 : }
530 :
531 3628 : int write_float(VSILFILE *fp, double dfData)
532 : {
533 3628 : float dfVal = (float)dfData;
534 3628 : CPL_MSBPTR32(&dfVal);
535 3628 : if (VSIFWriteL(&dfVal, 1, 4, fp) < 4)
536 : {
537 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
538 0 : return 0;
539 : };
540 3628 : return 1;
541 : }
542 :
543 116 : int read_floatarray(VSILFILE *fp, double **papadfData, vsi_l_offset nFileSize,
544 : bool bDiscard)
545 : {
546 116 : int nLength = 0;
547 116 : read_integer(fp, nLength);
548 116 : if (nLength < 0 || static_cast<unsigned>(nLength) / 4 > nFileSize)
549 : {
550 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
551 0 : return -1;
552 : }
553 116 : if (bDiscard)
554 : {
555 0 : if (VSIFSeekL(fp, nLength + 4, SEEK_CUR) != 0)
556 : {
557 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
558 0 : return -1;
559 : }
560 : }
561 : else
562 : {
563 116 : if (nLength == 0)
564 39 : *papadfData = nullptr;
565 : else
566 : {
567 77 : *papadfData =
568 77 : (double *)VSI_MALLOC2_VERBOSE(sizeof(double), nLength / 4);
569 77 : if (*papadfData == nullptr)
570 0 : return -1;
571 : }
572 1324 : for (int i = 0; i < nLength / 4; ++i)
573 1208 : if (read_float(fp, (*papadfData)[i]) == 0)
574 : {
575 0 : CPLFree(*papadfData);
576 0 : *papadfData = nullptr;
577 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
578 0 : return -1;
579 : }
580 116 : if (VSIFSeekL(fp, 4, SEEK_CUR) != 0)
581 : {
582 0 : CPLFree(*papadfData);
583 0 : *papadfData = nullptr;
584 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
585 0 : return -1;
586 : }
587 : }
588 116 : return nLength / 4;
589 : }
590 :
591 263 : int write_floatarray(VSILFILE *fp, double *papadfData, size_t nLength)
592 : {
593 263 : if (write_integer(fp, static_cast<int>(nLength * 4)) == 0)
594 0 : return 0;
595 3711 : for (size_t i = 0; i < nLength; ++i)
596 : {
597 3448 : if (write_float(fp, papadfData[i]) == 0)
598 : {
599 0 : CPLError(CE_Failure, CPLE_FileIO, "%s", SELAFIN_ERROR_MESSAGE);
600 0 : return 0;
601 : }
602 : }
603 263 : if (write_integer(fp, static_cast<int>(nLength * 4)) == 0)
604 0 : return 0;
605 263 : return 1;
606 : }
607 :
608 121 : void Header::UpdateFileSize()
609 : {
610 121 : VSIFSeekL(fp, 0, SEEK_END);
611 121 : nFileSize = VSIFTellL(fp);
612 121 : VSIRewindL(fp);
613 121 : }
614 :
615 21 : Header *read_header(VSILFILE *fp, const char *pszFilename)
616 : {
617 : // Save the filename
618 21 : Header *poHeader = new Header();
619 21 : poHeader->fp = fp;
620 21 : poHeader->UpdateFileSize();
621 21 : poHeader->pszFilename = CPLStrdup(pszFilename);
622 21 : int *panTemp = nullptr;
623 : // Read the title
624 21 : int nLength = read_string(fp, poHeader->pszTitle, poHeader->nFileSize);
625 21 : if (nLength == 0)
626 : {
627 0 : delete poHeader;
628 0 : return nullptr;
629 : }
630 : // Read the array of 2 integers, with the number of variables at the first
631 : // position
632 21 : nLength = read_intarray(fp, panTemp, poHeader->nFileSize);
633 21 : if (nLength != 2)
634 : {
635 0 : delete poHeader;
636 0 : CPLFree(panTemp);
637 0 : return nullptr;
638 : }
639 21 : poHeader->nVar = panTemp[0];
640 21 : poHeader->anUnused[0] = panTemp[1];
641 21 : CPLFree(panTemp);
642 21 : if (poHeader->nVar < 0)
643 : {
644 0 : poHeader->nVar = 0;
645 0 : delete poHeader;
646 0 : return nullptr;
647 : }
648 21 : if (poHeader->nVar > 1000000 && poHeader->nFileSize / sizeof(int) <
649 0 : static_cast<unsigned>(poHeader->nVar))
650 : {
651 0 : poHeader->nVar = 0;
652 0 : delete poHeader;
653 0 : return nullptr;
654 : }
655 : // For each variable, read its name as a string of 32 characters
656 21 : poHeader->papszVariables =
657 21 : (char **)VSI_MALLOC2_VERBOSE(sizeof(char *), poHeader->nVar);
658 21 : if (poHeader->nVar > 0 && poHeader->papszVariables == nullptr)
659 : {
660 0 : poHeader->nVar = 0;
661 0 : delete poHeader;
662 0 : return nullptr;
663 : }
664 24 : for (int i = 0; i < poHeader->nVar; ++i)
665 : {
666 : nLength =
667 3 : read_string(fp, poHeader->papszVariables[i], poHeader->nFileSize);
668 3 : if (nLength == 0)
669 : {
670 0 : poHeader->nVar = i;
671 0 : delete poHeader;
672 0 : return nullptr;
673 : }
674 : // We eliminate quotes in the names of the variables because SQL
675 : // requests don't seem to appreciate them
676 3 : char *pszc = poHeader->papszVariables[i];
677 17 : while (*pszc != 0)
678 : {
679 14 : if (*pszc == '\'')
680 0 : *pszc = ' ';
681 14 : pszc++;
682 : }
683 : }
684 : // Read an array of 10 integers
685 21 : nLength = read_intarray(fp, panTemp, poHeader->nFileSize);
686 21 : if (nLength < 10)
687 : {
688 0 : delete poHeader;
689 0 : CPLFree(panTemp);
690 0 : return nullptr;
691 : }
692 21 : poHeader->anUnused[1] = panTemp[0];
693 21 : poHeader->nEpsg = panTemp[1];
694 21 : poHeader->adfOrigin[0] = panTemp[2];
695 21 : poHeader->adfOrigin[1] = panTemp[3];
696 126 : for (size_t i = 4; i < 9; ++i)
697 105 : poHeader->anUnused[i - 2] = panTemp[i];
698 : // If the last integer was 1, read an array of 6 integers with the starting
699 : // date
700 21 : if (panTemp[9] == 1)
701 : {
702 : nLength =
703 0 : read_intarray(fp, poHeader->panStartDate, poHeader->nFileSize);
704 0 : if (nLength < 6)
705 : {
706 0 : delete poHeader;
707 0 : CPLFree(panTemp);
708 0 : return nullptr;
709 : }
710 : }
711 21 : CPLFree(panTemp);
712 : // Read an array of 4 integers with the number of elements, points and
713 : // points per element
714 21 : nLength = read_intarray(fp, panTemp, poHeader->nFileSize);
715 21 : if (nLength < 4)
716 : {
717 0 : delete poHeader;
718 0 : CPLFree(panTemp);
719 0 : return nullptr;
720 : }
721 21 : poHeader->nElements = panTemp[0];
722 21 : poHeader->nPoints = panTemp[1];
723 21 : poHeader->nPointsPerElement = panTemp[2];
724 21 : if (poHeader->nElements < 0 || poHeader->nPoints < 0 ||
725 21 : poHeader->nPointsPerElement < 0 || panTemp[3] != 1)
726 : {
727 0 : delete poHeader;
728 0 : CPLFree(panTemp);
729 0 : return nullptr;
730 : }
731 21 : CPLFree(panTemp);
732 : // Read the connectivity table as an array of nPointsPerElement*nElements
733 : // integers, and check if all point numbers are valid
734 21 : nLength = read_intarray(fp, poHeader->panConnectivity, poHeader->nFileSize);
735 21 : if (poHeader->nElements != 0 &&
736 0 : nLength / poHeader->nElements != poHeader->nPointsPerElement)
737 : {
738 0 : delete poHeader;
739 0 : return nullptr;
740 : }
741 21 : for (int i = 0; i < poHeader->nElements * poHeader->nPointsPerElement; ++i)
742 : {
743 0 : if (poHeader->panConnectivity[i] <= 0 ||
744 0 : poHeader->panConnectivity[i] > poHeader->nPoints)
745 : {
746 0 : delete poHeader;
747 0 : return nullptr;
748 : }
749 : }
750 : // Read the array of nPoints integers with the border points
751 21 : nLength = read_intarray(fp, poHeader->panBorder, poHeader->nFileSize);
752 21 : if (nLength != poHeader->nPoints)
753 : {
754 0 : delete poHeader;
755 0 : return nullptr;
756 : }
757 : // Read two arrays of nPoints floats with the coordinates of each point
758 63 : for (size_t i = 0; i < 2; ++i)
759 : {
760 42 : read_floatarray(fp, poHeader->paadfCoords + i, poHeader->nFileSize);
761 42 : if (nLength < poHeader->nPoints)
762 : {
763 0 : delete poHeader;
764 0 : return nullptr;
765 : }
766 42 : if (poHeader->nPoints != 0 && poHeader->paadfCoords[i] == nullptr)
767 : {
768 0 : delete poHeader;
769 0 : return nullptr;
770 : }
771 146 : for (int j = 0; j < poHeader->nPoints; ++j)
772 104 : poHeader->paadfCoords[i][j] += poHeader->adfOrigin[i];
773 : }
774 : // Update the boundinx box
775 21 : poHeader->updateBoundingBox();
776 : // Update the size of the header and calculate the number of time steps
777 21 : poHeader->setUpdated();
778 21 : int nPos = poHeader->getPosition(0);
779 21 : if (static_cast<vsi_l_offset>(nPos) > poHeader->nFileSize)
780 : {
781 0 : delete poHeader;
782 0 : return nullptr;
783 : }
784 : vsi_l_offset nStepsBig =
785 21 : poHeader->nVar != 0
786 21 : ? (poHeader->nFileSize - nPos) / (poHeader->getPosition(1) - nPos)
787 21 : : 0;
788 21 : if (nStepsBig > INT_MAX)
789 0 : poHeader->nSteps = INT_MAX;
790 : else
791 21 : poHeader->nSteps = static_cast<int>(nStepsBig);
792 21 : return poHeader;
793 : }
794 :
795 74 : int write_header(VSILFILE *fp, Header *poHeader)
796 : {
797 74 : VSIRewindL(fp);
798 74 : if (write_string(fp, poHeader->pszTitle, 80) == 0)
799 0 : return 0;
800 74 : int anTemp[10] = {0};
801 74 : anTemp[0] = poHeader->nVar;
802 74 : anTemp[1] = poHeader->anUnused[0];
803 74 : if (write_intarray(fp, anTemp, 2) == 0)
804 0 : return 0;
805 150 : for (int i = 0; i < poHeader->nVar; ++i)
806 76 : if (write_string(fp, poHeader->papszVariables[i], 32) == 0)
807 0 : return 0;
808 74 : anTemp[0] = poHeader->anUnused[1];
809 74 : anTemp[1] = poHeader->nEpsg;
810 74 : anTemp[2] = (int)poHeader->adfOrigin[0];
811 74 : anTemp[3] = (int)poHeader->adfOrigin[1];
812 444 : for (size_t i = 4; i < 9; ++i)
813 370 : anTemp[i] = poHeader->anUnused[i - 2];
814 74 : anTemp[9] = (poHeader->panStartDate != nullptr) ? 1 : 0;
815 74 : if (write_intarray(fp, anTemp, 10) == 0)
816 0 : return 0;
817 74 : if (poHeader->panStartDate != nullptr &&
818 0 : write_intarray(fp, poHeader->panStartDate, 6) == 0)
819 0 : return 0;
820 74 : anTemp[0] = poHeader->nElements;
821 74 : anTemp[1] = poHeader->nPoints;
822 74 : anTemp[2] = poHeader->nPointsPerElement;
823 74 : anTemp[3] = 1;
824 74 : if (write_intarray(fp, anTemp, 4) == 0)
825 0 : return 0;
826 148 : if (write_intarray(fp, poHeader->panConnectivity,
827 74 : static_cast<size_t>(poHeader->nElements) *
828 74 : poHeader->nPointsPerElement) == 0)
829 0 : return 0;
830 74 : if (write_intarray(fp, poHeader->panBorder, poHeader->nPoints) == 0)
831 0 : return 0;
832 : double *dfVals =
833 74 : (double *)VSI_MALLOC2_VERBOSE(sizeof(double), poHeader->nPoints);
834 74 : if (poHeader->nPoints > 0 && dfVals == nullptr)
835 0 : return 0;
836 222 : for (size_t i = 0; i < 2; ++i)
837 : {
838 2410 : for (int j = 0; j < poHeader->nPoints; ++j)
839 2262 : dfVals[j] = poHeader->paadfCoords[i][j] - poHeader->adfOrigin[i];
840 148 : if (write_floatarray(fp, dfVals, poHeader->nPoints) == 0)
841 : {
842 0 : CPLFree(dfVals);
843 0 : return 0;
844 : }
845 : }
846 74 : CPLFree(dfVals);
847 74 : return 1;
848 : }
849 :
850 : #ifdef notdef
851 : int read_step(VSILFILE *fp, const Header *poHeader, TimeStep *&poStep)
852 : {
853 : poStep = new TimeStep(poHeader->nPoints, poHeader->nVar);
854 : int nLength = 0;
855 : if (read_integer(fp, nLength) == 0 || nLength != 1)
856 : {
857 : delete poStep;
858 : return 0;
859 : }
860 : if (read_float(fp, poStep->dfDate) == 0)
861 : {
862 : delete poStep;
863 : return 0;
864 : }
865 : if (read_integer(fp, nLength) == 0 || nLength != 1)
866 : {
867 : delete poStep;
868 : return 0;
869 : }
870 : for (int i = 0; i < poHeader->nVar; ++i)
871 : {
872 : nLength = read_floatarray(fp, &(poStep->papadfData[i]));
873 : if (nLength != poHeader->nPoints)
874 : {
875 : delete poStep;
876 : return 0;
877 : }
878 : }
879 : return 1;
880 : }
881 :
882 : int write_step(VSILFILE *fp, const Header *poHeader, const TimeStep *poStep)
883 : {
884 : if (write_integer(fp, 1) == 0)
885 : return 0;
886 : if (write_float(fp, poStep->dfDate) == 0)
887 : return 0;
888 : if (write_integer(fp, 1) == 0)
889 : return 0;
890 : for (int i = 0; i < poHeader->nVar; ++i)
891 : {
892 : if (write_floatarray(fp, poStep->papadfData[i]) == 0)
893 : return 0;
894 : }
895 : return 1;
896 : }
897 :
898 : int read_steps(VSILFILE *fp, const Header *poHeader, TimeStepList *&poSteps)
899 : {
900 : poSteps = 0;
901 : TimeStepList *poCur, *poNew;
902 : for (int i = 0; i < poHeader->nSteps; ++i)
903 : {
904 : poNew = new TimeStepList(0, 0);
905 : if (read_step(fp, poHeader, poNew->poStep) == 0)
906 : {
907 : delete poSteps;
908 : return 0;
909 : }
910 : if (poSteps == 0)
911 : poSteps = poNew;
912 : else
913 : poCur->poNext = poNew;
914 : poCur = poNew;
915 : }
916 : return 1;
917 : }
918 :
919 : int write_steps(VSILFILE *fp, const Header *poHeader,
920 : const TimeStepList *poSteps)
921 : {
922 : const TimeStepList *poCur = poSteps;
923 : while (poCur != 0)
924 : {
925 : if (write_step(fp, poHeader, poCur->poStep) == 0)
926 : return 0;
927 : poCur = poCur->poNext;
928 : }
929 : return 1;
930 : }
931 : #endif
932 : } // namespace Selafin
|