LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfmodule.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 158 211 74.9 %
Date: 2026-04-19 18:43:50 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  ISO 8211 Access
       4             :  * Purpose:  Implements the DDFModule class.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1999, Frank Warmerdam
       9             :  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"
      15             : #include "iso8211.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <array>
      19             : #include <cstdio>
      20             : #include <cstring>
      21             : 
      22             : #include "cpl_conv.h"
      23             : #include "cpl_error.h"
      24             : #include "cpl_vsi.h"
      25             : 
      26             : /************************************************************************/
      27             : /*                             DDFModule()                              */
      28             : /************************************************************************/
      29             : 
      30             : /**
      31             :  * The constructor.
      32             :  */
      33             : 
      34             : DDFModule::DDFModule() = default;
      35             : 
      36             : /************************************************************************/
      37             : /*                             ~DDFModule()                             */
      38             : /************************************************************************/
      39             : 
      40             : /**
      41             :  * The destructor.
      42             :  */
      43             : 
      44         181 : DDFModule::~DDFModule()
      45             : 
      46             : {
      47         181 :     Close();
      48         181 : }
      49             : 
      50             : /************************************************************************/
      51             : /*                               Close()                                */
      52             : /*                                                                      */
      53             : /*      Note that closing a file also destroys essentially all other    */
      54             : /*      module datastructures.                                          */
      55             : /************************************************************************/
      56             : 
      57             : /**
      58             :  * Close an ISO 8211 file.
      59             :  */
      60             : 
      61         202 : void DDFModule::Close()
      62             : 
      63             : {
      64             :     /* -------------------------------------------------------------------- */
      65             :     /*      Close the file.                                                 */
      66             :     /* -------------------------------------------------------------------- */
      67         202 :     if (fpDDF != nullptr)
      68             :     {
      69         123 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpDDF));
      70         123 :         fpDDF = nullptr;
      71             :     }
      72             : 
      73         202 :     poRecord.reset();
      74             : 
      75         202 :     apoFieldDefns.clear();
      76         202 : }
      77             : 
      78             : /************************************************************************/
      79             : /*                                Open()                                */
      80             : /*                                                                      */
      81             : /*      Open an ISO 8211 file, and read the DDR record to build the     */
      82             : /*      field definitions.                                              */
      83             : /************************************************************************/
      84             : 
      85             : /**
      86             :  * Open a ISO 8211 (DDF) file for reading.
      87             :  *
      88             :  * If the open succeeds the data descriptive record (DDR) will have been
      89             :  * read, and all the field and subfield definitions will be available.
      90             :  *
      91             :  * @param pszFilename   The name of the file to open.
      92             :  * @param bFailQuietly If FALSE a CPL Error is issued for non-8211 files,
      93             :  * otherwise quietly return NULL.
      94             :  *
      95             :  * @return FALSE if the open fails or TRUE if it succeeds.  Errors messages
      96             :  * are issued internally with CPLError().
      97             :  */
      98             : 
      99         143 : int DDFModule::Open(const char *pszFilename, int bFailQuietly)
     100             : 
     101             : {
     102         143 :     constexpr int nLeaderSize = 24;
     103             : 
     104             :     /* -------------------------------------------------------------------- */
     105             :     /*      Close the existing file if there is one.                        */
     106             :     /* -------------------------------------------------------------------- */
     107         143 :     if (fpDDF != nullptr)
     108           0 :         Close();
     109             : 
     110             :     /* -------------------------------------------------------------------- */
     111             :     /*      Open the file.                                                  */
     112             :     /* -------------------------------------------------------------------- */
     113             :     VSIStatBufL sStat;
     114         143 :     if (VSIStatL(pszFilename, &sStat) == 0 && !VSI_ISDIR(sStat.st_mode))
     115         104 :         fpDDF = VSIFOpenL(pszFilename, "rb");
     116             : 
     117         143 :     if (fpDDF == nullptr)
     118             :     {
     119          39 :         if (!bFailQuietly)
     120           0 :             CPLError(CE_Failure, CPLE_OpenFailed,
     121             :                      "Unable to open DDF file `%s'.", pszFilename);
     122          39 :         return FALSE;
     123             :     }
     124             : 
     125             :     /* -------------------------------------------------------------------- */
     126             :     /*      Read the 24 byte leader.                                        */
     127             :     /* -------------------------------------------------------------------- */
     128             :     char achLeader[nLeaderSize];
     129             : 
     130         104 :     if (static_cast<int>(VSIFReadL(achLeader, 1, nLeaderSize, fpDDF)) !=
     131             :         nLeaderSize)
     132             :     {
     133           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpDDF));
     134           0 :         fpDDF = nullptr;
     135             : 
     136           0 :         if (!bFailQuietly)
     137           0 :             CPLError(CE_Failure, CPLE_FileIO,
     138             :                      "Leader is short on DDF file `%s'.", pszFilename);
     139             : 
     140           0 :         return FALSE;
     141             :     }
     142             : 
     143             :     /* -------------------------------------------------------------------- */
     144             :     /*      Verify that this appears to be a valid DDF file.                */
     145             :     /* -------------------------------------------------------------------- */
     146         104 :     int i, bValid = TRUE;
     147             : 
     148        2600 :     for (i = 0; i < nLeaderSize; i++)
     149             :     {
     150        2496 :         if (achLeader[i] < 32 || achLeader[i] > 126)
     151           0 :             bValid = FALSE;
     152             :     }
     153             : 
     154         104 :     if (achLeader[5] != '1' && achLeader[5] != '2' && achLeader[5] != '3')
     155           0 :         bValid = FALSE;
     156             : 
     157         104 :     if (achLeader[6] != 'L')
     158           0 :         bValid = FALSE;
     159         104 :     if (achLeader[8] != '1' && achLeader[8] != ' ')
     160           0 :         bValid = FALSE;
     161             : 
     162             :     /* -------------------------------------------------------------------- */
     163             :     /*      Extract information from leader.                                */
     164             :     /* -------------------------------------------------------------------- */
     165             : 
     166         104 :     if (bValid)
     167             :     {
     168         104 :         _recLength = DDFScanInt(achLeader + 0, 5);
     169         104 :         _interchangeLevel = achLeader[5];
     170         104 :         _leaderIden = achLeader[6];
     171         104 :         _inlineCodeExtensionIndicator = achLeader[7];
     172         104 :         _versionNumber = achLeader[8];
     173         104 :         _appIndicator = achLeader[9];
     174         104 :         _fieldControlLength = DDFScanInt(achLeader + 10, 2);
     175         104 :         _fieldAreaStart = DDFScanInt(achLeader + 12, 5);
     176         104 :         _extendedCharSet[0] = achLeader[17];
     177         104 :         _extendedCharSet[1] = achLeader[18];
     178         104 :         _extendedCharSet[2] = achLeader[19];
     179         104 :         _sizeFieldLength = DDFScanInt(achLeader + 20, 1);
     180         104 :         _sizeFieldPos = DDFScanInt(achLeader + 21, 1);
     181         104 :         _sizeFieldTag = DDFScanInt(achLeader + 23, 1);
     182             : 
     183         104 :         if (_recLength < nLeaderSize || _fieldControlLength <= 0 ||
     184         104 :             _fieldAreaStart < 24 || _sizeFieldLength <= 0 ||
     185         104 :             _sizeFieldPos <= 0 || _sizeFieldTag <= 0)
     186             :         {
     187           0 :             bValid = FALSE;
     188             :         }
     189             :     }
     190             : 
     191             :     /* -------------------------------------------------------------------- */
     192             :     /*      If the header is invalid, then clean up, report the error       */
     193             :     /*      and return.                                                     */
     194             :     /* -------------------------------------------------------------------- */
     195         104 :     if (!bValid)
     196             :     {
     197           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpDDF));
     198           0 :         fpDDF = nullptr;
     199             : 
     200           0 :         if (!bFailQuietly)
     201           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     202             :                      "File `%s' does not appear to have\n"
     203             :                      "a valid ISO 8211 header.\n",
     204             :                      pszFilename);
     205           0 :         return FALSE;
     206             :     }
     207             : 
     208             :     /* -------------------------------------------------------------------- */
     209             :     /*      Read the whole record info memory.                              */
     210             :     /* -------------------------------------------------------------------- */
     211         208 :     std::string osRecord;
     212         104 :     osRecord.assign(achLeader, nLeaderSize);
     213         104 :     osRecord.resize(_recLength);
     214             : 
     215         104 :     if (static_cast<int>(VSIFReadL(osRecord.data() + nLeaderSize, 1,
     216         104 :                                    _recLength - nLeaderSize, fpDDF)) !=
     217         104 :         _recLength - nLeaderSize)
     218             :     {
     219           0 :         if (!bFailQuietly)
     220           0 :             CPLError(CE_Failure, CPLE_FileIO,
     221             :                      "Header record is short on DDF file `%s'.", pszFilename);
     222             : 
     223           0 :         return FALSE;
     224             :     }
     225             : 
     226             :     /* -------------------------------------------------------------------- */
     227             :     /*      First make a pass counting the directory entries.               */
     228             :     /* -------------------------------------------------------------------- */
     229         104 :     int nFieldEntryWidth, nFDCount = 0;
     230             : 
     231         104 :     nFieldEntryWidth = _sizeFieldLength + _sizeFieldPos + _sizeFieldTag;
     232             : 
     233        1458 :     for (i = nLeaderSize; i + nFieldEntryWidth <= _recLength;
     234        1354 :          i += nFieldEntryWidth)
     235             :     {
     236        1458 :         if (osRecord[i] == DDF_FIELD_TERMINATOR)
     237         104 :             break;
     238             : 
     239        1354 :         nFDCount++;
     240             :     }
     241             : 
     242             :     /* -------------------------------------------------------------------- */
     243             :     /*      Allocate, and read field definitions.                           */
     244             :     /* -------------------------------------------------------------------- */
     245        1458 :     for (i = 0; i < nFDCount; i++)
     246             :     {
     247             :         char szTag[128];
     248        1354 :         int nEntryOffset = nLeaderSize + i * nFieldEntryWidth;
     249             :         int nFieldLength, nFieldPos;
     250             : 
     251        1354 :         strncpy(szTag, osRecord.c_str() + nEntryOffset, _sizeFieldTag);
     252        1354 :         szTag[_sizeFieldTag] = '\0';
     253             : 
     254        1354 :         nEntryOffset += _sizeFieldTag;
     255             :         nFieldLength =
     256        1354 :             DDFScanInt(osRecord.c_str() + nEntryOffset, _sizeFieldLength);
     257             : 
     258        1354 :         nEntryOffset += _sizeFieldLength;
     259        1354 :         nFieldPos = DDFScanInt(osRecord.c_str() + nEntryOffset, _sizeFieldPos);
     260             : 
     261        1354 :         if (nFieldPos < 0 || nFieldPos > INT_MAX - _fieldAreaStart ||
     262             :             nFieldLength <
     263        1354 :                 2 ||  // DDFFieldDefn::Initialize() assumes at least 2 bytes
     264        1354 :             _recLength - (_fieldAreaStart + nFieldPos) < nFieldLength)
     265             :         {
     266           0 :             if (!bFailQuietly)
     267           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     268             :                          "Header record invalid on DDF file `%s'.",
     269             :                          pszFilename);
     270             : 
     271           0 :             return FALSE;
     272             :         }
     273             : 
     274        2708 :         auto poFDefn = std::make_unique<DDFFieldDefn>();
     275        1354 :         if (poFDefn->Initialize(this, szTag, nFieldLength,
     276        1354 :                                 osRecord.c_str() + _fieldAreaStart + nFieldPos))
     277        1354 :             AddField(std::move(poFDefn));
     278             :     }
     279             : 
     280             :     /* -------------------------------------------------------------------- */
     281             :     /*      Record the current file offset, the beginning of the first      */
     282             :     /*      data record.                                                    */
     283             :     /* -------------------------------------------------------------------- */
     284         104 :     nFirstRecordOffset = static_cast<long>(VSIFTellL(fpDDF));
     285             : 
     286         104 :     return TRUE;
     287             : }
     288             : 
     289             : /************************************************************************/
     290             : /*                             Initialize()                             */
     291             : /************************************************************************/
     292             : 
     293          20 : int DDFModule::Initialize(char chInterchangeLevel, char chLeaderIden,
     294             :                           char chCodeExtensionIndicator, char chVersionNumber,
     295             :                           char chAppIndicator,
     296             :                           const std::array<char, 3> &achExtendedCharSet,
     297             :                           int nSizeFieldLength, int nSizeFieldPos,
     298             :                           int nSizeFieldTag)
     299             : 
     300             : {
     301          20 :     _interchangeLevel = chInterchangeLevel;
     302          20 :     _leaderIden = chLeaderIden;
     303          20 :     _inlineCodeExtensionIndicator = chCodeExtensionIndicator;
     304          20 :     _versionNumber = chVersionNumber;
     305          20 :     _appIndicator = chAppIndicator;
     306          20 :     _extendedCharSet = achExtendedCharSet;
     307          20 :     _sizeFieldLength = nSizeFieldLength;
     308          20 :     _sizeFieldPos = nSizeFieldPos;
     309          20 :     _sizeFieldTag = nSizeFieldTag;
     310             : 
     311          20 :     return TRUE;
     312             : }
     313             : 
     314             : /************************************************************************/
     315             : /*                               Create()                               */
     316             : /************************************************************************/
     317             : 
     318          20 : int DDFModule::Create(const char *pszFilename)
     319             : 
     320             : {
     321          20 :     CPLAssert(fpDDF == nullptr);
     322             : 
     323             :     /* -------------------------------------------------------------------- */
     324             :     /*      Create the file on disk.                                        */
     325             :     /* -------------------------------------------------------------------- */
     326          20 :     fpDDF = VSIFOpenL(pszFilename, "wb+");
     327          20 :     if (fpDDF == nullptr)
     328             :     {
     329           1 :         CPLError(CE_Failure, CPLE_OpenFailed,
     330             :                  "Failed to create file %s, check path and permissions.",
     331             :                  pszFilename);
     332           1 :         return FALSE;
     333             :     }
     334             : 
     335          19 :     bReadOnly = FALSE;
     336             : 
     337             :     /* -------------------------------------------------------------------- */
     338             :     /*      Prepare all the field definition information.                   */
     339             :     /* -------------------------------------------------------------------- */
     340          19 :     _recLength =
     341             :         24 +
     342          19 :         GetFieldCount() * (_sizeFieldLength + _sizeFieldPos + _sizeFieldTag) +
     343             :         1;
     344             : 
     345          19 :     _fieldAreaStart = _recLength;
     346             : 
     347         399 :     for (auto &poFieldDefn : apoFieldDefns)
     348             :     {
     349             :         int nLength;
     350             : 
     351         380 :         poFieldDefn->GenerateDDREntry(this, nullptr, &nLength);
     352         380 :         _recLength += nLength;
     353             :     }
     354             : 
     355             :     /* -------------------------------------------------------------------- */
     356             :     /*      Setup 24 byte leader.                                           */
     357             :     /* -------------------------------------------------------------------- */
     358             :     char achLeader[25];
     359             : 
     360          19 :     snprintf(achLeader + 0, sizeof(achLeader) - 0, "%05d", _recLength);
     361          19 :     achLeader[5] = _interchangeLevel;
     362          19 :     achLeader[6] = _leaderIden;
     363          19 :     achLeader[7] = _inlineCodeExtensionIndicator;
     364          19 :     achLeader[8] = _versionNumber;
     365          19 :     achLeader[9] = _appIndicator;
     366          19 :     snprintf(achLeader + 10, sizeof(achLeader) - 10, "%02d",
     367             :              _fieldControlLength);
     368          19 :     snprintf(achLeader + 12, sizeof(achLeader) - 12, "%05d", _fieldAreaStart);
     369          19 :     memcpy(achLeader + 17, _extendedCharSet.data(), 3);
     370          19 :     snprintf(achLeader + 20, sizeof(achLeader) - 20, "%1d", _sizeFieldLength);
     371          19 :     snprintf(achLeader + 21, sizeof(achLeader) - 21, "%1d", _sizeFieldPos);
     372          19 :     achLeader[22] = '0';
     373          19 :     snprintf(achLeader + 23, sizeof(achLeader) - 23, "%1d", _sizeFieldTag);
     374          19 :     int bRet = VSIFWriteL(achLeader, 24, 1, fpDDF) > 0;
     375             : 
     376             :     /* -------------------------------------------------------------------- */
     377             :     /*      Write out directory entries.                                    */
     378             :     /* -------------------------------------------------------------------- */
     379          19 :     int nOffset = 0;
     380         399 :     for (auto &poFieldDefn : apoFieldDefns)
     381             :     {
     382             :         char achDirEntry[255];
     383             :         char szFormat[32];
     384             :         int nLength;
     385             : 
     386         380 :         CPLAssert(_sizeFieldLength + _sizeFieldPos + _sizeFieldTag <
     387             :                   static_cast<int>(sizeof(achDirEntry)));
     388             : 
     389         380 :         poFieldDefn->GenerateDDREntry(this, nullptr, &nLength);
     390             : 
     391         380 :         CPLAssert(static_cast<int>(strlen(poFieldDefn->GetName())) ==
     392             :                   _sizeFieldTag);
     393         380 :         snprintf(achDirEntry, sizeof(achDirEntry), "%s",
     394             :                  poFieldDefn->GetName());
     395         380 :         snprintf(szFormat, sizeof(szFormat), "%%0%dd", _sizeFieldLength);
     396         380 :         snprintf(achDirEntry + _sizeFieldTag,
     397         380 :                  sizeof(achDirEntry) - _sizeFieldTag, szFormat, nLength);
     398         380 :         snprintf(szFormat, sizeof(szFormat), "%%0%dd", _sizeFieldPos);
     399         380 :         snprintf(achDirEntry + _sizeFieldTag + _sizeFieldLength,
     400         380 :                  sizeof(achDirEntry) - _sizeFieldTag - _sizeFieldLength,
     401             :                  szFormat, nOffset);
     402         380 :         nOffset += nLength;
     403             : 
     404         760 :         bRet &= VSIFWriteL(achDirEntry,
     405         380 :                            _sizeFieldLength + _sizeFieldPos + _sizeFieldTag, 1,
     406         380 :                            fpDDF) > 0;
     407             :     }
     408             : 
     409          19 :     char chUT = DDF_FIELD_TERMINATOR;
     410          19 :     bRet &= VSIFWriteL(&chUT, 1, 1, fpDDF) > 0;
     411             : 
     412             :     /* -------------------------------------------------------------------- */
     413             :     /*      Write out the field descriptions themselves.                    */
     414             :     /* -------------------------------------------------------------------- */
     415         399 :     for (auto &poFieldDefn : apoFieldDefns)
     416             :     {
     417         380 :         char *pachData = nullptr;
     418         380 :         int nLength = 0;
     419             : 
     420         380 :         poFieldDefn->GenerateDDREntry(this, &pachData, &nLength);
     421         380 :         bRet &= VSIFWriteL(pachData, nLength, 1, fpDDF) > 0;
     422         380 :         CPLFree(pachData);
     423             :     }
     424             : 
     425          19 :     return bRet ? TRUE : FALSE;
     426             : }
     427             : 
     428             : /************************************************************************/
     429             : /*                                Dump()                                */
     430             : /************************************************************************/
     431             : 
     432             : /**
     433             :  * Write out module info to debugging file.
     434             :  *
     435             :  * A variety of information about the module is written to the debugging
     436             :  * file.  This includes all the field and subfield definitions read from
     437             :  * the header.
     438             :  *
     439             :  * @param fp The standard IO file handle to write to.  i.e. stderr.
     440             :  */
     441             : 
     442           0 : void DDFModule::Dump(FILE *fp) const
     443             : 
     444             : {
     445           0 :     fprintf(fp, "DDFModule:\n");
     446           0 :     fprintf(fp, "    _recLength = %d\n", _recLength);
     447           0 :     fprintf(fp, "    _interchangeLevel = %c\n", _interchangeLevel);
     448           0 :     fprintf(fp, "    _leaderIden = %c\n", _leaderIden);
     449           0 :     fprintf(fp, "    _inlineCodeExtensionIndicator = %c\n",
     450           0 :             _inlineCodeExtensionIndicator);
     451           0 :     fprintf(fp, "    _versionNumber = %c\n", _versionNumber);
     452           0 :     fprintf(fp, "    _appIndicator = %c\n", _appIndicator);
     453           0 :     fprintf(fp, "    _extendedCharSet = `%c%c%c'\n", _extendedCharSet[0],
     454           0 :             _extendedCharSet[1], _extendedCharSet[2]);
     455           0 :     fprintf(fp, "    _fieldControlLength = %d\n", _fieldControlLength);
     456           0 :     fprintf(fp, "    _fieldAreaStart = %d\n", _fieldAreaStart);
     457           0 :     fprintf(fp, "    _sizeFieldLength = %d\n", _sizeFieldLength);
     458           0 :     fprintf(fp, "    _sizeFieldPos = %d\n", _sizeFieldPos);
     459           0 :     fprintf(fp, "    _sizeFieldTag = %d\n", _sizeFieldTag);
     460             : 
     461           0 :     for (const auto &poFieldDefn : apoFieldDefns)
     462             :     {
     463           0 :         poFieldDefn->Dump(fp);
     464             :     }
     465           0 : }
     466             : 
     467             : /************************************************************************/
     468             : /*                           FindFieldDefn()                            */
     469             : /************************************************************************/
     470             : 
     471             : /**
     472             :  * Fetch the definition of the named field.
     473             :  *
     474             :  * This function will scan the DDFFieldDefn's on this module, to find
     475             :  * one with the indicated field name.
     476             :  *
     477             :  * @param pszFieldName The name of the field to search for.  The comparison is
     478             :  *                     case insensitive.
     479             :  *
     480             :  * @return A pointer to the request DDFFieldDefn object is returned, or NULL
     481             :  * if none matching the name are found.  The return object remains owned by
     482             :  * the DDFModule, and should not be deleted by application code.
     483             :  */
     484             : 
     485      111555 : const DDFFieldDefn *DDFModule::FindFieldDefn(const char *pszFieldName) const
     486             : 
     487             : {
     488             :     /* -------------------------------------------------------------------- */
     489             :     /*      This pass tries to reduce the cost of comparing strings by      */
     490             :     /*      first checking the first character, and by using strcmp()       */
     491             :     /* -------------------------------------------------------------------- */
     492      888316 :     for (const auto &poFieldDefn : apoFieldDefns)
     493             :     {
     494      888313 :         const char *pszThisName = poFieldDefn->GetName();
     495             : 
     496      888313 :         if (*pszThisName == *pszFieldName && *pszFieldName != '\0' &&
     497      200032 :             strcmp(pszFieldName + 1, pszThisName + 1) == 0)
     498      111552 :             return poFieldDefn.get();
     499             :     }
     500             : 
     501             :     /* -------------------------------------------------------------------- */
     502             :     /*      Now do a more general check.  Application code may not          */
     503             :     /*      always use the correct name case.                               */
     504             :     /* -------------------------------------------------------------------- */
     505           9 :     for (const auto &poFieldDefn : apoFieldDefns)
     506             :     {
     507           6 :         if (EQUAL(pszFieldName, poFieldDefn->GetName()))
     508           0 :             return poFieldDefn.get();
     509             :     }
     510             : 
     511           3 :     return nullptr;
     512             : }
     513             : 
     514             : /************************************************************************/
     515             : /*                             ReadRecord()                             */
     516             : /*                                                                      */
     517             : /*      Read one record from the file, and return to the                */
     518             : /*      application.  The returned record is owned by the module,       */
     519             : /*      and is reused from call to call in order to preserve headers    */
     520             : /*      when they aren't being re-read from record to record.           */
     521             : /************************************************************************/
     522             : 
     523             : /**
     524             :  * Read one record from the file.
     525             :  *
     526             :  * @return A pointer to a DDFRecord object is returned, or NULL if a read
     527             :  * error, or end of file occurs.  The returned record is owned by the
     528             :  * module, and should not be deleted by the application.  The record is
     529             :  * only valid until the next ReadRecord() at which point it is overwritten.
     530             :  */
     531             : 
     532       28036 : DDFRecord *DDFModule::ReadRecord()
     533             : 
     534             : {
     535       28036 :     if (poRecord == nullptr)
     536         102 :         poRecord = std::make_unique<DDFRecord>(this);
     537             : 
     538       28036 :     if (poRecord->Read())
     539       27954 :         return poRecord.get();
     540             :     else
     541          82 :         return nullptr;
     542             : }
     543             : 
     544             : /************************************************************************/
     545             : /*                              AddField()                              */
     546             : /************************************************************************/
     547             : 
     548             : /**
     549             :  * Add new field definition.
     550             :  *
     551             :  * Field definitions may only be added to DDFModules being used for
     552             :  * writing, not those being used for reading.  Ownership of the
     553             :  * DDFFieldDefn object is taken by the DDFModule.
     554             :  *
     555             :  * @param poNewFDefn definition to be added to the module.
     556             :  */
     557             : 
     558        1754 : void DDFModule::AddField(std::unique_ptr<DDFFieldDefn> poNewFDefn)
     559             : 
     560             : {
     561        1754 :     apoFieldDefns.push_back(std::move(poNewFDefn));
     562        1754 : }
     563             : 
     564             : /************************************************************************/
     565             : /*                              GetField()                              */
     566             : /************************************************************************/
     567             : 
     568             : /**
     569             :  * Fetch a field definition by index.
     570             :  *
     571             :  * @param i (from 0 to GetFieldCount() - 1.
     572             :  * @return the returned field pointer or NULL if the index is out of range.
     573             :  */
     574             : 
     575          40 : DDFFieldDefn *DDFModule::GetField(int i)
     576             : 
     577             : {
     578          40 :     if (i < 0 || static_cast<size_t>(i) >= apoFieldDefns.size())
     579           0 :         return nullptr;
     580             :     else
     581          40 :         return apoFieldDefns[i].get();
     582             : }
     583             : 
     584             : /************************************************************************/
     585             : /*                               Rewind()                               */
     586             : /************************************************************************/
     587             : 
     588             : /**
     589             :  * Return to first record.
     590             :  *
     591             :  * The next call to ReadRecord() will read the first data record in the file.
     592             :  *
     593             :  * @param nOffset the offset in the file to return to.  By default this is
     594             :  * -1, a special value indicating that reading should return to the first
     595             :  * data record.  Otherwise it is an absolute byte offset in the file.
     596             :  */
     597             : 
     598           0 : void DDFModule::Rewind(vsi_l_offset nOffset)
     599             : 
     600             : {
     601           0 :     if (nOffset == static_cast<vsi_l_offset>(-1))
     602           0 :         nOffset = nFirstRecordOffset;
     603             : 
     604           0 :     if (fpDDF == nullptr)
     605           0 :         return;
     606             : 
     607           0 :     if (VSIFSeekL(fpDDF, nOffset, SEEK_SET) < 0)
     608           0 :         return;
     609             : 
     610           0 :     if (nOffset == nFirstRecordOffset && poRecord != nullptr)
     611           0 :         poRecord->Clear();
     612             : }

Generated by: LCOV version 1.14