LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfrecord.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 415 603 68.8 %
Date: 2024-04-29 17:29:47 Functions: 20 24 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISO 8211 Access
       4             :  * Purpose:  Implements the DDFRecord class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_port.h"
      31             : #include "iso8211.h"
      32             : 
      33             : #include <cstddef>
      34             : #include <cstdio>
      35             : #include <cstring>
      36             : #if HAVE_FCNTL_H
      37             : #include <fcntl.h>
      38             : #endif
      39             : 
      40             : #include "cpl_conv.h"
      41             : #include "cpl_error.h"
      42             : #include "cpl_vsi.h"
      43             : 
      44             : constexpr int nLeaderSize = 24;
      45             : 
      46             : /************************************************************************/
      47             : /*                             DDFRecord()                              */
      48             : /************************************************************************/
      49             : 
      50        2067 : DDFRecord::DDFRecord(DDFModule *poModuleIn)
      51             :     : poModule(poModuleIn), nReuseHeader(FALSE), nFieldOffset(0),
      52        2067 :       _sizeFieldTag(poModuleIn->GetSizeFieldTag()), _sizeFieldPos(5),
      53             :       _sizeFieldLength(5), nDataSize(0), pachData(nullptr), nFieldCount(0),
      54        2067 :       paoFields(nullptr), bIsClone(FALSE)
      55             : {
      56        2067 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                             ~DDFRecord()                             */
      60             : /************************************************************************/
      61             : 
      62        4134 : DDFRecord::~DDFRecord()
      63             : 
      64             : {
      65        2067 :     Clear();
      66             : 
      67        2067 :     if (bIsClone)
      68         423 :         poModule->RemoveCloneRecord(this);
      69        2067 : }
      70             : 
      71             : /************************************************************************/
      72             : /*                                Dump()                                */
      73             : /************************************************************************/
      74             : 
      75             : /**
      76             :  * Write out record contents to debugging file.
      77             :  *
      78             :  * A variety of information about this record, and all its fields and
      79             :  * subfields is written to the given debugging file handle.  Note that
      80             :  * field definition information (ala DDFFieldDefn) isn't written.
      81             :  *
      82             :  * @param fp The standard IO file handle to write to.  i.e. stderr
      83             :  */
      84             : 
      85           0 : void DDFRecord::Dump(FILE *fp)
      86             : 
      87             : {
      88           0 :     fprintf(fp, "DDFRecord:\n");
      89           0 :     fprintf(fp, "    nReuseHeader = %d\n", nReuseHeader);
      90           0 :     fprintf(fp, "    nDataSize = %d\n", nDataSize);
      91           0 :     fprintf(fp, "    _sizeFieldLength=%d, _sizeFieldPos=%d, _sizeFieldTag=%d\n",
      92             :             _sizeFieldLength, _sizeFieldPos, _sizeFieldTag);
      93             : 
      94           0 :     for (int i = 0; i < nFieldCount; i++)
      95             :     {
      96           0 :         paoFields[i].Dump(fp);
      97             :     }
      98           0 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                                Read()                                */
     102             : /*                                                                      */
     103             : /*      Read a record of data from the file, and parse the header to    */
     104             : /*      build a field list for the record (or reuse the existing one    */
     105             : /*      if reusing headers).  It is expected that the file pointer      */
     106             : /*      will be positioned at the beginning of a data record.  It is    */
     107             : /*      the DDFModule's responsibility to do so.                        */
     108             : /*                                                                      */
     109             : /*      This method should only be called by the DDFModule class.       */
     110             : /************************************************************************/
     111             : 
     112        2520 : int DDFRecord::Read()
     113             : 
     114             : {
     115             :     /* -------------------------------------------------------------------- */
     116             :     /*      Redefine the record on the basis of the header if needed.       */
     117             :     /*      As a side effect this will read the data for the record as well.*/
     118             :     /* -------------------------------------------------------------------- */
     119        2520 :     if (!nReuseHeader)
     120             :     {
     121        2084 :         return ReadHeader();
     122             :     }
     123         436 :     if (nFieldOffset < 0)
     124           0 :         return FALSE;
     125             : 
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      Otherwise we read just the data and carefully overlay it on     */
     128             :     /*      the previous records data without disturbing the rest of the    */
     129             :     /*      record.                                                         */
     130             :     /* -------------------------------------------------------------------- */
     131             :     size_t nReadBytes;
     132             : 
     133         436 :     CPLAssert(nFieldOffset <= nDataSize);
     134         436 :     nReadBytes = VSIFReadL(pachData + nFieldOffset, 1, nDataSize - nFieldOffset,
     135         436 :                            poModule->GetFP());
     136         443 :     if (nReadBytes != (size_t)(nDataSize - nFieldOffset) && nReadBytes == 0 &&
     137           7 :         VSIFEofL(poModule->GetFP()))
     138             :     {
     139           7 :         return FALSE;
     140             :     }
     141         429 :     else if (nReadBytes != (size_t)(nDataSize - nFieldOffset))
     142             :     {
     143           0 :         CPLError(CE_Failure, CPLE_FileIO,
     144             :                  "Data record is short on DDF file.\n");
     145             : 
     146           0 :         return FALSE;
     147             :     }
     148             : 
     149             :     // notdef: eventually we may have to do something at this point to
     150             :     // notify the DDFField's that their data values have changed.
     151             : 
     152         429 :     return TRUE;
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                               Write()                                */
     157             : /************************************************************************/
     158             : 
     159             : /**
     160             :  * Write record out to module.
     161             :  *
     162             :  * This method writes the current record to the module to which it is
     163             :  * attached.  Normally this would be at the end of the file, and only used
     164             :  * for modules newly created with DDFModule::Create().  Rewriting existing
     165             :  * records is not supported at this time.  Calling Write() multiple times
     166             :  * on a DDFRecord will result it multiple copies being written at the end of
     167             :  * the module.
     168             :  *
     169             :  * @return TRUE on success or FALSE on failure.
     170             :  */
     171             : 
     172         154 : int DDFRecord::Write()
     173             : 
     174             : {
     175         154 :     ResetDirectory();
     176             : 
     177             :     /* -------------------------------------------------------------------- */
     178             :     /*      Prepare leader.                                                 */
     179             :     /* -------------------------------------------------------------------- */
     180             :     char szLeader[nLeaderSize + 1];
     181             : 
     182         154 :     memset(szLeader, ' ', nLeaderSize);
     183             : 
     184         154 :     snprintf(szLeader + 0, sizeof(szLeader) - 0, "%05d",
     185         154 :              (int)(nDataSize + nLeaderSize));
     186         154 :     szLeader[5] = ' ';
     187         154 :     szLeader[6] = 'D';
     188             : 
     189         154 :     snprintf(szLeader + 12, sizeof(szLeader) - 12, "%05d",
     190         154 :              (int)(nFieldOffset + nLeaderSize));
     191         154 :     szLeader[17] = ' ';
     192             : 
     193         154 :     szLeader[20] = (char)('0' + _sizeFieldLength);
     194         154 :     szLeader[21] = (char)('0' + _sizeFieldPos);
     195         154 :     szLeader[22] = '0';
     196         154 :     szLeader[23] = (char)('0' + _sizeFieldTag);
     197             : 
     198             :     /* notdef: lots of stuff missing */
     199             : 
     200             :     /* -------------------------------------------------------------------- */
     201             :     /*      Write the leader.                                               */
     202             :     /* -------------------------------------------------------------------- */
     203         154 :     int bRet = VSIFWriteL(szLeader, nLeaderSize, 1, poModule->GetFP()) > 0;
     204             : 
     205             :     /* -------------------------------------------------------------------- */
     206             :     /*      Write the remainder of the record.                              */
     207             :     /* -------------------------------------------------------------------- */
     208         154 :     bRet &= VSIFWriteL(pachData, nDataSize, 1, poModule->GetFP()) > 0;
     209             : 
     210         154 :     return bRet ? TRUE : FALSE;
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /*                               Clear()                                */
     215             : /*                                                                      */
     216             : /*      Clear any information associated with the last header in        */
     217             : /*      preparation for reading a new header.                           */
     218             : /************************************************************************/
     219             : 
     220        4167 : void DDFRecord::Clear()
     221             : 
     222             : {
     223        4167 :     if (paoFields != nullptr)
     224        3931 :         delete[] paoFields;
     225             : 
     226        4167 :     paoFields = nullptr;
     227        4167 :     nFieldCount = 0;
     228             : 
     229        4167 :     if (pachData != nullptr)
     230        3931 :         CPLFree(pachData);
     231             : 
     232        4167 :     pachData = nullptr;
     233        4167 :     nDataSize = 0;
     234        4167 :     nReuseHeader = FALSE;
     235        4167 : }
     236             : 
     237             : /************************************************************************/
     238             : /*                             ReadHeader()                             */
     239             : /*                                                                      */
     240             : /*      This perform the header reading and parsing job for the         */
     241             : /*      Read() method.  It reads the header, and builds a field         */
     242             : /*      list.                                                           */
     243             : /************************************************************************/
     244             : 
     245        2084 : int DDFRecord::ReadHeader()
     246             : 
     247             : {
     248             :     /* -------------------------------------------------------------------- */
     249             :     /*      Clear any existing information.                                 */
     250             :     /* -------------------------------------------------------------------- */
     251        2084 :     Clear();
     252             : 
     253             :     /* -------------------------------------------------------------------- */
     254             :     /*      Read the 24 byte leader.                                        */
     255             :     /* -------------------------------------------------------------------- */
     256             :     char achLeader[nLeaderSize];
     257             :     int nReadBytes;
     258             : 
     259        2084 :     nReadBytes = static_cast<int>(
     260        2084 :         VSIFReadL(achLeader, 1, nLeaderSize, poModule->GetFP()));
     261        2084 :     if (nReadBytes == 0 && VSIFEofL(poModule->GetFP()))
     262             :     {
     263          80 :         nFieldOffset = -1;
     264          80 :         return FALSE;
     265             :     }
     266             :     // The ASRP and USRP specifications mentions that 0x5E / ^ character can be
     267             :     // used as a padding byte so that the file size is a multiple of 8192.
     268        2004 :     else if (achLeader[0] == '^')
     269             :     {
     270           8 :         nFieldOffset = -1;
     271           8 :         return FALSE;
     272             :     }
     273        1996 :     else if (nReadBytes != (int)nLeaderSize)
     274             :     {
     275           0 :         CPLError(CE_Failure, CPLE_FileIO, "Leader is short on DDF file.");
     276           0 :         nFieldOffset = -1;
     277           0 :         return FALSE;
     278             :     }
     279             : 
     280             :     /* -------------------------------------------------------------------- */
     281             :     /*      Extract information from leader.                                */
     282             :     /* -------------------------------------------------------------------- */
     283             :     int _recLength, _fieldAreaStart;
     284             :     char _leaderIden;
     285             : 
     286        1996 :     _recLength = DDFScanInt(achLeader + 0, 5);
     287        1996 :     _leaderIden = achLeader[6];
     288        1996 :     _fieldAreaStart = DDFScanInt(achLeader + 12, 5);
     289             : 
     290        1996 :     _sizeFieldLength = achLeader[20] - '0';
     291        1996 :     _sizeFieldPos = achLeader[21] - '0';
     292        1996 :     _sizeFieldTag = achLeader[23] - '0';
     293             : 
     294        1996 :     if (_sizeFieldLength <= 0 || _sizeFieldLength > 9 || _sizeFieldPos <= 0 ||
     295        1996 :         _sizeFieldPos > 9 || _sizeFieldTag <= 0 || _sizeFieldTag > 9)
     296             :     {
     297           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     298             :                  "ISO8211 record leader appears to be corrupt.");
     299           0 :         nFieldOffset = -1;
     300           0 :         return FALSE;
     301             :     }
     302             : 
     303        1996 :     if (_leaderIden == 'R')
     304          13 :         nReuseHeader = TRUE;
     305             : 
     306        1996 :     nFieldOffset = _fieldAreaStart - nLeaderSize;
     307             : 
     308             :     /* -------------------------------------------------------------------- */
     309             :     /*      Is there anything seemly screwy about this record?              */
     310             :     /* -------------------------------------------------------------------- */
     311        1996 :     if (((_recLength <= 24 || _recLength > 100000000) && (_recLength != 0)) ||
     312        1996 :         _fieldAreaStart < 24 || _fieldAreaStart > 100000)
     313             :     {
     314           0 :         CPLError(
     315             :             CE_Failure, CPLE_FileIO,
     316             :             "Data record appears to be corrupt on DDF file.\n"
     317             :             " -- ensure that the files were uncompressed without modifying\n"
     318             :             "carriage return/linefeeds (by default WINZIP does this).");
     319           0 :         nFieldOffset = -1;
     320           0 :         return FALSE;
     321             :     }
     322             : 
     323             :     /* ==================================================================== */
     324             :     /*      Handle the normal case with the record length available.        */
     325             :     /* ==================================================================== */
     326        1996 :     if (_recLength != 0)
     327             :     {
     328             :         /* --------------------------------------------------------------------
     329             :          */
     330             :         /*      Read the remainder of the record. */
     331             :         /* --------------------------------------------------------------------
     332             :          */
     333        1995 :         nDataSize = _recLength - nLeaderSize;
     334        1995 :         pachData = (char *)CPLMalloc(nDataSize + 1);
     335        1995 :         pachData[nDataSize] = '\0';
     336             : 
     337        1995 :         if (VSIFReadL(pachData, 1, nDataSize, poModule->GetFP()) !=
     338        1995 :             (size_t)nDataSize)
     339             :         {
     340           0 :             CPLError(CE_Failure, CPLE_FileIO,
     341             :                      "Data record is short on DDF file.");
     342           0 :             nFieldOffset = -1;
     343           0 :             return FALSE;
     344             :         }
     345             : 
     346             :         /* --------------------------------------------------------------------
     347             :          */
     348             :         /*      If we don't find a field terminator at the end of the record */
     349             :         /*      we will read extra bytes till we get to it. */
     350             :         /* --------------------------------------------------------------------
     351             :          */
     352        1995 :         int nDataSizeAlloc = nDataSize;
     353           0 :         while (
     354        1995 :             pachData[nDataSize - 1] != DDF_FIELD_TERMINATOR &&
     355           1 :             (nDataSize < 2 || pachData[nDataSize - 2] != DDF_FIELD_TERMINATOR))
     356             :         {
     357           0 :             nDataSize++;
     358           0 :             if (nDataSize > nDataSizeAlloc)
     359             :             {
     360           0 :                 nDataSizeAlloc *= 2;
     361           0 :                 pachData = (char *)CPLRealloc(pachData, nDataSizeAlloc + 1);
     362             :             }
     363           0 :             pachData[nDataSize] = '\0';
     364             : 
     365           0 :             if (VSIFReadL(pachData + nDataSize - 1, 1, 1, poModule->GetFP()) !=
     366             :                 1)
     367             :             {
     368           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     369             :                          "Data record is short on DDF file.");
     370           0 :                 nFieldOffset = -1;
     371           0 :                 return FALSE;
     372             :             }
     373             :             static bool bFirstTime = true;
     374           0 :             if (bFirstTime)
     375             :             {
     376           0 :                 bFirstTime = false;
     377           0 :                 CPLDebug("ISO8211",
     378             :                          "Didn't find field terminator, read one more byte.");
     379             :             }
     380             :         }
     381             : 
     382        1995 :         if (nFieldOffset >= nDataSize)
     383             :         {
     384           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     385             :                      "nFieldOffset < nDataSize");
     386           0 :             nFieldOffset = -1;
     387           0 :             return FALSE;
     388             :         }
     389             : 
     390             :         /* --------------------------------------------------------------------
     391             :          */
     392             :         /*      Loop over the directory entries, making a pass counting them. */
     393             :         /* --------------------------------------------------------------------
     394             :          */
     395             :         int i;
     396             :         int nFieldEntryWidth;
     397             : 
     398        1995 :         nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
     399        1995 :         if (nFieldEntryWidth <= 0)
     400             :         {
     401           0 :             CPLError(CE_Failure, CPLE_FileIO, "Invalid entry width = %d",
     402             :                      nFieldEntryWidth);
     403           0 :             nFieldOffset = -1;
     404           0 :             return FALSE;
     405             :         }
     406             : 
     407        1995 :         nFieldCount = 0;
     408        9544 :         for (i = 0; i + nFieldEntryWidth <= nDataSize; i += nFieldEntryWidth)
     409             :         {
     410        9544 :             if (pachData[i] == DDF_FIELD_TERMINATOR)
     411        1995 :                 break;
     412             : 
     413        7549 :             nFieldCount++;
     414             :         }
     415             : 
     416             :         /* --------------------------------------------------------------------
     417             :          */
     418             :         /*      Allocate, and read field definitions. */
     419             :         /* --------------------------------------------------------------------
     420             :          */
     421        9544 :         paoFields = new DDFField[nFieldCount];
     422             : 
     423        9544 :         for (i = 0; i < nFieldCount; i++)
     424             :         {
     425             :             char szTag[128];
     426        7549 :             int nEntryOffset = i * nFieldEntryWidth;
     427             :             int nFieldLength, nFieldPos;
     428             : 
     429             :             /* --------------------------------------------------------------------
     430             :              */
     431             :             /*      Read the position information and tag. */
     432             :             /* --------------------------------------------------------------------
     433             :              */
     434        7549 :             strncpy(szTag, pachData + nEntryOffset, _sizeFieldTag);
     435        7549 :             szTag[_sizeFieldTag] = '\0';
     436             : 
     437        7549 :             nEntryOffset += _sizeFieldTag;
     438             :             nFieldLength =
     439        7549 :                 DDFScanInt(pachData + nEntryOffset, _sizeFieldLength);
     440             : 
     441        7549 :             nEntryOffset += _sizeFieldLength;
     442        7549 :             nFieldPos = DDFScanInt(pachData + nEntryOffset, _sizeFieldPos);
     443             : 
     444             :             /* --------------------------------------------------------------------
     445             :              */
     446             :             /*      Find the corresponding field in the module directory. */
     447             :             /* --------------------------------------------------------------------
     448             :              */
     449        7549 :             DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn(szTag);
     450             : 
     451        7549 :             if (poFieldDefn == nullptr || nFieldLength < 0 || nFieldPos < 0)
     452             :             {
     453           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     454             :                          "Undefined field `%s' encountered in data record.",
     455             :                          szTag);
     456           0 :                 return FALSE;
     457             :             }
     458             : 
     459        7549 :             if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
     460        7549 :                 nDataSize - (_fieldAreaStart + nFieldPos - nLeaderSize) <
     461             :                     nFieldLength)
     462             :             {
     463           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     464             :                          "Not enough byte to initialize field `%s'.", szTag);
     465           0 :                 nFieldOffset = -1;
     466           0 :                 return FALSE;
     467             :             }
     468             : 
     469             :             /* --------------------------------------------------------------------
     470             :              */
     471             :             /*      Assign info the DDFField. */
     472             :             /* --------------------------------------------------------------------
     473             :              */
     474        7549 :             paoFields[i].Initialize(poFieldDefn,
     475        7549 :                                     pachData + _fieldAreaStart + nFieldPos -
     476             :                                         nLeaderSize,
     477             :                                     nFieldLength);
     478             :         }
     479             : 
     480        1995 :         return TRUE;
     481             :     }
     482             :     /* ==================================================================== */
     483             :     /*      Handle the exceptional case where the record length is          */
     484             :     /*      zero.  In this case we have to read all the data based on       */
     485             :     /*      the size of data items as per ISO8211 spec Annex C, 1.5.1.      */
     486             :     /*                                                                      */
     487             :     /*      See Bugzilla bug 181 and test with file US4CN21M.000.           */
     488             :     /* ==================================================================== */
     489             :     else
     490             :     {
     491           1 :         CPLDebug("ISO8211",
     492             :                  "Record with zero length, use variant (C.1.5.1) logic.");
     493             : 
     494             :         /* ----------------------------------------------------------------- */
     495             :         /*   _recLength == 0, handle the large record.                       */
     496             :         /*                                                                   */
     497             :         /*   Read the remainder of the record.                               */
     498             :         /* ----------------------------------------------------------------- */
     499           1 :         nDataSize = 0;
     500           1 :         pachData = nullptr;
     501             : 
     502             :         /* ----------------------------------------------------------------- */
     503             :         /*   Loop over the directory entries, making a pass counting them.   */
     504             :         /* ----------------------------------------------------------------- */
     505           1 :         int nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
     506           1 :         nFieldCount = 0;
     507           1 :         int i = 0;
     508             : 
     509           1 :         if (nFieldEntryWidth == 0)
     510             :         {
     511           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     512             :                      "Invalid record buffer size : %d.", nFieldEntryWidth);
     513           0 :             nFieldOffset = -1;
     514           0 :             return FALSE;
     515             :         }
     516             : 
     517           1 :         char *tmpBuf = (char *)VSI_MALLOC_VERBOSE(nFieldEntryWidth);
     518             : 
     519           1 :         if (tmpBuf == nullptr)
     520             :         {
     521           0 :             nFieldOffset = -1;
     522           0 :             return FALSE;
     523             :         }
     524             : 
     525             :         // while we're not at the end, store this entry,
     526             :         // and keep on reading...
     527           2 :         do
     528             :         {
     529             :             // read an Entry:
     530           3 :             if (nFieldEntryWidth !=
     531           3 :                 (int)VSIFReadL(tmpBuf, 1, nFieldEntryWidth, poModule->GetFP()))
     532             :             {
     533           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     534             :                          "Data record is short on DDF file.");
     535           0 :                 CPLFree(tmpBuf);
     536           0 :                 nFieldOffset = -1;
     537           0 :                 return FALSE;
     538             :             }
     539             : 
     540             :             // move this temp buffer into more permanent storage:
     541           3 :             char *newBuf = (char *)CPLMalloc(nDataSize + nFieldEntryWidth + 1);
     542           3 :             newBuf[nDataSize + nFieldEntryWidth] = '\0';
     543           3 :             if (pachData != nullptr)
     544             :             {
     545           2 :                 memcpy(newBuf, pachData, nDataSize);
     546           2 :                 CPLFree(pachData);
     547             :             }
     548           3 :             memcpy(&newBuf[nDataSize], tmpBuf, nFieldEntryWidth);
     549           3 :             pachData = newBuf;
     550           3 :             nDataSize += nFieldEntryWidth;
     551             : 
     552           3 :             if (DDF_FIELD_TERMINATOR != tmpBuf[0])
     553             :             {
     554           2 :                 nFieldCount++;
     555           2 :                 if (nFieldCount == 1000)
     556             :                 {
     557           0 :                     CPLError(CE_Failure, CPLE_FileIO,
     558             :                              "Too many fields in DDF file.");
     559           0 :                     CPLFree(tmpBuf);
     560           0 :                     nFieldOffset = -1;
     561           0 :                     return FALSE;
     562             :                 }
     563             :             }
     564           3 :         } while (DDF_FIELD_TERMINATOR != tmpBuf[0]);
     565             : 
     566           1 :         CPLFree(tmpBuf);
     567           1 :         tmpBuf = nullptr;
     568             : 
     569             :         // --------------------------------------------------------------------
     570             :         // Now, rewind a little.  Only the TERMINATOR should have been read
     571             :         // --------------------------------------------------------------------
     572           1 :         int rewindSize = nFieldEntryWidth - 1;
     573           1 :         VSILFILE *fp = poModule->GetFP();
     574           1 :         vsi_l_offset pos = VSIFTellL(fp) - rewindSize;
     575           1 :         if (VSIFSeekL(fp, pos, SEEK_SET) < 0)
     576           0 :             return FALSE;
     577           1 :         nDataSize -= rewindSize;
     578             : 
     579             :         // --------------------------------------------------------------------
     580             :         // Okay, now let's populate the heck out of pachData...
     581             :         // --------------------------------------------------------------------
     582           3 :         for (i = 0; i < nFieldCount; i++)
     583             :         {
     584           2 :             int nEntryOffset = (i * nFieldEntryWidth) + _sizeFieldTag;
     585             :             int nFieldLength =
     586           2 :                 DDFScanInt(pachData + nEntryOffset, _sizeFieldLength);
     587           2 :             tmpBuf = nullptr;
     588           2 :             if (nFieldLength >= 0)
     589           2 :                 tmpBuf = (char *)VSI_MALLOC_VERBOSE(nFieldLength);
     590           2 :             if (tmpBuf == nullptr)
     591             :             {
     592           0 :                 nFieldOffset = -1;
     593           0 :                 return FALSE;
     594             :             }
     595             : 
     596             :             // read an Entry:
     597           2 :             if (nFieldLength !=
     598           2 :                 (int)VSIFReadL(tmpBuf, 1, nFieldLength, poModule->GetFP()))
     599             :             {
     600           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     601             :                          "Data record is short on DDF file.");
     602           0 :                 CPLFree(tmpBuf);
     603           0 :                 nFieldOffset = -1;
     604           0 :                 return FALSE;
     605             :             }
     606             : 
     607             :             // move this temp buffer into more permanent storage:
     608             :             char *newBuf =
     609           2 :                 (char *)VSI_MALLOC_VERBOSE(nDataSize + nFieldLength + 1);
     610           2 :             if (newBuf == nullptr)
     611             :             {
     612           0 :                 CPLFree(tmpBuf);
     613           0 :                 nFieldOffset = -1;
     614           0 :                 return FALSE;
     615             :             }
     616           2 :             newBuf[nDataSize + nFieldLength] = '\0';
     617           2 :             memcpy(newBuf, pachData, nDataSize);
     618           2 :             CPLFree(pachData);
     619           2 :             memcpy(&newBuf[nDataSize], tmpBuf, nFieldLength);
     620           2 :             CPLFree(tmpBuf);
     621           2 :             pachData = newBuf;
     622           2 :             nDataSize += nFieldLength;
     623             :         }
     624             : 
     625           1 :         if (nFieldOffset >= nDataSize)
     626             :         {
     627           0 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     628             :                      "nFieldOffset < nDataSize");
     629           0 :             nFieldOffset = -1;
     630           0 :             return FALSE;
     631             :         }
     632             : 
     633             :         /* ----------------------------------------------------------------- */
     634             :         /*     Allocate, and read field definitions.                         */
     635             :         /* ----------------------------------------------------------------- */
     636           3 :         paoFields = new DDFField[nFieldCount];
     637             : 
     638           3 :         for (i = 0; i < nFieldCount; i++)
     639             :         {
     640             :             char szTag[128];
     641           2 :             int nEntryOffset = i * nFieldEntryWidth;
     642             :             int nFieldLength, nFieldPos;
     643             : 
     644             :             /* ------------------------------------------------------------- */
     645             :             /* Read the position information and tag.                        */
     646             :             /* ------------------------------------------------------------- */
     647           2 :             strncpy(szTag, pachData + nEntryOffset, _sizeFieldTag);
     648           2 :             szTag[_sizeFieldTag] = '\0';
     649             : 
     650           2 :             nEntryOffset += _sizeFieldTag;
     651             :             nFieldLength =
     652           2 :                 DDFScanInt(pachData + nEntryOffset, _sizeFieldLength);
     653             : 
     654           2 :             nEntryOffset += _sizeFieldLength;
     655           2 :             nFieldPos = DDFScanInt(pachData + nEntryOffset, _sizeFieldPos);
     656             : 
     657             :             /* ------------------------------------------------------------- */
     658             :             /* Find the corresponding field in the module directory.         */
     659             :             /* ------------------------------------------------------------- */
     660           2 :             DDFFieldDefn *poFieldDefn = poModule->FindFieldDefn(szTag);
     661             : 
     662           2 :             if (poFieldDefn == nullptr || nFieldLength < 0 || nFieldPos < 0)
     663             :             {
     664           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     665             :                          "Undefined field `%s' encountered in data record.",
     666             :                          szTag);
     667           0 :                 nFieldOffset = -1;
     668           0 :                 return FALSE;
     669             :             }
     670             : 
     671           2 :             if (_fieldAreaStart + nFieldPos - nLeaderSize < 0 ||
     672           2 :                 nDataSize - (_fieldAreaStart + nFieldPos - nLeaderSize) <
     673             :                     nFieldLength)
     674             :             {
     675           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     676             :                          "Not enough byte to initialize field `%s'.", szTag);
     677           0 :                 nFieldOffset = -1;
     678           0 :                 return FALSE;
     679             :             }
     680             : 
     681             :             /* ------------------------------------------------------------- */
     682             :             /* Assign info the DDFField.                                     */
     683             :             /* ------------------------------------------------------------- */
     684             : 
     685           2 :             paoFields[i].Initialize(poFieldDefn,
     686           2 :                                     pachData + _fieldAreaStart + nFieldPos -
     687             :                                         nLeaderSize,
     688             :                                     nFieldLength);
     689             :         }
     690             : 
     691           1 :         return TRUE;
     692             :     }
     693             : }
     694             : 
     695             : /************************************************************************/
     696             : /*                             FindField()                              */
     697             : /************************************************************************/
     698             : 
     699             : /**
     700             :  * Find the named field within this record.
     701             :  *
     702             :  * @param pszName The name of the field to fetch.  The comparison is
     703             :  * case insensitive.
     704             :  * @param iFieldIndex The instance of this field to fetch.  Use zero (the
     705             :  * default) for the first instance.
     706             :  *
     707             :  * @return Pointer to the requested DDFField.  This pointer is to an
     708             :  * internal object, and should not be freed.  It remains valid until
     709             :  * the next record read.
     710             :  */
     711             : 
     712       42222 : DDFField *DDFRecord::FindField(const char *pszName, int iFieldIndex)
     713             : 
     714             : {
     715      137832 :     for (int i = 0; i < nFieldCount; i++)
     716             :     {
     717      136161 :         DDFFieldDefn *poFieldDefn = paoFields[i].GetFieldDefn();
     718      136161 :         if (poFieldDefn && EQUAL(poFieldDefn->GetName(), pszName))
     719             :         {
     720       40573 :             if (iFieldIndex == 0)
     721       40551 :                 return paoFields + i;
     722             :             else
     723          22 :                 iFieldIndex--;
     724             :         }
     725             :     }
     726             : 
     727        1671 :     return nullptr;
     728             : }
     729             : 
     730             : /************************************************************************/
     731             : /*                              GetField()                              */
     732             : /************************************************************************/
     733             : 
     734             : /**
     735             :  * Fetch field object based on index.
     736             :  *
     737             :  * @param i The index of the field to fetch.  Between 0 and GetFieldCount()-1.
     738             :  *
     739             :  * @return A DDFField pointer, or NULL if the index is out of range.
     740             :  */
     741             : 
     742       17227 : DDFField *DDFRecord::GetField(int i)
     743             : 
     744             : {
     745       17227 :     if (i < 0 || i >= nFieldCount)
     746           0 :         return nullptr;
     747             :     else
     748       17227 :         return paoFields + i;
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                           GetIntSubfield()                           */
     753             : /************************************************************************/
     754             : 
     755             : /**
     756             :  * Fetch value of a subfield as an integer.  This is a convenience
     757             :  * function for fetching a subfield of a field within this record.
     758             :  *
     759             :  * @param pszField The name of the field containing the subfield.
     760             :  * @param iFieldIndex The instance of this field within the record.  Use
     761             :  * zero for the first instance of this field.
     762             :  * @param pszSubfield The name of the subfield within the selected field.
     763             :  * @param iSubfieldIndex The instance of this subfield within the record.
     764             :  * Use zero for the first instance.
     765             :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     766             :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     767             :  * success.
     768             :  * @return The value of the subfield, or zero if it failed for some reason.
     769             :  */
     770             : 
     771       26013 : int DDFRecord::GetIntSubfield(const char *pszField, int iFieldIndex,
     772             :                               const char *pszSubfield, int iSubfieldIndex,
     773             :                               int *pnSuccess)
     774             : 
     775             : {
     776       26013 :     int nDummyErr = FALSE;
     777             : 
     778       26013 :     if (pnSuccess == nullptr)
     779       23491 :         pnSuccess = &nDummyErr;
     780             : 
     781       26013 :     *pnSuccess = FALSE;
     782             : 
     783             :     /* -------------------------------------------------------------------- */
     784             :     /*      Fetch the field. If this fails, return zero.                    */
     785             :     /* -------------------------------------------------------------------- */
     786       26013 :     DDFField *poField = FindField(pszField, iFieldIndex);
     787       26013 :     if (poField == nullptr)
     788          33 :         return 0;
     789             : 
     790             :     /* -------------------------------------------------------------------- */
     791             :     /*      Get the subfield definition                                     */
     792             :     /* -------------------------------------------------------------------- */
     793             :     DDFSubfieldDefn *poSFDefn =
     794       25980 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
     795       25980 :     if (poSFDefn == nullptr)
     796          32 :         return 0;
     797             : 
     798             :     /* -------------------------------------------------------------------- */
     799             :     /*      Get a pointer to the data.                                      */
     800             :     /* -------------------------------------------------------------------- */
     801             :     int nBytesRemaining;
     802             : 
     803             :     const char *l_pachData =
     804       25948 :         poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
     805       25948 :     if (l_pachData == nullptr)
     806           0 :         return 0;
     807             : 
     808             :     /* -------------------------------------------------------------------- */
     809             :     /*      Return the extracted value.                                     */
     810             :     /*                                                                      */
     811             :     /*      Assume an error has occurred if no bytes are consumed.           */
     812             :     /* -------------------------------------------------------------------- */
     813       25948 :     int nConsumedBytes = 0;
     814             :     int nResult =
     815       25948 :         poSFDefn->ExtractIntData(l_pachData, nBytesRemaining, &nConsumedBytes);
     816             : 
     817       25948 :     if (nConsumedBytes > 0)
     818       25948 :         *pnSuccess = TRUE;
     819             : 
     820       25948 :     return nResult;
     821             : }
     822             : 
     823             : /************************************************************************/
     824             : /*                          GetFloatSubfield()                          */
     825             : /************************************************************************/
     826             : 
     827             : /**
     828             :  * Fetch value of a subfield as a float (double).  This is a convenience
     829             :  * function for fetching a subfield of a field within this record.
     830             :  *
     831             :  * @param pszField The name of the field containing the subfield.
     832             :  * @param iFieldIndex The instance of this field within the record.  Use
     833             :  * zero for the first instance of this field.
     834             :  * @param pszSubfield The name of the subfield within the selected field.
     835             :  * @param iSubfieldIndex The instance of this subfield within the record.
     836             :  * Use zero for the first instance.
     837             :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     838             :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     839             :  * success.
     840             :  * @return The value of the subfield, or zero if it failed for some reason.
     841             :  */
     842             : 
     843         140 : double DDFRecord::GetFloatSubfield(const char *pszField, int iFieldIndex,
     844             :                                    const char *pszSubfield, int iSubfieldIndex,
     845             :                                    int *pnSuccess)
     846             : 
     847             : {
     848         140 :     int nDummyErr = FALSE;
     849             : 
     850         140 :     if (pnSuccess == nullptr)
     851         104 :         pnSuccess = &nDummyErr;
     852             : 
     853         140 :     *pnSuccess = FALSE;
     854             : 
     855             :     /* -------------------------------------------------------------------- */
     856             :     /*      Fetch the field. If this fails, return zero.                    */
     857             :     /* -------------------------------------------------------------------- */
     858         140 :     DDFField *poField = FindField(pszField, iFieldIndex);
     859         140 :     if (poField == nullptr)
     860           0 :         return 0;
     861             : 
     862             :     /* -------------------------------------------------------------------- */
     863             :     /*      Get the subfield definition                                     */
     864             :     /* -------------------------------------------------------------------- */
     865             :     DDFSubfieldDefn *poSFDefn =
     866         140 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
     867         140 :     if (poSFDefn == nullptr)
     868           2 :         return 0;
     869             : 
     870             :     /* -------------------------------------------------------------------- */
     871             :     /*      Get a pointer to the data.                                      */
     872             :     /* -------------------------------------------------------------------- */
     873             :     int nBytesRemaining;
     874             : 
     875             :     const char *l_pachData =
     876         138 :         poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
     877         138 :     if (l_pachData == nullptr)
     878           0 :         return 0;
     879             : 
     880             :     /* -------------------------------------------------------------------- */
     881             :     /*      Return the extracted value.                                     */
     882             :     /* -------------------------------------------------------------------- */
     883         138 :     int nConsumedBytes = 0;
     884         138 :     double dfResult = poSFDefn->ExtractFloatData(l_pachData, nBytesRemaining,
     885             :                                                  &nConsumedBytes);
     886             : 
     887         138 :     if (nConsumedBytes > 0)
     888         138 :         *pnSuccess = TRUE;
     889             : 
     890         138 :     return dfResult;
     891             : }
     892             : 
     893             : /************************************************************************/
     894             : /*                         GetStringSubfield()                          */
     895             : /************************************************************************/
     896             : 
     897             : /**
     898             :  * Fetch value of a subfield as a string.  This is a convenience
     899             :  * function for fetching a subfield of a field within this record.
     900             :  *
     901             :  * @param pszField The name of the field containing the subfield.
     902             :  * @param iFieldIndex The instance of this field within the record.  Use
     903             :  * zero for the first instance of this field.
     904             :  * @param pszSubfield The name of the subfield within the selected field.
     905             :  * @param iSubfieldIndex The instance of this subfield within the record.
     906             :  * Use zero for the first instance.
     907             :  * @param pnSuccess Pointer to an int which will be set to TRUE if the fetch
     908             :  * succeeds, or FALSE if it fails.  Use NULL if you don't want to check
     909             :  * success.
     910             :  * @return The value of the subfield, or NULL if it failed for some reason.
     911             :  * The returned pointer is to internal data and should not be modified or
     912             :  * freed by the application.
     913             :  */
     914             : 
     915        2045 : const char *DDFRecord::GetStringSubfield(const char *pszField, int iFieldIndex,
     916             :                                          const char *pszSubfield,
     917             :                                          int iSubfieldIndex, int *pnSuccess)
     918             : 
     919             : {
     920        2045 :     int nDummyErr = FALSE;
     921             : 
     922        2045 :     if (pnSuccess == nullptr)
     923        1996 :         pnSuccess = &nDummyErr;
     924             : 
     925        2045 :     *pnSuccess = FALSE;
     926             : 
     927             :     /* -------------------------------------------------------------------- */
     928             :     /*      Fetch the field. If this fails, return zero.                    */
     929             :     /* -------------------------------------------------------------------- */
     930        2045 :     DDFField *poField = FindField(pszField, iFieldIndex);
     931        2045 :     if (poField == nullptr)
     932           0 :         return nullptr;
     933             : 
     934             :     /* -------------------------------------------------------------------- */
     935             :     /*      Get the subfield definition                                     */
     936             :     /* -------------------------------------------------------------------- */
     937             :     DDFSubfieldDefn *poSFDefn =
     938        2045 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
     939        2045 :     if (poSFDefn == nullptr)
     940          52 :         return nullptr;
     941             : 
     942             :     /* -------------------------------------------------------------------- */
     943             :     /*      Get a pointer to the data.                                      */
     944             :     /* -------------------------------------------------------------------- */
     945             :     int nBytesRemaining;
     946             : 
     947             :     const char *l_pachData =
     948        1993 :         poField->GetSubfieldData(poSFDefn, &nBytesRemaining, iSubfieldIndex);
     949        1993 :     if (l_pachData == nullptr)
     950           0 :         return nullptr;
     951             : 
     952             :     /* -------------------------------------------------------------------- */
     953             :     /*      Return the extracted value.                                     */
     954             :     /* -------------------------------------------------------------------- */
     955        1993 :     *pnSuccess = TRUE;
     956             : 
     957        1993 :     return poSFDefn->ExtractStringData(l_pachData, nBytesRemaining, nullptr);
     958             : }
     959             : 
     960             : /************************************************************************/
     961             : /*                               Clone()                                */
     962             : /************************************************************************/
     963             : 
     964             : /**
     965             :  * Make a copy of a record.
     966             :  *
     967             :  * This method is used to make a copy of a record that will become (mostly)
     968             :  * the properly of application.  However, it is automatically destroyed if
     969             :  * the DDFModule it was created relative to is destroyed, as its field
     970             :  * and subfield definitions relate to that DDFModule.  However, it does
     971             :  * persist even when the record returned by DDFModule::ReadRecord() is
     972             :  * invalidated, such as when reading a new record.  This allows an application
     973             :  * to cache whole DDFRecords.
     974             :  *
     975             :  * @return A new copy of the DDFRecord.  This can be delete'd by the
     976             :  * application when no longer needed, otherwise it will be cleaned up when
     977             :  * the DDFModule it relates to is destroyed or closed.
     978             :  */
     979             : 
     980        1781 : DDFRecord *DDFRecord::Clone()
     981             : 
     982             : {
     983        1781 :     DDFRecord *poNR = new DDFRecord(poModule);
     984             : 
     985        1781 :     poNR->nReuseHeader = FALSE;
     986        1781 :     poNR->nFieldOffset = nFieldOffset;
     987             : 
     988        1781 :     poNR->nDataSize = nDataSize;
     989        1781 :     poNR->pachData = (char *)CPLMalloc(nDataSize + 1);
     990        1781 :     memcpy(poNR->pachData, pachData, nDataSize);
     991        1781 :     poNR->pachData[nDataSize] = '\0';
     992             : 
     993        1781 :     poNR->nFieldCount = nFieldCount;
     994        8261 :     poNR->paoFields = new DDFField[nFieldCount];
     995        8261 :     for (int i = 0; i < nFieldCount; i++)
     996             :     {
     997             :         int nOffset;
     998             : 
     999        6480 :         nOffset = static_cast<int>(paoFields[i].GetData() - pachData);
    1000        6480 :         poNR->paoFields[i].Initialize(paoFields[i].GetFieldDefn(),
    1001        6480 :                                       poNR->pachData + nOffset,
    1002        6480 :                                       paoFields[i].GetDataSize());
    1003             :     }
    1004             : 
    1005        1781 :     poNR->bIsClone = TRUE;
    1006        1781 :     poModule->AddCloneRecord(poNR);
    1007             : 
    1008        1781 :     return poNR;
    1009             : }
    1010             : 
    1011             : /************************************************************************/
    1012             : /*                              CloneOn()                               */
    1013             : /************************************************************************/
    1014             : 
    1015             : /**
    1016             :  * Recreate a record referencing another module.
    1017             :  *
    1018             :  * Works similarly to the DDFRecord::Clone() method, but creates the
    1019             :  * new record with reference to a different DDFModule.  All DDFFieldDefn
    1020             :  * references are transcribed onto the new module based on field names.
    1021             :  * If any fields don't have a similarly named field on the target module
    1022             :  * the operation will fail.  No validation of field types and properties
    1023             :  * is done, but this operation is intended only to be used between
    1024             :  * modules with matching definitions of all affected fields.
    1025             :  *
    1026             :  * The new record will be managed as a clone by the target module in
    1027             :  * a manner similar to regular clones.
    1028             :  *
    1029             :  * @param poTargetModule the module on which the record copy should be
    1030             :  * created.
    1031             :  *
    1032             :  * @return NULL on failure or a pointer to the cloned record.
    1033             :  */
    1034             : 
    1035           0 : DDFRecord *DDFRecord::CloneOn(DDFModule *poTargetModule)
    1036             : 
    1037             : {
    1038             :     /* -------------------------------------------------------------------- */
    1039             :     /*      Verify that all fields have a corresponding field definition    */
    1040             :     /*      on the target module.                                           */
    1041             :     /* -------------------------------------------------------------------- */
    1042           0 :     for (int i = 0; i < nFieldCount; i++)
    1043             :     {
    1044           0 :         DDFFieldDefn *poDefn = paoFields[i].GetFieldDefn();
    1045             : 
    1046           0 :         if (poTargetModule->FindFieldDefn(poDefn->GetName()) == nullptr)
    1047           0 :             return nullptr;
    1048             :     }
    1049             : 
    1050             :     /* -------------------------------------------------------------------- */
    1051             :     /*      Create a clone.                                                 */
    1052             :     /* -------------------------------------------------------------------- */
    1053           0 :     DDFRecord *poClone = Clone();
    1054             : 
    1055             :     /* -------------------------------------------------------------------- */
    1056             :     /*      Update all internal information to reference other module.      */
    1057             :     /* -------------------------------------------------------------------- */
    1058           0 :     for (int i = 0; i < nFieldCount; i++)
    1059             :     {
    1060           0 :         DDFField *poField = poClone->paoFields + i;
    1061             :         DDFFieldDefn *poDefn =
    1062           0 :             poTargetModule->FindFieldDefn(poField->GetFieldDefn()->GetName());
    1063             : 
    1064           0 :         poField->Initialize(poDefn, poField->GetData(), poField->GetDataSize());
    1065             :     }
    1066             : 
    1067           0 :     poModule->RemoveCloneRecord(poClone);
    1068           0 :     poClone->poModule = poTargetModule;
    1069           0 :     poTargetModule->AddCloneRecord(poClone);
    1070             : 
    1071           0 :     return poClone;
    1072             : }
    1073             : 
    1074             : /************************************************************************/
    1075             : /*                            DeleteField()                             */
    1076             : /************************************************************************/
    1077             : 
    1078             : /**
    1079             :  * Delete a field instance from a record.
    1080             :  *
    1081             :  * Remove a field from this record, cleaning up the data
    1082             :  * portion and repacking the fields list.  We don't try to
    1083             :  * reallocate the data area of the record to be smaller.
    1084             :  *
    1085             :  * NOTE: This method doesn't actually remove the header
    1086             :  * information for this field from the record tag list yet.
    1087             :  * This should be added if the resulting record is even to be
    1088             :  * written back to disk!
    1089             :  *
    1090             :  * @param poTarget the field instance on this record to delete.
    1091             :  *
    1092             :  * @return TRUE on success, or FALSE on failure.  Failure can occur if
    1093             :  * poTarget isn't really a field on this record.
    1094             :  */
    1095             : 
    1096           0 : int DDFRecord::DeleteField(DDFField *poTarget)
    1097             : 
    1098             : {
    1099             :     int iTarget, i;
    1100             : 
    1101             :     /* -------------------------------------------------------------------- */
    1102             :     /*      Find which field we are to delete.                              */
    1103             :     /* -------------------------------------------------------------------- */
    1104           0 :     for (iTarget = 0; iTarget < nFieldCount; iTarget++)
    1105             :     {
    1106           0 :         if (paoFields + iTarget == poTarget)
    1107           0 :             break;
    1108             :     }
    1109             : 
    1110           0 :     if (iTarget == nFieldCount)
    1111           0 :         return FALSE;
    1112             : 
    1113             :     /* -------------------------------------------------------------------- */
    1114             :     /*      Change the target fields data size to zero.  This takes care    */
    1115             :     /*      of repacking the data array, and updating all the following     */
    1116             :     /*      field data pointers.                                            */
    1117             :     /* -------------------------------------------------------------------- */
    1118           0 :     ResizeField(poTarget, 0);
    1119             : 
    1120             :     /* -------------------------------------------------------------------- */
    1121             :     /*      remove the target field, moving down all the other fields       */
    1122             :     /*      one step in the field list.                                     */
    1123             :     /* -------------------------------------------------------------------- */
    1124           0 :     for (i = iTarget; i < nFieldCount - 1; i++)
    1125             :     {
    1126           0 :         paoFields[i] = paoFields[i + 1];
    1127             :     }
    1128             : 
    1129           0 :     nFieldCount--;
    1130             : 
    1131           0 :     return TRUE;
    1132             : }
    1133             : 
    1134             : /************************************************************************/
    1135             : /*                            ResizeField()                             */
    1136             : /************************************************************************/
    1137             : 
    1138             : /**
    1139             :  * Alter field data size within record.
    1140             :  *
    1141             :  * This method will rearrange a DDFRecord altering the amount of space
    1142             :  * reserved for one of the existing fields.  All following fields will
    1143             :  * be shifted accordingly.  This includes updating the DDFField infos,
    1144             :  * and actually moving stuff within the data array after reallocating
    1145             :  * to the desired size.
    1146             :  *
    1147             :  * @param poField the field to alter.
    1148             :  * @param nNewDataSize the number of data bytes to be reserved for the field.
    1149             :  *
    1150             :  * @return TRUE on success or FALSE on failure.
    1151             :  */
    1152             : 
    1153         748 : int DDFRecord::ResizeField(DDFField *poField, int nNewDataSize)
    1154             : 
    1155             : {
    1156             :     int iTarget, i;
    1157             :     int nBytesToMove;
    1158             : 
    1159             :     /* -------------------------------------------------------------------- */
    1160             :     /*      Find which field we are to resize.                              */
    1161             :     /* -------------------------------------------------------------------- */
    1162        1886 :     for (iTarget = 0; iTarget < nFieldCount; iTarget++)
    1163             :     {
    1164        1886 :         if (paoFields + iTarget == poField)
    1165         748 :             break;
    1166             :     }
    1167             : 
    1168         748 :     if (iTarget == nFieldCount)
    1169             :     {
    1170           0 :         CPLAssert(false);
    1171             :         return FALSE;
    1172             :     }
    1173             : 
    1174             :     /* -------------------------------------------------------------------- */
    1175             :     /*      Reallocate the data buffer accordingly.                         */
    1176             :     /* -------------------------------------------------------------------- */
    1177         748 :     int nBytesToAdd = nNewDataSize - poField->GetDataSize();
    1178         748 :     const char *pachOldData = pachData;
    1179             : 
    1180             :     // Don't realloc things smaller ... we will cut off some data.
    1181         748 :     if (nBytesToAdd > 0)
    1182             :     {
    1183         683 :         pachData = (char *)CPLRealloc(pachData, nDataSize + nBytesToAdd + 1);
    1184         683 :         pachData[nDataSize + nBytesToAdd] = '\0';
    1185             :     }
    1186             : 
    1187         748 :     nDataSize += nBytesToAdd;
    1188             : 
    1189             :     /* -------------------------------------------------------------------- */
    1190             :     /*      How much data needs to be shifted up or down after this field?  */
    1191             :     /* -------------------------------------------------------------------- */
    1192         748 :     nBytesToMove = nDataSize - static_cast<int>(poField->GetData() +
    1193         748 :                                                 poField->GetDataSize() -
    1194         748 :                                                 pachOldData + nBytesToAdd);
    1195             : 
    1196             :     /* -------------------------------------------------------------------- */
    1197             :     /*      Update fields to point into newly allocated buffer.             */
    1198             :     /* -------------------------------------------------------------------- */
    1199        2634 :     for (i = 0; i < nFieldCount; i++)
    1200             :     {
    1201             :         int nOffset;
    1202             : 
    1203        1886 :         nOffset = static_cast<int>(paoFields[i].GetData() - pachOldData);
    1204        1886 :         paoFields[i].Initialize(paoFields[i].GetFieldDefn(), pachData + nOffset,
    1205        1886 :                                 paoFields[i].GetDataSize());
    1206             :     }
    1207             : 
    1208             :     /* -------------------------------------------------------------------- */
    1209             :     /*      Shift the data beyond this field up or down as needed.          */
    1210             :     /* -------------------------------------------------------------------- */
    1211         748 :     if (nBytesToMove > 0)
    1212           0 :         memmove(
    1213           0 :             (char *)poField->GetData() + poField->GetDataSize() + nBytesToAdd,
    1214           0 :             (char *)poField->GetData() + poField->GetDataSize(), nBytesToMove);
    1215             : 
    1216             :     /* -------------------------------------------------------------------- */
    1217             :     /*      Update the target fields info.                                  */
    1218             :     /* -------------------------------------------------------------------- */
    1219         748 :     poField->Initialize(poField->GetFieldDefn(), poField->GetData(),
    1220         748 :                         poField->GetDataSize() + nBytesToAdd);
    1221             : 
    1222             :     /* -------------------------------------------------------------------- */
    1223             :     /*      Shift all following fields down, and update their data          */
    1224             :     /*      locations.                                                      */
    1225             :     /* -------------------------------------------------------------------- */
    1226         748 :     if (nBytesToAdd < 0)
    1227             :     {
    1228           0 :         for (i = iTarget + 1; i < nFieldCount; i++)
    1229             :         {
    1230           0 :             char *pszOldDataLocation = (char *)paoFields[i].GetData();
    1231             : 
    1232           0 :             paoFields[i].Initialize(paoFields[i].GetFieldDefn(),
    1233           0 :                                     pszOldDataLocation + nBytesToAdd,
    1234           0 :                                     paoFields[i].GetDataSize());
    1235             :         }
    1236             :     }
    1237             :     else
    1238             :     {
    1239         748 :         for (i = nFieldCount - 1; i > iTarget; i--)
    1240             :         {
    1241           0 :             char *pszOldDataLocation = (char *)paoFields[i].GetData();
    1242             : 
    1243           0 :             paoFields[i].Initialize(paoFields[i].GetFieldDefn(),
    1244           0 :                                     pszOldDataLocation + nBytesToAdd,
    1245           0 :                                     paoFields[i].GetDataSize());
    1246             :         }
    1247             :     }
    1248             : 
    1249         748 :     return TRUE;
    1250             : }
    1251             : 
    1252             : /************************************************************************/
    1253             : /*                              AddField()                              */
    1254             : /************************************************************************/
    1255             : 
    1256             : /**
    1257             :  * Add a new field to record.
    1258             :  *
    1259             :  * Add a new zero sized field to the record.  The new field is always
    1260             :  * added at the end of the record.
    1261             :  *
    1262             :  * NOTE: This method doesn't currently update the header information for
    1263             :  * the record to include the field information for this field, so the
    1264             :  * resulting record image isn't suitable for writing to disk.  However,
    1265             :  * everything else about the record state should be updated properly to
    1266             :  * reflect the new field.
    1267             :  *
    1268             :  * @param poDefn the definition of the field to be added.
    1269             :  *
    1270             :  * @return the field object on success, or NULL on failure.
    1271             :  */
    1272             : 
    1273         513 : DDFField *DDFRecord::AddField(DDFFieldDefn *poDefn)
    1274             : 
    1275             : {
    1276             :     /* -------------------------------------------------------------------- */
    1277             :     /*      Reallocate the fields array larger by one, and initialize       */
    1278             :     /*      the new field.                                                  */
    1279             :     /* -------------------------------------------------------------------- */
    1280        1678 :     DDFField *paoNewFields = new DDFField[nFieldCount + 1];
    1281         513 :     if (nFieldCount > 0)
    1282             :     {
    1283         359 :         memcpy(paoNewFields, paoFields, sizeof(DDFField) * nFieldCount);
    1284         359 :         delete[] paoFields;
    1285             :     }
    1286         513 :     paoFields = paoNewFields;
    1287         513 :     nFieldCount++;
    1288             : 
    1289             :     /* -------------------------------------------------------------------- */
    1290             :     /*      Initialize the new field properly.                              */
    1291             :     /* -------------------------------------------------------------------- */
    1292         513 :     if (nFieldCount == 1)
    1293             :     {
    1294         154 :         paoFields[0].Initialize(poDefn, GetData(), 0);
    1295             :     }
    1296             :     else
    1297             :     {
    1298         718 :         paoFields[nFieldCount - 1].Initialize(
    1299             :             poDefn,
    1300         359 :             paoFields[nFieldCount - 2].GetData() +
    1301         359 :                 paoFields[nFieldCount - 2].GetDataSize(),
    1302             :             0);
    1303             :     }
    1304             : 
    1305             :     /* -------------------------------------------------------------------- */
    1306             :     /*      Initialize field.                                               */
    1307             :     /* -------------------------------------------------------------------- */
    1308         513 :     CreateDefaultFieldInstance(paoFields + nFieldCount - 1, 0);
    1309             : 
    1310         513 :     return paoFields + (nFieldCount - 1);
    1311             : }
    1312             : 
    1313             : /************************************************************************/
    1314             : /*                            SetFieldRaw()                             */
    1315             : /************************************************************************/
    1316             : 
    1317             : /**
    1318             :  * Set the raw contents of a field instance.
    1319             :  *
    1320             :  * @param poField the field to set data within.
    1321             :  * @param iIndexWithinField The instance of this field to replace.  Must
    1322             :  * be a value between 0 and GetRepeatCount().  If GetRepeatCount() is used, a
    1323             :  * new instance of the field is appended.
    1324             :  * @param pachRawData the raw data to replace this field instance with.
    1325             :  * @param nRawDataSize the number of bytes pointed to by pachRawData.
    1326             :  *
    1327             :  * @return TRUE on success or FALSE on failure.
    1328             :  */
    1329             : 
    1330         676 : int DDFRecord::SetFieldRaw(DDFField *poField, int iIndexWithinField,
    1331             :                            const char *pachRawData, int nRawDataSize)
    1332             : 
    1333             : {
    1334             :     int iTarget, nRepeatCount;
    1335             : 
    1336             :     /* -------------------------------------------------------------------- */
    1337             :     /*      Find which field we are to update.                              */
    1338             :     /* -------------------------------------------------------------------- */
    1339        1742 :     for (iTarget = 0; iTarget < nFieldCount; iTarget++)
    1340             :     {
    1341        1742 :         if (paoFields + iTarget == poField)
    1342         676 :             break;
    1343             :     }
    1344             : 
    1345         676 :     if (iTarget == nFieldCount)
    1346           0 :         return FALSE;
    1347             : 
    1348         676 :     nRepeatCount = poField->GetRepeatCount();
    1349             : 
    1350         676 :     if (iIndexWithinField < 0 || iIndexWithinField > nRepeatCount)
    1351           0 :         return FALSE;
    1352             : 
    1353             :     /* -------------------------------------------------------------------- */
    1354             :     /*      Are we adding an instance?  This is easier and different        */
    1355             :     /*      than replacing an existing instance.                            */
    1356             :     /* -------------------------------------------------------------------- */
    1357        1139 :     if (iIndexWithinField == nRepeatCount ||
    1358         463 :         !poField->GetFieldDefn()->IsRepeating())
    1359             :     {
    1360         563 :         if (!poField->GetFieldDefn()->IsRepeating() && iIndexWithinField != 0)
    1361           0 :             return FALSE;
    1362             : 
    1363         563 :         int nOldSize = poField->GetDataSize();
    1364         563 :         if (nOldSize == 0)
    1365         513 :             nOldSize++;  // for added DDF_FIELD_TERMINATOR.
    1366             : 
    1367         563 :         if (!ResizeField(poField, nOldSize + nRawDataSize))
    1368           0 :             return FALSE;
    1369             : 
    1370         563 :         char *pachFieldData = (char *)poField->GetData();
    1371         563 :         memcpy(pachFieldData + nOldSize - 1, pachRawData, nRawDataSize);
    1372         563 :         pachFieldData[nOldSize + nRawDataSize - 1] = DDF_FIELD_TERMINATOR;
    1373             : 
    1374         563 :         return TRUE;
    1375             :     }
    1376             : 
    1377             :     /* -------------------------------------------------------------------- */
    1378             :     /*      Get a pointer to the start of the existing data for this        */
    1379             :     /*      iteration of the field.                                         */
    1380             :     /* -------------------------------------------------------------------- */
    1381         113 :     const char *pachWrkData = nullptr;
    1382         113 :     int nInstanceSize = 0;
    1383             : 
    1384             :     // We special case this to avoid a lot of warnings when initializing
    1385             :     // the field the first time.
    1386         113 :     if (poField->GetDataSize() == 0)
    1387             :     {
    1388           0 :         pachWrkData = poField->GetData();
    1389             :     }
    1390             :     else
    1391             :     {
    1392             :         pachWrkData =
    1393         113 :             poField->GetInstanceData(iIndexWithinField, &nInstanceSize);
    1394             :     }
    1395             : 
    1396             :     /* -------------------------------------------------------------------- */
    1397             :     /*      Create new image of this whole field.                           */
    1398             :     /* -------------------------------------------------------------------- */
    1399         113 :     int nNewFieldSize = poField->GetDataSize() - nInstanceSize + nRawDataSize;
    1400             : 
    1401         113 :     char *pachNewImage = (char *)CPLMalloc(nNewFieldSize);
    1402             : 
    1403         113 :     int nPreBytes = static_cast<int>(pachWrkData - poField->GetData());
    1404         113 :     int nPostBytes = poField->GetDataSize() - nPreBytes - nInstanceSize;
    1405             : 
    1406         113 :     memcpy(pachNewImage, poField->GetData(), nPreBytes);
    1407         226 :     memcpy(pachNewImage + nPreBytes + nRawDataSize,
    1408         113 :            poField->GetData() + nPreBytes + nInstanceSize, nPostBytes);
    1409         113 :     memcpy(pachNewImage + nPreBytes, pachRawData, nRawDataSize);
    1410             : 
    1411             :     /* -------------------------------------------------------------------- */
    1412             :     /*      Resize the field to the desired new size.                       */
    1413             :     /* -------------------------------------------------------------------- */
    1414         113 :     ResizeField(poField, nNewFieldSize);
    1415             : 
    1416         113 :     memcpy((void *)poField->GetData(), pachNewImage, nNewFieldSize);
    1417         113 :     CPLFree(pachNewImage);
    1418             : 
    1419         113 :     return TRUE;
    1420             : }
    1421             : 
    1422             : /************************************************************************/
    1423             : /*                           UpdateFieldRaw()                           */
    1424             : /************************************************************************/
    1425             : 
    1426          72 : int DDFRecord::UpdateFieldRaw(DDFField *poField, int iIndexWithinField,
    1427             :                               int nStartOffset, int nOldSize,
    1428             :                               const char *pachRawData, int nRawDataSize)
    1429             : 
    1430             : {
    1431             :     int iTarget, nRepeatCount;
    1432             : 
    1433             :     /* -------------------------------------------------------------------- */
    1434             :     /*      Find which field we are to update.                              */
    1435             :     /* -------------------------------------------------------------------- */
    1436         144 :     for (iTarget = 0; iTarget < nFieldCount; iTarget++)
    1437             :     {
    1438         144 :         if (paoFields + iTarget == poField)
    1439          72 :             break;
    1440             :     }
    1441             : 
    1442          72 :     if (iTarget == nFieldCount)
    1443           0 :         return FALSE;
    1444             : 
    1445          72 :     nRepeatCount = poField->GetRepeatCount();
    1446             : 
    1447          72 :     if (iIndexWithinField < 0 || iIndexWithinField >= nRepeatCount)
    1448           0 :         return FALSE;
    1449             : 
    1450             :     /* -------------------------------------------------------------------- */
    1451             :     /*      Figure out how much pre and post data there is.                 */
    1452             :     /* -------------------------------------------------------------------- */
    1453          72 :     int nInstanceSize = 0;
    1454             : 
    1455             :     char *pachWrkData =
    1456          72 :         (char *)poField->GetInstanceData(iIndexWithinField, &nInstanceSize);
    1457             :     int nPreBytes =
    1458          72 :         static_cast<int>(pachWrkData - poField->GetData() + nStartOffset);
    1459          72 :     int nPostBytes = poField->GetDataSize() - nPreBytes - nOldSize;
    1460             : 
    1461             :     /* -------------------------------------------------------------------- */
    1462             :     /*      If we aren't changing the size, just copy over the existing     */
    1463             :     /*      data.                                                           */
    1464             :     /* -------------------------------------------------------------------- */
    1465          72 :     if (nOldSize == nRawDataSize)
    1466             :     {
    1467           0 :         memcpy(pachWrkData + nStartOffset, pachRawData, nRawDataSize);
    1468           0 :         return TRUE;
    1469             :     }
    1470             : 
    1471             :     /* -------------------------------------------------------------------- */
    1472             :     /*      If we are shrinking, move in the new data, and shuffle down     */
    1473             :     /*      the old before resizing.                                        */
    1474             :     /* -------------------------------------------------------------------- */
    1475          72 :     if (nRawDataSize < nOldSize)
    1476             :     {
    1477           0 :         memcpy(((char *)poField->GetData()) + nPreBytes, pachRawData,
    1478             :                nRawDataSize);
    1479           0 :         memmove(((char *)poField->GetData()) + nPreBytes + nRawDataSize,
    1480           0 :                 ((char *)poField->GetData()) + nPreBytes + nOldSize,
    1481             :                 nPostBytes);
    1482             :     }
    1483             : 
    1484             :     /* -------------------------------------------------------------------- */
    1485             :     /*      Resize the whole buffer.                                        */
    1486             :     /* -------------------------------------------------------------------- */
    1487          72 :     if (!ResizeField(poField, poField->GetDataSize() - nOldSize + nRawDataSize))
    1488           0 :         return FALSE;
    1489             : 
    1490             :     /* -------------------------------------------------------------------- */
    1491             :     /*      If we growing the buffer, shuffle up the post data, and         */
    1492             :     /*      move in our new values.                                         */
    1493             :     /* -------------------------------------------------------------------- */
    1494          72 :     if (nRawDataSize >= nOldSize)
    1495             :     {
    1496         216 :         memmove(((char *)poField->GetData()) + nPreBytes + nRawDataSize,
    1497          72 :                 ((char *)poField->GetData()) + nPreBytes + nOldSize,
    1498             :                 nPostBytes);
    1499          72 :         memcpy(((char *)poField->GetData()) + nPreBytes, pachRawData,
    1500             :                nRawDataSize);
    1501             :     }
    1502             : 
    1503          72 :     return TRUE;
    1504             : }
    1505             : 
    1506             : /************************************************************************/
    1507             : /*                           ResetDirectory()                           */
    1508             : /*                                                                      */
    1509             : /*      Re-prepares the directory information for the record.           */
    1510             : /************************************************************************/
    1511             : 
    1512         154 : void DDFRecord::ResetDirectory()
    1513             : 
    1514             : {
    1515             :     int iField;
    1516             : 
    1517             :     /* -------------------------------------------------------------------- */
    1518             :     /*      Eventually we should try to optimize the size of offset and     */
    1519             :     /*      field length.                                                   */
    1520             :     /* -------------------------------------------------------------------- */
    1521             : 
    1522             :     /* -------------------------------------------------------------------- */
    1523             :     /*      Compute how large the directory needs to be.                    */
    1524             :     /* -------------------------------------------------------------------- */
    1525             :     int nEntrySize, nDirSize;
    1526             : 
    1527         154 :     nEntrySize = _sizeFieldPos + _sizeFieldLength + _sizeFieldTag;
    1528         154 :     nDirSize = nEntrySize * nFieldCount + 1;
    1529             : 
    1530             :     /* -------------------------------------------------------------------- */
    1531             :     /*      If the directory size is different than what is currently       */
    1532             :     /*      reserved for it, we must resize.                                */
    1533             :     /* -------------------------------------------------------------------- */
    1534         154 :     if (nDirSize != nFieldOffset)
    1535             :     {
    1536         154 :         const int nNewDataSize = nDataSize - nFieldOffset + nDirSize;
    1537         154 :         char *pachNewData = (char *)CPLMalloc(nNewDataSize + 1);
    1538         154 :         pachNewData[nNewDataSize] = '\0';
    1539         154 :         memcpy(pachNewData + nDirSize, pachData + nFieldOffset,
    1540         154 :                nNewDataSize - nDirSize);
    1541             : 
    1542         667 :         for (iField = 0; paoFields != nullptr && iField < nFieldCount; iField++)
    1543             :         {
    1544             :             int nOffset;
    1545         513 :             DDFField *poField = /*GetField( iField )*/ paoFields + iField;
    1546             : 
    1547         513 :             nOffset = static_cast<int>(poField->GetData() - pachData -
    1548         513 :                                        nFieldOffset + nDirSize);
    1549         513 :             poField->Initialize(poField->GetFieldDefn(), pachNewData + nOffset,
    1550             :                                 poField->GetDataSize());
    1551             :         }
    1552             : 
    1553         154 :         CPLFree(pachData);
    1554         154 :         pachData = pachNewData;
    1555         154 :         nDataSize = nNewDataSize;
    1556         154 :         nFieldOffset = nDirSize;
    1557             :     }
    1558             : 
    1559             :     /* -------------------------------------------------------------------- */
    1560             :     /*      Now set each directory entry.                                   */
    1561             :     /* -------------------------------------------------------------------- */
    1562         667 :     for (iField = 0; paoFields != nullptr && iField < nFieldCount; iField++)
    1563             :     {
    1564         513 :         DDFField *poField = /*GetField( iField )*/ paoFields + iField;
    1565         513 :         DDFFieldDefn *poDefn = poField->GetFieldDefn();
    1566             :         char szFormat[128];
    1567             : 
    1568         513 :         snprintf(szFormat, sizeof(szFormat), "%%%ds%%0%dd%%0%dd", _sizeFieldTag,
    1569             :                  _sizeFieldLength, _sizeFieldPos);
    1570             : 
    1571         513 :         snprintf(pachData + nEntrySize * iField, nEntrySize + 1, szFormat,
    1572             :                  poDefn->GetName(), poField->GetDataSize(),
    1573         513 :                  poField->GetData() - pachData - nFieldOffset);
    1574             :     }
    1575             : 
    1576         154 :     pachData[nEntrySize * nFieldCount] = DDF_FIELD_TERMINATOR;
    1577         154 : }
    1578             : 
    1579             : /************************************************************************/
    1580             : /*                     CreateDefaultFieldInstance()                     */
    1581             : /************************************************************************/
    1582             : 
    1583             : /**
    1584             :  * Initialize default instance.
    1585             :  *
    1586             :  * This method is normally only used internally by the AddField() method
    1587             :  * to initialize the new field instance with default subfield values.  It
    1588             :  * installs default data for one instance of the field in the record
    1589             :  * using the DDFFieldDefn::GetDefaultValue() method and
    1590             :  * DDFRecord::SetFieldRaw().
    1591             :  *
    1592             :  * @param poField the field within the record to be assign a default
    1593             :  * instance.
    1594             :  * @param iIndexWithinField the instance to set (may not have been tested with
    1595             :  * values other than 0).
    1596             :  *
    1597             :  * @return TRUE on success or FALSE on failure.
    1598             :  */
    1599             : 
    1600         563 : int DDFRecord::CreateDefaultFieldInstance(DDFField *poField,
    1601             :                                           int iIndexWithinField)
    1602             : 
    1603             : {
    1604         563 :     int nRawSize = 0;
    1605         563 :     char *pachRawData = poField->GetFieldDefn()->GetDefaultValue(&nRawSize);
    1606         563 :     if (pachRawData == nullptr)
    1607         154 :         return FALSE;
    1608             : 
    1609             :     const int nSuccess =
    1610         409 :         SetFieldRaw(poField, iIndexWithinField, pachRawData, nRawSize);
    1611             : 
    1612         409 :     CPLFree(pachRawData);
    1613             : 
    1614         409 :     return nSuccess;
    1615             : }
    1616             : 
    1617             : /************************************************************************/
    1618             : /*                         SetStringSubfield()                          */
    1619             : /************************************************************************/
    1620             : 
    1621             : /**
    1622             :  * Set a string subfield in record.
    1623             :  *
    1624             :  * The value of a given subfield is replaced with a new string value
    1625             :  * formatted appropriately.
    1626             :  *
    1627             :  * @param pszField the field name to operate on.
    1628             :  * @param iFieldIndex the field index to operate on (zero based).
    1629             :  * @param pszSubfield the subfield name to operate on.
    1630             :  * @param iSubfieldIndex the subfield index to operate on (zero based).
    1631             :  * @param pszValue the new string to place in the subfield.  This may be
    1632             :  * arbitrary binary bytes if nValueLength is specified.
    1633             :  * @param nValueLength the number of valid bytes in pszValue, may be -1 to
    1634             :  * internally fetch with strlen().
    1635             :  *
    1636             :  * @return TRUE if successful, and FALSE if not.
    1637             :  */
    1638             : 
    1639         262 : int DDFRecord::SetStringSubfield(const char *pszField, int iFieldIndex,
    1640             :                                  const char *pszSubfield, int iSubfieldIndex,
    1641             :                                  const char *pszValue, int nValueLength)
    1642             : 
    1643             : {
    1644             :     /* -------------------------------------------------------------------- */
    1645             :     /*      Fetch the field. If this fails, return zero.                    */
    1646             :     /* -------------------------------------------------------------------- */
    1647         262 :     DDFField *poField = FindField(pszField, iFieldIndex);
    1648         262 :     if (poField == nullptr)
    1649           0 :         return FALSE;
    1650             : 
    1651             :     /* -------------------------------------------------------------------- */
    1652             :     /*      Get the subfield definition                                     */
    1653             :     /* -------------------------------------------------------------------- */
    1654             :     DDFSubfieldDefn *poSFDefn =
    1655         262 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
    1656         262 :     if (poSFDefn == nullptr)
    1657           0 :         return FALSE;
    1658             : 
    1659             :     /* -------------------------------------------------------------------- */
    1660             :     /*      How long will the formatted value be?                           */
    1661             :     /* -------------------------------------------------------------------- */
    1662             :     int nFormattedLen;
    1663             : 
    1664         262 :     if (!poSFDefn->FormatStringValue(nullptr, 0, &nFormattedLen, pszValue,
    1665             :                                      nValueLength))
    1666           0 :         return FALSE;
    1667             : 
    1668             :     /* -------------------------------------------------------------------- */
    1669             :     /*      Get a pointer to the data.                                      */
    1670             :     /* -------------------------------------------------------------------- */
    1671             :     int nMaxBytes;
    1672             :     char *pachSubfieldData =
    1673         262 :         (char *)poField->GetSubfieldData(poSFDefn, &nMaxBytes, iSubfieldIndex);
    1674         262 :     if (pachSubfieldData == nullptr)
    1675           0 :         return FALSE;
    1676             : 
    1677             :     /* -------------------------------------------------------------------- */
    1678             :     /*      Add new instance if we have run out of data.                    */
    1679             :     /* -------------------------------------------------------------------- */
    1680         262 :     if (nMaxBytes == 0 ||
    1681         262 :         (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR))
    1682             :     {
    1683          50 :         CreateDefaultFieldInstance(poField, iSubfieldIndex);
    1684             : 
    1685             :         // Refetch.
    1686          50 :         pachSubfieldData = (char *)poField->GetSubfieldData(
    1687             :             poSFDefn, &nMaxBytes, iSubfieldIndex);
    1688          50 :         if (pachSubfieldData == nullptr)
    1689           0 :             return FALSE;
    1690             :     }
    1691             : 
    1692             :     /* -------------------------------------------------------------------- */
    1693             :     /*      If the new length matches the existing length, just overlay     */
    1694             :     /*      and return.                                                     */
    1695             :     /* -------------------------------------------------------------------- */
    1696             :     int nExistingLength;
    1697             : 
    1698         262 :     poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
    1699             : 
    1700         262 :     if (nExistingLength == nFormattedLen)
    1701             :     {
    1702         190 :         return poSFDefn->FormatStringValue(pachSubfieldData, nFormattedLen,
    1703         190 :                                            nullptr, pszValue, nValueLength);
    1704             :     }
    1705             : 
    1706             :     /* -------------------------------------------------------------------- */
    1707             :     /*      We will need to resize the raw data.                            */
    1708             :     /* -------------------------------------------------------------------- */
    1709          72 :     int nInstanceSize = 0;
    1710             : 
    1711             :     const char *pachFieldInstData =
    1712          72 :         poField->GetInstanceData(iFieldIndex, &nInstanceSize);
    1713             : 
    1714          72 :     const int nStartOffset =
    1715          72 :         static_cast<int>(pachSubfieldData - pachFieldInstData);
    1716             : 
    1717          72 :     char *pachNewData = (char *)CPLMalloc(nFormattedLen);
    1718          72 :     poSFDefn->FormatStringValue(pachNewData, nFormattedLen, nullptr, pszValue,
    1719             :                                 nValueLength);
    1720             : 
    1721             :     const int nSuccess =
    1722          72 :         UpdateFieldRaw(poField, iFieldIndex, nStartOffset, nExistingLength,
    1723             :                        pachNewData, nFormattedLen);
    1724             : 
    1725          72 :     CPLFree(pachNewData);
    1726             : 
    1727          72 :     return nSuccess;
    1728             : }
    1729             : 
    1730             : /************************************************************************/
    1731             : /*                           SetIntSubfield()                           */
    1732             : /************************************************************************/
    1733             : 
    1734             : /**
    1735             :  * Set an integer subfield in record.
    1736             :  *
    1737             :  * The value of a given subfield is replaced with a new integer value
    1738             :  * formatted appropriately.
    1739             :  *
    1740             :  * @param pszField the field name to operate on.
    1741             :  * @param iFieldIndex the field index to operate on (zero based).
    1742             :  * @param pszSubfield the subfield name to operate on.
    1743             :  * @param iSubfieldIndex the subfield index to operate on (zero based).
    1744             :  * @param nNewValue the new value to place in the subfield.
    1745             :  *
    1746             :  * @return TRUE if successful, and FALSE if not.
    1747             :  */
    1748             : 
    1749        1556 : int DDFRecord::SetIntSubfield(const char *pszField, int iFieldIndex,
    1750             :                               const char *pszSubfield, int iSubfieldIndex,
    1751             :                               int nNewValue)
    1752             : 
    1753             : {
    1754             :     /* -------------------------------------------------------------------- */
    1755             :     /*      Fetch the field. If this fails, return zero.                    */
    1756             :     /* -------------------------------------------------------------------- */
    1757        1556 :     DDFField *poField = FindField(pszField, iFieldIndex);
    1758        1556 :     if (poField == nullptr)
    1759           0 :         return FALSE;
    1760             : 
    1761             :     /* -------------------------------------------------------------------- */
    1762             :     /*      Get the subfield definition                                     */
    1763             :     /* -------------------------------------------------------------------- */
    1764             :     DDFSubfieldDefn *poSFDefn =
    1765        1556 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
    1766        1556 :     if (poSFDefn == nullptr)
    1767           0 :         return FALSE;
    1768             : 
    1769             :     /* -------------------------------------------------------------------- */
    1770             :     /*      How long will the formatted value be?                           */
    1771             :     /* -------------------------------------------------------------------- */
    1772             :     int nFormattedLen;
    1773             : 
    1774        1556 :     if (!poSFDefn->FormatIntValue(nullptr, 0, &nFormattedLen, nNewValue))
    1775           0 :         return FALSE;
    1776             : 
    1777             :     /* -------------------------------------------------------------------- */
    1778             :     /*      Get a pointer to the data.                                      */
    1779             :     /* -------------------------------------------------------------------- */
    1780             :     int nMaxBytes;
    1781             :     char *pachSubfieldData =
    1782        1556 :         (char *)poField->GetSubfieldData(poSFDefn, &nMaxBytes, iSubfieldIndex);
    1783        1556 :     if (pachSubfieldData == nullptr)
    1784           0 :         return FALSE;
    1785             : 
    1786             :     /* -------------------------------------------------------------------- */
    1787             :     /*      Add new instance if we have run out of data.                    */
    1788             :     /* -------------------------------------------------------------------- */
    1789        1556 :     if (nMaxBytes == 0 ||
    1790        1556 :         (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR))
    1791             :     {
    1792           0 :         CreateDefaultFieldInstance(poField, iSubfieldIndex);
    1793             : 
    1794             :         // Refetch.
    1795           0 :         pachSubfieldData = (char *)poField->GetSubfieldData(
    1796             :             poSFDefn, &nMaxBytes, iSubfieldIndex);
    1797           0 :         if (pachSubfieldData == nullptr)
    1798           0 :             return FALSE;
    1799             :     }
    1800             : 
    1801             :     /* -------------------------------------------------------------------- */
    1802             :     /*      If the new length matches the existing length, just overlay     */
    1803             :     /*      and return.                                                     */
    1804             :     /* -------------------------------------------------------------------- */
    1805             :     int nExistingLength;
    1806             : 
    1807        1556 :     poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
    1808             : 
    1809        1556 :     if (nExistingLength == nFormattedLen)
    1810             :     {
    1811        1556 :         return poSFDefn->FormatIntValue(pachSubfieldData, nFormattedLen,
    1812        1556 :                                         nullptr, nNewValue);
    1813             :     }
    1814             : 
    1815             :     /* -------------------------------------------------------------------- */
    1816             :     /*      We will need to resize the raw data.                            */
    1817             :     /* -------------------------------------------------------------------- */
    1818           0 :     int nInstanceSize = 0;
    1819             : 
    1820             :     const char *pachFieldInstData =
    1821           0 :         poField->GetInstanceData(iFieldIndex, &nInstanceSize);
    1822             : 
    1823           0 :     const int nStartOffset =
    1824           0 :         static_cast<int>(pachSubfieldData - pachFieldInstData);
    1825             : 
    1826           0 :     char *pachNewData = (char *)CPLMalloc(nFormattedLen);
    1827           0 :     poSFDefn->FormatIntValue(pachNewData, nFormattedLen, nullptr, nNewValue);
    1828             : 
    1829             :     const int nSuccess =
    1830           0 :         UpdateFieldRaw(poField, iFieldIndex, nStartOffset, nExistingLength,
    1831             :                        pachNewData, nFormattedLen);
    1832             : 
    1833           0 :     CPLFree(pachNewData);
    1834             : 
    1835           0 :     return nSuccess;
    1836             : }
    1837             : 
    1838             : /************************************************************************/
    1839             : /*                          SetFloatSubfield()                          */
    1840             : /************************************************************************/
    1841             : 
    1842             : /**
    1843             :  * Set a float subfield in record.
    1844             :  *
    1845             :  * The value of a given subfield is replaced with a new float value
    1846             :  * formatted appropriately.
    1847             :  *
    1848             :  * @param pszField the field name to operate on.
    1849             :  * @param iFieldIndex the field index to operate on (zero based).
    1850             :  * @param pszSubfield the subfield name to operate on.
    1851             :  * @param iSubfieldIndex the subfield index to operate on (zero based).
    1852             :  * @param dfNewValue the new value to place in the subfield.
    1853             :  *
    1854             :  * @return TRUE if successful, and FALSE if not.
    1855             :  */
    1856             : 
    1857           0 : int DDFRecord::SetFloatSubfield(const char *pszField, int iFieldIndex,
    1858             :                                 const char *pszSubfield, int iSubfieldIndex,
    1859             :                                 double dfNewValue)
    1860             : 
    1861             : {
    1862             :     /* -------------------------------------------------------------------- */
    1863             :     /*      Fetch the field. If this fails, return zero.                    */
    1864             :     /* -------------------------------------------------------------------- */
    1865           0 :     DDFField *poField = FindField(pszField, iFieldIndex);
    1866           0 :     if (poField == nullptr)
    1867           0 :         return FALSE;
    1868             : 
    1869             :     /* -------------------------------------------------------------------- */
    1870             :     /*      Get the subfield definition                                     */
    1871             :     /* -------------------------------------------------------------------- */
    1872             :     DDFSubfieldDefn *poSFDefn =
    1873           0 :         poField->GetFieldDefn()->FindSubfieldDefn(pszSubfield);
    1874           0 :     if (poSFDefn == nullptr)
    1875           0 :         return FALSE;
    1876             : 
    1877             :     /* -------------------------------------------------------------------- */
    1878             :     /*      How long will the formatted value be?                           */
    1879             :     /* -------------------------------------------------------------------- */
    1880             :     int nFormattedLen;
    1881             : 
    1882           0 :     if (!poSFDefn->FormatFloatValue(nullptr, 0, &nFormattedLen, dfNewValue))
    1883           0 :         return FALSE;
    1884             : 
    1885             :     /* -------------------------------------------------------------------- */
    1886             :     /*      Get a pointer to the data.                                      */
    1887             :     /* -------------------------------------------------------------------- */
    1888             :     int nMaxBytes;
    1889             :     char *pachSubfieldData =
    1890           0 :         (char *)poField->GetSubfieldData(poSFDefn, &nMaxBytes, iSubfieldIndex);
    1891           0 :     if (pachSubfieldData == nullptr)
    1892           0 :         return FALSE;
    1893             : 
    1894             :     /* -------------------------------------------------------------------- */
    1895             :     /*      Add new instance if we have run out of data.                    */
    1896             :     /* -------------------------------------------------------------------- */
    1897           0 :     if (nMaxBytes == 0 ||
    1898           0 :         (nMaxBytes == 1 && pachSubfieldData[0] == DDF_FIELD_TERMINATOR))
    1899             :     {
    1900           0 :         CreateDefaultFieldInstance(poField, iSubfieldIndex);
    1901             : 
    1902             :         // Refetch.
    1903           0 :         pachSubfieldData = (char *)poField->GetSubfieldData(
    1904             :             poSFDefn, &nMaxBytes, iSubfieldIndex);
    1905           0 :         if (pachSubfieldData == nullptr)
    1906           0 :             return FALSE;
    1907             :     }
    1908             : 
    1909             :     /* -------------------------------------------------------------------- */
    1910             :     /*      If the new length matches the existing length, just overlay     */
    1911             :     /*      and return.                                                     */
    1912             :     /* -------------------------------------------------------------------- */
    1913             :     int nExistingLength;
    1914             : 
    1915           0 :     poSFDefn->GetDataLength(pachSubfieldData, nMaxBytes, &nExistingLength);
    1916             : 
    1917           0 :     if (nExistingLength == nFormattedLen)
    1918             :     {
    1919           0 :         return poSFDefn->FormatFloatValue(pachSubfieldData, nFormattedLen,
    1920           0 :                                           nullptr, dfNewValue);
    1921             :     }
    1922             : 
    1923             :     /* -------------------------------------------------------------------- */
    1924             :     /*      We will need to resize the raw data.                            */
    1925             :     /* -------------------------------------------------------------------- */
    1926           0 :     int nInstanceSize = 0;
    1927             : 
    1928             :     const char *pachFieldInstData =
    1929           0 :         poField->GetInstanceData(iFieldIndex, &nInstanceSize);
    1930             : 
    1931           0 :     const int nStartOffset = (int)(pachSubfieldData - pachFieldInstData);
    1932             : 
    1933           0 :     char *pachNewData = (char *)CPLMalloc(nFormattedLen);
    1934           0 :     poSFDefn->FormatFloatValue(pachNewData, nFormattedLen, nullptr, dfNewValue);
    1935             : 
    1936             :     const int nSuccess =
    1937           0 :         UpdateFieldRaw(poField, iFieldIndex, nStartOffset, nExistingLength,
    1938             :                        pachNewData, nFormattedLen);
    1939             : 
    1940           0 :     CPLFree(pachNewData);
    1941             : 
    1942           0 :     return nSuccess;
    1943             : }

Generated by: LCOV version 1.14