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

Generated by: LCOV version 1.14