LCOV - code coverage report
Current view: top level - frmts/hfa - hfaentry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 328 390 84.1 %
Date: 2024-05-06 22:33:47 Functions: 31 32 96.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Erdas Imagine (.img) Translator
       4             :  * Purpose:  Implementation of the HFAEntry class for reading and relating
       5             :  *           one node in the HFA object tree structure.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Intergraph Corporation
      10             :  * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ******************************************************************************
      30             :  *
      31             :  * hfaentry.cpp
      32             :  *
      33             :  * Implementation of the HFAEntry class.
      34             :  *
      35             :  */
      36             : 
      37             : #include "cpl_port.h"
      38             : #include "hfa_p.h"
      39             : 
      40             : #include <cerrno>
      41             : #include <climits>
      42             : #include <cstddef>
      43             : #include <cstdio>
      44             : #include <cstring>
      45             : #if HAVE_FCNTL_H
      46             : #include <fcntl.h>
      47             : #endif
      48             : #include <vector>
      49             : 
      50             : #include "cpl_conv.h"
      51             : #include "cpl_error.h"
      52             : #include "cpl_string.h"
      53             : #include "cpl_vsi.h"
      54             : 
      55             : /************************************************************************/
      56             : /*                              HFAEntry()                              */
      57             : /************************************************************************/
      58             : 
      59        5049 : HFAEntry::HFAEntry()
      60             :     : bDirty(false), nFilePos(0), psHFA(nullptr), poParent(nullptr),
      61             :       poPrev(nullptr), nNextPos(0), poNext(nullptr), nChildPos(0),
      62             :       poChild(nullptr), poType(nullptr), nDataPos(0), nDataSize(0),
      63        5049 :       pabyData(nullptr), bIsMIFObject(false)
      64             : {
      65        5049 :     szName[0] = '\0';
      66        5049 :     szType[0] = '\0';
      67        5049 : }
      68             : 
      69             : /************************************************************************/
      70             : /*                              HFAEntry()                              */
      71             : /*                                                                      */
      72             : /*      Construct an HFAEntry from the source file.                     */
      73             : /************************************************************************/
      74             : 
      75        5049 : HFAEntry *HFAEntry::New(HFAInfo_t *psHFAIn, GUInt32 nPos, HFAEntry *poParentIn,
      76             :                         HFAEntry *poPrevIn)
      77             : 
      78             : {
      79        5049 :     HFAEntry *poEntry = new HFAEntry;
      80        5049 :     poEntry->psHFA = psHFAIn;
      81             : 
      82        5049 :     poEntry->nFilePos = nPos;
      83        5049 :     poEntry->poParent = poParentIn;
      84        5049 :     poEntry->poPrev = poPrevIn;
      85             : 
      86             :     // Read the entry information from the file.
      87        5049 :     GInt32 anEntryNums[6] = {};
      88             : 
      89       10098 :     if (VSIFSeekL(poEntry->psHFA->fp, poEntry->nFilePos, SEEK_SET) == -1 ||
      90        5049 :         VSIFReadL(anEntryNums, sizeof(GInt32) * 6, 1, poEntry->psHFA->fp) < 1)
      91             :     {
      92           4 :         CPLError(CE_Failure, CPLE_FileIO,
      93             :                  "VSIFReadL(%p,6*4) @ %u failed in HFAEntry().\n%s",
      94           2 :                  poEntry->psHFA->fp, poEntry->nFilePos, VSIStrerror(errno));
      95           2 :         delete poEntry;
      96           2 :         return nullptr;
      97             :     }
      98             : 
      99       35329 :     for (int i = 0; i < 6; i++)
     100             :         HFAStandard(4, anEntryNums + i);
     101             : 
     102        5047 :     poEntry->nNextPos = anEntryNums[0];
     103        5047 :     poEntry->nChildPos = anEntryNums[3];
     104        5047 :     poEntry->nDataPos = anEntryNums[4];
     105        5047 :     poEntry->nDataSize = anEntryNums[5];
     106             : 
     107             :     // Read the name, and type.
     108       10094 :     if (VSIFReadL(poEntry->szName, 64, 1, poEntry->psHFA->fp) < 1 ||
     109        5047 :         VSIFReadL(poEntry->szType, 32, 1, poEntry->psHFA->fp) < 1)
     110             :     {
     111           0 :         poEntry->szName[sizeof(poEntry->szName) - 1] = '\0';
     112           0 :         poEntry->szType[sizeof(poEntry->szType) - 1] = '\0';
     113           0 :         CPLError(CE_Failure, CPLE_FileIO, "VSIFReadL() failed in HFAEntry().");
     114           0 :         delete poEntry;
     115           0 :         return nullptr;
     116             :     }
     117        5047 :     poEntry->szName[sizeof(poEntry->szName) - 1] = '\0';
     118        5047 :     poEntry->szType[sizeof(poEntry->szType) - 1] = '\0';
     119        5047 :     return poEntry;
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                              HFAEntry()                              */
     124             : /*                                                                      */
     125             : /*      Construct an HFAEntry in memory, with the intention that it     */
     126             : /*      would be written to disk later.                                 */
     127             : /************************************************************************/
     128             : 
     129        1914 : HFAEntry::HFAEntry(HFAInfo_t *psHFAIn, const char *pszNodeName,
     130        1914 :                    const char *pszTypeName, HFAEntry *poParentIn)
     131             :     : nFilePos(0), psHFA(psHFAIn), poParent(poParentIn), poPrev(nullptr),
     132             :       nNextPos(0), poNext(nullptr), nChildPos(0), poChild(nullptr),
     133             :       poType(nullptr), nDataPos(0), nDataSize(0), pabyData(nullptr),
     134        1914 :       bIsMIFObject(false)
     135             : {
     136             :     // Initialize Entry.
     137        1914 :     SetName(pszNodeName);
     138        1914 :     memset(szType, 0, sizeof(szType));
     139        1914 :     snprintf(szType, sizeof(szType), "%s", pszTypeName);
     140             : 
     141             :     // Update the previous or parent node to refer to this one.
     142        1914 :     if (poParent == nullptr)
     143             :     {
     144             :         // Do nothing.
     145             :     }
     146        1728 :     else if (poParent->poChild == nullptr)
     147             :     {
     148         625 :         poParent->poChild = this;
     149         625 :         poParent->MarkDirty();
     150             :     }
     151             :     else
     152             :     {
     153        1103 :         poPrev = poParent->poChild;
     154        2444 :         while (poPrev->poNext != nullptr)
     155        1341 :             poPrev = poPrev->poNext;
     156             : 
     157        1103 :         poPrev->poNext = this;
     158        1103 :         poPrev->MarkDirty();
     159             :     }
     160             : 
     161        1914 :     MarkDirty();
     162        1914 : }
     163             : 
     164             : /************************************************************************/
     165             : /*                              New()                                   */
     166             : /*                                                                      */
     167             : /*      Construct an HFAEntry in memory, with the intention that it     */
     168             : /*      would be written to disk later.                                 */
     169             : /************************************************************************/
     170             : 
     171        1728 : HFAEntry *HFAEntry::New(HFAInfo_t *psHFAIn, const char *pszNodeName,
     172             :                         const char *pszTypeName, HFAEntry *poParentIn)
     173             : {
     174        1728 :     CPLAssert(poParentIn != nullptr);
     175        1728 :     return new HFAEntry(psHFAIn, pszNodeName, pszTypeName, poParentIn);
     176             : }
     177             : 
     178             : /************************************************************************/
     179             : /*                      BuildEntryFromMIFObject()                       */
     180             : /*                                                                      */
     181             : /*      Create a pseudo-HFAEntry wrapping a MIFObject.                  */
     182             : /************************************************************************/
     183             : 
     184           2 : HFAEntry *HFAEntry::BuildEntryFromMIFObject(HFAEntry *poContainer,
     185             :                                             const char *pszMIFObjectPath)
     186             : {
     187           4 :     CPLString osFieldName;
     188             : 
     189           2 :     osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFDictionary");
     190           2 :     const char *pszField = poContainer->GetStringField(osFieldName.c_str());
     191           2 :     if (pszField == nullptr)
     192             :     {
     193           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
     194             :                  osFieldName.c_str());
     195           0 :         return nullptr;
     196             :     }
     197           4 :     CPLString osDictionary = pszField;
     198             : 
     199           2 :     osFieldName.Printf("%s.%s", pszMIFObjectPath, "type.string");
     200           2 :     pszField = poContainer->GetStringField(osFieldName.c_str());
     201           2 :     if (pszField == nullptr)
     202             :     {
     203           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
     204             :                  osFieldName.c_str());
     205           0 :         return nullptr;
     206             :     }
     207           4 :     CPLString osType = pszField;
     208             : 
     209           2 :     osFieldName.Printf("%s.%s", pszMIFObjectPath, "MIFObject");
     210           2 :     int nRemainingDataSize = 0;
     211           2 :     pszField = poContainer->GetStringField(osFieldName.c_str(), nullptr,
     212             :                                            &nRemainingDataSize);
     213           2 :     if (pszField == nullptr)
     214             :     {
     215           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find %s entry",
     216             :                  osFieldName.c_str());
     217           0 :         return nullptr;
     218             :     }
     219             : 
     220           2 :     GInt32 nMIFObjectSize = 0;
     221             :     // We rudely look before the field data to get at the pointer/size info.
     222           2 :     memcpy(&nMIFObjectSize, pszField - 8, 4);
     223             :     HFAStandard(4, &nMIFObjectSize);
     224           2 :     if (nMIFObjectSize <= 0)
     225             :     {
     226           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid MIF object size (%d)",
     227             :                  nMIFObjectSize);
     228           0 :         return nullptr;
     229             :     }
     230             : 
     231             :     // Check that we won't copy more bytes than available in the buffer.
     232           2 :     if (nMIFObjectSize > nRemainingDataSize)
     233             :     {
     234           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     235             :                  "Invalid MIF object size (%d > %d)", nMIFObjectSize,
     236             :                  nRemainingDataSize);
     237           0 :         return nullptr;
     238             :     }
     239             : 
     240           2 :     GByte *l_pabyData = static_cast<GByte *>(VSIMalloc(nMIFObjectSize));
     241           2 :     if (l_pabyData == nullptr)
     242           0 :         return nullptr;
     243             : 
     244           2 :     memcpy(l_pabyData, pszField, nMIFObjectSize);
     245             : 
     246           2 :     return new HFAEntry(osDictionary, osType, nMIFObjectSize, l_pabyData);
     247             : }
     248             : 
     249             : /************************************************************************/
     250             : /*                              HFAEntry()                              */
     251             : /*                                                                      */
     252             : /*      Create a pseudo-HFAEntry wrapping a MIFObject.                  */
     253             : /************************************************************************/
     254             : 
     255           2 : HFAEntry::HFAEntry(const char *pszDictionary, const char *pszTypeName,
     256           2 :                    int nDataSizeIn, GByte *pabyDataIn)
     257             :     : bDirty(false), nFilePos(0), poParent(nullptr), poPrev(nullptr),
     258             :       nNextPos(0), poNext(nullptr), nChildPos(0), poChild(nullptr), nDataPos(0),
     259           2 :       nDataSize(0), bIsMIFObject(true)
     260             : {
     261             :     // Initialize Entry
     262           2 :     memset(szName, 0, sizeof(szName));
     263             : 
     264             :     // Create a dummy HFAInfo_t.
     265           2 :     psHFA = static_cast<HFAInfo_t *>(CPLCalloc(sizeof(HFAInfo_t), 1));
     266             : 
     267           2 :     psHFA->eAccess = HFA_ReadOnly;
     268           2 :     psHFA->bTreeDirty = false;
     269           2 :     psHFA->poRoot = this;
     270             : 
     271           2 :     psHFA->poDictionary = new HFADictionary(pszDictionary);
     272             : 
     273             :     // Work out the type for this MIFObject.
     274           2 :     memset(szType, 0, sizeof(szType));
     275           2 :     snprintf(szType, sizeof(szType), "%s", pszTypeName);
     276             : 
     277           2 :     poType = psHFA->poDictionary->FindType(szType);
     278             : 
     279           2 :     nDataSize = nDataSizeIn;
     280           2 :     pabyData = pabyDataIn;
     281           2 : }
     282             : 
     283             : /************************************************************************/
     284             : /*                             ~HFAEntry()                              */
     285             : /*                                                                      */
     286             : /*      Ensure that children are cleaned up when this node is           */
     287             : /*      cleaned up.                                                     */
     288             : /************************************************************************/
     289             : 
     290       20895 : HFAEntry::~HFAEntry()
     291             : 
     292             : {
     293        6965 :     CPLFree(pabyData);
     294             : 
     295        6965 :     if (poNext != nullptr)
     296        3976 :         delete poNext;
     297             : 
     298        6965 :     if (poChild != nullptr)
     299        2241 :         delete poChild;
     300             : 
     301        6965 :     if (bIsMIFObject)
     302             :     {
     303           2 :         delete psHFA->poDictionary;
     304           2 :         CPLFree(psHFA);
     305             :     }
     306       13930 : }
     307             : 
     308             : /************************************************************************/
     309             : /*                          RemoveAndDestroy()                          */
     310             : /*                                                                      */
     311             : /*      Removes this entry, and its children from the current           */
     312             : /*      tree.  The parent and/or siblings are appropriately updated     */
     313             : /*      so that they will be flushed back to disk without the           */
     314             : /*      reference to this node.                                         */
     315             : /************************************************************************/
     316             : 
     317           9 : CPLErr HFAEntry::RemoveAndDestroy()
     318             : 
     319             : {
     320           9 :     if (poPrev != nullptr)
     321             :     {
     322           9 :         poPrev->poNext = poNext;
     323           9 :         if (poNext != nullptr)
     324           7 :             poPrev->nNextPos = poNext->nFilePos;
     325             :         else
     326           2 :             poPrev->nNextPos = 0;
     327           9 :         poPrev->MarkDirty();
     328             :     }
     329           9 :     if (poParent != nullptr && poParent->poChild == this)
     330             :     {
     331           0 :         poParent->poChild = poNext;
     332           0 :         if (poNext)
     333           0 :             poParent->nChildPos = poNext->nFilePos;
     334             :         else
     335           0 :             poParent->nChildPos = 0;
     336           0 :         poParent->MarkDirty();
     337             :     }
     338             : 
     339           9 :     if (poNext != nullptr)
     340             :     {
     341           7 :         poNext->poPrev = poPrev;
     342             :     }
     343             : 
     344           9 :     poNext = nullptr;
     345           9 :     poPrev = nullptr;
     346           9 :     poParent = nullptr;
     347             : 
     348           9 :     delete this;
     349             : 
     350           9 :     return CE_None;
     351             : }
     352             : 
     353             : /************************************************************************/
     354             : /*                              SetName()                               */
     355             : /*                                                                      */
     356             : /*    Changes the name assigned to this node                            */
     357             : /************************************************************************/
     358             : 
     359        1921 : void HFAEntry::SetName(const char *pszNodeName)
     360             : {
     361        1921 :     memset(szName, 0, sizeof(szName));
     362        1921 :     snprintf(szName, sizeof(szName), "%s", pszNodeName);
     363             : 
     364        1921 :     MarkDirty();
     365        1921 : }
     366             : 
     367             : /************************************************************************/
     368             : /*                              GetChild()                              */
     369             : /************************************************************************/
     370             : 
     371       22135 : HFAEntry *HFAEntry::GetChild()
     372             : 
     373             : {
     374             :     // Do we need to create the child node?
     375       22135 :     if (poChild == nullptr && nChildPos != 0)
     376             :     {
     377        1618 :         poChild = HFAEntry::New(psHFA, nChildPos, this, nullptr);
     378        1618 :         if (poChild == nullptr)
     379           2 :             nChildPos = 0;
     380             :     }
     381             : 
     382       22135 :     return poChild;
     383             : }
     384             : 
     385             : /************************************************************************/
     386             : /*                              GetNext()                               */
     387             : /************************************************************************/
     388             : 
     389       63816 : HFAEntry *HFAEntry::GetNext()
     390             : 
     391             : {
     392             :     // Do we need to create the next node?
     393       63816 :     if (poNext == nullptr && nNextPos != 0)
     394             :     {
     395             :         // Check if we have a loop on the next node in this sibling chain.
     396             :         HFAEntry *poPast;
     397             : 
     398        9763 :         for (poPast = this; poPast != nullptr && poPast->nFilePos != nNextPos;
     399        6880 :              poPast = poPast->poPrev)
     400             :         {
     401             :         }
     402             : 
     403        2883 :         if (poPast != nullptr)
     404             :         {
     405           1 :             CPLError(CE_Warning, CPLE_AppDefined,
     406             :                      "Corrupt (looping) entry in %s, "
     407             :                      "ignoring some entries after %s.",
     408           1 :                      psHFA->pszFilename, szName);
     409           1 :             nNextPos = 0;
     410           1 :             return nullptr;
     411             :         }
     412             : 
     413        2882 :         poNext = HFAEntry::New(psHFA, nNextPos, poParent, this);
     414        2882 :         if (poNext == nullptr)
     415           0 :             nNextPos = 0;
     416             :     }
     417             : 
     418       63815 :     return poNext;
     419             : }
     420             : 
     421             : /************************************************************************/
     422             : /*                              LoadData()                              */
     423             : /*                                                                      */
     424             : /*      Load the data for this entry, and build up the field            */
     425             : /*      information for it.                                             */
     426             : /************************************************************************/
     427             : 
     428       56237 : void HFAEntry::LoadData()
     429             : 
     430             : {
     431       56237 :     if (pabyData != nullptr || nDataSize == 0)
     432       53343 :         return;
     433        2894 :     if (nDataSize > INT_MAX - 1)
     434             :     {
     435           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     436             :                  "Invalid value for nDataSize = %u", nDataSize);
     437           0 :         return;
     438             :     }
     439             : 
     440             :     // Allocate buffer, and read data.
     441        2894 :     pabyData = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nDataSize + 1));
     442        2894 :     if (pabyData == nullptr)
     443             :     {
     444           0 :         return;
     445             :     }
     446             : 
     447        2894 :     if (VSIFSeekL(psHFA->fp, nDataPos, SEEK_SET) < 0)
     448             :     {
     449           0 :         CPLError(CE_Failure, CPLE_FileIO,
     450             :                  "VSIFSeekL() failed in HFAEntry::LoadData().");
     451           0 :         return;
     452             :     }
     453             : 
     454        2894 :     if (VSIFReadL(pabyData, nDataSize, 1, psHFA->fp) < 1)
     455             :     {
     456           0 :         CPLError(CE_Failure, CPLE_FileIO,
     457             :                  "VSIFReadL() failed in HFAEntry::LoadData().");
     458           0 :         return;
     459             :     }
     460             : 
     461             :     // Make sure the buffer is always null terminated to avoid
     462             :     // issues when extracting strings from a corrupted file.
     463        2894 :     pabyData[nDataSize] = '\0';
     464             : 
     465             :     // Get the type corresponding to this entry.
     466        2894 :     poType = psHFA->poDictionary->FindType(szType);
     467        2894 :     if (poType == nullptr)
     468           0 :         return;
     469             : }
     470             : 
     471             : /************************************************************************/
     472             : /*                           GetTypeObject()                            */
     473             : /************************************************************************/
     474             : 
     475         163 : HFAType *HFAEntry::GetTypeObject()
     476             : 
     477             : {
     478         163 :     if (poType == nullptr)
     479         163 :         poType = psHFA->poDictionary->FindType(szType);
     480             : 
     481         163 :     return poType;
     482             : }
     483             : 
     484             : /************************************************************************/
     485             : /*                              MakeData()                              */
     486             : /*                                                                      */
     487             : /*      Create a data block on the this HFAEntry in memory.  By         */
     488             : /*      default it will create the data the correct size for fixed      */
     489             : /*      sized types, or do nothing for variable length types.           */
     490             : /*      However, the caller can supply a desired size for variable      */
     491             : /*      sized fields.                                                   */
     492             : /************************************************************************/
     493             : 
     494       12829 : GByte *HFAEntry::MakeData(int nSize)
     495             : 
     496             : {
     497       12829 :     if (poType == nullptr)
     498             :     {
     499        1565 :         poType = psHFA->poDictionary->FindType(szType);
     500        1565 :         if (poType == nullptr)
     501           0 :             return nullptr;
     502             :     }
     503             : 
     504       12829 :     if (nSize == 0 && poType->nBytes > 0)
     505        2854 :         nSize = poType->nBytes;
     506             : 
     507             :     // nDataSize is a GUInt32.
     508       12829 :     if (static_cast<int>(nDataSize) < nSize && nSize > 0)
     509             :     {
     510        1732 :         pabyData = static_cast<GByte *>(CPLRealloc(pabyData, nSize));
     511        1732 :         memset(pabyData + nDataSize, 0, nSize - nDataSize);
     512        1732 :         nDataSize = nSize;
     513             : 
     514        1732 :         MarkDirty();
     515             : 
     516             :         // If the data already had a file position, we now need to
     517             :         // clear that, forcing it to be rewritten at the end of the
     518             :         // file.  Referencing nodes will need to be marked dirty so
     519             :         // they are rewritten.
     520        1732 :         if (nFilePos != 0)
     521             :         {
     522           5 :             nFilePos = 0;
     523           5 :             nDataPos = 0;
     524           5 :             if (poPrev != nullptr)
     525           2 :                 poPrev->MarkDirty();
     526           5 :             if (poNext != nullptr)
     527           4 :                 poNext->MarkDirty();
     528           5 :             if (poChild != nullptr)
     529           0 :                 poChild->MarkDirty();
     530           5 :             if (poParent != nullptr)
     531           5 :                 poParent->MarkDirty();
     532             :         }
     533             :     }
     534             :     else
     535             :     {
     536       11097 :         LoadData();  // Make sure the data is loaded before we return pointer.
     537             :     }
     538             : 
     539       12829 :     return pabyData;
     540             : }
     541             : 
     542             : /************************************************************************/
     543             : /*                          DumpFieldValues()                           */
     544             : /************************************************************************/
     545             : 
     546           0 : void HFAEntry::DumpFieldValues(FILE *fp, const char *pszPrefix)
     547             : 
     548             : {
     549           0 :     if (pszPrefix == nullptr)
     550           0 :         pszPrefix = "";
     551             : 
     552           0 :     LoadData();
     553             : 
     554           0 :     if (pabyData == nullptr || poType == nullptr)
     555           0 :         return;
     556             : 
     557           0 :     poType->DumpInstValue(fp, pabyData, nDataPos, nDataSize, pszPrefix);
     558             : }
     559             : 
     560             : /************************************************************************/
     561             : /*                            FindChildren()                            */
     562             : /*                                                                      */
     563             : /*      Find all the children of the current node that match the        */
     564             : /*      name and type provided.  Either may be NULL if it is not a      */
     565             : /*      factor.  The pszName should be just the node name, not a        */
     566             : /*      path.                                                           */
     567             : /************************************************************************/
     568             : 
     569        1249 : std::vector<HFAEntry *> HFAEntry::FindChildren(const char *pszName,
     570             :                                                const char *pszType,
     571             :                                                int nRecLevel,
     572             :                                                int *pbErrorDetected)
     573             : 
     574             : {
     575        1249 :     std::vector<HFAEntry *> apoChildren;
     576             : 
     577        1249 :     if (*pbErrorDetected)
     578           0 :         return apoChildren;
     579        1249 :     if (nRecLevel == 50)
     580             :     {
     581           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     582             :                  "Bad entry structure: recursion detected !");
     583           0 :         *pbErrorDetected = TRUE;
     584           0 :         return apoChildren;
     585             :     }
     586             : 
     587        2366 :     for (HFAEntry *poEntry = GetChild(); poEntry != nullptr;
     588        1117 :          poEntry = poEntry->GetNext())
     589             :     {
     590        1117 :         std::vector<HFAEntry *> apoEntryChildren;
     591             : 
     592        2138 :         if ((pszName == nullptr || EQUAL(poEntry->GetName(), pszName)) &&
     593        1021 :             (pszType == nullptr || EQUAL(poEntry->GetType(), pszType)))
     594          40 :             apoChildren.push_back(poEntry);
     595             : 
     596        2234 :         apoEntryChildren = poEntry->FindChildren(
     597        1117 :             pszName, pszType, nRecLevel + 1, pbErrorDetected);
     598        1117 :         if (*pbErrorDetected)
     599           0 :             return apoChildren;
     600             : 
     601        1162 :         for (size_t i = 0; i < apoEntryChildren.size(); i++)
     602          45 :             apoChildren.push_back(apoEntryChildren[i]);
     603             :     }
     604             : 
     605        1249 :     return apoChildren;
     606             : }
     607             : 
     608         132 : std::vector<HFAEntry *> HFAEntry::FindChildren(const char *pszName,
     609             :                                                const char *pszType)
     610             : 
     611             : {
     612         132 :     int bErrorDetected = FALSE;
     613         264 :     return FindChildren(pszName, pszType, 0, &bErrorDetected);
     614             : }
     615             : 
     616             : /************************************************************************/
     617             : /*                           GetNamedChild()                            */
     618             : /************************************************************************/
     619             : 
     620       18151 : HFAEntry *HFAEntry::GetNamedChild(const char *pszName)
     621             : 
     622             : {
     623             :     // Establish how much of this name path is for the next child.
     624             :     // Up to the '.' or end of the string.
     625       18151 :     int nNameLen = 0;
     626      265725 :     for (; pszName[nNameLen] != '.' && pszName[nNameLen] != '\0' &&
     627      247574 :            pszName[nNameLen] != ':';
     628             :          nNameLen++)
     629             :     {
     630             :     }
     631             : 
     632             :     // Scan children looking for this name.
     633       73305 :     for (HFAEntry *poEntry = GetChild(); poEntry != nullptr;
     634       55154 :          poEntry = poEntry->GetNext())
     635             :     {
     636       63388 :         if (EQUALN(poEntry->GetName(), pszName, nNameLen) &&
     637        4689 :             static_cast<int>(strlen(poEntry->GetName())) == nNameLen)
     638             :         {
     639        3721 :             if (pszName[nNameLen] == '.')
     640             :             {
     641             :                 HFAEntry *poResult;
     642             : 
     643         574 :                 poResult = poEntry->GetNamedChild(pszName + nNameLen + 1);
     644         574 :                 if (poResult != nullptr)
     645         398 :                     return poResult;
     646             :             }
     647             :             else
     648        3147 :                 return poEntry;
     649             :         }
     650             :     }
     651             : 
     652       14606 :     return nullptr;
     653             : }
     654             : 
     655             : /************************************************************************/
     656             : /*                           GetFieldValue()                            */
     657             : /************************************************************************/
     658             : 
     659       32254 : bool HFAEntry::GetFieldValue(const char *pszFieldPath, char chReqType,
     660             :                              void *pReqReturn, int *pnRemainingDataSize)
     661             : 
     662             : {
     663             :     // Is there a node path in this string?
     664       32254 :     if (strchr(pszFieldPath, ':') != nullptr)
     665             :     {
     666           0 :         HFAEntry *poEntry = GetNamedChild(pszFieldPath);
     667           0 :         if (poEntry == nullptr)
     668           0 :             return false;
     669             : 
     670           0 :         pszFieldPath = strchr(pszFieldPath, ':') + 1;
     671             :     }
     672             : 
     673             :     // Do we have the data and type for this node?
     674       32254 :     LoadData();
     675             : 
     676       32254 :     if (pabyData == nullptr)
     677          26 :         return false;
     678             : 
     679       32228 :     if (poType == nullptr)
     680           0 :         return false;
     681             : 
     682             :     // Extract the instance information.
     683       32228 :     return poType->ExtractInstValue(pszFieldPath, pabyData, nDataPos, nDataSize,
     684       32228 :                                     chReqType, pReqReturn, pnRemainingDataSize);
     685             : }
     686             : 
     687             : /************************************************************************/
     688             : /*                           GetFieldCount()                            */
     689             : /************************************************************************/
     690             : 
     691         886 : int HFAEntry::GetFieldCount(const char *pszFieldPath, CPLErr * /* peErr */)
     692             : {
     693             :     // Is there a node path in this string?
     694         886 :     if (strchr(pszFieldPath, ':') != nullptr)
     695             :     {
     696           0 :         HFAEntry *poEntry = GetNamedChild(pszFieldPath);
     697           0 :         if (poEntry == nullptr)
     698           0 :             return -1;
     699             : 
     700           0 :         pszFieldPath = strchr(pszFieldPath, ':') + 1;
     701             :     }
     702             : 
     703             :     // Do we have the data and type for this node?
     704         886 :     LoadData();
     705             : 
     706         886 :     if (pabyData == nullptr)
     707           0 :         return -1;
     708             : 
     709         886 :     if (poType == nullptr)
     710           0 :         return -1;
     711             : 
     712             :     // Extract the instance information.
     713             : 
     714         886 :     return poType->GetInstCount(pszFieldPath, pabyData, nDataPos, nDataSize);
     715             : }
     716             : 
     717             : /************************************************************************/
     718             : /*                            GetIntField()                             */
     719             : /************************************************************************/
     720             : 
     721       21195 : GInt32 HFAEntry::GetIntField(const char *pszFieldPath, CPLErr *peErr)
     722             : 
     723             : {
     724       21195 :     GInt32 nIntValue = 0;
     725             : 
     726       21195 :     if (!GetFieldValue(pszFieldPath, 'i', &nIntValue, nullptr))
     727             :     {
     728          31 :         if (peErr != nullptr)
     729          12 :             *peErr = CE_Failure;
     730             : 
     731          31 :         return 0;
     732             :     }
     733             : 
     734       21164 :     if (peErr != nullptr)
     735       10045 :         *peErr = CE_None;
     736             : 
     737       21164 :     return nIntValue;
     738             : }
     739             : 
     740             : /************************************************************************/
     741             : /*                           GetBigIntField()                           */
     742             : /*                                                                      */
     743             : /*      This is just a helper method that reads two ULONG array         */
     744             : /*      entries as a GIntBig.  The passed name should be the name of    */
     745             : /*      the array with no array index.  Array indexes 0 and 1 will      */
     746             : /*      be concatenated.                                                */
     747             : /************************************************************************/
     748             : 
     749          32 : GIntBig HFAEntry::GetBigIntField(const char *pszFieldPath, CPLErr *peErr)
     750             : 
     751             : {
     752             :     char szFullFieldPath[1024];
     753             : 
     754          32 :     snprintf(szFullFieldPath, sizeof(szFullFieldPath), "%s[0]", pszFieldPath);
     755          32 :     const GUInt32 nLower = GetIntField(szFullFieldPath, peErr);
     756          32 :     if (peErr != nullptr && *peErr != CE_None)
     757           0 :         return 0;
     758             : 
     759          32 :     snprintf(szFullFieldPath, sizeof(szFullFieldPath), "%s[1]", pszFieldPath);
     760          32 :     const GUInt32 nUpper = GetIntField(szFullFieldPath, peErr);
     761          32 :     if (peErr != nullptr && *peErr != CE_None)
     762           0 :         return 0;
     763             : 
     764          32 :     return nLower + (static_cast<GIntBig>(nUpper) << 32);
     765             : }
     766             : 
     767             : /************************************************************************/
     768             : /*                           GetDoubleField()                           */
     769             : /************************************************************************/
     770             : 
     771        7575 : double HFAEntry::GetDoubleField(const char *pszFieldPath, CPLErr *peErr)
     772             : 
     773             : {
     774        7575 :     double dfDoubleValue = 0;
     775             : 
     776        7575 :     if (!GetFieldValue(pszFieldPath, 'd', &dfDoubleValue, nullptr))
     777             :     {
     778         242 :         if (peErr != nullptr)
     779          24 :             *peErr = CE_Failure;
     780             : 
     781         242 :         return 0.0;
     782             :     }
     783             : 
     784        7333 :     if (peErr != nullptr)
     785        1089 :         *peErr = CE_None;
     786             : 
     787        7333 :     return dfDoubleValue;
     788             : }
     789             : 
     790             : /************************************************************************/
     791             : /*                           GetStringField()                           */
     792             : /************************************************************************/
     793             : 
     794        3484 : const char *HFAEntry::GetStringField(const char *pszFieldPath, CPLErr *peErr,
     795             :                                      int *pnRemainingDataSize)
     796             : 
     797             : {
     798        3484 :     char *pszResult = nullptr;
     799             : 
     800        3484 :     if (!GetFieldValue(pszFieldPath, 's', &pszResult, pnRemainingDataSize))
     801             :     {
     802         348 :         if (peErr != nullptr)
     803          35 :             *peErr = CE_Failure;
     804             : 
     805         348 :         return nullptr;
     806             :     }
     807             : 
     808        3136 :     if (peErr != nullptr)
     809         665 :         *peErr = CE_None;
     810             : 
     811        3136 :     return pszResult;
     812             : }
     813             : 
     814             : /************************************************************************/
     815             : /*                           SetFieldValue()                            */
     816             : /************************************************************************/
     817             : 
     818       11438 : CPLErr HFAEntry::SetFieldValue(const char *pszFieldPath, char chReqType,
     819             :                                void *pValue)
     820             : 
     821             : {
     822             :     // Is there a node path in this string?
     823       11438 :     if (strchr(pszFieldPath, ':') != nullptr)
     824             :     {
     825           0 :         HFAEntry *poEntry = GetNamedChild(pszFieldPath);
     826           0 :         if (poEntry == nullptr)
     827           0 :             return CE_Failure;
     828             : 
     829           0 :         pszFieldPath = strchr(pszFieldPath, ':') + 1;
     830             :     }
     831             : 
     832             :     // Do we have the data and type for this node?  Try loading
     833             :     // from a file, or instantiating a new node.
     834       11438 :     LoadData();
     835       11438 :     if (MakeData() == nullptr || pabyData == nullptr || poType == nullptr)
     836             :     {
     837          16 :         return CE_Failure;
     838             :     }
     839             : 
     840             :     // Extract the instance information.
     841       11422 :     MarkDirty();
     842             : 
     843       11422 :     return poType->SetInstValue(pszFieldPath, pabyData, nDataPos, nDataSize,
     844       11422 :                                 chReqType, pValue);
     845             : }
     846             : 
     847             : /************************************************************************/
     848             : /*                           SetStringField()                           */
     849             : /************************************************************************/
     850             : 
     851        2619 : CPLErr HFAEntry::SetStringField(const char *pszFieldPath, const char *pszValue)
     852             : 
     853             : {
     854        2619 :     return SetFieldValue(pszFieldPath, 's', (void *)pszValue);
     855             : }
     856             : 
     857             : /************************************************************************/
     858             : /*                            SetIntField()                             */
     859             : /************************************************************************/
     860             : 
     861        3382 : CPLErr HFAEntry::SetIntField(const char *pszFieldPath, int nValue)
     862             : 
     863             : {
     864        3382 :     return SetFieldValue(pszFieldPath, 'i', &nValue);
     865             : }
     866             : 
     867             : /************************************************************************/
     868             : /*                           SetDoubleField()                           */
     869             : /************************************************************************/
     870             : 
     871        5437 : CPLErr HFAEntry::SetDoubleField(const char *pszFieldPath, double dfValue)
     872             : 
     873             : {
     874        5437 :     return SetFieldValue(pszFieldPath, 'd', &dfValue);
     875             : }
     876             : 
     877             : /************************************************************************/
     878             : /*                            SetPosition()                             */
     879             : /*                                                                      */
     880             : /*      Set the disk position for this entry, and recursively apply     */
     881             : /*      to any children of this node.  The parent will take care of     */
     882             : /*      our siblings.                                                   */
     883             : /************************************************************************/
     884             : 
     885        4236 : void HFAEntry::SetPosition()
     886             : 
     887             : {
     888             :     // Establish the location of this entry, and its data.
     889        4236 :     if (nFilePos == 0)
     890             :     {
     891        1919 :         nFilePos =
     892        1919 :             HFAAllocateSpace(psHFA, psHFA->nEntryHeaderLength + nDataSize);
     893             : 
     894        1919 :         if (nDataSize > 0)
     895        1732 :             nDataPos = nFilePos + psHFA->nEntryHeaderLength;
     896             :     }
     897             : 
     898             :     // Force all children to set their position.
     899        6956 :     for (HFAEntry *poThisChild = poChild; poThisChild != nullptr;
     900        2720 :          poThisChild = poThisChild->poNext)
     901             :     {
     902        2720 :         poThisChild->SetPosition();
     903             :     }
     904        4236 : }
     905             : 
     906             : /************************************************************************/
     907             : /*                            FlushToDisk()                             */
     908             : /*                                                                      */
     909             : /*      Write this entry, and its data to disk if the entries           */
     910             : /*      information is dirty.  Also force children to do the same.      */
     911             : /************************************************************************/
     912             : 
     913        3074 : CPLErr HFAEntry::FlushToDisk()
     914             : 
     915             : {
     916             :     // If we are the root node, call SetPosition() on the whole
     917             :     // tree to ensure that all entries have an allocated position.
     918        3074 :     if (poParent == nullptr)
     919         377 :         SetPosition();
     920             : 
     921             :     // Only write this node out if it is dirty.
     922        3074 :     if (bDirty)
     923             :     {
     924             :         // Ensure we know where the relative entries are located.
     925        2230 :         if (poNext != nullptr)
     926        1185 :             nNextPos = poNext->nFilePos;
     927             : 
     928        2230 :         if (poChild != nullptr)
     929         672 :             nChildPos = poChild->nFilePos;
     930             : 
     931             :         // Write the Ehfa_Entry fields.
     932             : 
     933             :         // VSIFFlushL(psHFA->fp);
     934        2230 :         if (VSIFSeekL(psHFA->fp, nFilePos, SEEK_SET) != 0)
     935             :         {
     936           0 :             CPLError(CE_Failure, CPLE_FileIO,
     937             :                      "Failed to seek to %d for writing, out of disk space?",
     938             :                      nFilePos);
     939           6 :             return CE_Failure;
     940             :         }
     941             : 
     942        2230 :         GUInt32 nLong = nNextPos;
     943             :         HFAStandard(4, &nLong);
     944        2230 :         bool bOK = VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     945             : 
     946        2230 :         if (poPrev != nullptr)
     947        1350 :             nLong = poPrev->nFilePos;
     948             :         else
     949         880 :             nLong = 0;
     950             :         HFAStandard(4, &nLong);
     951        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     952             : 
     953        2230 :         if (poParent != nullptr)
     954        2043 :             nLong = poParent->nFilePos;
     955             :         else
     956         187 :             nLong = 0;
     957             :         HFAStandard(4, &nLong);
     958        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     959             : 
     960        2230 :         nLong = nChildPos;
     961             :         HFAStandard(4, &nLong);
     962        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     963             : 
     964        2230 :         nLong = nDataPos;
     965             :         HFAStandard(4, &nLong);
     966        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     967             : 
     968        2230 :         nLong = nDataSize;
     969             :         HFAStandard(4, &nLong);
     970        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     971             : 
     972        2230 :         bOK &= VSIFWriteL(szName, 1, 64, psHFA->fp) > 0;
     973        2230 :         bOK &= VSIFWriteL(szType, 1, 32, psHFA->fp) > 0;
     974             : 
     975        2230 :         nLong = 0;  // Should we keep the time, or set it more reasonably?
     976        2230 :         bOK &= VSIFWriteL(&nLong, 4, 1, psHFA->fp) > 0;
     977        2230 :         if (!bOK)
     978             :         {
     979           5 :             CPLError(CE_Failure, CPLE_FileIO,
     980             :                      "Failed to write HFAEntry %s(%s), out of disk space?",
     981           5 :                      szName, szType);
     982           5 :             return CE_Failure;
     983             :         }
     984             : 
     985             :         // Write out the data.
     986             :         // VSIFFlushL(psHFA->fp);
     987        2225 :         if (nDataSize > 0 && pabyData != nullptr)
     988             :         {
     989        3702 :             if (VSIFSeekL(psHFA->fp, nDataPos, SEEK_SET) != 0 ||
     990        1851 :                 VSIFWriteL(pabyData, nDataSize, 1, psHFA->fp) != 1)
     991             :             {
     992           1 :                 CPLError(CE_Failure, CPLE_FileIO,
     993             :                          "Failed to write %d bytes HFAEntry %s(%s) data, "
     994             :                          "out of disk space?",
     995           1 :                          nDataSize, szName, szType);
     996           1 :                 return CE_Failure;
     997             :             }
     998             :         }
     999             : 
    1000             :         // VSIFFlushL(psHFA->fp);
    1001             :     }
    1002             : 
    1003             :     // Process all the children of this node.
    1004        5763 :     for (HFAEntry *poThisChild = poChild; poThisChild != nullptr;
    1005        2695 :          poThisChild = poThisChild->poNext)
    1006             :     {
    1007        2697 :         CPLErr eErr = poThisChild->FlushToDisk();
    1008        2697 :         if (eErr != CE_None)
    1009           2 :             return eErr;
    1010             :     }
    1011             : 
    1012        3066 :     bDirty = false;
    1013             : 
    1014        3066 :     return CE_None;
    1015             : }
    1016             : 
    1017             : /************************************************************************/
    1018             : /*                             MarkDirty()                              */
    1019             : /*                                                                      */
    1020             : /*      Mark this node as dirty (in need of writing to disk), and       */
    1021             : /*      also mark the tree as a whole as being dirty.                   */
    1022             : /************************************************************************/
    1023             : 
    1024       19237 : void HFAEntry::MarkDirty()
    1025             : 
    1026             : {
    1027       19237 :     bDirty = true;
    1028       19237 :     psHFA->bTreeDirty = true;
    1029       19237 : }

Generated by: LCOV version 1.14