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-05-02 22:57:13 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             :  * 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

Generated by: LCOV version 1.14