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