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

Generated by: LCOV version 1.14