LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - avc_e00read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 416 732 56.8 %
Date: 2025-01-18 12:42:00 Functions: 14 20 70.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     avc_e00read.c
       4             :  * Project:  Arc/Info vector coverage (AVC)  BIN->E00 conversion library
       5             :  * Language: ANSI C
       6             :  * Purpose:  Functions to open a binary coverage and read it as if it
       7             :  *           was an ASCII E00 file.  This file is the main entry point
       8             :  *           for the library.
       9             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
      10             :  *
      11             :  **********************************************************************
      12             :  * Copyright (c) 1999-2005, Daniel Morissette
      13             :  *
      14             :  * SPDX-License-Identifier: MIT
      15             :  **********************************************************************
      16             :  *
      17             :  * $Log: avc_e00read.c,v $
      18             :  * Revision 1.28  2008/07/30 19:22:18  dmorissette
      19             :  * Move detection of EXP header directly in AVCE00ReadOpenE00() and use
      20             :  * VSIFGets() instead of CPLReadLine() to avoid problem with huge one line
      21             :  * files (GDAL/OGR ticket #1989)
      22             :  *
      23             :  * Revision 1.27  2008/07/30 18:35:53  dmorissette
      24             :  * Avoid scanning the whole E00 input file in AVCE00ReadOpenE00() if the
      25             :  * file does not start with an EXP line (GDAL/OGR ticket 1989)
      26             :  *
      27             :  * Revision 1.26  2008/07/30 16:17:46  dmorissette
      28             :  * Detect compressed E00 input files and refuse to open them instead of
      29             :  * crashing (bug 1928, GDAL/OGR ticket 2513)
      30             :  *
      31             :  * Revision 1.25  2008/07/24 20:34:12  dmorissette
      32             :  * Fixed VC++ WIN32 build problems in GDAL/OGR environment
      33             :  * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2500)
      34             :  *
      35             :  * Revision 1.24  2008/07/24 13:49:20  dmorissette
      36             :  * Fixed GCC compiler warning (GDAL ticket #2495)
      37             :  *
      38             :  * Revision 1.23  2006/08/17 19:51:01  dmorissette
      39             :  * #include <unistd.h> to solve warning on 64 bit platforms (bug 1461)
      40             :  *
      41             :  * Revision 1.22  2006/08/17 18:56:42  dmorissette
      42             :  * Support for reading standalone info tables (just tables, no coverage
      43             :  * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549).
      44             :  *
      45             :  * Revision 1.21  2006/06/27 18:38:43  dmorissette
      46             :  * Cleaned up E00 reading (bug 1497, patch from James F.)
      47             :  *
      48             :  * Revision 1.20  2006/06/27 18:06:34  dmorissette
      49             :  * Applied patch for EOP processing from James F. (bug 1497)
      50             :  *
      51             :  * Revision 1.19  2006/06/16 11:48:11  daniel
      52             :  * New functions to read E00 files directly as opposed to translating to
      53             :  * binary coverage. Used in the implementation of E00 read support in OGR.
      54             :  * Contributed by James E. Flemer. (bug 1497)
      55             :  *
      56             :  * Revision 1.18  2006/06/14 16:31:28  daniel
      57             :  * Added support for AVCCoverPC2 type (bug 1491)
      58             :  *
      59             :  * Revision 1.17  2005/06/03 03:49:58  daniel
      60             :  * Update email address, website url, and copyright dates
      61             :  *
      62             :  * Revision 1.16  2004/07/14 18:49:50  daniel
      63             :  * Fixed leak when trying to open something that's not a coverage (bug513)
      64             :  *
      65             :  * Revision 1.15  2002/08/27 15:46:15  daniel
      66             :  * Applied fix made in GDAL/OGR by 'aubin' (moved include ctype.h after avc.h)
      67             :  *
      68             :  * Revision 1.14  2000/09/22 19:45:21  daniel
      69             :  * Switch to MIT-style license
      70             :  *
      71             :  * Revision 1.13  2000/05/29 15:31:31  daniel
      72             :  * Added Japanese DBCS support
      73             :  *
      74             :  * Revision 1.12  2000/02/14 17:21:01  daniel
      75             :  * Made more robust for corrupted or invalid files in cover directory
      76             :  *
      77             :  * Revision 1.11  2000/02/02 04:26:04  daniel
      78             :  * Support reading TX6/TX7/RXP/RPL files in weird coverages
      79             :  *
      80             :  * Revision 1.10  2000/01/10 02:56:30  daniel
      81             :  * Added read support for "weird" coverages
      82             :  *
      83             :  * Revision 1.9  2000/01/07 07:12:49  daniel
      84             :  * Added support for reading PC Coverage TXT files
      85             :  *
      86             :  * Revision 1.8  1999/12/24 07:41:08  daniel
      87             :  * Check fname length before testing for extension in AVCE00ReadFindCoverType()
      88             :  *
      89             :  * Revision 1.7  1999/12/24 07:18:34  daniel
      90             :  * Added PC Arc/Info coverages support
      91             :  *
      92             :  * Revision 1.6  1999/08/26 17:22:18  daniel
      93             :  * Use VSIFopen() instead of fopen() directly
      94             :  *
      95             :  * Revision 1.5  1999/08/23 18:21:41  daniel
      96             :  * New syntax for AVCBinReadListTables()
      97             :  *
      98             :  * Revision 1.4  1999/05/11 02:10:01  daniel
      99             :  * Free psInfo struct inside AVCE00ReadClose()
     100             :  *
     101             :  * Revision 1.3  1999/04/06 19:43:26  daniel
     102             :  * Added E00 coverage path in EXP 0  header line
     103             :  *
     104             :  * Revision 1.2  1999/02/25 04:19:01  daniel
     105             :  * Added TXT, TX6/TX7, RXP and RPL support + other minor changes
     106             :  *
     107             :  * Revision 1.1  1999/01/29 16:28:52  daniel
     108             :  * Initial revision
     109             :  *
     110             :  **********************************************************************/
     111             : 
     112             : #include "avc.h"
     113             : 
     114             : #ifdef _WIN32
     115             : #include <direct.h> /* getcwd() */
     116             : #else
     117             : #include <unistd.h> /* getcwd() */
     118             : #endif
     119             : 
     120             : #include <ctype.h> /* toupper() */
     121             : 
     122             : // Should be 80 but let's be laxer
     123             : constexpr int knMAX_CHARS_PER_LINE = 1024;
     124             : 
     125             : static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead);
     126             : static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo,
     127             :                                      char **papszCoverDir);
     128             : static AVCCoverType _AVCE00ReadFindCoverType(char **papszCoverDir);
     129             : 
     130             : /**********************************************************************
     131             :  *                          AVCE00ReadOpen()
     132             :  *
     133             :  * Open a Arc/Info coverage to read it as if it was an E00 file.
     134             :  *
     135             :  * You can either pass the name of the coverage directory, or the path
     136             :  * to one of the files in the coverage directory.  The name of the
     137             :  * coverage MUST be included in pszCoverPath... this means that
     138             :  * passing "." is invalid.
     139             :  * The following are all valid values for pszCoverPath:
     140             :  *               /home/data/country
     141             :  *               /home/data/country/
     142             :  *               /home/data/country/arc.adf
     143             :  * (Of course you should replace the '/' with '\\' on DOS systems!)
     144             :  *
     145             :  * Returns a new AVCE00ReadPtr handle or nullptr if the coverage could
     146             :  * not be opened or if it does not appear to be a valid Arc/Info coverage.
     147             :  *
     148             :  * The handle will eventually have to be released with AVCE00ReadClose().
     149             :  **********************************************************************/
     150         454 : AVCE00ReadPtr AVCE00ReadOpen(const char *pszCoverPath)
     151             : {
     152             :     AVCE00ReadPtr psInfo;
     153             :     int i, nLen, nCoverPrecision;
     154             :     VSIStatBufL sStatBuf;
     155         454 :     char **papszCoverDir = nullptr;
     156             : 
     157         454 :     CPLErrorReset();
     158             : 
     159             :     /*-----------------------------------------------------------------
     160             :      * pszCoverPath must be either a valid directory name or a valid
     161             :      * file name.
     162             :      *----------------------------------------------------------------*/
     163         908 :     if (pszCoverPath == nullptr || strlen(pszCoverPath) == 0 ||
     164         454 :         VSIStatL(pszCoverPath, &sStatBuf) == -1)
     165             :     {
     166           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Invalid coverage path: %s.",
     167             :                  pszCoverPath ? pszCoverPath : "(nullptr)");
     168           0 :         return nullptr;
     169             :     }
     170             : 
     171             :     /*-----------------------------------------------------------------
     172             :      * Alloc the AVCE00ReadPtr handle
     173             :      *----------------------------------------------------------------*/
     174         454 :     psInfo = (AVCE00ReadPtr)CPLCalloc(1, sizeof(struct AVCE00ReadInfo_t));
     175             : 
     176             :     /*-----------------------------------------------------------------
     177             :      * 2 possibilities about the value passed in pszCoverPath:
     178             :      * - It can be the directory name of the coverage
     179             :      * - or it can be the path to one of the files in the coverage
     180             :      *
     181             :      * If the name passed in pszCoverPath is not a directory, then we
     182             :      * need to strip the last part of the filename to keep only the
     183             :      * path, terminated by a '/' (or a '\\').
     184             :      *----------------------------------------------------------------*/
     185         454 :     if (VSI_ISDIR(sStatBuf.st_mode))
     186             :     {
     187             :         /*-------------------------------------------------------------
     188             :          * OK, we have a valid directory name... make sure it is
     189             :          * terminated with a '/' (or '\\')
     190             :          *------------------------------------------------------------*/
     191         424 :         nLen = (int)strlen(pszCoverPath);
     192             : 
     193         424 :         if (pszCoverPath[nLen - 1] == '/' || pszCoverPath[nLen - 1] == '\\')
     194           0 :             psInfo->pszCoverPath = CPLStrdup(pszCoverPath);
     195             :         else
     196             :         {
     197             : #ifdef _WIN32
     198             :             psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s\\", pszCoverPath));
     199             : #else
     200         424 :             psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s/", pszCoverPath));
     201             : #endif
     202             :         }
     203             :     }
     204             :     else
     205             :     {
     206             :         /*-------------------------------------------------------------
     207             :          * We are dealing with a filename.
     208             :          * Extract the coverage path component and store it.
     209             :          * The coverage path will remain terminated by a '/' or '\\' char.
     210             :          *------------------------------------------------------------*/
     211          30 :         psInfo->pszCoverPath = CPLStrdup(pszCoverPath);
     212             : 
     213         462 :         for (i = (int)strlen(psInfo->pszCoverPath) - 1;
     214         462 :              i > 0 && psInfo->pszCoverPath[i] != '/' &&
     215         432 :              psInfo->pszCoverPath[i] != '\\';
     216             :              i--)
     217             :         {
     218             :         }
     219             : 
     220          30 :         psInfo->pszCoverPath[i + 1] = '\0';
     221             :     }
     222             : 
     223             :     /*-----------------------------------------------------------------
     224             :      * Extract the coverage name from the coverage path.  Note that
     225             :      * for this the coverage path must be in the form:
     226             :      * "dir1/dir2/dir3/covername/" ... if it is not the case, then
     227             :      * we would have to use getcwd() to find the current directory name...
     228             :      * but for now we'll just produce an error if this happens.
     229             :      *----------------------------------------------------------------*/
     230         454 :     nLen = 0;
     231         454 :     for (i = (int)strlen(psInfo->pszCoverPath) - 1;
     232        7847 :          i > 0 && psInfo->pszCoverPath[i - 1] != '/' &&
     233       15248 :          psInfo->pszCoverPath[i - 1] != '\\' &&
     234        7397 :          psInfo->pszCoverPath[i - 1] != ':';
     235             :          i--)
     236             :     {
     237        7397 :         nLen++;
     238             :     }
     239             : 
     240         454 :     if (nLen > 0)
     241             :     {
     242         454 :         psInfo->pszCoverName = CPLStrdup(psInfo->pszCoverPath + i);
     243         454 :         psInfo->pszCoverName[nLen] = '\0';
     244             :     }
     245             :     else
     246             :     {
     247           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     248             :                  "Invalid coverage path (%s): "
     249             :                  "coverage name must be included in path.",
     250             :                  pszCoverPath);
     251             : 
     252           0 :         CPLFree(psInfo->pszCoverPath);
     253           0 :         CPLFree(psInfo);
     254           0 :         return nullptr;
     255             :     }
     256             : 
     257             :     /*-----------------------------------------------------------------
     258             :      * Read the coverage directory listing and try to establish the cover type
     259             :      *----------------------------------------------------------------*/
     260         454 :     papszCoverDir = VSIReadDir(psInfo->pszCoverPath);
     261             : 
     262         454 :     psInfo->eCoverType = _AVCE00ReadFindCoverType(papszCoverDir);
     263             : 
     264         454 :     if (psInfo->eCoverType == AVCCoverTypeUnknown)
     265             :     {
     266         451 :         CPLError(CE_Failure, CPLE_OpenFailed,
     267             :                  "Invalid coverage (%s): directory does not appear to "
     268             :                  "contain any supported vector coverage file.",
     269             :                  pszCoverPath);
     270         451 :         CPLFree(psInfo->pszCoverName);
     271         451 :         CPLFree(psInfo->pszCoverPath);
     272         451 :         CPLFree(psInfo->pszInfoPath);
     273         451 :         CPLFree(psInfo);
     274         451 :         CSLDestroy(papszCoverDir);
     275         451 :         return nullptr;
     276             :     }
     277             : 
     278             :     /*-----------------------------------------------------------------
     279             :      * INFO path: PC Coverages have all files in the same dir, and unix
     280             :      * covers have the INFO files in ../info
     281             :      *----------------------------------------------------------------*/
     282           3 :     if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2)
     283             :     {
     284           0 :         psInfo->pszInfoPath = CPLStrdup(psInfo->pszCoverPath);
     285             :     }
     286             :     else
     287             :     {
     288             :         /*-------------------------------------------------------------
     289             :          * Lazy way to build the INFO path: simply add "../info/"...
     290             :          * this could probably be improved!
     291             :          *------------------------------------------------------------*/
     292           3 :         size_t nInfoPathLen = strlen(psInfo->pszCoverPath) + 9;
     293           3 :         psInfo->pszInfoPath = (char *)CPLMalloc(nInfoPathLen);
     294             : #ifdef _WIN32
     295             : #define AVC_INFOPATH "..\\info\\"
     296             : #else
     297             : #define AVC_INFOPATH "../info/"
     298             : #endif
     299           3 :         snprintf(psInfo->pszInfoPath, nInfoPathLen, "%s%s",
     300             :                  psInfo->pszCoverPath, AVC_INFOPATH);
     301             : 
     302           3 :         AVCAdjustCaseSensitiveFilename(psInfo->pszInfoPath);
     303             :     }
     304             : 
     305             :     /*-----------------------------------------------------------------
     306             :      * For Unix coverages, check that the info directory exists and
     307             :      * contains the "arc.dir".  In AVCCoverWeird, the arc.dir is
     308             :      * called "../INFO/ARCDR9".
     309             :      * PC Coverages have their info tables in the same directory as
     310             :      * the coverage files.
     311             :      *----------------------------------------------------------------*/
     312           6 :     if (((psInfo->eCoverType == AVCCoverV7 ||
     313           0 :           psInfo->eCoverType == AVCCoverV7Tables) &&
     314           6 :          !AVCFileExists(psInfo->pszInfoPath, "arc.dir")) ||
     315           3 :         (psInfo->eCoverType == AVCCoverWeird &&
     316           0 :          !AVCFileExists(psInfo->pszInfoPath, "arcdr9")))
     317             :     {
     318           0 :         CPLError(
     319             :             CE_Failure, CPLE_OpenFailed,
     320             :             "Invalid coverage (%s): 'info' directory not found or invalid.",
     321             :             pszCoverPath);
     322           0 :         CPLFree(psInfo->pszCoverName);
     323           0 :         CPLFree(psInfo->pszCoverPath);
     324           0 :         CPLFree(psInfo->pszInfoPath);
     325           0 :         CPLFree(psInfo);
     326           0 :         CSLDestroy(papszCoverDir);
     327           0 :         return nullptr;
     328             :     }
     329             : 
     330             :     /*-----------------------------------------------------------------
     331             :      * Make sure there was no error until now before we build skeleton.
     332             :      *----------------------------------------------------------------*/
     333           3 :     if (CPLGetLastErrorNo() != 0)
     334             :     {
     335           0 :         CPLFree(psInfo->pszCoverName);
     336           0 :         CPLFree(psInfo->pszCoverPath);
     337           0 :         CPLFree(psInfo->pszInfoPath);
     338           0 :         CPLFree(psInfo);
     339           0 :         CSLDestroy(papszCoverDir);
     340           0 :         return nullptr;
     341             :     }
     342             : 
     343             :     /*-----------------------------------------------------------------
     344             :      * Build the E00 file skeleton and be ready to return a E00 header...
     345             :      * We'll also read the coverage precision by the same way.
     346             :      *----------------------------------------------------------------*/
     347           3 :     nCoverPrecision = _AVCE00ReadBuildSqueleton(psInfo, papszCoverDir);
     348             : 
     349             :     /* Ignore warnings produced while building skeleton */
     350           3 :     CPLErrorReset();
     351             : 
     352           3 :     CSLDestroy(papszCoverDir);
     353           3 :     papszCoverDir = nullptr;
     354             : 
     355           3 :     psInfo->iCurSection = 0;
     356           3 :     psInfo->iCurStep = AVC_GEN_NOTSTARTED;
     357           3 :     psInfo->bReadAllSections = TRUE;
     358             : 
     359             :     /*-----------------------------------------------------------------
     360             :      * Init the E00 generator.
     361             :      *----------------------------------------------------------------*/
     362           3 :     psInfo->hGenInfo = AVCE00GenInfoAlloc(nCoverPrecision);
     363             : 
     364             :     /*-----------------------------------------------------------------
     365             :      * Init multibyte encoding info
     366             :      *----------------------------------------------------------------*/
     367           3 :     psInfo->psDBCSInfo = AVCAllocDBCSInfo();
     368             : 
     369             :     /*-----------------------------------------------------------------
     370             :      * If an error happened during the open call, cleanup and return nullptr.
     371             :      *----------------------------------------------------------------*/
     372           3 :     if (CPLGetLastErrorNo() != 0)
     373             :     {
     374           0 :         AVCE00ReadClose(psInfo);
     375           0 :         psInfo = nullptr;
     376             :     }
     377             : 
     378           3 :     return psInfo;
     379             : }
     380             : 
     381             : /**********************************************************************
     382             :  *                          AVCE00ReadOpenE00()
     383             :  *
     384             :  * Open a E00 file for reading.
     385             :  *
     386             :  * Returns a new AVCE00ReadE00Ptr handle or nullptr if the file could
     387             :  * not be opened or if it does not appear to be a valid E00 file.
     388             :  *
     389             :  * The handle will eventually have to be released with
     390             :  * AVCE00ReadCloseE00().
     391             :  **********************************************************************/
     392          11 : AVCE00ReadE00Ptr AVCE00ReadOpenE00(const char *pszE00FileName)
     393             : {
     394             :     AVCE00ReadE00Ptr psRead;
     395             :     VSIStatBufL sStatBuf;
     396             :     VSILFILE *fp;
     397             :     char *p;
     398             :     char szHeader[10];
     399             : 
     400          11 :     CPLErrorReset();
     401             : 
     402             :     /*-----------------------------------------------------------------
     403             :      * pszE00FileName must be a valid file that can be opened for
     404             :      * reading
     405             :      *----------------------------------------------------------------*/
     406          11 :     if (pszE00FileName == nullptr || strlen(pszE00FileName) == 0 ||
     407          33 :         VSIStatL(pszE00FileName, &sStatBuf) == -1 ||
     408          11 :         VSI_ISDIR(sStatBuf.st_mode))
     409             :     {
     410           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Invalid E00 file path: %s.",
     411             :                  pszE00FileName ? pszE00FileName : "(nullptr)");
     412           0 :         return nullptr;
     413             :     }
     414             : 
     415          11 :     if (nullptr == (fp = VSIFOpenL(pszE00FileName, "r")))
     416           0 :         return nullptr;
     417             : 
     418             :     /*-----------------------------------------------------------------
     419             :      * Make sure the file starts with a "EXP  0" or "EXP  1" header
     420             :      *----------------------------------------------------------------*/
     421          11 :     memset(szHeader, 0, sizeof(szHeader));
     422          11 :     if (VSIFReadL(szHeader, 5, 1, fp) == 0 || !STARTS_WITH_CI(szHeader, "EXP "))
     423             :     {
     424           0 :         CPLError(CE_Failure, CPLE_OpenFailed,
     425             :                  "This does not look like a E00 file: does not start with "
     426             :                  "a EXP header.");
     427           0 :         VSIFCloseL(fp);
     428           0 :         return nullptr;
     429             :     }
     430          11 :     VSIRewindL(fp);
     431             : 
     432             :     /*-----------------------------------------------------------------
     433             :      * Alloc the AVCE00ReadE00Ptr handle
     434             :      *----------------------------------------------------------------*/
     435          11 :     psRead = (AVCE00ReadE00Ptr)CPLCalloc(1, sizeof(struct AVCE00ReadInfoE00_t));
     436             : 
     437          11 :     psRead->hFile = fp;
     438          11 :     psRead->pszCoverPath = CPLStrdup(pszE00FileName);
     439          11 :     psRead->eCurFileType = AVCFileUnknown;
     440             : 
     441             :     /*-----------------------------------------------------------------
     442             :      * Extract the coverage name from the coverage path.
     443             :      *----------------------------------------------------------------*/
     444          22 :     if (nullptr != (p = strrchr(psRead->pszCoverPath, '/')) ||
     445          11 :         nullptr != (p = strrchr(psRead->pszCoverPath, '\\')) ||
     446           0 :         nullptr != (p = strrchr(psRead->pszCoverPath, ':')))
     447             :     {
     448          11 :         psRead->pszCoverName = CPLStrdup(p + 1);
     449             :     }
     450             :     else
     451             :     {
     452           0 :         psRead->pszCoverName = CPLStrdup(psRead->pszCoverPath);
     453             :     }
     454          11 :     if (nullptr != (p = strrchr(psRead->pszCoverName, '.')))
     455             :     {
     456          11 :         *p = '\0';
     457             :     }
     458             : 
     459             :     /*-----------------------------------------------------------------
     460             :      * Make sure there was no error until now before we scan file.
     461             :      *----------------------------------------------------------------*/
     462          11 :     if (CPLGetLastErrorNo() != 0)
     463             :     {
     464           0 :         AVCE00ReadCloseE00(psRead);
     465           0 :         return nullptr;
     466             :     }
     467             : 
     468          11 :     psRead->hParseInfo = AVCE00ParseInfoAlloc();
     469             : 
     470             :     /*-----------------------------------------------------------------
     471             :      * Scan the E00 file for sections
     472             :      *----------------------------------------------------------------*/
     473          11 :     _AVCE00ReadScanE00(psRead);
     474          11 :     if (CPLGetLastErrorNo() != 0)
     475             :     {
     476           1 :         AVCE00ReadCloseE00(psRead);
     477           1 :         return nullptr;
     478             :     }
     479             : 
     480          10 :     AVCE00ReadRewindE00(psRead);
     481          10 :     CPLErrorReset();
     482             : 
     483          10 :     if (psRead->numSections < 1)
     484             :     {
     485           0 :         AVCE00ReadCloseE00(psRead);
     486           0 :         return nullptr;
     487             :     }
     488             : 
     489          10 :     psRead->bReadAllSections = TRUE;
     490             : 
     491             :     /*-----------------------------------------------------------------
     492             :      * If an error happened during the open call, cleanup and return nullptr.
     493             :      *----------------------------------------------------------------*/
     494          10 :     if (CPLGetLastErrorNo() != 0)
     495             :     {
     496           0 :         AVCE00ReadCloseE00(psRead);
     497           0 :         psRead = nullptr;
     498             :     }
     499             : 
     500          10 :     return psRead;
     501             : }
     502             : 
     503             : /**********************************************************************
     504             :  *                          AVCE00ReadClose()
     505             :  *
     506             :  * Close a coverage and release all memory used by the AVCE00ReadPtr
     507             :  * handle.
     508             :  **********************************************************************/
     509           3 : void AVCE00ReadClose(AVCE00ReadPtr psInfo)
     510             : {
     511           3 :     CPLErrorReset();
     512             : 
     513           3 :     if (psInfo == nullptr)
     514           0 :         return;
     515             : 
     516           3 :     CPLFree(psInfo->pszCoverPath);
     517           3 :     CPLFree(psInfo->pszInfoPath);
     518           3 :     CPLFree(psInfo->pszCoverName);
     519             : 
     520           3 :     if (psInfo->hFile)
     521           0 :         AVCBinReadClose(psInfo->hFile);
     522             : 
     523           3 :     if (psInfo->hGenInfo)
     524           3 :         AVCE00GenInfoFree(psInfo->hGenInfo);
     525             : 
     526           3 :     if (psInfo->pasSections)
     527             :     {
     528             :         int i;
     529          41 :         for (i = 0; i < psInfo->numSections; i++)
     530             :         {
     531          38 :             CPLFree(psInfo->pasSections[i].pszName);
     532          38 :             CPLFree(psInfo->pasSections[i].pszFilename);
     533             :         }
     534           3 :         CPLFree(psInfo->pasSections);
     535             :     }
     536             : 
     537           3 :     AVCFreeDBCSInfo(psInfo->psDBCSInfo);
     538             : 
     539           3 :     CPLFree(psInfo);
     540             : }
     541             : 
     542             : /**********************************************************************
     543             :  *                          AVCE00ReadCloseE00()
     544             :  *
     545             :  * Close a coverage and release all memory used by the AVCE00ReadE00Ptr
     546             :  * handle.
     547             :  **********************************************************************/
     548          11 : void AVCE00ReadCloseE00(AVCE00ReadE00Ptr psRead)
     549             : {
     550          11 :     if (psRead == nullptr)
     551           0 :         return;
     552             : 
     553          11 :     CPLFree(psRead->pszCoverPath);
     554          11 :     CPLFree(psRead->pszCoverName);
     555             : 
     556          11 :     if (psRead->hFile)
     557             :     {
     558          11 :         VSIFCloseL(psRead->hFile);
     559          11 :         psRead->hFile = nullptr;
     560             :     }
     561             : 
     562          11 :     if (psRead->pasSections)
     563             :     {
     564             :         int i;
     565          86 :         for (i = 0; i < psRead->numSections; i++)
     566             :         {
     567          76 :             CPLFree(psRead->pasSections[i].pszName);
     568          76 :             CPLFree(psRead->pasSections[i].pszFilename);
     569             :         }
     570          10 :         CPLFree(psRead->pasSections);
     571             :     }
     572             : 
     573             :     /* These Free calls handle nullptr's */
     574          11 :     AVCE00ParseInfoFree(psRead->hParseInfo);
     575          11 :     psRead->hParseInfo = nullptr;
     576             : 
     577          11 :     CPLFree(psRead);
     578             : }
     579             : 
     580             : /**********************************************************************
     581             :  *                          _AVCIncreaseSectionsArray()
     582             :  *
     583             :  * Add a number of structures to the Sections array and return the
     584             :  * index of the first one that was added.  Note that the address of the
     585             :  * original array (*pasArray) is quite likely to change!
     586             :  *
     587             :  * The value of *pnumItems will be updated to reflect the new array size.
     588             :  **********************************************************************/
     589         100 : static int _AVCIncreaseSectionsArray(AVCE00Section **pasArray, int *pnumItems,
     590             :                                      int numToAdd)
     591             : {
     592             :     int i;
     593             : 
     594         200 :     *pasArray = (AVCE00Section *)CPLRealloc(
     595         100 :         *pasArray, (*pnumItems + numToAdd) * sizeof(AVCE00Section));
     596             : 
     597         214 :     for (i = 0; i < numToAdd; i++)
     598             :     {
     599         114 :         (*pasArray)[*pnumItems + i].eType = AVCFileUnknown;
     600         114 :         (*pasArray)[*pnumItems + i].pszName = nullptr;
     601         114 :         (*pasArray)[*pnumItems + i].pszFilename = nullptr;
     602         114 :         (*pasArray)[*pnumItems + i].nLineNum = 0;
     603         114 :         (*pasArray)[*pnumItems + i].nFeatureCount = -1;
     604             :     }
     605             : 
     606         100 :     i = *pnumItems;
     607         100 :     (*pnumItems) += numToAdd;
     608             : 
     609         100 :     return i;
     610             : }
     611             : 
     612             : /**********************************************************************
     613             :  *                         _AVCE00ReadFindCoverType()
     614             :  *
     615             :  * This functions tries to establish the coverage type by looking
     616             :  * at the coverage directory listing passed as argument.
     617             :  *
     618             :  * Returns one of AVCCoverV7 for Arc/Info V7 (Unix) coverages, or
     619             :  *                AVCCoverPC for PC Arc/Info coverages.
     620             :  *                AVCCoverWeird for an hybrid between V7 and PC
     621             :  *
     622             :  * If coverage type cannot be established then AVCCoverTypeUnknown is
     623             :  * returned.
     624             :  **********************************************************************/
     625         454 : static AVCCoverType _AVCE00ReadFindCoverType(char **papszCoverDir)
     626             : {
     627             :     int i, nLen;
     628         454 :     GBool bFoundAdfFile = FALSE, bFoundArcFile = FALSE, bFoundTableFile = FALSE,
     629         454 :           bFoundDbfFile = FALSE, bFoundArcDirFile = FALSE;
     630             : 
     631             :     /*-----------------------------------------------------------------
     632             :      * Scan the list of files, looking for well known filenames.
     633             :      * Start with the funky types first...
     634             :      *----------------------------------------------------------------*/
     635       22747 :     for (i = 0; papszCoverDir && papszCoverDir[i]; i++)
     636             :     {
     637       22293 :         nLen = (int)strlen(papszCoverDir[i]);
     638       22293 :         if (nLen > 4 && EQUAL(papszCoverDir[i] + nLen - 4, ".adf"))
     639             :         {
     640          24 :             bFoundAdfFile = TRUE;
     641             :         }
     642       22269 :         else if (nLen > 4 && EQUAL(papszCoverDir[i] + nLen - 4, ".dbf"))
     643             :         {
     644           0 :             bFoundDbfFile = TRUE;
     645             :         }
     646       22269 :         else if (EQUAL(papszCoverDir[i], "arc") ||
     647       22269 :                  EQUAL(papszCoverDir[i], "cnt") ||
     648       22269 :                  EQUAL(papszCoverDir[i], "pal") ||
     649       22269 :                  EQUAL(papszCoverDir[i], "lab") ||
     650       22269 :                  EQUAL(papszCoverDir[i], "prj") ||
     651       22269 :                  EQUAL(papszCoverDir[i], "tol"))
     652             :         {
     653           0 :             bFoundArcFile = TRUE;
     654             :         }
     655       22269 :         else if (EQUAL(papszCoverDir[i], "aat") ||
     656       22269 :                  EQUAL(papszCoverDir[i], "pat") ||
     657       22269 :                  EQUAL(papszCoverDir[i], "bnd") ||
     658       22269 :                  EQUAL(papszCoverDir[i], "tic"))
     659             :         {
     660           0 :             bFoundTableFile = TRUE;
     661             :         }
     662       22269 :         else if (EQUAL(papszCoverDir[i], "arc.dir"))
     663             :         {
     664           0 :             bFoundArcDirFile = TRUE;
     665             :         }
     666             :     }
     667             : 
     668             :     /*-----------------------------------------------------------------
     669             :      * Check for PC Arc/Info coverage - variant 1.
     670             :      * These PC coverages have files with no extension (e.g. "ARC","PAL",...)
     671             :      * and their tables filenames are in the form "???.dbf"
     672             :      *----------------------------------------------------------------*/
     673         454 :     if (bFoundArcFile && bFoundDbfFile)
     674           0 :         return AVCCoverPC;
     675             : 
     676             :     /*-----------------------------------------------------------------
     677             :      * Check for PC Arc/Info coverage - variant 2.
     678             :      * looks like a hybrid between AVCCoverPC and AVCCoverV7
     679             :      * These PC coverages have files with .adf extension (e.g."ARC.ADF"),
     680             :      * and their tables filenames are in the form "???.dbf"
     681             :      *----------------------------------------------------------------*/
     682         454 :     if (bFoundAdfFile && bFoundDbfFile)
     683           0 :         return AVCCoverPC2;
     684             : 
     685             :     /*-----------------------------------------------------------------
     686             :      * Check for the weird coverages.
     687             :      * Their coverage files have no extension just like PC Coverages,
     688             :      * and their tables have 3 letters filenames with no extension
     689             :      * either (e.g. "AAT", "PAT", etc.)
     690             :      * They also have a ../info directory, but we don't really need
     691             :      * to check that (not yet!).
     692             :      *----------------------------------------------------------------*/
     693         454 :     if (bFoundArcFile && bFoundTableFile)
     694           0 :         return AVCCoverWeird;
     695             : 
     696             :     /*-----------------------------------------------------------------
     697             :      * V7 Coverages... they are the easiest to recognize
     698             :      * because of the ".adf" file extension
     699             :      *----------------------------------------------------------------*/
     700         454 :     if (bFoundAdfFile)
     701           3 :         return AVCCoverV7;
     702             : 
     703             :     /*-----------------------------------------------------------------
     704             :      * Standalone info tables.
     705             :      * We were pointed at the "info" directory. We'll treat this as
     706             :      * a coverage with just info tables.
     707             :      *----------------------------------------------------------------*/
     708         451 :     if (bFoundArcDirFile)
     709           0 :         return AVCCoverV7Tables;
     710             : 
     711         451 :     return AVCCoverTypeUnknown;
     712             : }
     713             : 
     714             : /**********************************************************************
     715             :  *                         _AVCE00ReadAddJabberwockySection()
     716             :  *
     717             :  * Add to the skeleton a section that contains subsections
     718             :  * for all the files with a given extension.
     719             :  *
     720             :  * Returns Updated Coverage precision
     721             :  **********************************************************************/
     722           9 : static int _AVCE00ReadAddJabberwockySection(
     723             :     AVCE00ReadPtr psInfo, AVCFileType eFileType, const char *pszSectionName,
     724             :     int nCoverPrecision, const char *pszFileExtension, char **papszCoverDir)
     725             : {
     726             :     int iSect, iDirEntry, nLen, nExtLen;
     727           9 :     GBool bFoundFiles = FALSE;
     728           9 :     AVCBinFile *psFile = nullptr;
     729             : 
     730           9 :     nExtLen = (int)strlen(pszFileExtension);
     731             : 
     732             :     /*-----------------------------------------------------------------
     733             :      * Scan the directory for files with a ".txt" extension.
     734             :      *----------------------------------------------------------------*/
     735             : 
     736          99 :     for (iDirEntry = 0; papszCoverDir && papszCoverDir[iDirEntry]; iDirEntry++)
     737             :     {
     738          90 :         nLen = (int)strlen(papszCoverDir[iDirEntry]);
     739             : 
     740         162 :         if (nLen > nExtLen &&
     741          72 :             EQUAL(papszCoverDir[iDirEntry] + nLen - nExtLen,
     742         162 :                   pszFileExtension) &&
     743           0 :             (psFile = AVCBinReadOpen(
     744           0 :                  psInfo->pszCoverPath, papszCoverDir[iDirEntry],
     745             :                  psInfo->eCoverType, eFileType, psInfo->psDBCSInfo)) != nullptr)
     746             :         {
     747           0 :             if (nCoverPrecision == AVC_DEFAULT_PREC)
     748           0 :                 nCoverPrecision = psFile->nPrecision;
     749           0 :             AVCBinReadClose(psFile);
     750             : 
     751           0 :             if (bFoundFiles == FALSE)
     752             :             {
     753             :                 /* Insert a "TX6 #" header before the first TX6 file
     754             :                  */
     755           0 :                 iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
     756             :                                                   &(psInfo->numSections), 1);
     757           0 :                 psInfo->pasSections[iSect].eType = AVCFileUnknown;
     758             : 
     759           0 :                 psInfo->pasSections[iSect].pszName = CPLStrdup(CPLSPrintf(
     760             :                     "%s  %c", pszSectionName,
     761             :                     (nCoverPrecision == AVC_DOUBLE_PREC) ? '3' : '2'));
     762             : 
     763           0 :                 bFoundFiles = TRUE;
     764             :             }
     765             : 
     766             :             /* Add this file to the skeleton
     767             :              */
     768           0 :             iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
     769             :                                               &(psInfo->numSections), 1);
     770             : 
     771           0 :             psInfo->pasSections[iSect].eType = eFileType;
     772           0 :             psInfo->pasSections[iSect].pszFilename =
     773           0 :                 CPLStrdup(papszCoverDir[iDirEntry]);
     774             : 
     775             :             /* pszName will contain only the classname without the file
     776             :              * extension */
     777           0 :             psInfo->pasSections[iSect].pszName =
     778           0 :                 CPLStrdup(papszCoverDir[iDirEntry]);
     779           0 :             psInfo->pasSections[iSect].pszName[nLen - nExtLen] = '\0';
     780             :         }
     781             :     }
     782             : 
     783           9 :     if (bFoundFiles)
     784             :     {
     785             :         /* Add a line to close the TX6 section.
     786             :          */
     787           0 :         iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
     788             :                                           &(psInfo->numSections), 1);
     789           0 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
     790           0 :         psInfo->pasSections[iSect].pszName = CPLStrdup("JABBERWOCKY");
     791             :     }
     792             : 
     793           9 :     return nCoverPrecision;
     794             : }
     795             : 
     796             : /**********************************************************************
     797             :  *                     _AVCE00ReadNextLineE00()
     798             :  *
     799             :  * Processes the next line of input from the E00 file.
     800             :  * (See AVCE00WriteNextLine() for similar processing.)
     801             :  *
     802             :  * Returns the next object from the E00 file, or nullptr.
     803             :  **********************************************************************/
     804        3121 : static void *_AVCE00ReadNextLineE00(AVCE00ReadE00Ptr psRead,
     805             :                                     const char *pszLine)
     806             : {
     807             :     /* int nStatus = 0; */
     808        3121 :     void *psObj = nullptr;
     809             : 
     810        3121 :     AVCE00ParseInfo *psInfo = psRead->hParseInfo;
     811             : 
     812        3121 :     CPLErrorReset();
     813             : 
     814        3121 :     ++psInfo->nCurLineNum;
     815             : 
     816        3121 :     if (psInfo->bForceEndOfSection)
     817             :     {
     818             :         /*-------------------------------------------------------------
     819             :          * The last call encountered an implicit end of section, so
     820             :          * we close the section now without waiting for an end-of-section
     821             :          * line (there won't be any!)... and get ready to proceed with
     822             :          * the next section.
     823             :          * This is used for TABLEs.
     824             :          *------------------------------------------------------------*/
     825          60 :         AVCE00ParseSectionEnd(psInfo, pszLine, TRUE);
     826          60 :         psRead->eCurFileType = AVCFileUnknown;
     827             :     }
     828             : 
     829             :     /*-----------------------------------------------------------------
     830             :      * If we're at the top level inside a supersection... check if this
     831             :      * supersection ends here.
     832             :      *----------------------------------------------------------------*/
     833        3121 :     if (AVCE00ParseSuperSectionEnd(psInfo, pszLine) == TRUE)
     834             :     {
     835             :         /* Nothing to do... it is all been done by the call to
     836             :          * AVCE00ParseSuperSectionEnd()
     837             :          */
     838             :     }
     839        3111 :     else if (psRead->eCurFileType == AVCFileUnknown)
     840             :     {
     841             :         /*-------------------------------------------------------------
     842             :          * We're at the top level or inside a supersection... waiting
     843             :          * to encounter a valid section or supersection header
     844             :          * (i.e. "ARC  2", etc...)
     845             :          *------------------------------------------------------------*/
     846             : 
     847             :         /*-------------------------------------------------------------
     848             :          * First check for a supersection header (TX6, RXP, IFO, ...)
     849             :          *------------------------------------------------------------*/
     850         276 :         if (AVCE00ParseSuperSectionHeader(psInfo, pszLine) == AVCFileUnknown)
     851             :         {
     852             :             /*---------------------------------------------------------
     853             :              * This was not a supersection header... check if it is a simple
     854             :              * section header
     855             :              *--------------------------------------------------------*/
     856         261 :             psRead->eCurFileType = AVCE00ParseSectionHeader(psInfo, pszLine);
     857             :         }
     858             :         else
     859             :         {
     860             :             /* got supersection */
     861             :         }
     862             : 
     863         276 :         if (psRead->eCurFileType == AVCFileTABLE)
     864             :         {
     865             :             /*---------------------------------------------------------
     866             :              * send the first header line to the parser and wait until
     867             :              * the whole header has been read.
     868             :              *--------------------------------------------------------*/
     869          55 :             AVCE00ParseNextLine(psInfo, pszLine);
     870             :         }
     871         221 :         else if (psRead->eCurFileType != AVCFileUnknown)
     872             :         {
     873             :             /*---------------------------------------------------------
     874             :              * found a valid section header
     875             :              *--------------------------------------------------------*/
     876             :         }
     877             :     }
     878        2835 :     else if (psRead->eCurFileType == AVCFileTABLE && !psInfo->bTableHdrComplete)
     879             :     {
     880             :         /*-------------------------------------------------------------
     881             :          * We're reading a TABLE header... continue reading lines
     882             :          * from the header
     883             :          *
     884             :          * Note: When parsing a TABLE, the first object returned will
     885             :          * be the AVCTableDef, then data records will follow.
     886             :          *------------------------------------------------------------*/
     887         283 :         psObj = AVCE00ParseNextLine(psInfo, pszLine);
     888         283 :         if (psObj)
     889             :         {
     890             :             /* got table header */
     891             :             /* TODO: Enable return of table definition? */
     892          55 :             psObj = nullptr;
     893             :         }
     894             :     }
     895             :     else
     896             :     {
     897             :         /*-------------------------------------------------------------
     898             :          * We're are in the middle of a section... first check if we
     899             :          * have reached the end.
     900             :          *
     901             :          * note: The first call to AVCE00ParseSectionEnd() with FALSE will
     902             :          *       not reset the parser until we close the file... and then
     903             :          *       we call the function again to reset the parser.
     904             :          *------------------------------------------------------------*/
     905        2552 :         if (AVCE00ParseSectionEnd(psInfo, pszLine, FALSE))
     906             :         {
     907          70 :             psRead->eCurFileType = AVCFileUnknown;
     908          70 :             AVCE00ParseSectionEnd(psInfo, pszLine, TRUE);
     909             :         }
     910             :         else
     911             :         /*-------------------------------------------------------------
     912             :          * ... not at the end yet, so continue reading objects.
     913             :          *------------------------------------------------------------*/
     914             :         {
     915        2482 :             psObj = AVCE00ParseNextLine(psInfo, pszLine);
     916             : 
     917             :             if (psObj)
     918             :             {
     919             :                 /* got object */
     920             :             }
     921             :         }
     922             :     }
     923             : 
     924             : #if 0
     925             :     if (CPLGetLastErrorNo() != 0)
     926             :         nStatus = -1;
     927             : #endif
     928             : 
     929        3121 :     return psObj;
     930             : }
     931             : 
     932             : /**********************************************************************
     933             :  *                         _AVCE00ReadBuildSqueleton()
     934             :  *
     935             :  * Build the skeleton of the E00 file corresponding to the specified
     936             :  * coverage and set the appropriate fields in the AVCE00ReadPtr struct.
     937             :  *
     938             :  * Note that the order of the sections in the skeleton is important
     939             :  * since some software may rely on this ordering when they read E00 files.
     940             :  *
     941             :  * The function returns the coverage precision that it will read from one
     942             :  * of the file headers.
     943             :  **********************************************************************/
     944           3 : static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo, char **papszCoverDir)
     945             : {
     946             :     int iTable, numTables, iFile, nLen;
     947           3 :     char **papszTables, **papszFiles, szCWD[75] = "", *pcTmp;
     948           3 :     char *pszEXPPath = nullptr;
     949           3 :     int nCoverPrecision = AVC_DEFAULT_PREC;
     950           3 :     char cPrecisionCode = '2';
     951           3 :     const char *szFname = nullptr;
     952           3 :     AVCBinFile *psFile = nullptr;
     953             : 
     954           3 :     psInfo->numSections = 0;
     955           3 :     psInfo->pasSections = nullptr;
     956             : 
     957             :     /*-----------------------------------------------------------------
     958             :      * Build the absolute coverage path to include in the EXP  0 line
     959             :      * This line usually contains the full path of the E00 file that
     960             :      * is being created, but since the lib does not write the output
     961             :      * file directly, there is no simple way to get that value.  Instead,
     962             :      * we will use the absolute coverage path to which we add a .E00
     963             :      * extension.
     964             :      * We need also make sure cover path is all in uppercase.
     965             :      *----------------------------------------------------------------*/
     966             : #ifdef _WIN32
     967             :     if (psInfo->pszCoverPath[0] != '\\' &&
     968             :         !(isalpha((unsigned char)psInfo->pszCoverPath[0]) &&
     969             :           psInfo->pszCoverPath[1] == ':'))
     970             : #else
     971           3 :     if (psInfo->pszCoverPath[0] != '/')
     972             : #endif
     973             :     {
     974           3 :         if (getcwd(szCWD, 74) == nullptr)
     975           0 :             szCWD[0] = '\0'; /* Failed: buffer may be too small */
     976             : 
     977           3 :         nLen = (int)strlen(szCWD);
     978             : 
     979             : #ifdef _WIN32
     980             :         if (nLen > 0 && szCWD[nLen - 1] != '\\')
     981             :             strcat(szCWD, "\\");
     982             : #else
     983           3 :         if (nLen > 0 && szCWD[nLen - 1] != '/')
     984           3 :             strcat(szCWD, "/");
     985             : #endif
     986             :     }
     987             : 
     988           3 :     CPLString osCoverPathTruncated(psInfo->pszCoverPath);
     989           3 :     osCoverPathTruncated.pop_back();
     990           3 :     pszEXPPath = CPLStrdup(
     991             :         CPLSPrintf("EXP  0 %s%s.E00", szCWD, osCoverPathTruncated.c_str()));
     992           3 :     pcTmp = pszEXPPath;
     993         249 :     for (; *pcTmp != '\0'; pcTmp++)
     994         246 :         *pcTmp = (char)CPLToupper(static_cast<unsigned char>(*pcTmp));
     995             : 
     996             :     /*-----------------------------------------------------------------
     997             :      * EXP Header
     998             :      *----------------------------------------------------------------*/
     999             :     {
    1000           3 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1001             :                                                     &(psInfo->numSections), 1);
    1002           3 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1003           3 :         psInfo->pasSections[iSect].pszName = pszEXPPath;
    1004             :     }
    1005             : 
    1006             :     /*-----------------------------------------------------------------
    1007             :      * We have to try to open each file as we go for 2 reasons:
    1008             :      * - To validate the file's signature in order to detect cases like a user
    1009             :      *   that places files such as "mystuff.txt" in the cover directory...
    1010             :      *   this has already happened and obviously lead to problems!)
    1011             :      * - We also need to find the coverage's precision from the headers
    1012             :      *----------------------------------------------------------------*/
    1013             : 
    1014             :     /*-----------------------------------------------------------------
    1015             :      * ARC section (arc.adf)
    1016             :      *----------------------------------------------------------------*/
    1017           3 :     szFname =
    1018           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1019           3 :             ? "arc.adf"
    1020             :             : "arc";
    1021           5 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1022             :         (psFile =
    1023           2 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1024             :                             AVCFileARC, psInfo->psDBCSInfo)) != nullptr)
    1025             :     {
    1026           2 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1027           2 :             nCoverPrecision = psFile->nPrecision;
    1028           2 :         AVCBinReadClose(psFile);
    1029           2 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1030             :                                                     &(psInfo->numSections), 1);
    1031             : 
    1032           2 :         psInfo->pasSections[iSect].eType = AVCFileARC;
    1033           2 :         psInfo->pasSections[iSect].pszName = CPLStrdup("ARC");
    1034           4 :         psInfo->pasSections[iSect].pszFilename =
    1035           2 :             CPLStrdup(papszCoverDir[iFile]);
    1036             :     }
    1037             : 
    1038             :     /*-----------------------------------------------------------------
    1039             :      * CNT section (cnt.adf)
    1040             :      *----------------------------------------------------------------*/
    1041           3 :     szFname =
    1042           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1043           3 :             ? "cnt.adf"
    1044             :             : "cnt";
    1045           4 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1046             :         (psFile =
    1047           1 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1048             :                             AVCFileCNT, psInfo->psDBCSInfo)) != nullptr)
    1049             :     {
    1050           1 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1051           0 :             nCoverPrecision = psFile->nPrecision;
    1052           1 :         AVCBinReadClose(psFile);
    1053           1 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1054             :                                                     &(psInfo->numSections), 1);
    1055             : 
    1056           1 :         psInfo->pasSections[iSect].eType = AVCFileCNT;
    1057           1 :         psInfo->pasSections[iSect].pszName = CPLStrdup("CNT");
    1058           2 :         psInfo->pasSections[iSect].pszFilename =
    1059           1 :             CPLStrdup(papszCoverDir[iFile]);
    1060             :     }
    1061             : 
    1062             :     /*-----------------------------------------------------------------
    1063             :      * LAB section (lab.adf)
    1064             :      *----------------------------------------------------------------*/
    1065           3 :     szFname =
    1066           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1067           3 :             ? "lab.adf"
    1068             :             : "lab";
    1069           6 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1070             :         (psFile =
    1071           3 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1072             :                             AVCFileLAB, psInfo->psDBCSInfo)) != nullptr)
    1073             :     {
    1074           3 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1075           1 :             nCoverPrecision = psFile->nPrecision;
    1076           3 :         AVCBinReadClose(psFile);
    1077           3 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1078             :                                                     &(psInfo->numSections), 1);
    1079             : 
    1080           3 :         psInfo->pasSections[iSect].eType = AVCFileLAB;
    1081           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("LAB");
    1082           6 :         psInfo->pasSections[iSect].pszFilename =
    1083           3 :             CPLStrdup(papszCoverDir[iFile]);
    1084             :     }
    1085             : 
    1086             :     /*-----------------------------------------------------------------
    1087             :      * PAL section (pal.adf)
    1088             :      *----------------------------------------------------------------*/
    1089           3 :     szFname =
    1090           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1091           3 :             ? "pal.adf"
    1092             :             : "pal";
    1093           4 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1094             :         (psFile =
    1095           1 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1096             :                             AVCFilePAL, psInfo->psDBCSInfo)) != nullptr)
    1097             :     {
    1098           1 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1099           0 :             nCoverPrecision = psFile->nPrecision;
    1100           1 :         AVCBinReadClose(psFile);
    1101           1 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1102             :                                                     &(psInfo->numSections), 1);
    1103             : 
    1104           1 :         psInfo->pasSections[iSect].eType = AVCFilePAL;
    1105           1 :         psInfo->pasSections[iSect].pszName = CPLStrdup("PAL");
    1106           2 :         psInfo->pasSections[iSect].pszFilename =
    1107           1 :             CPLStrdup(papszCoverDir[iFile]);
    1108             :     }
    1109             : 
    1110             :     /*-----------------------------------------------------------------
    1111             :      * TOL section (tol.adf for single precision, par.adf for double)
    1112             :      *----------------------------------------------------------------*/
    1113           3 :     szFname =
    1114           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1115           3 :             ? "tol.adf"
    1116             :             : "tol";
    1117           6 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1118             :         (psFile =
    1119           3 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1120             :                             AVCFileTOL, psInfo->psDBCSInfo)) != nullptr)
    1121             :     {
    1122           3 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1123           0 :             nCoverPrecision = psFile->nPrecision;
    1124           3 :         AVCBinReadClose(psFile);
    1125           3 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1126             :                                                     &(psInfo->numSections), 1);
    1127             : 
    1128           3 :         psInfo->pasSections[iSect].eType = AVCFileTOL;
    1129           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("TOL");
    1130           6 :         psInfo->pasSections[iSect].pszFilename =
    1131           3 :             CPLStrdup(papszCoverDir[iFile]);
    1132             :     }
    1133             : 
    1134           3 :     szFname =
    1135           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1136           3 :             ? "par.adf"
    1137             :             : "par";
    1138           3 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1139             :         (psFile =
    1140           0 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1141             :                             AVCFileTOL, psInfo->psDBCSInfo)) != nullptr)
    1142             :     {
    1143           0 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1144           0 :             nCoverPrecision = psFile->nPrecision;
    1145           0 :         AVCBinReadClose(psFile);
    1146           0 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1147             :                                                     &(psInfo->numSections), 1);
    1148             : 
    1149           0 :         psInfo->pasSections[iSect].eType = AVCFileTOL;
    1150           0 :         psInfo->pasSections[iSect].pszName = CPLStrdup("TOL");
    1151           0 :         psInfo->pasSections[iSect].pszFilename =
    1152           0 :             CPLStrdup(papszCoverDir[iFile]);
    1153             :     }
    1154             : 
    1155             :     /*-----------------------------------------------------------------
    1156             :      * TXT section (txt.adf)
    1157             :      *----------------------------------------------------------------*/
    1158           3 :     szFname =
    1159           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1160           3 :             ? "txt.adf"
    1161             :             : "txt";
    1162           3 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1 &&
    1163             :         (psFile =
    1164           0 :              AVCBinReadOpen(psInfo->pszCoverPath, szFname, psInfo->eCoverType,
    1165             :                             AVCFileTXT, psInfo->psDBCSInfo)) != nullptr)
    1166             :     {
    1167           0 :         if (nCoverPrecision == AVC_DEFAULT_PREC)
    1168           0 :             nCoverPrecision = psFile->nPrecision;
    1169           0 :         AVCBinReadClose(psFile);
    1170           0 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1171             :                                                     &(psInfo->numSections), 1);
    1172             : 
    1173           0 :         psInfo->pasSections[iSect].eType = AVCFileTXT;
    1174           0 :         psInfo->pasSections[iSect].pszName = CPLStrdup("TXT");
    1175           0 :         psInfo->pasSections[iSect].pszFilename =
    1176           0 :             CPLStrdup(papszCoverDir[iFile]);
    1177             :     }
    1178             : 
    1179             :     /*-----------------------------------------------------------------
    1180             :      * TX6 section (*.txt)
    1181             :      * Scan the directory for files with a ".txt" extension.
    1182             :      * Note: Never seen those in a PC Arc/Info coverage!
    1183             :      * In weird coverages, the filename ends with "txt" but there is no "."
    1184             :      *----------------------------------------------------------------*/
    1185           3 :     if (psInfo->eCoverType == AVCCoverV7)
    1186           3 :         nCoverPrecision = _AVCE00ReadAddJabberwockySection(
    1187             :             psInfo, AVCFileTX6, "TX6", nCoverPrecision, ".txt", papszCoverDir);
    1188           0 :     else if (psInfo->eCoverType == AVCCoverWeird)
    1189           0 :         nCoverPrecision = _AVCE00ReadAddJabberwockySection(
    1190             :             psInfo, AVCFileTX6, "TX6", nCoverPrecision, "txt", papszCoverDir);
    1191             : 
    1192             :     /*-----------------------------------------------------------------
    1193             :      * At this point, we should have read the coverage precision... and if
    1194             :      * we haven't yet then we'll just use single by default.
    1195             :      * We'll need cPrecisionCode for some of the sections that follow.
    1196             :      *----------------------------------------------------------------*/
    1197           3 :     if (nCoverPrecision == AVC_DOUBLE_PREC)
    1198           0 :         cPrecisionCode = '3';
    1199             :     else
    1200           3 :         cPrecisionCode = '2';
    1201             : 
    1202             :     /*-----------------------------------------------------------------
    1203             :      * SIN  2/3 and EOX lines ... ???
    1204             :      *----------------------------------------------------------------*/
    1205             :     {
    1206           3 :         int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1207             :                                               &(psInfo->numSections), 2);
    1208           3 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1209           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("SIN  X");
    1210           3 :         psInfo->pasSections[iSect].pszName[5] = cPrecisionCode;
    1211           3 :         iSect++;
    1212           3 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1213           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("EOX");
    1214             :     }
    1215             : 
    1216             :     /*-----------------------------------------------------------------
    1217             :      * LOG section (log.adf) (ends with EOL)
    1218             :      *----------------------------------------------------------------*/
    1219             : 
    1220             :     /*-----------------------------------------------------------------
    1221             :      * PRJ section (prj.adf) (ends with EOP)
    1222             :      *----------------------------------------------------------------*/
    1223           3 :     szFname =
    1224           0 :         (psInfo->eCoverType == AVCCoverV7 || psInfo->eCoverType == AVCCoverPC2)
    1225           3 :             ? "prj.adf"
    1226             :             : "prj";
    1227           3 :     if ((iFile = CSLFindString(papszCoverDir, szFname)) != -1)
    1228             :     {
    1229           2 :         const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1230             :                                                     &(psInfo->numSections), 1);
    1231             : 
    1232           2 :         psInfo->pasSections[iSect].eType = AVCFilePRJ;
    1233           2 :         psInfo->pasSections[iSect].pszName = CPLStrdup("PRJ");
    1234           4 :         psInfo->pasSections[iSect].pszFilename =
    1235           2 :             CPLStrdup(papszCoverDir[iFile]);
    1236             :     }
    1237             : 
    1238             :     /*-----------------------------------------------------------------
    1239             :      * RXP section (*.rxp)
    1240             :      * Scan the directory for files with a ".rxp" extension.
    1241             :      *----------------------------------------------------------------*/
    1242           3 :     if (psInfo->eCoverType == AVCCoverV7)
    1243           3 :         _AVCE00ReadAddJabberwockySection(
    1244             :             psInfo, AVCFileRXP, "RXP", nCoverPrecision, ".rxp", papszCoverDir);
    1245           0 :     else if (psInfo->eCoverType == AVCCoverWeird)
    1246           0 :         _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRXP, "RXP",
    1247             :                                          nCoverPrecision, "rxp", papszCoverDir);
    1248             : 
    1249             :     /*-----------------------------------------------------------------
    1250             :      * RPL section (*.pal)
    1251             :      * Scan the directory for files with a ".rpl" extension.
    1252             :      *----------------------------------------------------------------*/
    1253           3 :     if (psInfo->eCoverType == AVCCoverV7)
    1254           3 :         _AVCE00ReadAddJabberwockySection(
    1255             :             psInfo, AVCFileRPL, "RPL", nCoverPrecision, ".pal", papszCoverDir);
    1256           0 :     else if (psInfo->eCoverType == AVCCoverWeird)
    1257           0 :         _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRPL, "RPL",
    1258             :                                          nCoverPrecision, "rpl", papszCoverDir);
    1259             : 
    1260             :     /*-----------------------------------------------------------------
    1261             :      * IFO section (tables)
    1262             :      *----------------------------------------------------------------*/
    1263           3 :     papszTables = papszFiles = nullptr;
    1264           3 :     if (psInfo->eCoverType == AVCCoverV7 ||
    1265           0 :         psInfo->eCoverType == AVCCoverV7Tables ||
    1266           0 :         psInfo->eCoverType == AVCCoverWeird)
    1267             :     {
    1268             :         /*-------------------------------------------------------------
    1269             :          * Unix coverages: get tables from the ../info/arc.dir
    1270             :          * Weird coverages: the arc.dir is similar but called "arcdr9"
    1271             :          *------------------------------------------------------------*/
    1272           3 :         papszTables = AVCBinReadListTables(
    1273           3 :             psInfo->pszInfoPath, psInfo->pszCoverName, &papszFiles,
    1274             :             psInfo->eCoverType, psInfo->psDBCSInfo);
    1275             :     }
    1276           0 :     else if (psInfo->eCoverType == AVCCoverPC ||
    1277           0 :              psInfo->eCoverType == AVCCoverPC2)
    1278             :     {
    1279             :         /*-------------------------------------------------------------
    1280             :          * PC coverages: look for "???.dbf" in the coverage directory
    1281             :          *               and build the table name using the coverage name
    1282             :          *               as the table basename, and the dbf file basename
    1283             :          *               as the table extension.
    1284             :          *------------------------------------------------------------*/
    1285           0 :         for (iFile = 0; papszCoverDir && papszCoverDir[iFile]; iFile++)
    1286             :         {
    1287           0 :             if ((nLen = (int)strlen(papszCoverDir[iFile])) == 7 &&
    1288           0 :                 EQUAL(papszCoverDir[iFile] + nLen - 4, ".dbf"))
    1289             :             {
    1290           0 :                 papszCoverDir[iFile][nLen - 4] = '\0';
    1291           0 :                 szFname = CPLSPrintf("%s.%s", psInfo->pszCoverName,
    1292           0 :                                      papszCoverDir[iFile]);
    1293           0 :                 pcTmp = (char *)szFname;
    1294           0 :                 for (; *pcTmp != '\0'; pcTmp++)
    1295           0 :                     *pcTmp =
    1296           0 :                         (char)CPLToupper(static_cast<unsigned char>(*pcTmp));
    1297           0 :                 papszCoverDir[iFile][nLen - 4] = '.';
    1298             : 
    1299           0 :                 papszTables = CSLAddString(papszTables, szFname);
    1300           0 :                 papszFiles = CSLAddString(papszFiles, papszCoverDir[iFile]);
    1301             :             }
    1302             :         }
    1303             :     }
    1304             : 
    1305           3 :     if (papszTables != nullptr && (numTables = CSLCount(papszTables)) > 0)
    1306             :     {
    1307           3 :         int iSect = _AVCIncreaseSectionsArray(
    1308             :             &(psInfo->pasSections), &(psInfo->numSections), numTables + 2);
    1309             : 
    1310           3 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1311           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("IFO  X");
    1312           3 :         psInfo->pasSections[iSect].pszName[5] = cPrecisionCode;
    1313           3 :         iSect++;
    1314             : 
    1315          11 :         for (iTable = 0; iTable < numTables; iTable++)
    1316             :         {
    1317           8 :             psInfo->pasSections[iSect].eType = AVCFileTABLE;
    1318           8 :             psInfo->pasSections[iSect].pszName = CPLStrdup(papszTables[iTable]);
    1319           8 :             if (papszFiles)
    1320             :             {
    1321          16 :                 psInfo->pasSections[iSect].pszFilename =
    1322           8 :                     CPLStrdup(papszFiles[iTable]);
    1323             :             }
    1324           8 :             iSect++;
    1325             :         }
    1326             : 
    1327           3 :         psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1328           3 :         psInfo->pasSections[iSect].pszName = CPLStrdup("EOI");
    1329             :     }
    1330           3 :     CSLDestroy(papszTables);
    1331           3 :     CSLDestroy(papszFiles);
    1332             : 
    1333             :     /*-----------------------------------------------------------------
    1334             :      * File ends with EOS
    1335             :      *----------------------------------------------------------------*/
    1336           3 :     const int iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
    1337             :                                                 &(psInfo->numSections), 1);
    1338           3 :     psInfo->pasSections[iSect].eType = AVCFileUnknown;
    1339           3 :     psInfo->pasSections[iSect].pszName = CPLStrdup("EOS");
    1340             : 
    1341           6 :     return nCoverPrecision;
    1342             : }
    1343             : 
    1344             : /**********************************************************************
    1345             :  *                     _AVCE00ReadScanE00()
    1346             :  *
    1347             :  * Processes an entire E00 file to find all the interesting sections.
    1348             :  **********************************************************************/
    1349          11 : static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead)
    1350             : {
    1351          11 :     AVCE00ParseInfo *psInfo = psRead->hParseInfo;
    1352             : 
    1353             :     const char *pszLine;
    1354          11 :     const char *pszName = nullptr;
    1355             :     void *obj;
    1356          11 :     int iSect = 0;
    1357          11 :     GBool bFirstLine = TRUE;
    1358             : 
    1359        3656 :     while (CPLGetLastErrorNo() == 0 &&
    1360        1828 :            (pszLine = CPLReadLine2L(psRead->hFile, knMAX_CHARS_PER_LINE,
    1361             :                                     nullptr)) != nullptr)
    1362             :     {
    1363        1818 :         if (bFirstLine)
    1364             :         {
    1365             :             /* Look for the first non-empty line, after the EXP header,
    1366             :              * trying to detect compressed E00 files. If the file is
    1367             :              * compressed, the first line of data should be 79 or 80 chars
    1368             :              * long and contain several '~' characters.
    1369             :              */
    1370          22 :             int nLen = (int)strlen(pszLine);
    1371          22 :             if (nLen == 0 || STARTS_WITH_CI(pszLine, "EXP "))
    1372          11 :                 continue; /* Skip empty and EXP header lines */
    1373          11 :             else if ((nLen == 79 || nLen == 80) &&
    1374           1 :                      strchr(pszLine, '~') != nullptr)
    1375             :             {
    1376             :                 /* Looks like a compressed file. Just log an error and return.
    1377             :                  * The caller should reject the file because it contains 0
    1378             :                  * sections
    1379             :                  */
    1380           1 :                 CPLError(CE_Failure, CPLE_OpenFailed,
    1381             :                          "This looks like a compressed E00 file and cannot be "
    1382             :                          "processed directly. You may need to uncompress it "
    1383             :                          "first using the E00compr library or the e00conv "
    1384             :                          "program.");
    1385           1 :                 return;
    1386             :             }
    1387             : 
    1388             :             /* All seems fine. Continue with normal processing */
    1389          10 :             bFirstLine = FALSE;
    1390             :         }
    1391             : 
    1392             :         /* coverity[tainted_data] */
    1393        1806 :         obj = _AVCE00ReadNextLineE00(psRead, pszLine);
    1394             : 
    1395        1806 :         if (obj)
    1396             :         {
    1397         823 :             pszName = nullptr;
    1398         823 :             switch (psInfo->eFileType)
    1399             :             {
    1400          49 :                 case AVCFileARC:
    1401          49 :                     pszName = "ARC";
    1402          49 :                     break;
    1403             : 
    1404          20 :                 case AVCFilePAL:
    1405          20 :                     pszName = "PAL";
    1406          20 :                     break;
    1407             : 
    1408          20 :                 case AVCFileCNT:
    1409          20 :                     pszName = "CNT";
    1410          20 :                     break;
    1411             : 
    1412         254 :                 case AVCFileLAB:
    1413         254 :                     pszName = "LAB";
    1414         254 :                     break;
    1415             : 
    1416           0 :                 case AVCFileRPL:
    1417           0 :                     pszName = "RPL";
    1418           0 :                     break;
    1419             : 
    1420           0 :                 case AVCFileTXT:
    1421           0 :                     pszName = "TXT";
    1422           0 :                     break;
    1423             : 
    1424           0 :                 case AVCFileTX6:
    1425           0 :                     pszName = "TX6";
    1426           0 :                     break;
    1427             : 
    1428           7 :                 case AVCFilePRJ:
    1429           7 :                     pszName = "PRJ";
    1430           7 :                     break;
    1431             : 
    1432         373 :                 case AVCFileTABLE:
    1433         373 :                     pszName = psInfo->hdr.psTableDef->szTableName;
    1434         373 :                     break;
    1435             : 
    1436         100 :                 default:
    1437         100 :                     break;
    1438             :             }
    1439             : 
    1440         823 :             if (pszName &&
    1441         723 :                 (psRead->numSections == 0 ||
    1442         713 :                  psRead->pasSections[iSect].eType != psInfo->eFileType ||
    1443         679 :                  !EQUAL(pszName, psRead->pasSections[iSect].pszName)))
    1444             :             {
    1445          76 :                 iSect = _AVCIncreaseSectionsArray(&(psRead->pasSections),
    1446             :                                                   &(psRead->numSections), 1);
    1447             : 
    1448          76 :                 psRead->pasSections[iSect].eType = psInfo->eFileType;
    1449             :                 /* psRead->pasSections[iSect].pszName =
    1450             :                  * CPLStrdup(psRead->pszCoverName); */
    1451          76 :                 psRead->pasSections[iSect].pszName = CPLStrdup(pszName);
    1452         152 :                 psRead->pasSections[iSect].pszFilename =
    1453          76 :                     CPLStrdup(psRead->pszCoverPath);
    1454          76 :                 psRead->pasSections[iSect].nLineNum = psInfo->nStartLineNum;
    1455          76 :                 psRead->pasSections[iSect].nFeatureCount = 0;
    1456             :             }
    1457             : 
    1458         823 :             if (pszName && psRead->numSections)
    1459             :             {
    1460             :                 /* increase feature count for current layer */
    1461         723 :                 ++psRead->pasSections[iSect].nFeatureCount;
    1462             :             }
    1463             :         }
    1464             :     }
    1465             : }
    1466             : 
    1467             : /**********************************************************************
    1468             :  *                         _AVCE00ReadNextTableLine()
    1469             :  *
    1470             :  * Return the next line of the E00 representation of a info table.
    1471             :  *
    1472             :  * This function is used by AVCE00ReadNextLine() to generate table
    1473             :  * output... it should never be called directly.
    1474             :  **********************************************************************/
    1475           0 : static const char *_AVCE00ReadNextTableLine(AVCE00ReadPtr psInfo)
    1476             : {
    1477           0 :     const char *pszLine = nullptr;
    1478             :     AVCE00Section *psSect;
    1479             : 
    1480           0 :     psSect = &(psInfo->pasSections[psInfo->iCurSection]);
    1481             : 
    1482           0 :     CPLAssert(psSect->eType == AVCFileTABLE);
    1483             : 
    1484           0 :     if (psInfo->iCurStep == AVC_GEN_NOTSTARTED)
    1485             :     {
    1486             :         /*---------------------------------------------------------
    1487             :          * Open table and start returning header
    1488             :          *--------------------------------------------------------*/
    1489           0 :         if (psInfo->eCoverType == AVCCoverPC ||
    1490           0 :             psInfo->eCoverType == AVCCoverPC2)
    1491             :         {
    1492             :             /*---------------------------------------------------------
    1493             :              * PC Arc/Info: We pass the DBF table's full filename + the
    1494             :              * Arc/Info table name (for E00 header)
    1495             :              *--------------------------------------------------------*/
    1496             :             char *pszFname;
    1497           0 :             pszFname = CPLStrdup(
    1498             :                 CPLSPrintf("%s%s", psInfo->pszInfoPath, psSect->pszFilename));
    1499           0 :             psInfo->hFile =
    1500           0 :                 AVCBinReadOpen(pszFname, psSect->pszName, psInfo->eCoverType,
    1501             :                                psSect->eType, psInfo->psDBCSInfo);
    1502           0 :             CPLFree(pszFname);
    1503             :         }
    1504             :         else
    1505             :         {
    1506             :             /*---------------------------------------------------------
    1507             :              * AVCCoverV7 and AVCCoverWeird:
    1508             :              * We pass the INFO dir's path, and the Arc/Info table name
    1509             :              * will be searched in the arc.dir
    1510             :              *--------------------------------------------------------*/
    1511           0 :             psInfo->hFile = AVCBinReadOpen(psInfo->pszInfoPath, psSect->pszName,
    1512             :                                            psInfo->eCoverType, psSect->eType,
    1513             :                                            psInfo->psDBCSInfo);
    1514             :         }
    1515             : 
    1516             :         /* For some reason the file could not be opened... abort now.
    1517             :          * An error message should have already been produced by
    1518             :          * AVCBinReadOpen()
    1519             :          */
    1520           0 :         if (psInfo->hFile == nullptr)
    1521           0 :             return nullptr;
    1522             : 
    1523           0 :         psInfo->iCurStep = AVC_GEN_TABLEHEADER;
    1524             : 
    1525           0 :         pszLine = AVCE00GenTableHdr(psInfo->hGenInfo,
    1526           0 :                                     psInfo->hFile->hdr.psTableDef, FALSE);
    1527             :     }
    1528             : 
    1529           0 :     if (pszLine == nullptr && psInfo->iCurStep == AVC_GEN_TABLEHEADER)
    1530             :     {
    1531             :         /*---------------------------------------------------------
    1532             :          * Continue table header
    1533             :          *--------------------------------------------------------*/
    1534           0 :         pszLine = AVCE00GenTableHdr(psInfo->hGenInfo,
    1535           0 :                                     psInfo->hFile->hdr.psTableDef, TRUE);
    1536             : 
    1537           0 :         if (pszLine == nullptr)
    1538             :         {
    1539             :             /* Finished with table header... time to proceed with the
    1540             :              * table data.
    1541             :              * Reset the AVCE00GenInfo struct. so that it returns nullptr,
    1542             :              * which will force reading of the first record from the
    1543             :              * file on the next call to AVCE00ReadNextLine()
    1544             :              */
    1545           0 :             AVCE00GenReset(psInfo->hGenInfo);
    1546           0 :             psInfo->iCurStep = AVC_GEN_TABLEDATA;
    1547             :         }
    1548             :     }
    1549             : 
    1550           0 :     if (pszLine == nullptr && psInfo->iCurStep == AVC_GEN_TABLEDATA)
    1551             :     {
    1552             :         /*---------------------------------------------------------
    1553             :          * Continue with records of data
    1554             :          *--------------------------------------------------------*/
    1555             : 
    1556           0 :         pszLine = AVCE00GenTableRec(psInfo->hGenInfo,
    1557           0 :                                     psInfo->hFile->hdr.psTableDef->numFields,
    1558           0 :                                     psInfo->hFile->hdr.psTableDef->pasFieldDef,
    1559           0 :                                     psInfo->hFile->cur.pasFields, TRUE);
    1560             : 
    1561           0 :         if (pszLine == nullptr)
    1562             :         {
    1563             :             /* Current record is finished generating... we need to read
    1564             :              * a new one from the file.
    1565             :              */
    1566           0 :             if (AVCBinReadNextObject(psInfo->hFile) != nullptr)
    1567             :             {
    1568           0 :                 pszLine = AVCE00GenTableRec(
    1569           0 :                     psInfo->hGenInfo, psInfo->hFile->hdr.psTableDef->numFields,
    1570           0 :                     psInfo->hFile->hdr.psTableDef->pasFieldDef,
    1571           0 :                     psInfo->hFile->cur.pasFields, FALSE);
    1572             :             }
    1573             :         }
    1574             :     }
    1575             : 
    1576           0 :     if (pszLine == nullptr)
    1577             :     {
    1578             :         /*---------------------------------------------------------
    1579             :          * No more lines to output for this table ... Close it.
    1580             :          *--------------------------------------------------------*/
    1581           0 :         AVCBinReadClose(psInfo->hFile);
    1582           0 :         psInfo->hFile = nullptr;
    1583             : 
    1584             :         /*---------------------------------------------------------
    1585             :          * And now proceed to the next section...
    1586             :          * OK, I don't really like recursion, but it was
    1587             :          * the simplest way to do this, and anyways we should never
    1588             :          * have more than one level of recursion.
    1589             :          *--------------------------------------------------------*/
    1590           0 :         if (psInfo->bReadAllSections)
    1591           0 :             psInfo->iCurSection++;
    1592             :         else
    1593           0 :             psInfo->iCurSection = psInfo->numSections;
    1594           0 :         psInfo->iCurStep = AVC_GEN_NOTSTARTED;
    1595             : 
    1596           0 :         pszLine = AVCE00ReadNextLine(psInfo);
    1597             :     }
    1598             : 
    1599             :     /*-----------------------------------------------------------------
    1600             :      * Check for errors... if any error happened, then return nullptr.
    1601             :      *----------------------------------------------------------------*/
    1602           0 :     if (CPLGetLastErrorNo() != 0)
    1603             :     {
    1604           0 :         pszLine = nullptr;
    1605             :     }
    1606             : 
    1607           0 :     return pszLine;
    1608             : }
    1609             : 
    1610             : /**********************************************************************
    1611             :  *                          AVCE00ReadNextLine()
    1612             :  *
    1613             :  * Returns the next line of the E00 representation of the coverage
    1614             :  * or nullptr when there are no more lines to generate, or if an error happened.
    1615             :  * The returned line is a null-terminated string, and it does not
    1616             :  * include a newline character.
    1617             :  *
    1618             :  * Call CPLGetLastErrorNo() after calling AVCE00ReadNextLine() to
    1619             :  * make sure that the line was generated successfully.
    1620             :  *
    1621             :  * Note that AVCE00ReadNextLine() returns a reference to an
    1622             :  * internal buffer whose contents will
    1623             :  * be valid only until the next call to this function.  The caller should
    1624             :  * not attempt to free() the returned pointer.
    1625             :  **********************************************************************/
    1626           0 : const char *AVCE00ReadNextLine(AVCE00ReadPtr psInfo)
    1627             : {
    1628           0 :     const char *pszLine = nullptr;
    1629             :     AVCE00Section *psSect;
    1630             : 
    1631           0 :     CPLErrorReset();
    1632             : 
    1633             :     /*-----------------------------------------------------------------
    1634             :      * Check if we have finished generating E00 output
    1635             :      *----------------------------------------------------------------*/
    1636           0 :     if (psInfo->iCurSection >= psInfo->numSections)
    1637           0 :         return nullptr;
    1638             : 
    1639           0 :     psSect = &(psInfo->pasSections[psInfo->iCurSection]);
    1640             : 
    1641             :     /*-----------------------------------------------------------------
    1642             :      * For simplicity, the generation of table output is in a separate
    1643             :      * function.
    1644             :      *----------------------------------------------------------------*/
    1645           0 :     if (psSect->eType == AVCFileTABLE)
    1646             :     {
    1647           0 :         return _AVCE00ReadNextTableLine(psInfo);
    1648             :     }
    1649             : 
    1650           0 :     if (psSect->eType == AVCFileUnknown)
    1651             :     {
    1652             :         /*-----------------------------------------------------------------
    1653             :          * Section not attached to any file, used to hold header lines
    1654             :          * or section separators, etc... just return the line directly and
    1655             :          * move pointer to the next section.
    1656             :          *----------------------------------------------------------------*/
    1657           0 :         pszLine = psSect->pszName;
    1658           0 :         if (psInfo->bReadAllSections)
    1659           0 :             psInfo->iCurSection++;
    1660             :         else
    1661           0 :             psInfo->iCurSection = psInfo->numSections;
    1662           0 :         psInfo->iCurStep = AVC_GEN_NOTSTARTED;
    1663             :     }
    1664             :     /*=================================================================
    1665             :      *              ARC, PAL, CNT, LAB, TOL and TXT
    1666             :      *================================================================*/
    1667           0 :     else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED &&
    1668           0 :              (psSect->eType == AVCFileARC || psSect->eType == AVCFilePAL ||
    1669           0 :               psSect->eType == AVCFileRPL || psSect->eType == AVCFileCNT ||
    1670           0 :               psSect->eType == AVCFileLAB || psSect->eType == AVCFileTOL ||
    1671           0 :               psSect->eType == AVCFileTXT || psSect->eType == AVCFileTX6 ||
    1672           0 :               psSect->eType == AVCFileRXP))
    1673             :     {
    1674             :         /*-----------------------------------------------------------------
    1675             :          * Start processing of an ARC, PAL, CNT, LAB or TOL section:
    1676             :          *   Open the file, get ready to read the first object from the
    1677             :          *   file, and return the header line.
    1678             :          *  If the file fails to open then we will return nullptr.
    1679             :          *----------------------------------------------------------------*/
    1680           0 :         psInfo->hFile = AVCBinReadOpen(psInfo->pszCoverPath,
    1681           0 :                                        psSect->pszFilename, psInfo->eCoverType,
    1682             :                                        psSect->eType, psInfo->psDBCSInfo);
    1683             : 
    1684             :         /*-------------------------------------------------------------
    1685             :          * For some reason the file could not be opened... abort now.
    1686             :          * An error message should have already been produced by
    1687             :          * AVCBinReadOpen()
    1688             :          *------------------------------------------------------------*/
    1689           0 :         if (psInfo->hFile == nullptr)
    1690           0 :             return nullptr;
    1691             : 
    1692           0 :         pszLine = AVCE00GenStartSection(psInfo->hGenInfo, psSect->eType,
    1693           0 :                                         psSect->pszName);
    1694             : 
    1695             :         /*-------------------------------------------------------------
    1696             :          * Reset the AVCE00GenInfo struct. so that it returns nullptr,
    1697             :          * which will force reading of the first object from the
    1698             :          * file on the next call to AVCE00ReadNextLine()
    1699             :          *------------------------------------------------------------*/
    1700           0 :         AVCE00GenReset(psInfo->hGenInfo);
    1701           0 :         psInfo->iCurStep = AVC_GEN_DATA;
    1702             :     }
    1703           0 :     else if (psInfo->iCurStep == AVC_GEN_DATA &&
    1704           0 :              (psSect->eType == AVCFileARC || psSect->eType == AVCFilePAL ||
    1705           0 :               psSect->eType == AVCFileRPL || psSect->eType == AVCFileCNT ||
    1706           0 :               psSect->eType == AVCFileLAB || psSect->eType == AVCFileTOL ||
    1707           0 :               psSect->eType == AVCFileTXT || psSect->eType == AVCFileTX6 ||
    1708           0 :               psSect->eType == AVCFileRXP))
    1709             :     {
    1710             :         /*-----------------------------------------------------------------
    1711             :          * Return the next line of an ARC/PAL/CNT/TOL/TXT object...
    1712             :          * if necessary, read the next object from the binary file.
    1713             :          *----------------------------------------------------------------*/
    1714           0 :         pszLine = AVCE00GenObject(
    1715             :             psInfo->hGenInfo, psSect->eType,
    1716           0 :             (psSect->eType == AVCFileARC   ? (void *)(psInfo->hFile->cur.psArc)
    1717           0 :              : psSect->eType == AVCFilePAL ? (void *)(psInfo->hFile->cur.psPal)
    1718           0 :              : psSect->eType == AVCFileRPL ? (void *)(psInfo->hFile->cur.psPal)
    1719           0 :              : psSect->eType == AVCFileCNT ? (void *)(psInfo->hFile->cur.psCnt)
    1720           0 :              : psSect->eType == AVCFileLAB ? (void *)(psInfo->hFile->cur.psLab)
    1721           0 :              : psSect->eType == AVCFileTOL ? (void *)(psInfo->hFile->cur.psTol)
    1722           0 :              : psSect->eType == AVCFileTXT ? (void *)(psInfo->hFile->cur.psTxt)
    1723           0 :              : psSect->eType == AVCFileTX6 ? (void *)(psInfo->hFile->cur.psTxt)
    1724           0 :              : psSect->eType == AVCFileRXP ? (void *)(psInfo->hFile->cur.psRxp)
    1725             :                                            : nullptr),
    1726             :             TRUE);
    1727           0 :         if (pszLine == nullptr)
    1728             :         {
    1729             :             /*---------------------------------------------------------
    1730             :              * Current object is finished generating... we need to read
    1731             :              * a new one from the file.
    1732             :              *--------------------------------------------------------*/
    1733           0 :             if (AVCBinReadNextObject(psInfo->hFile) != nullptr)
    1734             :             {
    1735             :                 pszLine =
    1736           0 :                     AVCE00GenObject(psInfo->hGenInfo, psSect->eType,
    1737           0 :                                     (psSect->eType == AVCFileARC
    1738           0 :                                          ? (void *)(psInfo->hFile->cur.psArc)
    1739           0 :                                      : psSect->eType == AVCFilePAL
    1740           0 :                                          ? (void *)(psInfo->hFile->cur.psPal)
    1741           0 :                                      : psSect->eType == AVCFileRPL
    1742           0 :                                          ? (void *)(psInfo->hFile->cur.psPal)
    1743           0 :                                      : psSect->eType == AVCFileCNT
    1744           0 :                                          ? (void *)(psInfo->hFile->cur.psCnt)
    1745           0 :                                      : psSect->eType == AVCFileLAB
    1746           0 :                                          ? (void *)(psInfo->hFile->cur.psLab)
    1747           0 :                                      : psSect->eType == AVCFileTOL
    1748           0 :                                          ? (void *)(psInfo->hFile->cur.psTol)
    1749           0 :                                      : psSect->eType == AVCFileTXT
    1750           0 :                                          ? (void *)(psInfo->hFile->cur.psTxt)
    1751           0 :                                      : psSect->eType == AVCFileTX6
    1752           0 :                                          ? (void *)(psInfo->hFile->cur.psTxt)
    1753           0 :                                      : psSect->eType == AVCFileRXP
    1754           0 :                                          ? (void *)(psInfo->hFile->cur.psRxp)
    1755             :                                          : nullptr),
    1756             :                                     FALSE);
    1757             :             }
    1758             :         }
    1759           0 :         if (pszLine == nullptr)
    1760             :         {
    1761             :             /*---------------------------------------------------------
    1762             :              * Still nullptr ??? This means we finished reading this file...
    1763             :              * Start returning the "end of section" line(s)...
    1764             :              *--------------------------------------------------------*/
    1765           0 :             AVCBinReadClose(psInfo->hFile);
    1766           0 :             psInfo->hFile = nullptr;
    1767           0 :             psInfo->iCurStep = AVC_GEN_ENDSECTION;
    1768             :             pszLine =
    1769           0 :                 AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, FALSE);
    1770             :         }
    1771             :     }
    1772             :     /*=================================================================
    1773             :      *                          PRJ
    1774             :      *================================================================*/
    1775           0 :     else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED &&
    1776           0 :              psSect->eType == AVCFilePRJ)
    1777             :     {
    1778             :         /*-------------------------------------------------------------
    1779             :          * Start processing of PRJ section... return first header line.
    1780             :          *------------------------------------------------------------*/
    1781             :         pszLine =
    1782           0 :             AVCE00GenStartSection(psInfo->hGenInfo, psSect->eType, nullptr);
    1783             : 
    1784           0 :         psInfo->hFile = nullptr;
    1785           0 :         psInfo->iCurStep = AVC_GEN_DATA;
    1786             :     }
    1787           0 :     else if (psInfo->iCurStep == AVC_GEN_DATA && psSect->eType == AVCFilePRJ)
    1788             :     {
    1789             :         /*-------------------------------------------------------------
    1790             :          * Return the next line of a PRJ section
    1791             :          *------------------------------------------------------------*/
    1792           0 :         if (psInfo->hFile == nullptr)
    1793             :         {
    1794             :             /*---------------------------------------------------------
    1795             :              * File has not been read yet...
    1796             :              * Read the PRJ file, and return the first PRJ line.
    1797             :              *--------------------------------------------------------*/
    1798           0 :             psInfo->hFile = AVCBinReadOpen(
    1799           0 :                 psInfo->pszCoverPath, psSect->pszFilename, psInfo->eCoverType,
    1800             :                 psSect->eType, psInfo->psDBCSInfo);
    1801             : 
    1802             :             /* For some reason the file could not be opened... abort now.
    1803             :              * An error message should have already been produced by
    1804             :              * AVCBinReadOpen()
    1805             :              */
    1806           0 :             if (psInfo->hFile == nullptr)
    1807           0 :                 return nullptr;
    1808             : 
    1809           0 :             pszLine = AVCE00GenPrj(psInfo->hGenInfo,
    1810           0 :                                    psInfo->hFile->cur.papszPrj, FALSE);
    1811             :         }
    1812             :         else
    1813             :         {
    1814             :             /*---------------------------------------------------------
    1815             :              * Generate the next line of output.
    1816             :              *--------------------------------------------------------*/
    1817           0 :             pszLine = AVCE00GenPrj(psInfo->hGenInfo,
    1818           0 :                                    psInfo->hFile->cur.papszPrj, TRUE);
    1819             :         }
    1820             : 
    1821           0 :         if (pszLine == nullptr)
    1822             :         {
    1823             :             /*---------------------------------------------------------
    1824             :              * Still nullptr ??? This means we finished generating this PRJ
    1825             :              * section...
    1826             :              * Start returning the "end of section" line(s)...
    1827             :              *--------------------------------------------------------*/
    1828           0 :             AVCBinReadClose(psInfo->hFile);
    1829           0 :             psInfo->hFile = nullptr;
    1830           0 :             psInfo->iCurStep = AVC_GEN_ENDSECTION;
    1831             :             pszLine =
    1832           0 :                 AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, FALSE);
    1833             :         }
    1834             :     }
    1835           0 :     else if (psInfo->iCurStep != AVC_GEN_ENDSECTION)
    1836             :     {
    1837             :         /* We should never get here! */
    1838           0 :         CPLAssert(FALSE);
    1839             :     }
    1840             : 
    1841             :     /*=================================================================
    1842             :      *                End of section, for all files
    1843             :      *================================================================*/
    1844             : 
    1845             :     /*-----------------------------------------------------------------
    1846             :      * Finished processing of an ARC, PAL, CNT, LAB, TOL, PRJ file ...
    1847             :      * continue returning the "end of section" line(s), and move the pointer
    1848             :      * to the next section once we're done.
    1849             :      *----------------------------------------------------------------*/
    1850           0 :     if (psInfo->iCurStep == AVC_GEN_ENDSECTION && pszLine == nullptr)
    1851             :     {
    1852           0 :         pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, TRUE);
    1853             : 
    1854           0 :         if (pszLine == nullptr)
    1855             :         {
    1856             :             /*---------------------------------------------------------
    1857             :              * Finished returning the last lines of the section...
    1858             :              * proceed to the next section...
    1859             :              * OK, I don't really like recursion, but it was
    1860             :              * the simplest way to do this, and anyways we should never
    1861             :              * have more than one level of recursion.
    1862             :              *--------------------------------------------------------*/
    1863           0 :             if (psInfo->bReadAllSections)
    1864           0 :                 psInfo->iCurSection++;
    1865             :             else
    1866           0 :                 psInfo->iCurSection = psInfo->numSections;
    1867           0 :             psInfo->iCurStep = AVC_GEN_NOTSTARTED;
    1868             : 
    1869           0 :             pszLine = AVCE00ReadNextLine(psInfo);
    1870             :         }
    1871             :     }
    1872             : 
    1873           0 :     return pszLine;
    1874             : }
    1875             : 
    1876             : /**********************************************************************
    1877             :  *                         AVCE00ReadSectionsList()
    1878             :  *
    1879             :  * Returns an array of AVCE00Section structures that describe the
    1880             :  * skeleton of the whole coverage.  The value of *numSect will be
    1881             :  * set to the number of sections in the array.
    1882             :  *
    1883             :  * You can scan the returned array, and use AVCE00ReadGotoSection() to move
    1884             :  * the read pointer directly to the beginning of a given section
    1885             :  * of the file.
    1886             :  *
    1887             :  * Sections of type AVCFileUnknown correspond to lines in the
    1888             :  * E00 output that are not directly linked to any coverage file, like
    1889             :  * the "EXP 0" line, the "IFO X", "SIN X", etc.
    1890             :  *
    1891             :  * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE
    1892             :  * MODIFIED OR FREED BY THE CALLER... its contents will be valid
    1893             :  * for as long as the coverage will remain open.
    1894             :  **********************************************************************/
    1895           0 : AVCE00Section *AVCE00ReadSectionsList(AVCE00ReadPtr psInfo, int *numSect)
    1896             : {
    1897           0 :     CPLErrorReset();
    1898             : 
    1899           0 :     *numSect = psInfo->numSections;
    1900           0 :     return psInfo->pasSections;
    1901             : }
    1902             : 
    1903             : /**********************************************************************
    1904             :  *                         AVCE00ReadGotoSection()
    1905             :  *
    1906             :  * Move the read pointer to the E00 section (coverage file) described in
    1907             :  * the psSect structure.  Call AVCE00ReadSectionsList() to get the list of
    1908             :  * sections for the current coverage.
    1909             :  *
    1910             :  * if bContinue=TRUE, then reading will automatically continue with the
    1911             :  * next sections of the file once the requested section is finished.
    1912             :  * Otherwise, if bContinue=FALSE then reading will stop at the end
    1913             :  * of this section (i.e. AVCE00ReadNextLine() will return nullptr when
    1914             :  * it reaches the end of this section)
    1915             :  *
    1916             :  * Sections of type AVCFileUnknown returned by AVCE00ReadSectionsList()
    1917             :  * correspond to lines in the E00 output that are not directly linked
    1918             :  * to any coverage file, like the "EXP 0" line, the "IFO X", "SIN X", etc.
    1919             :  * You can jump to these sections or any other one without problems.
    1920             :  *
    1921             :  * This function returns 0 on success or -1 on error.
    1922             :  **********************************************************************/
    1923           0 : int AVCE00ReadGotoSection(AVCE00ReadPtr psInfo, AVCE00Section *psSect,
    1924             :                           GBool bContinue)
    1925             : {
    1926             :     int iSect;
    1927           0 :     GBool bFound = FALSE;
    1928             : 
    1929           0 :     CPLErrorReset();
    1930             : 
    1931             :     /*-----------------------------------------------------------------
    1932             :      * Locate the requested section in the array.
    1933             :      *----------------------------------------------------------------*/
    1934           0 :     for (iSect = 0; iSect < psInfo->numSections; iSect++)
    1935             :     {
    1936           0 :         if (psInfo->pasSections[iSect].eType == psSect->eType &&
    1937           0 :             EQUAL(psInfo->pasSections[iSect].pszName, psSect->pszName))
    1938             :         {
    1939           0 :             bFound = TRUE;
    1940           0 :             break;
    1941             :         }
    1942             :     }
    1943             : 
    1944             :     /*-----------------------------------------------------------------
    1945             :      * Not found ... generate an error...
    1946             :      *----------------------------------------------------------------*/
    1947           0 :     if (!bFound)
    1948             :     {
    1949           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
    1950             :                  "Requested E00 section does not exist!");
    1951           0 :         return -1;
    1952             :     }
    1953             : 
    1954             :     /*-----------------------------------------------------------------
    1955             :      * Found it ... close current section and get ready to read
    1956             :      * the new one.
    1957             :      *----------------------------------------------------------------*/
    1958           0 :     if (psInfo->hFile)
    1959             :     {
    1960           0 :         AVCBinReadClose(psInfo->hFile);
    1961           0 :         psInfo->hFile = nullptr;
    1962             :     }
    1963             : 
    1964           0 :     psInfo->bReadAllSections = bContinue;
    1965           0 :     psInfo->iCurSection = iSect;
    1966           0 :     psInfo->iCurStep = AVC_GEN_NOTSTARTED;
    1967             : 
    1968           0 :     return 0;
    1969             : }
    1970             : 
    1971             : /**********************************************************************
    1972             :  *                         AVCE00ReadRewind()
    1973             :  *
    1974             :  * Rewinds the AVCE00ReadPtr just like the stdio rewind()
    1975             :  * function would do if you were reading an ASCII E00 file.
    1976             :  *
    1977             :  * Returns 0 on success or -1 on error.
    1978             :  **********************************************************************/
    1979           0 : int AVCE00ReadRewind(AVCE00ReadPtr psInfo)
    1980             : {
    1981           0 :     CPLErrorReset();
    1982             : 
    1983           0 :     return AVCE00ReadGotoSection(psInfo, &(psInfo->pasSections[0]), TRUE);
    1984             : }
    1985             : 
    1986             : /**********************************************************************
    1987             :  *                         AVCE00ReadRewindE00()
    1988             :  *
    1989             :  * Rewinds the AVCE00ReadE00Ptr just like the stdio rewind()
    1990             :  * function would do if you were reading an ASCII E00 file.
    1991             :  *
    1992             :  * Returns 0 on success or -1 on error.
    1993             :  **********************************************************************/
    1994          28 : int AVCE00ReadRewindE00(AVCE00ReadE00Ptr psRead)
    1995             : {
    1996          28 :     CPLErrorReset();
    1997             : 
    1998          28 :     psRead->bReadAllSections = TRUE;
    1999          28 :     psRead->eCurFileType = AVCFileUnknown;
    2000             : 
    2001          28 :     psRead->hParseInfo->nCurLineNum = 0;
    2002          28 :     psRead->hParseInfo->nStartLineNum = 0;
    2003          28 :     psRead->hParseInfo->bForceEndOfSection = TRUE;
    2004          28 :     psRead->hParseInfo->eSuperSectionType = AVCFileUnknown;
    2005          28 :     AVCE00ParseSectionEnd(psRead->hParseInfo, nullptr, 1);
    2006             : 
    2007          28 :     return VSIFSeekL(psRead->hFile, 0, SEEK_SET);
    2008             : }
    2009             : 
    2010             : /**********************************************************************
    2011             :  *                        _AVCE00ReadSeekE00()
    2012             :  *
    2013             :  * Seeks to a new location in the E00 file, keeping parse state
    2014             :  * appropriately.
    2015             :  *
    2016             :  * NOTE: This is a pretty slow implementation.
    2017             :  * NOTE: The SEEK_END is not implemented.
    2018             :  *
    2019             :  * Returns 0 on success or -1 on error.
    2020             :  **********************************************************************/
    2021          18 : static int _AVCE00ReadSeekE00(AVCE00ReadE00Ptr psRead, int nOffset, int nWhence)
    2022             : {
    2023             :     const char *pszLine;
    2024             :     /* void       *obj; */
    2025             : 
    2026          18 :     switch (nWhence)
    2027             :     {
    2028           0 :         case SEEK_CUR:
    2029           0 :             break;
    2030             : 
    2031          18 :         case SEEK_SET:
    2032          18 :             AVCE00ReadRewindE00(psRead);
    2033          18 :             break;
    2034             : 
    2035           0 :         default:
    2036           0 :             CPLAssert(nWhence == SEEK_CUR || nWhence == SEEK_SET);
    2037           0 :             break;
    2038             :     }
    2039             : 
    2040        1766 :     while (nOffset-- && CPLGetLastErrorNo() == 0 &&
    2041         874 :            (pszLine = CPLReadLine2L(psRead->hFile, knMAX_CHARS_PER_LINE,
    2042             :                                     nullptr)) != nullptr)
    2043             :     {
    2044             :         /* obj = */
    2045             :         /* coverity[tainted_data] */
    2046         874 :         _AVCE00ReadNextLineE00(psRead, pszLine);
    2047             :     }
    2048             : 
    2049          18 :     return nOffset ? -1 : 0;
    2050             : }
    2051             : 
    2052             : /**********************************************************************
    2053             :  *                      AVCE00ReadNextObjectE00()
    2054             :  *
    2055             :  * Returns the next object in an E00 file or nullptr when there are no
    2056             :  * more objects, or if an error happened.  The object type can be
    2057             :  * determined via the eCurFileType attribute of the
    2058             :  * AVCE00ReadE00Ptr object.
    2059             :  *
    2060             :  * Note that AVCE00ReadNextLine() returns a reference to an internal
    2061             :  * buffer whose contents will be valid only until the next call to
    2062             :  * this function.  The caller should not attempt to free() the
    2063             :  * returned pointer.
    2064             :  **********************************************************************/
    2065         218 : void *AVCE00ReadNextObjectE00(AVCE00ReadE00Ptr psRead)
    2066             : {
    2067             :     const char *pszLine;
    2068         218 :     void *obj = nullptr;
    2069             : 
    2070         223 :     do
    2071             :     {
    2072         441 :         pszLine = CPLReadLine2L(psRead->hFile, knMAX_CHARS_PER_LINE, nullptr);
    2073         441 :         if (pszLine == nullptr)
    2074           0 :             break;
    2075             :         /* coverity[tainted_data] */
    2076         441 :         obj = _AVCE00ReadNextLineE00(psRead, pszLine);
    2077             :     } while (
    2078         226 :         obj == nullptr &&
    2079         664 :         (psRead->bReadAllSections || psRead->eCurFileType != AVCFileUnknown) &&
    2080         223 :         CPLGetLastErrorNo() == 0);
    2081         218 :     return obj;
    2082             : }
    2083             : 
    2084             : /**********************************************************************
    2085             :  *                         AVCE00ReadSectionsListE00()
    2086             :  *
    2087             :  * Returns an array of AVCE00Section structures that describe the
    2088             :  * sections in the E00 file.  The value of *numSect will be set to the
    2089             :  * number of sections in the array.
    2090             :  *
    2091             :  * You can scan the returned array, and use AVCE00ReadGotoSectionE00()
    2092             :  * to move the read pointer directly to the beginning of a given
    2093             :  * section of the file.
    2094             :  *
    2095             :  * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE
    2096             :  * MODIFIED OR FREED BY THE CALLER... its contents will be valid
    2097             :  * for as long as the coverage will remain open.
    2098             :  **********************************************************************/
    2099           0 : AVCE00Section *AVCE00ReadSectionsListE00(AVCE00ReadE00Ptr psRead, int *numSect)
    2100             : {
    2101           0 :     CPLErrorReset();
    2102             : 
    2103           0 :     *numSect = psRead->numSections;
    2104           0 :     return psRead->pasSections;
    2105             : }
    2106             : 
    2107             : /**********************************************************************
    2108             :  *                         AVCE00ReadGotoSectionE00()
    2109             :  *
    2110             :  * Move the read pointer to the E00 section described in the psSect
    2111             :  * structure.  Call AVCE00ReadSectionsListE00() to get the list of
    2112             :  * sections for the current coverage.
    2113             :  *
    2114             :  * If bContinue is TRUE, then reading will automatically continue with
    2115             :  * the next section of the file once the requested section is finished.
    2116             :  * Otherwise, if bContinue is FALSE then reading will stop at the end
    2117             :  * of this section (i.e. AVCE00ReadNextObjectE00() will return nullptr
    2118             :  * when the end of this section is reached)
    2119             :  *
    2120             :  * This function returns 0 on success or -1 on error.
    2121             :  **********************************************************************/
    2122          18 : int AVCE00ReadGotoSectionE00(AVCE00ReadE00Ptr psRead, AVCE00Section *psSect,
    2123             :                              GBool bContinue)
    2124             : {
    2125             :     int iSect;
    2126          18 :     GBool bFound = FALSE;
    2127             : 
    2128          18 :     CPLErrorReset();
    2129             : 
    2130             :     /*-----------------------------------------------------------------
    2131             :      * Locate the requested section in the array.
    2132             :      *----------------------------------------------------------------*/
    2133          52 :     for (iSect = 0; iSect < psRead->numSections; iSect++)
    2134             :     {
    2135          52 :         if (psRead->pasSections[iSect].eType == psSect->eType &&
    2136          26 :             EQUAL(psRead->pasSections[iSect].pszName, psSect->pszName))
    2137             :         {
    2138          18 :             bFound = TRUE;
    2139          18 :             break;
    2140             :         }
    2141             :     }
    2142             : 
    2143             :     /*-----------------------------------------------------------------
    2144             :      * Not found ... generate an error...
    2145             :      *----------------------------------------------------------------*/
    2146          18 :     if (!bFound)
    2147             :     {
    2148           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
    2149             :                  "Requested E00 section does not exist!");
    2150           0 :         return -1;
    2151             :     }
    2152             : 
    2153             :     /*-----------------------------------------------------------------
    2154             :      * Found it ... advance parser to line number of start of section
    2155             :      *----------------------------------------------------------------*/
    2156          18 :     _AVCE00ReadSeekE00(psRead, psRead->pasSections[iSect].nLineNum, SEEK_SET);
    2157             : 
    2158          18 :     psRead->bReadAllSections = bContinue;
    2159             : 
    2160          18 :     return 0;
    2161             : }

Generated by: LCOV version 1.14