LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/selafin - io_selafin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 315 498 63.3 %
Date: 2024-11-21 22:18:42 Functions: 23 24 95.8 %

          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

Generated by: LCOV version 1.14