LCOV - code coverage report
Current view: top level - frmts/iso8211 - ddfmodule.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 199 251 79.3 %
Date: 2024-11-21 22:18:42 Functions: 12 14 85.7 %

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

Generated by: LCOV version 1.14