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

Generated by: LCOV version 1.14