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

Generated by: LCOV version 1.14