LCOV - code coverage report
Current view: top level - frmts/hfa - hfafield.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 411 785 52.4 %
Date: 2024-11-21 22:18:42 Functions: 8 11 72.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Erdas Imagine (.img) Translator
       4             :  * Purpose:  Implementation of the HFAField class for managing information
       5             :  *           about one field in a HFA dictionary type.  Managed by HFAType.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 1999, Intergraph Corporation
      10             :  * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : #include "hfa_p.h"
      17             : 
      18             : #include <cerrno>
      19             : #include <climits>
      20             : #include <cstddef>
      21             : #include <cstdio>
      22             : #include <cstring>
      23             : #if HAVE_FCNTL_H
      24             : #include <fcntl.h>
      25             : #endif
      26             : #include <algorithm>
      27             : #include <cmath>
      28             : #include <limits>
      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             : constexpr int MAX_ENTRY_REPORT = 16;
      37             : 
      38             : namespace
      39             : {
      40             : 
      41           0 : int FloatToIntClamp(float fValue)
      42             : {
      43           0 :     if (std::isnan(fValue))
      44           0 :         return 0;
      45           0 :     if (fValue >= static_cast<float>(std::numeric_limits<int>::max()))
      46           0 :         return std::numeric_limits<int>::max();
      47           0 :     if (fValue <= static_cast<float>(std::numeric_limits<int>::min()))
      48           0 :         return std::numeric_limits<int>::min();
      49           0 :     return static_cast<int>(fValue);
      50             : }
      51             : 
      52             : }  // namespace
      53             : 
      54             : /************************************************************************/
      55             : /* ==================================================================== */
      56             : /*                              HFAField                                */
      57             : /* ==================================================================== */
      58             : /************************************************************************/
      59             : 
      60             : /************************************************************************/
      61             : /*                              HFAField()                              */
      62             : /************************************************************************/
      63             : 
      64      103521 : HFAField::HFAField()
      65             :     : nBytes(0), nItemCount(0), chPointer('\0'), chItemType('\0'),
      66             :       pszItemObjectType(nullptr), poItemObjectType(nullptr),
      67      103521 :       papszEnumNames(nullptr), pszFieldName(nullptr)
      68             : {
      69      103521 :     memset(szNumberString, 0, sizeof(szNumberString));
      70      103521 : }
      71             : 
      72             : /************************************************************************/
      73             : /*                             ~HFAField()                              */
      74             : /************************************************************************/
      75             : 
      76      207042 : HFAField::~HFAField()
      77             : 
      78             : {
      79      103521 :     CPLFree(pszItemObjectType);
      80      103521 :     CSLDestroy(papszEnumNames);
      81      103521 :     CPLFree(pszFieldName);
      82      103521 : }
      83             : 
      84             : /************************************************************************/
      85             : /*                             Initialize()                             */
      86             : /************************************************************************/
      87             : 
      88      103521 : const char *HFAField::Initialize(const char *pszInput)
      89             : 
      90             : {
      91             :     // Read the number.
      92      103521 :     nItemCount = atoi(pszInput);
      93      103521 :     if (nItemCount < 0)
      94           0 :         return nullptr;
      95             : 
      96      209244 :     while (*pszInput != '\0' && *pszInput != ':')
      97      105723 :         pszInput++;
      98             : 
      99      103521 :     if (*pszInput == '\0')
     100           0 :         return nullptr;
     101             : 
     102      103521 :     pszInput++;
     103             : 
     104             :     // Is this a pointer?
     105      103521 :     if (*pszInput == 'p' || *pszInput == '*')
     106       23748 :         chPointer = *(pszInput++);
     107             : 
     108             :     // Get the general type.
     109      103521 :     if (*pszInput == '\0')
     110           0 :         return nullptr;
     111             : 
     112      103521 :     chItemType = *(pszInput++);
     113             : 
     114      103521 :     if (strchr("124cCesStlLfdmMbox", chItemType) == nullptr)
     115             :     {
     116           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Unrecognized item type: %c",
     117           1 :                  chItemType);
     118           1 :         return nullptr;
     119             :     }
     120             : 
     121             :     // If this is an object, we extract the type of the object.
     122      103520 :     int i = 0;  // TODO: Describe why i needs to span chItemType blocks.
     123             : 
     124      103520 :     if (chItemType == 'o')
     125             :     {
     126      168015 :         for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
     127             :         {
     128             :         }
     129       12363 :         if (pszInput[i] == '\0')
     130           0 :             return nullptr;
     131             : 
     132       12363 :         pszItemObjectType = static_cast<char *>(CPLMalloc(i + 1));
     133       12363 :         strncpy(pszItemObjectType, pszInput, i);
     134       12363 :         pszItemObjectType[i] = '\0';
     135             : 
     136       12363 :         pszInput += i + 1;
     137             :     }
     138             : 
     139             :     // If this is an inline object, we need to skip past the
     140             :     // definition, and then extract the object class name.
     141             :     //
     142             :     // We ignore the actual definition, so if the object type isn't
     143             :     // already defined, things will not work properly.  See the
     144             :     // file lceugr250_00_pct.aux for an example of inline defs.
     145      103520 :     if (chItemType == 'x' && *pszInput == '{')
     146             :     {
     147        2814 :         int nBraceDepth = 1;
     148        2814 :         pszInput++;
     149             : 
     150             :         // Skip past the definition.
     151       91758 :         while (nBraceDepth > 0 && *pszInput != '\0')
     152             :         {
     153       88944 :             if (*pszInput == '{')
     154        1409 :                 nBraceDepth++;
     155       87535 :             else if (*pszInput == '}')
     156        4223 :                 nBraceDepth--;
     157             : 
     158       88944 :             pszInput++;
     159             :         }
     160        2814 :         if (*pszInput == '\0')
     161           0 :             return nullptr;
     162             : 
     163        2814 :         chItemType = 'o';
     164             : 
     165             :         // Find the comma terminating the type name.
     166       35904 :         for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
     167             :         {
     168             :         }
     169        2814 :         if (pszInput[i] == '\0')
     170           0 :             return nullptr;
     171             : 
     172        2814 :         pszItemObjectType = static_cast<char *>(CPLMalloc(i + 1));
     173        2814 :         strncpy(pszItemObjectType, pszInput, i);
     174        2814 :         pszItemObjectType[i] = '\0';
     175             : 
     176        2814 :         pszInput += i + 1;
     177             :     }
     178             : 
     179             :     // If this is an enumeration we have to extract all the
     180             :     // enumeration values.
     181      103520 :     if (chItemType == 'e')
     182             :     {
     183       14134 :         const int nEnumCount = atoi(pszInput);
     184             : 
     185       14134 :         if (nEnumCount < 0 || nEnumCount > 100000)
     186           0 :             return nullptr;
     187             : 
     188       14134 :         pszInput = strchr(pszInput, ':');
     189       14134 :         if (pszInput == nullptr)
     190           0 :             return nullptr;
     191             : 
     192       14134 :         pszInput++;
     193             : 
     194       14134 :         papszEnumNames =
     195       14134 :             static_cast<char **>(VSICalloc(sizeof(char *), nEnumCount + 1));
     196       14134 :         if (papszEnumNames == nullptr)
     197           0 :             return nullptr;
     198             : 
     199       80022 :         for (int iEnum = 0; iEnum < nEnumCount; iEnum++)
     200             :         {
     201      637808 :             for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
     202             :             {
     203             :             }
     204             : 
     205       65888 :             if (pszInput[i] != ',')
     206           0 :                 return nullptr;
     207             : 
     208       65888 :             char *pszToken = static_cast<char *>(CPLMalloc(i + 1));
     209       65888 :             strncpy(pszToken, pszInput, i);
     210       65888 :             pszToken[i] = '\0';
     211             : 
     212       65888 :             papszEnumNames[iEnum] = pszToken;
     213             : 
     214       65888 :             pszInput += i + 1;
     215             :         }
     216             :     }
     217             : 
     218             :     // Extract the field name.
     219     1000120 :     for (i = 0; pszInput[i] != '\0' && pszInput[i] != ','; i++)
     220             :     {
     221             :     }
     222      103520 :     if (pszInput[i] == '\0')
     223           0 :         return nullptr;
     224             : 
     225      103520 :     pszFieldName = static_cast<char *>(CPLMalloc(i + 1));
     226      103520 :     strncpy(pszFieldName, pszInput, i);
     227      103520 :     pszFieldName[i] = '\0';
     228             : 
     229      103520 :     pszInput += i + 1;
     230             : 
     231      103520 :     return pszInput;
     232             : }
     233             : 
     234             : /************************************************************************/
     235             : /*                            CompleteDefn()                            */
     236             : /*                                                                      */
     237             : /*      Establish size, and pointers to component types.                */
     238             : /************************************************************************/
     239             : 
     240      103514 : bool HFAField::CompleteDefn(HFADictionary *poDict)
     241             : 
     242             : {
     243             :     // Get a reference to the type object if we have a type name
     244             :     // for this field (not a built in).
     245      103514 :     if (pszItemObjectType != nullptr)
     246       15171 :         poItemObjectType = poDict->FindType(pszItemObjectType);
     247             : 
     248             :     // Figure out the size.
     249      103514 :     if (chPointer == 'p')
     250             :     {
     251       16317 :         nBytes = -1;  // We can't know the instance size.
     252             :     }
     253       87197 :     else if (poItemObjectType != nullptr)
     254             :     {
     255       11550 :         if (!poItemObjectType->CompleteDefn(poDict))
     256           2 :             return false;
     257       11548 :         if (poItemObjectType->nBytes == -1)
     258        9382 :             nBytes = -1;
     259        2166 :         else if (poItemObjectType->nBytes != 0 &&
     260        2166 :                  nItemCount > INT_MAX / poItemObjectType->nBytes)
     261           0 :             nBytes = -1;
     262             :         else
     263        2166 :             nBytes = poItemObjectType->nBytes * nItemCount;
     264             : 
     265             :         // TODO(schwehr): What does the 8 represent?
     266       11548 :         if (chPointer == '*' && nBytes != -1)
     267             :         {
     268        2166 :             if (nBytes > INT_MAX - 8)
     269           0 :                 nBytes = -1;
     270             :             else
     271        2166 :                 nBytes += 8;  // Count, and offset.
     272             :         }
     273             :     }
     274             :     else
     275             :     {
     276       75647 :         const int nItemSize = poDict->GetItemSize(chItemType);
     277       75647 :         if (nItemSize != 0 && nItemCount > INT_MAX / nItemSize)
     278        3868 :             nBytes = -1;
     279             :         else
     280       71779 :             nBytes = nItemSize * nItemCount;
     281             :     }
     282      103512 :     return true;
     283             : }
     284             : 
     285             : /************************************************************************/
     286             : /*                                Dump()                                */
     287             : /************************************************************************/
     288             : 
     289           0 : void HFAField::Dump(FILE *fp)
     290             : 
     291             : {
     292             :     const char *pszTypeName;
     293             : 
     294           0 :     switch (chItemType)
     295             :     {
     296           0 :         case '1':
     297           0 :             pszTypeName = "U1";
     298           0 :             break;
     299             : 
     300           0 :         case '2':
     301           0 :             pszTypeName = "U2";
     302           0 :             break;
     303             : 
     304           0 :         case '4':
     305           0 :             pszTypeName = "U4";
     306           0 :             break;
     307             : 
     308           0 :         case 'c':
     309           0 :             pszTypeName = "UCHAR";
     310           0 :             break;
     311             : 
     312           0 :         case 'C':
     313           0 :             pszTypeName = "CHAR";
     314           0 :             break;
     315             : 
     316           0 :         case 'e':
     317           0 :             pszTypeName = "ENUM";
     318           0 :             break;
     319             : 
     320           0 :         case 's':
     321           0 :             pszTypeName = "USHORT";
     322           0 :             break;
     323             : 
     324           0 :         case 'S':
     325           0 :             pszTypeName = "SHORT";
     326           0 :             break;
     327             : 
     328           0 :         case 't':
     329           0 :             pszTypeName = "TIME";
     330           0 :             break;
     331             : 
     332           0 :         case 'l':
     333           0 :             pszTypeName = "ULONG";
     334           0 :             break;
     335             : 
     336           0 :         case 'L':
     337           0 :             pszTypeName = "LONG";
     338           0 :             break;
     339             : 
     340           0 :         case 'f':
     341           0 :             pszTypeName = "FLOAT";
     342           0 :             break;
     343             : 
     344           0 :         case 'd':
     345           0 :             pszTypeName = "DOUBLE";
     346           0 :             break;
     347             : 
     348           0 :         case 'm':
     349           0 :             pszTypeName = "COMPLEX";
     350           0 :             break;
     351             : 
     352           0 :         case 'M':
     353           0 :             pszTypeName = "DCOMPLEX";
     354           0 :             break;
     355             : 
     356           0 :         case 'b':
     357           0 :             pszTypeName = "BASEDATA";
     358           0 :             break;
     359             : 
     360           0 :         case 'o':
     361           0 :             pszTypeName = pszItemObjectType;
     362           0 :             break;
     363             : 
     364           0 :         case 'x':
     365           0 :             pszTypeName = "InlineType";
     366           0 :             break;
     367             : 
     368           0 :         default:
     369           0 :             CPLAssert(false);
     370             :             pszTypeName = "Unknown";
     371             :     }
     372             : 
     373           0 :     CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "    %-19s %c %s[%d];\n", pszTypeName,
     374           0 :                                   chPointer ? chPointer : ' ', pszFieldName,
     375             :                                   nItemCount));
     376             : 
     377           0 :     if (papszEnumNames != nullptr)
     378             :     {
     379           0 :         for (int i = 0; papszEnumNames[i] != nullptr; i++)
     380             :         {
     381           0 :             CPL_IGNORE_RET_VAL(
     382           0 :                 VSIFPrintf(fp, "        %s=%d\n", papszEnumNames[i], i));
     383             :         }
     384             :     }
     385           0 : }
     386             : 
     387             : /************************************************************************/
     388             : /*                            SetInstValue()                            */
     389             : /************************************************************************/
     390             : 
     391       14276 : CPLErr HFAField::SetInstValue(const char *pszField, int nIndexValue,
     392             :                               GByte *pabyData, GUInt32 nDataOffset,
     393             :                               int nDataSize, char chReqType, void *pValue)
     394             : 
     395             : {
     396             :     // If this field contains a pointer, then we will adjust the
     397             :     // data offset relative to it.
     398       14276 :     if (chPointer != '\0')
     399             :     {
     400        7356 :         GUInt32 nCount = 0;
     401             : 
     402             :         // The count returned for BASEDATA's are the contents,
     403             :         // but here we really want to mark it as one BASEDATA instance
     404             :         // (see #2144).
     405        7356 :         if (chItemType == 'b')
     406             :         {
     407          45 :             nCount = 1;
     408             :         }
     409             :         // Set the size from string length.
     410        7311 :         else if (chReqType == 's' && (chItemType == 'c' || chItemType == 'C'))
     411             :         {
     412        1696 :             if (pValue != nullptr)
     413        1398 :                 nCount = static_cast<GUInt32>(strlen((char *)pValue) + 1);
     414             :         }
     415             :         // Set size based on index. Assumes in-order setting of array.
     416             :         else
     417             :         {
     418        5615 :             nCount = nIndexValue + 1;
     419             :         }
     420             : 
     421             :         // TODO(schwehr): What does the 8 represent?
     422        7356 :         if (static_cast<int>(nCount) + 8 > nDataSize)
     423             :         {
     424           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     425             :                      "Attempt to extend field %s in node past end of data, "
     426             :                      "not currently supported.",
     427             :                      pszField);
     428           0 :             return CE_Failure;
     429             :         }
     430             : 
     431             :         // We will update the object count iff we are writing beyond the end.
     432        7356 :         GUInt32 nOffset = 0;
     433        7356 :         memcpy(&nOffset, pabyData, 4);
     434             :         HFAStandard(4, &nOffset);
     435        7356 :         if (nOffset < nCount)
     436             :         {
     437        5688 :             nOffset = nCount;
     438             :             HFAStandard(4, &nOffset);
     439        5688 :             memcpy(pabyData, &nOffset, 4);
     440             :         }
     441             : 
     442        7356 :         if (pValue == nullptr)
     443         298 :             nOffset = 0;
     444             :         else
     445        7058 :             nOffset = nDataOffset + 8;
     446             :         HFAStandard(4, &nOffset);
     447        7356 :         memcpy(pabyData + 4, &nOffset, 4);
     448             : 
     449        7356 :         pabyData += 8;
     450             : 
     451        7356 :         nDataOffset += 8;
     452        7356 :         nDataSize -= 8;
     453             :     }
     454             : 
     455             :     // Pointers to char or uchar arrays requested as strings are
     456             :     // handled as a special case.
     457       14276 :     if ((chItemType == 'c' || chItemType == 'C') && chReqType == 's')
     458             :     {
     459        1696 :         int nBytesToCopy = 0;
     460             : 
     461        1696 :         if (nBytes == -1)
     462             :         {
     463        1696 :             if (pValue != nullptr)
     464        1398 :                 nBytesToCopy = static_cast<int>(strlen((char *)pValue) + 1);
     465             :         }
     466             :         else
     467             :         {
     468           0 :             nBytesToCopy = nBytes;
     469             :         }
     470             : 
     471        1696 :         if (nBytesToCopy > nDataSize)
     472             :         {
     473           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     474             :                      "Attempt to extend field %s in node past end of data "
     475             :                      "not currently supported.",
     476             :                      pszField);
     477           0 :             return CE_Failure;
     478             :         }
     479             : 
     480        1696 :         memset(pabyData, 0, nBytesToCopy);
     481             : 
     482        1696 :         if (pValue != nullptr)
     483        1398 :             strncpy((char *)pabyData, (char *)pValue, nBytesToCopy);
     484             : 
     485        1696 :         return CE_None;
     486             :     }
     487             : 
     488             :     // Translate the passed type into different representations.
     489       12580 :     int nIntValue = 0;
     490       12580 :     double dfDoubleValue = 0.0;
     491             : 
     492       12580 :     if (chReqType == 's')
     493             :     {
     494        2016 :         CPLAssert(pValue != nullptr);
     495        2016 :         nIntValue = atoi((char *)pValue);
     496        2016 :         dfDoubleValue = CPLAtof((char *)pValue);
     497             :     }
     498       10564 :     else if (chReqType == 'd')
     499             :     {
     500        7147 :         CPLAssert(pValue != nullptr);
     501        7147 :         dfDoubleValue = *((double *)pValue);
     502        7147 :         if (dfDoubleValue > INT_MAX)
     503           0 :             nIntValue = INT_MAX;
     504        7147 :         else if (dfDoubleValue < INT_MIN)
     505           1 :             nIntValue = INT_MIN;
     506             :         else
     507        7146 :             nIntValue = static_cast<int>(dfDoubleValue);
     508             :     }
     509        3417 :     else if (chReqType == 'i')
     510             :     {
     511        3417 :         CPLAssert(pValue != nullptr);
     512        3417 :         nIntValue = *((int *)pValue);
     513        3417 :         dfDoubleValue = nIntValue;
     514             :     }
     515           0 :     else if (chReqType == 'p')
     516             :     {
     517           0 :         CPLError(
     518             :             CE_Failure, CPLE_NotSupported,
     519             :             "HFAField::SetInstValue() not supported yet for pointer values.");
     520             : 
     521           0 :         return CE_Failure;
     522             :     }
     523             :     else
     524             :     {
     525           0 :         CPLAssert(false);
     526             :         return CE_Failure;
     527             :     }
     528             : 
     529             :     // Handle by type.
     530       12580 :     switch (chItemType)
     531             :     {
     532           0 :         case 'c':
     533             :         case 'C':
     534           0 :             if (nIndexValue + 1 > nDataSize)
     535             :             {
     536           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     537             :                          "Attempt to extend field %s in node past end of data, "
     538             :                          "not currently supported.",
     539             :                          pszField);
     540           0 :                 return CE_Failure;
     541             :             }
     542             : 
     543           0 :             if (chReqType == 's')
     544             :             {
     545           0 :                 CPLAssert(pValue != nullptr);
     546           0 :                 pabyData[nIndexValue] = ((char *)pValue)[0];
     547             :             }
     548             :             else
     549             :             {
     550           0 :                 pabyData[nIndexValue] = static_cast<char>(nIntValue);
     551             :             }
     552           0 :             break;
     553             : 
     554        1441 :         case 'e':
     555             :         case 's':
     556             :         {
     557        1441 :             if (chItemType == 'e' && chReqType == 's')
     558             :             {
     559         882 :                 CPLAssert(pValue != nullptr);
     560         882 :                 nIntValue = CSLFindString(papszEnumNames, (char *)pValue);
     561         882 :                 if (nIntValue == -1)
     562             :                 {
     563           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     564             :                              "Attempt to set enumerated field with unknown"
     565             :                              " value `%s'.",
     566             :                              (char *)pValue);
     567           0 :                     return CE_Failure;
     568             :                 }
     569             :             }
     570             : 
     571        1441 :             if (nIndexValue * 2 + 2 > nDataSize)
     572             :             {
     573           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     574             :                          "Attempt to extend field %s in node past end of data, "
     575             :                          "not currently supported.",
     576             :                          pszField);
     577           0 :                 return CE_Failure;
     578             :             }
     579             : 
     580             :             // TODO(schwehr): Warn on clamping.
     581        1441 :             unsigned short nNumber = static_cast<unsigned short>(nIntValue);
     582             :             // TODO(schwehr): What is this 2?
     583             :             HFAStandard(2, &nNumber);
     584        1441 :             memcpy(pabyData + nIndexValue * 2, &nNumber, 2);
     585             :         }
     586        1441 :         break;
     587             : 
     588           0 :         case 'S':
     589             :         {
     590           0 :             if (nIndexValue * 2 + 2 > nDataSize)
     591             :             {
     592           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     593             :                          "Attempt to extend field %s in node past end of data, "
     594             :                          "not currently supported.",
     595             :                          pszField);
     596           0 :                 return CE_Failure;
     597             :             }
     598             : 
     599             :             // TODO(schwehr): Warn on clamping.
     600           0 :             short nNumber = static_cast<short>(nIntValue);
     601             :             // TODO(schwehr): What is this 2?
     602             :             HFAStandard(2, &nNumber);
     603           0 :             memcpy(pabyData + nIndexValue * 2, &nNumber, 2);
     604             :         }
     605           0 :         break;
     606             : 
     607        2208 :         case 't':
     608             :         case 'l':
     609             :         {
     610        2208 :             if (nIndexValue * 4 + 4 > nDataSize)
     611             :             {
     612           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     613             :                          "Attempt to extend field %s in node past end of data, "
     614             :                          "not currently supported.",
     615             :                          pszField);
     616           0 :                 return CE_Failure;
     617             :             }
     618             : 
     619        2208 :             GUInt32 nNumber = nIntValue;
     620             :             // TODO(schwehr): What is this 4?
     621             :             HFAStandard(4, &nNumber);
     622        2208 :             memcpy(pabyData + nIndexValue * 4, &nNumber, 4);
     623             :         }
     624        2208 :         break;
     625             : 
     626         581 :         case 'L':
     627             :         {
     628         581 :             if (nIndexValue * 4 + 4 > nDataSize)
     629             :             {
     630           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     631             :                          "Attempt to extend field %s in node past end of data, "
     632             :                          "not currently supported.",
     633             :                          pszField);
     634           0 :                 return CE_Failure;
     635             :             }
     636             : 
     637         581 :             GInt32 nNumber = nIntValue;
     638             :             HFAStandard(4, &nNumber);
     639         581 :             memcpy(pabyData + nIndexValue * 4, &nNumber, 4);
     640             :         }
     641         581 :         break;
     642             : 
     643           0 :         case 'f':
     644             :         {
     645           0 :             if (nIndexValue * 4 + 4 > nDataSize)
     646             :             {
     647           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     648             :                          "Attempt to extend field %s in node past end of data, "
     649             :                          "not currently supported.",
     650             :                          pszField);
     651           0 :                 return CE_Failure;
     652             :             }
     653             : 
     654             :             // TODO(schwehr): Warn on clamping.
     655           0 :             float fNumber = static_cast<float>(dfDoubleValue);
     656             :             // TODO(schwehr): 4 == sizeof(float)?
     657             :             HFAStandard(4, &fNumber);
     658           0 :             memcpy(pabyData + nIndexValue * 4, &fNumber, 4);
     659             :         }
     660           0 :         break;
     661             : 
     662        5414 :         case 'd':
     663             :         {
     664        5414 :             if (nIndexValue * 8 + 8 > nDataSize)
     665             :             {
     666           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     667             :                          "Attempt to extend field %s in node past end of data, "
     668             :                          "not currently supported.",
     669             :                          pszField);
     670           0 :                 return CE_Failure;
     671             :             }
     672             : 
     673        5414 :             double dfNumber = dfDoubleValue;
     674             :             HFAStandard(8, &dfNumber);
     675        5414 :             memcpy(pabyData + nIndexValue * 8, &dfNumber, 8);
     676             :         }
     677        5414 :         break;
     678             : 
     679          45 :         case 'b':
     680             :         {
     681             :             // Extract existing rows, columns, and datatype.
     682          45 :             GInt32 nRows = 1;  // TODO(schwehr): Why init to 1 instead of 0?
     683          45 :             memcpy(&nRows, pabyData, 4);
     684             :             HFAStandard(4, &nRows);
     685             : 
     686          45 :             GInt32 nColumns = 1;  // TODO(schwehr): Why init to 1 instead of 0?
     687          45 :             memcpy(&nColumns, pabyData + 4, 4);
     688             :             HFAStandard(4, &nColumns);
     689             : 
     690          45 :             GInt16 nBaseItemType = 0;
     691          45 :             memcpy(&nBaseItemType, pabyData + 8, 2);
     692             :             HFAStandard(2, &nBaseItemType);
     693             : 
     694             :             // Are we using special index values to update the rows, columns
     695             :             // or type?
     696             : 
     697          45 :             if (nIndexValue == -3)
     698          10 :                 nBaseItemType = static_cast<GInt16>(nIntValue);
     699          35 :             else if (nIndexValue == -2)
     700          10 :                 nColumns = nIntValue;
     701          25 :             else if (nIndexValue == -1)
     702          10 :                 nRows = nIntValue;
     703             : 
     704          45 :             if (nIndexValue < -3 || nIndexValue >= nRows * nColumns)
     705           1 :                 return CE_Failure;
     706             : 
     707             :             // Write back the rows, columns and basedatatype.
     708             :             HFAStandard(4, &nRows);
     709          44 :             memcpy(pabyData, &nRows, 4);
     710             :             HFAStandard(4, &nColumns);
     711          44 :             memcpy(pabyData + 4, &nColumns, 4);
     712             :             HFAStandard(2, &nBaseItemType);
     713          44 :             memcpy(pabyData + 8, &nBaseItemType, 2);
     714             :             HFAStandard(2, &nBaseItemType);  // Swap back for our use.
     715             : 
     716          44 :             if (nBaseItemType < EPT_MIN || nBaseItemType > EPT_MAX)
     717           0 :                 return CE_Failure;
     718          44 :             const EPTType eBaseItemType = static_cast<EPTType>(nBaseItemType);
     719             : 
     720             :             // We ignore the 2 byte objecttype value.
     721             : 
     722          44 :             nDataSize -= 12;
     723             : 
     724          44 :             if (nIndexValue >= 0)
     725             :             {
     726          28 :                 if ((nIndexValue + 1) *
     727          14 :                         (HFAGetDataTypeBits(eBaseItemType) / 8) >
     728             :                     nDataSize)
     729             :                 {
     730           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     731             :                              "Attempt to extend field %s in node past end of "
     732             :                              "data, not currently supported.",
     733             :                              pszField);
     734           0 :                     return CE_Failure;
     735             :                 }
     736             : 
     737          14 :                 if (eBaseItemType == EPT_f64)
     738             :                 {
     739          14 :                     double dfNumber = dfDoubleValue;
     740             : 
     741             :                     HFAStandard(8, &dfNumber);
     742          14 :                     memcpy(pabyData + 12 + nIndexValue * 8, &dfNumber, 8);
     743             :                 }
     744           0 :                 else if (eBaseItemType == EPT_u8)
     745             :                 {
     746             :                     // TODO(schwehr): Warn on clamping.
     747           0 :                     unsigned char nNumber =
     748           0 :                         static_cast<unsigned char>(dfDoubleValue);
     749           0 :                     memcpy(pabyData + 12 + nIndexValue, &nNumber, 1);
     750             :                 }
     751             :                 else
     752             :                 {
     753           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     754             :                              "Setting basedata field %s with type %s "
     755             :                              "not currently supported.",
     756             :                              pszField, HFAGetDataTypeName(eBaseItemType));
     757           0 :                     return CE_Failure;
     758             :                 }
     759             :             }
     760             :         }
     761          44 :         break;
     762             : 
     763        2891 :         case 'o':
     764        2891 :             if (poItemObjectType != nullptr)
     765             :             {
     766        2891 :                 int nExtraOffset = 0;
     767             : 
     768        2891 :                 if (poItemObjectType->nBytes > 0)
     769             :                 {
     770        1193 :                     if (nIndexValue != 0 &&
     771          43 :                         poItemObjectType->nBytes > INT_MAX / nIndexValue)
     772             :                     {
     773           0 :                         return CE_Failure;
     774             :                     }
     775        1193 :                     nExtraOffset = poItemObjectType->nBytes * nIndexValue;
     776             :                 }
     777             :                 else
     778             :                 {
     779        1707 :                     for (int iIndexCounter = 0; iIndexCounter < nIndexValue &&
     780             :                                                 nExtraOffset < nDataSize;
     781             :                          iIndexCounter++)
     782             :                     {
     783           9 :                         std::set<HFAField *> oVisitedFields;
     784          18 :                         const int nInc = poItemObjectType->GetInstBytes(
     785           9 :                             pabyData + nExtraOffset, nDataSize - nExtraOffset,
     786             :                             oVisitedFields);
     787           9 :                         if (nInc <= 0 || nExtraOffset > INT_MAX - nInc)
     788             :                         {
     789           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
     790             :                                      "Invalid return value");
     791           0 :                             return CE_Failure;
     792             :                         }
     793             : 
     794           9 :                         nExtraOffset += nInc;
     795             :                     }
     796             :                 }
     797             : 
     798        2891 :                 if (nExtraOffset >= nDataSize)
     799           1 :                     return CE_Failure;
     800             : 
     801        2890 :                 if (pszField != nullptr && strlen(pszField) > 0)
     802             :                 {
     803        5780 :                     return poItemObjectType->SetInstValue(
     804        2890 :                         pszField, pabyData + nExtraOffset,
     805        2890 :                         nDataOffset + nExtraOffset, nDataSize - nExtraOffset,
     806        2890 :                         chReqType, pValue);
     807             :                 }
     808             :                 else
     809             :                 {
     810           0 :                     CPLAssert(false);
     811             :                     return CE_Failure;
     812             :                 }
     813             :             }
     814           0 :             break;
     815             : 
     816           0 :         default:
     817           0 :             CPLAssert(false);
     818             :             return CE_Failure;
     819             :             break;
     820             :     }
     821             : 
     822        9688 :     return CE_None;
     823             : }
     824             : 
     825             : /************************************************************************/
     826             : /*                          ExtractInstValue()                          */
     827             : /*                                                                      */
     828             : /*      Extract the value of an instance of a field.                    */
     829             : /*                                                                      */
     830             : /*      pszField should be NULL if this field is not a                  */
     831             : /*      substructure.                                                   */
     832             : /************************************************************************/
     833             : 
     834       46020 : bool HFAField::ExtractInstValue(const char *pszField, int nIndexValue,
     835             :                                 GByte *pabyData, GUInt32 nDataOffset,
     836             :                                 int nDataSize, char chReqType, void *pReqReturn,
     837             :                                 int *pnRemainingDataSize)
     838             : 
     839             : {
     840       46020 :     const int nInstItemCount = GetInstCount(pabyData, nDataSize);
     841             : 
     842       46020 :     if (pnRemainingDataSize)
     843         424 :         *pnRemainingDataSize = -1;
     844             : 
     845             :     // Check the index value is valid.
     846             :     // Eventually this will have to account for variable fields.
     847       46020 :     if (nIndexValue < 0 || nIndexValue >= nInstItemCount)
     848             :     {
     849         558 :         if (chItemType == 'b' && nIndexValue >= -3 && nIndexValue < 0)
     850             :             /* ok - special index values */;
     851             :         else
     852         558 :             return false;
     853             :     }
     854             : 
     855             :     // If this field contains a pointer, then we will adjust the
     856             :     // data offset relative to it.
     857       45462 :     if (chPointer != '\0')
     858             :     {
     859       19036 :         if (nDataSize < 8)
     860             :         {
     861           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     862           0 :             return false;
     863             :         }
     864             : 
     865       19036 :         GUInt32 nOffset = 0;
     866       19036 :         memcpy(&nOffset, pabyData + 4, 4);
     867             :         HFAStandard(4, &nOffset);
     868             : 
     869             : #if DEBUG_VERBOSE
     870             :         if (nOffset != static_cast<GUInt32>(nDataOffset + 8))
     871             :         {
     872             :             // TODO(schwehr): Debug why this is happening.
     873             :             CPLError(CE_Warning, CPLE_AppDefined,
     874             :                      "ExtractInstValue: "
     875             :                      "%s.%s points at %d, not %d as expected",
     876             :                      pszFieldName, pszField ? pszField : "", nOffset,
     877             :                      nDataOffset + 8);
     878             :         }
     879             : #endif
     880             : 
     881       19036 :         pabyData += 8;
     882       19036 :         nDataOffset += 8;
     883       19036 :         nDataSize -= 8;
     884             :     }
     885             : 
     886             :     // Pointers to char or uchar arrays requested as strings are
     887             :     // handled as a special case.
     888       45462 :     if ((chItemType == 'c' || chItemType == 'C') && chReqType == 's')
     889             :     {
     890        2011 :         *((GByte **)pReqReturn) = pabyData;
     891        2011 :         if (pnRemainingDataSize)
     892         212 :             *pnRemainingDataSize = nDataSize;
     893        2011 :         return pabyData != nullptr;
     894             :     }
     895             : 
     896             :     // Handle by type.
     897       43451 :     char *pszStringRet = nullptr;
     898       43451 :     int nIntRet = 0;
     899       43451 :     double dfDoubleRet = 0.0;
     900       43451 :     GByte *pabyRawData = nullptr;
     901             : 
     902       43451 :     switch (chItemType)
     903             :     {
     904           0 :         case 'c':
     905             :         case 'C':
     906           0 :             if (nIndexValue >= nDataSize)
     907             :             {
     908           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     909           0 :                 return false;
     910             :             }
     911           0 :             nIntRet = pabyData[nIndexValue];
     912           0 :             dfDoubleRet = nIntRet;
     913           0 :             break;
     914             : 
     915        8728 :         case 'e':
     916             :         case 's':
     917             :         {
     918        8728 :             if (nIndexValue * 2 + 2 > nDataSize)
     919             :             {
     920           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     921           0 :                 return false;
     922             :             }
     923        8728 :             unsigned short nNumber = 0;
     924        8728 :             memcpy(&nNumber, pabyData + nIndexValue * 2, 2);
     925             :             HFAStandard(2, &nNumber);
     926        8728 :             nIntRet = nNumber;
     927        8728 :             dfDoubleRet = nIntRet;
     928             : 
     929       17456 :             if (chItemType == 'e' &&
     930        8728 :                 nNumber < static_cast<unsigned>(CSLCount(papszEnumNames)))
     931             :             {
     932        8727 :                 pszStringRet = papszEnumNames[nNumber];
     933             :             }
     934             :         }
     935        8728 :         break;
     936             : 
     937           0 :         case 'S':
     938             :         {
     939           0 :             if (nIndexValue * 2 + 2 > nDataSize)
     940             :             {
     941           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     942           0 :                 return false;
     943             :             }
     944           0 :             short nNumber = 0;
     945           0 :             memcpy(&nNumber, pabyData + nIndexValue * 2, 2);
     946             :             HFAStandard(2, &nNumber);
     947           0 :             nIntRet = nNumber;
     948           0 :             dfDoubleRet = nIntRet;
     949             :         }
     950           0 :         break;
     951             : 
     952       10462 :         case 't':
     953             :         case 'l':
     954             :         {
     955       10462 :             if (nIndexValue * 4 + 4 > nDataSize)
     956             :             {
     957           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     958           0 :                 return false;
     959             :             }
     960       10462 :             GUInt32 nNumber = 0;
     961       10462 :             memcpy(&nNumber, pabyData + nIndexValue * 4, 4);
     962             :             HFAStandard(4, &nNumber);
     963       10462 :             nIntRet = nNumber;
     964       10462 :             dfDoubleRet = nIntRet;
     965             :         }
     966       10462 :         break;
     967             : 
     968        3037 :         case 'L':
     969             :         {
     970        3037 :             if (nIndexValue * 4 + 4 > nDataSize)
     971             :             {
     972           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     973           0 :                 return false;
     974             :             }
     975        3037 :             GInt32 nNumber = 0;
     976             :             // TODO(schwehr): What is 4?
     977        3037 :             memcpy(&nNumber, pabyData + nIndexValue * 4, 4);
     978             :             HFAStandard(4, &nNumber);
     979        3037 :             nIntRet = nNumber;
     980        3037 :             dfDoubleRet = nIntRet;
     981             :         }
     982        3037 :         break;
     983             : 
     984           0 :         case 'f':
     985             :         {
     986           0 :             if (nIndexValue * 4 + 4 > nDataSize)
     987             :             {
     988           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
     989           0 :                 return false;
     990             :             }
     991           0 :             float fNumber = 0.0f;
     992             :             // TODO(schwehr): What is 4?
     993           0 :             memcpy(&fNumber, pabyData + nIndexValue * 4, 4);
     994             :             HFAStandard(4, &fNumber);
     995           0 :             if (static_cast<double>(fNumber) >
     996           0 :                     std::numeric_limits<int>::max() ||
     997           0 :                 static_cast<double>(fNumber) <
     998           0 :                     std::numeric_limits<int>::min() ||
     999           0 :                 std::isnan(fNumber))
    1000             :             {
    1001           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Too large for int: %f",
    1002             :                          fNumber);
    1003           0 :                 return false;
    1004             :             }
    1005           0 :             dfDoubleRet = fNumber;
    1006           0 :             nIntRet = static_cast<int>(fNumber);
    1007             :         }
    1008           0 :         break;
    1009             : 
    1010        7251 :         case 'd':
    1011             :         {
    1012        7251 :             if (nIndexValue * 8 + 8 > nDataSize)
    1013             :             {
    1014           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1015           0 :                 return false;
    1016             :             }
    1017        7251 :             double dfNumber = 0;
    1018        7251 :             memcpy(&dfNumber, pabyData + nIndexValue * 8, 8);
    1019             :             HFAStandard(8, &dfNumber);
    1020        7251 :             dfDoubleRet = dfNumber;
    1021        7251 :             if (dfNumber > std::numeric_limits<int>::max() ||
    1022       14502 :                 dfNumber < std::numeric_limits<int>::min() ||
    1023        7251 :                 std::isnan(dfNumber))
    1024             :             {
    1025           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Too large for int: %f",
    1026             :                          dfNumber);
    1027           0 :                 return false;
    1028             :             }
    1029        7251 :             nIntRet = static_cast<int>(dfNumber);
    1030             :         }
    1031        7251 :         break;
    1032             : 
    1033         135 :         case 'b':
    1034             :         {
    1035         135 :             if (nDataSize < 12)
    1036           0 :                 return false;
    1037             : 
    1038         135 :             GInt32 nRows = 0;
    1039         135 :             memcpy(&nRows, pabyData, 4);
    1040             :             HFAStandard(4, &nRows);
    1041             : 
    1042         135 :             GInt32 nColumns = 0;
    1043         135 :             memcpy(&nColumns, pabyData + 4, 4);
    1044             :             HFAStandard(4, &nColumns);
    1045             : 
    1046         135 :             GInt16 nBaseItemType = 0;
    1047         135 :             memcpy(&nBaseItemType, pabyData + 8, 2);
    1048             :             HFAStandard(2, &nBaseItemType);
    1049             :             // We ignore the 2 byte objecttype value.
    1050             : 
    1051         135 :             if (nIndexValue < -3 || nRows <= 0 || nColumns <= 0 ||
    1052         135 :                 nRows > INT_MAX / nColumns || nIndexValue >= nRows * nColumns)
    1053           0 :                 return false;
    1054             : 
    1055         135 :             pabyData += 12;
    1056         135 :             nDataSize -= 12;
    1057             : 
    1058         135 :             if (nIndexValue == -3)
    1059             :             {
    1060           0 :                 dfDoubleRet = nBaseItemType;
    1061           0 :                 nIntRet = nBaseItemType;
    1062             :             }
    1063         135 :             else if (nIndexValue == -2)
    1064             :             {
    1065           0 :                 dfDoubleRet = nColumns;
    1066           0 :                 nIntRet = nColumns;
    1067             :             }
    1068         135 :             else if (nIndexValue == -1)
    1069             :             {
    1070           0 :                 dfDoubleRet = nRows;
    1071           0 :                 nIntRet = nRows;
    1072             :             }
    1073         135 :             else if (nBaseItemType == EPT_u1)
    1074             :             {
    1075             :                 // TODO(schwehr): What are these constants like 8 and 0x7?
    1076           0 :                 if (nIndexValue * 8 >= nDataSize)
    1077             :                 {
    1078           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1079           0 :                     return false;
    1080             :                 }
    1081             : 
    1082           0 :                 if (pabyData[nIndexValue >> 3] & (1 << (nIndexValue & 0x7)))
    1083             :                 {
    1084           0 :                     dfDoubleRet = 1;
    1085           0 :                     nIntRet = 1;
    1086             :                 }
    1087             :                 else
    1088             :                 {
    1089           0 :                     dfDoubleRet = 0.0;
    1090           0 :                     nIntRet = 0;
    1091             :                 }
    1092             :             }
    1093         135 :             else if (nBaseItemType == EPT_u2)
    1094             :             {
    1095           0 :                 const int nBitOffset = nIndexValue & 0x3;
    1096           0 :                 const int nByteOffset = nIndexValue >> 2;
    1097             : 
    1098           0 :                 if (nByteOffset >= nDataSize)
    1099             :                 {
    1100           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1101           0 :                     return false;
    1102             :                 }
    1103             : 
    1104           0 :                 const int nMask = 0x3;
    1105           0 :                 nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
    1106           0 :                 dfDoubleRet = nIntRet;
    1107             :             }
    1108         135 :             else if (nBaseItemType == EPT_u4)
    1109             :             {
    1110           0 :                 const int nBitOffset = nIndexValue & 0x7;
    1111           0 :                 const int nByteOffset = nIndexValue >> 3;
    1112             : 
    1113           0 :                 if (nByteOffset >= nDataSize)
    1114             :                 {
    1115           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1116           0 :                     return false;
    1117             :                 }
    1118             : 
    1119           0 :                 const int nMask = 0x7;
    1120           0 :                 nIntRet = (pabyData[nByteOffset] >> nBitOffset) & nMask;
    1121           0 :                 dfDoubleRet = nIntRet;
    1122             :             }
    1123         135 :             else if (nBaseItemType == EPT_u8)
    1124             :             {
    1125          18 :                 if (nIndexValue >= nDataSize)
    1126             :                 {
    1127           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1128           0 :                     return false;
    1129             :                 }
    1130          18 :                 dfDoubleRet = pabyData[nIndexValue];
    1131          18 :                 nIntRet = pabyData[nIndexValue];
    1132             :             }
    1133         117 :             else if (nBaseItemType == EPT_s8)
    1134             :             {
    1135           0 :                 if (nIndexValue >= nDataSize)
    1136             :                 {
    1137           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1138           0 :                     return false;
    1139             :                 }
    1140           0 :                 dfDoubleRet = ((signed char *)pabyData)[nIndexValue];
    1141           0 :                 nIntRet = ((signed char *)pabyData)[nIndexValue];
    1142             :             }
    1143         117 :             else if (nBaseItemType == EPT_s16)
    1144             :             {
    1145           0 :                 if (nIndexValue * 2 + 2 > nDataSize)
    1146             :                 {
    1147           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1148           0 :                     return false;
    1149             :                 }
    1150           0 :                 GInt16 nValue = 0;
    1151           0 :                 memcpy(&nValue, pabyData + 2 * nIndexValue, 2);
    1152             :                 HFAStandard(2, &nValue);
    1153             : 
    1154           0 :                 dfDoubleRet = nValue;
    1155           0 :                 nIntRet = nValue;
    1156             :             }
    1157         117 :             else if (nBaseItemType == EPT_u16)
    1158             :             {
    1159           0 :                 if (nIndexValue * 2 + 2 > nDataSize)
    1160             :                 {
    1161           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1162           0 :                     return false;
    1163             :                 }
    1164           0 :                 GUInt16 nValue = 0;
    1165           0 :                 memcpy(&nValue, pabyData + 2 * nIndexValue, 2);
    1166             :                 HFAStandard(2, &nValue);
    1167             : 
    1168           0 :                 dfDoubleRet = nValue;
    1169           0 :                 nIntRet = nValue;
    1170             :             }
    1171         117 :             else if (nBaseItemType == EPT_s32)
    1172             :             {
    1173           0 :                 if (nIndexValue * 4 + 4 > nDataSize)
    1174             :                 {
    1175           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1176           0 :                     return false;
    1177             :                 }
    1178           0 :                 GInt32 nValue = 0;
    1179           0 :                 memcpy(&nValue, pabyData + 4 * nIndexValue, 4);
    1180             :                 HFAStandard(4, &nValue);
    1181             : 
    1182           0 :                 dfDoubleRet = nValue;
    1183           0 :                 nIntRet = nValue;
    1184             :             }
    1185         117 :             else if (nBaseItemType == EPT_u32)
    1186             :             {
    1187           0 :                 if (nIndexValue * 4 + 4 > nDataSize)
    1188             :                 {
    1189           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1190           0 :                     return false;
    1191             :                 }
    1192           0 :                 GUInt32 nValue = 0;
    1193           0 :                 memcpy(&nValue, pabyData + 4 * nIndexValue, 4);
    1194             :                 HFAStandard(4, &nValue);
    1195             : 
    1196           0 :                 dfDoubleRet = nValue;
    1197           0 :                 nIntRet = nValue;
    1198             :             }
    1199         117 :             else if (nBaseItemType == EPT_f32)
    1200             :             {
    1201           0 :                 if (nIndexValue * 4 + 4 > nDataSize)
    1202             :                 {
    1203           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1204           0 :                     return false;
    1205             :                 }
    1206           0 :                 float fValue = 0.0f;
    1207           0 :                 memcpy(&fValue, pabyData + 4 * nIndexValue, 4);
    1208             :                 HFAStandard(4, &fValue);
    1209             : 
    1210           0 :                 dfDoubleRet = fValue;
    1211           0 :                 nIntRet = FloatToIntClamp(fValue);
    1212             :             }
    1213         117 :             else if (nBaseItemType == EPT_f64)
    1214             :             {
    1215         117 :                 if (nIndexValue * 8 + 8 > nDataSize)
    1216             :                 {
    1217           0 :                     CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1218           0 :                     return false;
    1219             :                 }
    1220         117 :                 double dfValue = 0.0;
    1221         117 :                 memcpy(&dfValue, pabyData + 8 * nIndexValue, 8);
    1222             :                 HFAStandard(8, &dfValue);
    1223             : 
    1224         117 :                 dfDoubleRet = dfValue;
    1225         117 :                 const int nMax = std::numeric_limits<int>::max();
    1226         117 :                 const int nMin = std::numeric_limits<int>::min();
    1227         117 :                 if (dfDoubleRet >= nMax)
    1228             :                 {
    1229           0 :                     nIntRet = nMax;
    1230             :                 }
    1231         117 :                 else if (dfDoubleRet <= nMin)
    1232             :                 {
    1233           1 :                     nIntRet = nMin;
    1234             :                 }
    1235         116 :                 else if (std::isnan(dfDoubleRet))
    1236             :                 {
    1237           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
    1238             :                              "NaN converted to INT_MAX.");
    1239           0 :                     nIntRet = nMax;
    1240             :                 }
    1241             :                 else
    1242             :                 {
    1243         116 :                     nIntRet = static_cast<int>(dfDoubleRet);
    1244             :                 }
    1245             :             }
    1246             :             else
    1247             :             {
    1248           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1249             :                          "Unknown base item type: %d", nBaseItemType);
    1250           0 :                 return false;
    1251             :             }
    1252             :         }
    1253         135 :         break;
    1254             : 
    1255       13838 :         case 'o':
    1256       13838 :             if (poItemObjectType != nullptr)
    1257             :             {
    1258       13838 :                 int nExtraOffset = 0;
    1259             : 
    1260       13838 :                 if (poItemObjectType->nBytes > 0)
    1261             :                 {
    1262       11304 :                     if (nIndexValue != 0 &&
    1263        9228 :                         poItemObjectType->nBytes > INT_MAX / nIndexValue)
    1264             :                         // TODO(schwehr): Why was this CE_Failure when the
    1265             :                         // others are false?
    1266           0 :                         return false;
    1267       11304 :                     nExtraOffset = poItemObjectType->nBytes * nIndexValue;
    1268             :                 }
    1269             :                 else
    1270             :                 {
    1271        2555 :                     for (int iIndexCounter = 0; iIndexCounter < nIndexValue &&
    1272             :                                                 nExtraOffset < nDataSize;
    1273             :                          iIndexCounter++)
    1274             :                     {
    1275          21 :                         std::set<HFAField *> oVisitedFields;
    1276          42 :                         const int nInc = poItemObjectType->GetInstBytes(
    1277          21 :                             pabyData + nExtraOffset, nDataSize - nExtraOffset,
    1278             :                             oVisitedFields);
    1279          21 :                         if (nInc <= 0 || nExtraOffset > INT_MAX - nInc)
    1280             :                         {
    1281           0 :                             CPLError(CE_Failure, CPLE_AppDefined,
    1282             :                                      "Invalid return value");
    1283             :                             // TODO(schwehr): Verify this false is okay.
    1284           0 :                             return false;
    1285             :                         }
    1286             : 
    1287          21 :                         nExtraOffset += nInc;
    1288             :                     }
    1289             :                 }
    1290             : 
    1291       13838 :                 if (nExtraOffset >= nDataSize)
    1292           0 :                     return false;
    1293             : 
    1294       13838 :                 pabyRawData = pabyData + nExtraOffset;
    1295             : 
    1296       13838 :                 if (pszField != nullptr && strlen(pszField) > 0)
    1297             :                 {
    1298       27676 :                     return poItemObjectType->ExtractInstValue(
    1299       13838 :                         pszField, pabyRawData, nDataOffset + nExtraOffset,
    1300             :                         nDataSize - nExtraOffset, chReqType, pReqReturn,
    1301       13838 :                         pnRemainingDataSize);
    1302             :                 }
    1303             :             }
    1304             :             else
    1305             :             {
    1306             :                 // E. Rouault: not completely sure about this, but helps avoid
    1307             :                 // DoS timeouts in cases like
    1308             :                 // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1806
    1309           0 :                 return false;
    1310             :             }
    1311           0 :             break;
    1312             : 
    1313           0 :         default:
    1314           0 :             return false;
    1315             :             break;
    1316             :     }
    1317             : 
    1318             :     // Return the appropriate representation.
    1319       29613 :     if (chReqType == 's')
    1320             :     {
    1321        1085 :         if (pszStringRet == nullptr)
    1322             :         {
    1323             :             // HFAEntry:: BuildEntryFromMIFObject() expects to have always 8
    1324             :             // bytes before the data. In normal situations, it should not go
    1325             :             // here, but that can happen if the file is corrupted so reserve the
    1326             :             // first 8 bytes before the string to contain null bytes.
    1327          39 :             memset(szNumberString, 0, 8);
    1328          39 :             CPLsnprintf(szNumberString + 8, sizeof(szNumberString) - 8, "%.14g",
    1329             :                         dfDoubleRet);
    1330          39 :             pszStringRet = szNumberString + 8;
    1331             :         }
    1332             : 
    1333        1085 :         *((char **)pReqReturn) = pszStringRet;
    1334        1085 :         return true;
    1335             :     }
    1336       28528 :     else if (chReqType == 'd')
    1337             :     {
    1338        7347 :         *((double *)pReqReturn) = dfDoubleRet;
    1339        7347 :         return true;
    1340             :     }
    1341       21181 :     else if (chReqType == 'i')
    1342             :     {
    1343       21181 :         *((int *)pReqReturn) = nIntRet;
    1344       21181 :         return true;
    1345             :     }
    1346           0 :     else if (chReqType == 'p')
    1347             :     {
    1348           0 :         *((GByte **)pReqReturn) = pabyRawData;
    1349           0 :         return true;
    1350             :     }
    1351             :     else
    1352             :     {
    1353           0 :         CPLAssert(false);
    1354             :         return false;
    1355             :     }
    1356             : }
    1357             : 
    1358             : /************************************************************************/
    1359             : /*                            GetInstBytes()                            */
    1360             : /*                                                                      */
    1361             : /*      Get the number of bytes in a particular instance of a           */
    1362             : /*      field.  This will normally be the fixed internal nBytes         */
    1363             : /*      value, but for pointer objects will include the variable        */
    1364             : /*      portion.                                                        */
    1365             : /************************************************************************/
    1366             : 
    1367      165738 : int HFAField::GetInstBytes(GByte *pabyData, int nDataSize,
    1368             :                            std::set<HFAField *> &oVisitedFields)
    1369             : 
    1370             : {
    1371      165738 :     if (oVisitedFields.find(this) != oVisitedFields.end())
    1372             :     {
    1373           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Recursion detected");
    1374           0 :         return -1;
    1375             :     }
    1376             : 
    1377      165738 :     if (nBytes > -1)
    1378      133142 :         return nBytes;
    1379             : 
    1380       32596 :     int nCount = 1;
    1381       32596 :     int nInstBytes = 0;
    1382             : 
    1383       32596 :     if (chPointer != '\0')
    1384             :     {
    1385       30217 :         if (nDataSize < 4)
    1386             :         {
    1387           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1388           0 :             return -1;
    1389             :         }
    1390             : 
    1391       30217 :         memcpy(&nCount, pabyData, 4);
    1392             :         HFAStandard(4, &nCount);
    1393             : 
    1394       30217 :         pabyData += 8;
    1395       30217 :         nInstBytes += 8;
    1396             :     }
    1397             : 
    1398       32596 :     if (chItemType == 'b' && nCount != 0)  // BASEDATA
    1399             :     {
    1400         515 :         if (nDataSize - nInstBytes < 4 + 4 + 2)
    1401             :         {
    1402           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Buffer too small");
    1403           0 :             return -1;
    1404             :         }
    1405             : 
    1406         515 :         GInt32 nRows = 0;
    1407         515 :         memcpy(&nRows, pabyData, 4);
    1408             :         HFAStandard(4, &nRows);
    1409         515 :         GInt32 nColumns = 0;
    1410         515 :         memcpy(&nColumns, pabyData + 4, 4);
    1411             :         HFAStandard(4, &nColumns);
    1412         515 :         GInt16 nBaseItemType = 0;
    1413         515 :         memcpy(&nBaseItemType, pabyData + 8, 2);
    1414             :         HFAStandard(2, &nBaseItemType);
    1415         515 :         if (nBaseItemType < EPT_MIN || nBaseItemType > EPT_MAX)
    1416           0 :             return -1;
    1417             : 
    1418         515 :         EPTType eBaseItemType = static_cast<EPTType>(nBaseItemType);
    1419             : 
    1420         515 :         nInstBytes += 12;
    1421             : 
    1422         515 :         if (nRows < 0 || nColumns < 0)
    1423           0 :             return -1;
    1424         515 :         if (nColumns != 0 && nRows > INT_MAX / nColumns)
    1425           0 :             return -1;
    1426        1022 :         if (nRows != 0 &&
    1427         507 :             ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) > INT_MAX / nRows)
    1428           0 :             return -1;
    1429        1022 :         if (nColumns != 0 &&
    1430         507 :             ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows >
    1431         507 :                 INT_MAX / nColumns)
    1432           0 :             return -1;
    1433         515 :         if (((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows * nColumns >
    1434         515 :             INT_MAX - nInstBytes)
    1435           0 :             return -1;
    1436             : 
    1437         515 :         nInstBytes +=
    1438         515 :             ((HFAGetDataTypeBits(eBaseItemType) + 7) / 8) * nRows * nColumns;
    1439             :     }
    1440       32081 :     else if (poItemObjectType == nullptr)
    1441             :     {
    1442       48262 :         if (nCount != 0 &&
    1443       19538 :             HFADictionary::GetItemSize(chItemType) > INT_MAX / nCount)
    1444           0 :             return -1;
    1445       28724 :         if (nCount * HFADictionary::GetItemSize(chItemType) >
    1446       28724 :             INT_MAX - nInstBytes)
    1447           0 :             return -1;
    1448       28724 :         nInstBytes += nCount * HFADictionary::GetItemSize(chItemType);
    1449             :     }
    1450             :     else
    1451             :     {
    1452        3357 :         oVisitedFields.insert(this);
    1453        5790 :         for (int i = 0; i < nCount && nInstBytes < nDataSize && nInstBytes >= 0;
    1454             :              i++)
    1455             :         {
    1456        2433 :             const int nThisBytes = poItemObjectType->GetInstBytes(
    1457             :                 pabyData, nDataSize - nInstBytes, oVisitedFields);
    1458        2433 :             if (nThisBytes <= 0 || nInstBytes > INT_MAX - nThisBytes)
    1459             :             {
    1460           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid return value");
    1461           0 :                 return -1;
    1462             :             }
    1463             : 
    1464        2433 :             nInstBytes += nThisBytes;
    1465        2433 :             pabyData += nThisBytes;
    1466             :         }
    1467        3357 :         oVisitedFields.erase(this);
    1468             :     }
    1469             : 
    1470       32596 :     return nInstBytes;
    1471             : }
    1472             : 
    1473             : /************************************************************************/
    1474             : /*                            GetInstCount()                            */
    1475             : /*                                                                      */
    1476             : /*      Get the count for a particular instance of a field.  This       */
    1477             : /*      will normally be the built in value, but for variable fields    */
    1478             : /*      this is extracted from the data itself.                         */
    1479             : /************************************************************************/
    1480             : 
    1481       46918 : int HFAField::GetInstCount(GByte *pabyData, int nDataSize) const
    1482             : 
    1483             : {
    1484       46918 :     if (chPointer == '\0')
    1485       27065 :         return nItemCount;
    1486             : 
    1487       19853 :     if (chItemType == 'b')
    1488             :     {
    1489         210 :         if (nDataSize < 20)
    1490           0 :             return 0;
    1491             : 
    1492         210 :         GInt32 nRows = 0;
    1493         210 :         memcpy(&nRows, pabyData + 8, 4);
    1494             :         HFAStandard(4, &nRows);
    1495         210 :         GInt32 nColumns = 0;
    1496         210 :         memcpy(&nColumns, pabyData + 12, 4);
    1497             :         HFAStandard(4, &nColumns);
    1498             : 
    1499         210 :         if (nRows < 0 || nColumns < 0)
    1500           0 :             return 0;
    1501         210 :         if (nColumns != 0 && nRows > INT_MAX / nColumns)
    1502           0 :             return 0;
    1503             : 
    1504         210 :         return nRows * nColumns;
    1505             :     }
    1506             : 
    1507       19643 :     if (nDataSize < 4)
    1508           0 :         return 0;
    1509             : 
    1510       19643 :     GInt32 nCount = 0;
    1511       19643 :     memcpy(&nCount, pabyData, 4);
    1512             :     HFAStandard(4, &nCount);
    1513       19643 :     return nCount;
    1514             : }
    1515             : 
    1516             : /************************************************************************/
    1517             : /*                           DumpInstValue()                            */
    1518             : /************************************************************************/
    1519             : 
    1520           0 : void HFAField::DumpInstValue(FILE *fpOut, GByte *pabyData, GUInt32 nDataOffset,
    1521             :                              int nDataSize, const char *pszPrefix)
    1522             : 
    1523             : {
    1524           0 :     const int nEntries = GetInstCount(pabyData, nDataSize);
    1525             : 
    1526             :     // Special case for arrays of chars or uchars which are printed
    1527             :     // as a string.
    1528           0 :     if ((chItemType == 'c' || chItemType == 'C') && nEntries > 0)
    1529             :     {
    1530           0 :         void *pReturn = nullptr;
    1531           0 :         if (ExtractInstValue(nullptr, 0, pabyData, nDataOffset, nDataSize, 's',
    1532             :                              &pReturn))
    1533           0 :             CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s = `%s'\n", pszPrefix,
    1534             :                                           pszFieldName,
    1535             :                                           static_cast<char *>(pReturn)));
    1536             :         else
    1537           0 :             CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s = (access failed)\n",
    1538             :                                           pszPrefix, pszFieldName));
    1539             : 
    1540           0 :         return;
    1541             :     }
    1542             : 
    1543             :     // For BASEDATA objects, we want to first dump their dimension and type.
    1544           0 :     if (chItemType == 'b')
    1545             :     {
    1546           0 :         int nDataType = 0;
    1547           0 :         const bool bSuccess = ExtractInstValue(
    1548             :             nullptr, -3, pabyData, nDataOffset, nDataSize, 'i', &nDataType);
    1549           0 :         if (bSuccess)
    1550             :         {
    1551           0 :             int nColumns = 0;
    1552           0 :             ExtractInstValue(nullptr, -2, pabyData, nDataOffset, nDataSize, 'i',
    1553             :                              &nColumns);
    1554           0 :             int nRows = 0;
    1555           0 :             ExtractInstValue(nullptr, -1, pabyData, nDataOffset, nDataSize, 'i',
    1556             :                              &nRows);
    1557           0 :             CPL_IGNORE_RET_VAL(VSIFPrintf(
    1558             :                 fpOut, "%sBASEDATA(%s): %dx%d of %s\n", pszPrefix, pszFieldName,
    1559             :                 nColumns, nRows,
    1560           0 :                 (nDataType >= EPT_MIN && nDataType <= EPT_MAX)
    1561           0 :                     ? HFAGetDataTypeName(static_cast<EPTType>(nDataType))
    1562             :                     : "invalid type"));
    1563             :         }
    1564             :         else
    1565             :         {
    1566           0 :             CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%sBASEDATA(%s): empty\n",
    1567             :                                           pszPrefix, pszFieldName));
    1568             :         }
    1569             :     }
    1570             : 
    1571             :     // Dump each entry in the field array.
    1572           0 :     void *pReturn = nullptr;
    1573             : 
    1574           0 :     const int nMaxEntry = std::min(MAX_ENTRY_REPORT, nEntries);
    1575           0 :     for (int iEntry = 0; iEntry < nMaxEntry; iEntry++)
    1576             :     {
    1577           0 :         if (nEntries == 1)
    1578           0 :             CPL_IGNORE_RET_VAL(
    1579           0 :                 VSIFPrintf(fpOut, "%s%s = ", pszPrefix, pszFieldName));
    1580             :         else
    1581           0 :             CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%s%s[%d] = ", pszPrefix,
    1582             :                                           pszFieldName, iEntry));
    1583             : 
    1584           0 :         switch (chItemType)
    1585             :         {
    1586           0 :             case 'f':
    1587             :             case 'd':
    1588             :             {
    1589           0 :                 double dfValue = 0.0;
    1590           0 :                 if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
    1591             :                                      nDataSize, 'd', &dfValue))
    1592           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%f\n", dfValue));
    1593             :                 else
    1594           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
    1595             :             }
    1596           0 :             break;
    1597             : 
    1598           0 :             case 'b':
    1599             :             {
    1600           0 :                 double dfValue = 0.0;
    1601             : 
    1602           0 :                 if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
    1603             :                                      nDataSize, 'd', &dfValue))
    1604           0 :                     CPL_IGNORE_RET_VAL(
    1605           0 :                         VSIFPrintf(fpOut, "%s%.15g\n", pszPrefix, dfValue));
    1606             :                 else
    1607           0 :                     CPL_IGNORE_RET_VAL(
    1608           0 :                         VSIFPrintf(fpOut, "%s(access failed)\n", pszPrefix));
    1609             :             }
    1610           0 :             break;
    1611             : 
    1612           0 :             case 'e':
    1613           0 :                 if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
    1614             :                                      nDataSize, 's', &pReturn))
    1615           0 :                     CPL_IGNORE_RET_VAL(
    1616           0 :                         VSIFPrintf(fpOut, "%s\n", (char *)pReturn));
    1617             :                 else
    1618           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
    1619           0 :                 break;
    1620             : 
    1621           0 :             case 'o':
    1622           0 :                 if (!ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
    1623             :                                       nDataSize, 'p', &pReturn))
    1624             :                 {
    1625           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
    1626             :                 }
    1627             :                 else
    1628             :                 {
    1629           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "\n"));
    1630             : 
    1631           0 :                     const int nByteOffset =
    1632           0 :                         static_cast<int>(((GByte *)pReturn) - pabyData);
    1633             : 
    1634           0 :                     char szLongFieldName[256] = {};
    1635           0 :                     snprintf(szLongFieldName, sizeof(szLongFieldName), "%s    ",
    1636             :                              pszPrefix);
    1637             : 
    1638           0 :                     if (poItemObjectType)
    1639           0 :                         poItemObjectType->DumpInstValue(
    1640           0 :                             fpOut, pabyData + nByteOffset,
    1641           0 :                             nDataOffset + nByteOffset, nDataSize - nByteOffset,
    1642             :                             szLongFieldName);
    1643             :                 }
    1644           0 :                 break;
    1645             : 
    1646           0 :             default:
    1647             :             {
    1648           0 :                 GInt32 nIntValue = 0;
    1649             : 
    1650           0 :                 if (ExtractInstValue(nullptr, iEntry, pabyData, nDataOffset,
    1651             :                                      nDataSize, 'i', &nIntValue))
    1652           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "%d\n", nIntValue));
    1653             :                 else
    1654           0 :                     CPL_IGNORE_RET_VAL(VSIFPrintf(fpOut, "(access failed)\n"));
    1655             :             }
    1656           0 :             break;
    1657             :         }
    1658             :     }
    1659             : 
    1660           0 :     if (nEntries > MAX_ENTRY_REPORT)
    1661           0 :         CPL_IGNORE_RET_VAL(VSIFPrintf(
    1662             :             fpOut, "%s ... remaining instances omitted ...\n", pszPrefix));
    1663             : 
    1664           0 :     if (nEntries == 0)
    1665           0 :         CPL_IGNORE_RET_VAL(
    1666           0 :             VSIFPrintf(fpOut, "%s%s = (no values)\n", pszPrefix, pszFieldName));
    1667             : }

Generated by: LCOV version 1.14