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: 2024-11-21 22:18:42 Functions: 14 20 70.0 %

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

Generated by: LCOV version 1.14