LCOV - code coverage report
Current view: top level - frmts/hfa - hfaentry.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 339 400 84.8 %
Date: 2026-05-28 11:29:44 Functions: 30 31 96.8 %

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

Generated by: LCOV version 1.14