LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - avc_bin.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 445 938 47.4 %
Date: 2025-01-18 12:42:00 Functions: 22 34 64.7 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     avc_bin.c
       4             :  * Project:  Arc/Info vector coverage (AVC)  BIN->E00 conversion library
       5             :  * Language: ANSI C
       6             :  * Purpose:  Binary files access functions.
       7             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       8             :  *
       9             :  **********************************************************************
      10             :  * Copyright (c) 1999-2005, Daniel Morissette
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  **********************************************************************
      14             :  *
      15             :  * $Log: avc_bin.c,v $
      16             :  * Revision 1.30  2008/07/23 20:51:38  dmorissette
      17             :  * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
      18             :  * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
      19             :  *
      20             :  * Revision 1.29  2006/08/17 18:56:42  dmorissette
      21             :  * Support for reading standalone info tables (just tables, no coverage
      22             :  * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549).
      23             :  *
      24             :  * Revision 1.28  2006/06/14 16:31:28  daniel
      25             :  * Added support for AVCCoverPC2 type (bug 1491)
      26             :  *
      27             :  * Revision 1.27  2005/06/03 03:49:58  daniel
      28             :  * Update email address, website url, and copyright dates
      29             :  *
      30             :  * Revision 1.26  2004/02/28 06:35:49  warmerda
      31             :  * Fixed AVCBinReadObject() index support to use 'x' or 'X' for index
      32             :  * depending on the case of the original name.
      33             :  * Fixed so that PC Arc/Info coverages with the extra 256 byte header work
      34             :  * properly when using indexes to read them.
      35             :  *   http://bugzilla.remotesensing.org/show_bug.cgi?id=493
      36             :  *
      37             :  * Revision 1.25  2004/02/11 05:49:44  daniel
      38             :  * Added support for deleted flag in arc.dir (bug 2332)
      39             :  *
      40             :  * Revision 1.24  2002/08/27 15:26:06  daniel
      41             :  * Removed C++ style comments for IRIX compiler (GDAL bug 192)
      42             :  *
      43             :  * Revision 1.23  2002/04/16 20:04:24  daniel
      44             :  * Use record size while reading ARC, PAL, CNT to skip junk bytes. (bug940)
      45             :  *
      46             :  * Revision 1.22  2002/03/18 19:03:37  daniel
      47             :  * Fixed AVCBinReadObject() for PAL objects (bug 848)
      48             :  *
      49             :  * Revision 1.21  2002/02/14 22:54:13  warmerda
      50             :  * added polygon and table support for random reading
      51             :  *
      52             :  * Revision 1.20  2002/02/13 20:35:24  warmerda
      53             :  * added AVCBinReadObject
      54             :  *
      55             :  * Revision 1.19  2001/11/25 22:01:23  daniel
      56             :  * Fixed order of args to AVCRawBinFSeek() in _AVCBinReadNextTableRec()
      57             :  *
      58             :  * Revision 1.18  2000/10/16 16:16:20  daniel
      59             :  * Accept TXT files in AVCCoverWeird that use both PC or V7 TXT structure
      60             :  *
      61             :  * Revision 1.17  2000/09/26 20:21:04  daniel
      62             :  * Added AVCCoverPC write
      63             :  *
      64             :  * Revision 1.16  2000/09/22 19:45:20  daniel
      65             :  * Switch to MIT-style license
      66             :  *
      67             :  * Revision 1.15  2000/09/20 15:09:34  daniel
      68             :  * Check for DAT/NIT fnames sometimes truncated to 8 chars in weird coverages
      69             :  *
      70             :  * Revision 1.14  2000/06/05 21:38:53  daniel
      71             :  * Handle precision field > 1000 in cover file header as meaning double prec.
      72             :  *
      73             :  * Revision 1.13  2000/05/29 15:31:30  daniel
      74             :  * Added Japanese DBCS support
      75             :  *
      76             :  * Revision 1.12  2000/02/14 17:22:36  daniel
      77             :  * Check file signature (9993 or 9994) when reading header.
      78             :  *
      79             :  * Revision 1.11  2000/02/02 04:24:52  daniel
      80             :  * Support double precision "weird" coverages
      81             :  *
      82             :  * Revision 1.10  2000/01/10 02:54:10  daniel
      83             :  * Added read support for "weird" coverages
      84             :  *
      85             :  * Revision 1.9  2000/01/07 07:11:51  daniel
      86             :  * Added support for reading PC Coverage TXT files
      87             :  *
      88             :  * Revision 1.8  1999/12/24 07:38:10  daniel
      89             :  * Added missing DBFClose()
      90             :  *
      91             :  * Revision 1.7  1999/12/24 07:18:34  daniel
      92             :  * Added PC Arc/Info coverages support
      93             :  *
      94             :  * Revision 1.6  1999/08/23 18:17:16  daniel
      95             :  * Modified AVCBinReadListTables() to return INFO fnames for DeleteCoverage()
      96             :  *
      97             :  * Revision 1.5  1999/05/11 01:49:08  daniel
      98             :  * Simple changes required by addition of coverage write support
      99             :  *
     100             :  * Revision 1.4  1999/03/03 18:42:53  daniel
     101             :  * Fixed problem with INFO table headers (arc.dir) that sometimes contain an
     102             :  * invalid number of records.
     103             :  *
     104             :  * Revision 1.3  1999/02/25 17:01:53  daniel
     105             :  * Added support for 16 bit integers in INFO tables (type=50, size=2)
     106             :  *
     107             :  * Revision 1.2  1999/02/25 03:41:28  daniel
     108             :  * Added TXT, TX6/TX7, RXP and RPL support
     109             :  *
     110             :  * Revision 1.1  1999/01/29 16:28:52  daniel
     111             :  * Initial revision
     112             :  *
     113             :  **********************************************************************/
     114             : 
     115             : #include "avc.h"
     116             : 
     117             : #include <ctype.h> /* for isspace() */
     118             : 
     119             : #ifdef WITHOUT_SHAPEFILE
     120             : 
     121             : #define SHP_VSI_ONLY_SETUP_HOOKS
     122             : #define SAOffset vsi_l_offset
     123             : #define SHPAPI_CAL
     124             : 
     125             : #define DBFAddField OGRAVC_DBFAddField
     126             : #define DBFAddNativeFieldType OGRAVC_DBFAddNativeFieldType
     127             : #define DBFAlterFieldDefn OGRAVC_DBFAlterFieldDefn
     128             : #define DBFCloneEmpty OGRAVC_DBFCloneEmpty
     129             : #define DBFClose OGRAVC_DBFClose
     130             : #define DBFCreateEx OGRAVC_DBFCreateEx
     131             : #define DBFCreate OGRAVC_DBFCreate
     132             : #define DBFCreateLL OGRAVC_DBFCreateLL
     133             : #define DBFDeleteField OGRAVC_DBFDeleteField
     134             : #define DBFFlushRecord OGRAVC_DBFFlushRecord
     135             : #define DBFGetCodePage OGRAVC_DBFGetCodePage
     136             : #define DBFGetFieldCount OGRAVC_DBFGetFieldCount
     137             : #define DBFGetFieldIndex OGRAVC_DBFGetFieldIndex
     138             : #define DBFGetFieldInfo OGRAVC_DBFGetFieldInfo
     139             : #define DBFGetLenWithoutExtension OGRAVC_DBFGetLenWithoutExtension
     140             : #define DBFGetNativeFieldType OGRAVC_DBFGetNativeFieldType
     141             : #define DBFGetNullCharacter OGRAVC_DBFGetNullCharacter
     142             : #define DBFGetRecordCount OGRAVC_DBFGetRecordCount
     143             : #define DBFIsAttributeNULL OGRAVC_DBFIsAttributeNULL
     144             : #define DBFIsRecordDeleted OGRAVC_DBFIsRecordDeleted
     145             : #define DBFIsValueNULL OGRAVC_DBFIsValueNULL
     146             : #define DBFLoadRecord OGRAVC_DBFLoadRecord
     147             : #define DBFMarkRecordDeleted OGRAVC_DBFMarkRecordDeleted
     148             : #define DBFOpen OGRAVC_DBFOpen
     149             : #define DBFOpenLL OGRAVC_DBFOpenLL
     150             : #define DBFReadAttribute OGRAVC_DBFReadAttribute
     151             : #define DBFReadDoubleAttribute OGRAVC_DBFReadDoubleAttribute
     152             : #define DBFReadIntegerAttribute OGRAVC_DBFReadIntegerAttribute
     153             : #define DBFReadLogicalAttribute OGRAVC_DBFReadLogicalAttribute
     154             : #define DBFReadStringAttribute OGRAVC_DBFReadStringAttribute
     155             : #define DBFReadDateAttribute OGRAVC_DBFReadDateAttribute
     156             : #define DBFReadTuple OGRAVC_DBFReadTuple
     157             : #define DBFReorderFields OGRAVC_DBFReorderFields
     158             : #define DBFSetLastModifiedDate OGRAVC_DBFSetLastModifiedDate
     159             : #define DBFSetWriteEndOfFileChar OGRAVC_DBFSetWriteEndOfFileChar
     160             : #define DBFUpdateHeader OGRAVC_DBFUpdateHeader
     161             : #define DBFWriteAttributeDirectly OGRAVC_DBFWriteAttributeDirectly
     162             : #define DBFWriteAttribute OGRAVC_DBFWriteAttribute
     163             : #define DBFWriteDoubleAttribute OGRAVC_DBFWriteDoubleAttribute
     164             : #define DBFWriteHeader OGRAVC_DBFWriteHeader
     165             : #define DBFWriteIntegerAttribute OGRAVC_DBFWriteIntegerAttribute
     166             : #define DBFWriteLogicalAttribute OGRAVC_DBFWriteLogicalAttribute
     167             : #define DBFWriteNULLAttribute OGRAVC_DBFWriteNULLAttribute
     168             : #define DBFWriteStringAttribute OGRAVC_DBFWriteStringAttribute
     169             : #define DBFWriteDateAttribute OGRAVC_DBFWriteDateAttribute
     170             : #define DBFWriteTuple OGRAVC_DBFWriteTuple
     171             : 
     172             : #define VSI_SHP_WriteMoreDataOK OGRAVC_VSI_SHP_WriteMoreDataOK
     173             : #define SASetupDefaultHooks OGRAVC_SASetupDefaultHooks
     174             : 
     175             : #include "../shape/shapefil.h"
     176             : #include "../shape/dbfopen.c"
     177             : #include "../shape/shp_vsi.c"
     178             : 
     179             : #else
     180             : 
     181             : #ifdef RENAME_INTERNAL_SHAPELIB_SYMBOLS
     182             : #include "gdal_shapelib_symbol_rename.h"
     183             : #endif
     184             : #include "shapefil.h"
     185             : 
     186             : #endif  // WITHOUT_SHAPEFILE
     187             : 
     188             : /* Used by avc_binwr.c */
     189             : extern int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir);
     190             : 
     191             : /*=====================================================================
     192             :  * Prototypes for some static functions
     193             :  *====================================================================*/
     194             : 
     195             : static AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath,
     196             :                                         const char *pszTableName,
     197             :                                         AVCCoverType eCoverType,
     198             :                                         AVCDBCSInfo *psDBCSInfo);
     199             : static AVCBinFile *_AVCBinReadOpenDBFTable(const char *pszInfoPath,
     200             :                                            const char *pszTableName);
     201             : static AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath, const char *pszName);
     202             : 
     203             : static int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields,
     204             :                                    AVCFieldInfo *pasDef, AVCField *pasFields,
     205             :                                    int nRecordSize);
     206             : static int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex,
     207             :                                       int nFields, AVCFieldInfo *pasDef,
     208             :                                       AVCField *pasFields);
     209             : 
     210             : /*=====================================================================
     211             :  * Stuff related to reading the binary coverage files
     212             :  *====================================================================*/
     213             : 
     214             : /**********************************************************************
     215             :  *                          AVCBinReadOpen()
     216             :  *
     217             :  * Open a coverage file for reading, read the file header if applicable,
     218             :  * and initialize a temp. storage structure to be ready to read objects
     219             :  * from the file.
     220             :  *
     221             :  * pszPath is the coverage (or info directory) path, terminated by
     222             :  *         a '/' or a '\\'
     223             :  * pszName is the name of the file to open relative to this directory.
     224             :  *
     225             :  * Note: For most file types except tables, passing pszPath="" and
     226             :  * including the coverage path as part of pszName instead would work.
     227             :  *
     228             :  * Returns a valid AVCBinFile handle, or nullptr if the file could
     229             :  * not be opened.
     230             :  *
     231             :  * AVCBinClose() will eventually have to be called to release the
     232             :  * resources used by the AVCBinFile structure.
     233             :  **********************************************************************/
     234          26 : AVCBinFile *AVCBinReadOpen(const char *pszPath, const char *pszName,
     235             :                            AVCCoverType eCoverType, AVCFileType eFileType,
     236             :                            AVCDBCSInfo *psDBCSInfo)
     237             : {
     238             :     AVCBinFile *psFile;
     239             : 
     240             :     /*-----------------------------------------------------------------
     241             :      * The case of INFO tables is a bit more complicated...
     242             :      * pass the control to a separate function.
     243             :      *----------------------------------------------------------------*/
     244          26 :     if (eFileType == AVCFileTABLE)
     245             :     {
     246           7 :         if (eCoverType == AVCCoverPC || eCoverType == AVCCoverPC2)
     247           0 :             return _AVCBinReadOpenDBFTable(pszPath, pszName);
     248             :         else
     249           7 :             return _AVCBinReadOpenTable(pszPath, pszName, eCoverType,
     250           7 :                                         psDBCSInfo);
     251             :     }
     252             : 
     253             :     /*-----------------------------------------------------------------
     254             :      * PRJ files are text files... we won't use the AVCRawBin*()
     255             :      * functions for them...
     256             :      *----------------------------------------------------------------*/
     257          19 :     if (eFileType == AVCFilePRJ)
     258             :     {
     259           2 :         return _AVCBinReadOpenPrj(pszPath, pszName);
     260             :     }
     261             : 
     262             :     /*-----------------------------------------------------------------
     263             :      * All other file types share a very similar opening method.
     264             :      *----------------------------------------------------------------*/
     265          17 :     psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
     266             : 
     267          17 :     psFile->eFileType = eFileType;
     268          17 :     psFile->eCoverType = eCoverType;
     269             : 
     270          17 :     psFile->pszFilename =
     271          17 :         (char *)CPLMalloc(strlen(pszPath) + strlen(pszName) + 1);
     272          17 :     snprintf(psFile->pszFilename, strlen(pszPath) + strlen(pszName) + 1, "%s%s",
     273             :              pszPath, pszName);
     274             : 
     275          17 :     AVCAdjustCaseSensitiveFilename(psFile->pszFilename);
     276             : 
     277          17 :     psFile->psRawBinFile = AVCRawBinOpen(
     278          17 :         psFile->pszFilename, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo);
     279             : 
     280          17 :     if (psFile->psRawBinFile == nullptr)
     281             :     {
     282             :         /* Failed to open file... just return nullptr since an error message
     283             :          * has already been issued by AVCRawBinOpen()
     284             :          */
     285           0 :         CPLFree(psFile->pszFilename);
     286           0 :         CPLFree(psFile);
     287           0 :         return nullptr;
     288             :     }
     289             : 
     290             :     /*-----------------------------------------------------------------
     291             :      * Read the header, and set the precision field if applicable
     292             :      *----------------------------------------------------------------*/
     293          17 :     if (AVCBinReadRewind(psFile) != 0)
     294             :     {
     295           0 :         AVCRawBinClose(psFile->psRawBinFile);
     296           0 :         CPLFree(psFile->pszFilename);
     297           0 :         CPLFree(psFile);
     298           0 :         return nullptr;
     299             :     }
     300             : 
     301             :     /*-----------------------------------------------------------------
     302             :      * Allocate a temp. structure to use to read objects from the file
     303             :      * (Using Calloc() will automatically initialize the struct contents
     304             :      *  to nullptr... this is very important for ARCs and PALs)
     305             :      *----------------------------------------------------------------*/
     306          17 :     if (psFile->eFileType == AVCFileARC)
     307             :     {
     308           5 :         psFile->cur.psArc = (AVCArc *)CPLCalloc(1, sizeof(AVCArc));
     309             :     }
     310          12 :     else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL)
     311             :     {
     312           3 :         psFile->cur.psPal = (AVCPal *)CPLCalloc(1, sizeof(AVCPal));
     313             :     }
     314           9 :     else if (psFile->eFileType == AVCFileCNT)
     315             :     {
     316           1 :         psFile->cur.psCnt = (AVCCnt *)CPLCalloc(1, sizeof(AVCCnt));
     317             :     }
     318           8 :     else if (psFile->eFileType == AVCFileLAB)
     319             :     {
     320           5 :         psFile->cur.psLab = (AVCLab *)CPLCalloc(1, sizeof(AVCLab));
     321             :     }
     322           3 :     else if (psFile->eFileType == AVCFileTOL)
     323             :     {
     324           3 :         psFile->cur.psTol = (AVCTol *)CPLCalloc(1, sizeof(AVCTol));
     325             :     }
     326           0 :     else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6)
     327             :     {
     328           0 :         psFile->cur.psTxt = (AVCTxt *)CPLCalloc(1, sizeof(AVCTxt));
     329             :     }
     330           0 :     else if (psFile->eFileType == AVCFileRXP)
     331             :     {
     332           0 :         psFile->cur.psRxp = (AVCRxp *)CPLCalloc(1, sizeof(AVCRxp));
     333             :     }
     334             :     else
     335             :     {
     336           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     337             :                  "%s: Unsupported file type or corrupted file.",
     338             :                  psFile->pszFilename);
     339           0 :         AVCRawBinClose(psFile->psRawBinFile);
     340           0 :         CPLFree(psFile->pszFilename);
     341           0 :         CPLFree(psFile);
     342           0 :         psFile = nullptr;
     343             :     }
     344             : 
     345          17 :     return psFile;
     346             : }
     347             : 
     348             : /**********************************************************************
     349             :  *                          AVCBinReadClose()
     350             :  *
     351             :  * Close a coverage file, and release all memory (object strcut., buffers,
     352             :  * etc.) associated with this file.
     353             :  **********************************************************************/
     354          26 : void AVCBinReadClose(AVCBinFile *psFile)
     355             : {
     356          26 :     AVCRawBinClose(psFile->psRawBinFile);
     357          26 :     psFile->psRawBinFile = nullptr;
     358             : 
     359          26 :     CPLFree(psFile->pszFilename);
     360          26 :     psFile->pszFilename = nullptr;
     361             : 
     362          26 :     if (psFile->hDBFFile)
     363           0 :         DBFClose(psFile->hDBFFile);
     364             : 
     365          26 :     if (psFile->psIndexFile != nullptr)
     366           1 :         AVCRawBinClose(psFile->psIndexFile);
     367             : 
     368          26 :     if (psFile->eFileType == AVCFileARC)
     369             :     {
     370           5 :         if (psFile->cur.psArc)
     371           5 :             CPLFree(psFile->cur.psArc->pasVertices);
     372           5 :         CPLFree(psFile->cur.psArc);
     373             :     }
     374          21 :     else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL)
     375             :     {
     376           3 :         if (psFile->cur.psPal)
     377           3 :             CPLFree(psFile->cur.psPal->pasArcs);
     378           3 :         CPLFree(psFile->cur.psPal);
     379             :     }
     380          18 :     else if (psFile->eFileType == AVCFileCNT)
     381             :     {
     382           1 :         if (psFile->cur.psCnt)
     383           1 :             CPLFree(psFile->cur.psCnt->panLabelIds);
     384           1 :         CPLFree(psFile->cur.psCnt);
     385             :     }
     386          17 :     else if (psFile->eFileType == AVCFileLAB)
     387             :     {
     388           5 :         CPLFree(psFile->cur.psLab);
     389             :     }
     390          12 :     else if (psFile->eFileType == AVCFileTOL)
     391             :     {
     392           3 :         CPLFree(psFile->cur.psTol);
     393             :     }
     394           9 :     else if (psFile->eFileType == AVCFilePRJ)
     395             :     {
     396           2 :         CSLDestroy(psFile->cur.papszPrj);
     397             :     }
     398           7 :     else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6)
     399             :     {
     400           0 :         if (psFile->cur.psTxt)
     401             :         {
     402           0 :             CPLFree(psFile->cur.psTxt->pasVertices);
     403           0 :             CPLFree(psFile->cur.psTxt->pszText);
     404             :         }
     405           0 :         CPLFree(psFile->cur.psTxt);
     406             :     }
     407           7 :     else if (psFile->eFileType == AVCFileRXP)
     408             :     {
     409           0 :         CPLFree(psFile->cur.psRxp);
     410             :     }
     411           7 :     else if (psFile->eFileType == AVCFileTABLE)
     412             :     {
     413           7 :         _AVCDestroyTableFields(psFile->hdr.psTableDef, psFile->cur.pasFields);
     414           7 :         _AVCDestroyTableDef(psFile->hdr.psTableDef);
     415             :     }
     416             :     else
     417             :     {
     418           0 :         CPLError(CE_Failure, CPLE_IllegalArg,
     419             :                  "Unsupported file type or invalid file handle!");
     420             :     }
     421             : 
     422          26 :     CPLFree(psFile);
     423          26 : }
     424             : 
     425             : /**********************************************************************
     426             :  *                          _AVCBinReadHeader()
     427             :  *
     428             :  * (This function is for internal library use... external calls should
     429             :  * go to AVCBinReadRewind() instead)
     430             :  *
     431             :  * Read the first 100 bytes header of the file and fill the AVCHeader
     432             :  * structure.
     433             :  *
     434             :  * Returns 0 on success or -1 on error.
     435             :  **********************************************************************/
     436          14 : static int _AVCBinReadHeader(AVCRawBinFile *psFile, AVCBinHeader *psHeader,
     437             :                              AVCCoverType eCoverType)
     438             : {
     439          14 :     int nStatus = 0;
     440             : 
     441             :     /*-----------------------------------------------------------------
     442             :      * For AVCCoverPC coverages (files without the .adf extension),
     443             :      * there is a first 256 bytes header that we just skip and that
     444             :      * precedes the 100 bytes header block.
     445             :      *
     446             :      * In AVCCoverV7, we only have the 100 bytes header.
     447             :      *----------------------------------------------------------------*/
     448          14 :     if (eCoverType == AVCCoverPC)
     449           0 :         AVCRawBinFSeek(psFile, 256, SEEK_SET);
     450             :     else
     451          14 :         AVCRawBinFSeek(psFile, 0, SEEK_SET);
     452             : 
     453          14 :     psHeader->nSignature = AVCRawBinReadInt32(psFile);
     454             : 
     455          14 :     if (AVCRawBinEOF(psFile))
     456           0 :         nStatus = -1;
     457             : 
     458          14 :     psHeader->nPrecision = AVCRawBinReadInt32(psFile);
     459          14 :     psHeader->nRecordSize = AVCRawBinReadInt32(psFile);
     460             : 
     461             :     /* Jump to 24th byte in header */
     462          14 :     AVCRawBinFSeek(psFile, 12, SEEK_CUR);
     463          14 :     psHeader->nLength = AVCRawBinReadInt32(psFile);
     464          14 :     if (psHeader->nLength < 0 || psHeader->nLength > (INT_MAX - 256) / 2)
     465             :     {
     466           0 :         return -1;
     467             :     }
     468             : 
     469             :     /*-----------------------------------------------------------------
     470             :      * File length, in words (16 bits)... pass the info to the RawBinFile
     471             :      * to prevent it from trying to read junk bytes at the end of files...
     472             :      * this problem happens specially with PC Arc/Info files.
     473             :      *----------------------------------------------------------------*/
     474          14 :     if (eCoverType == AVCCoverPC)
     475           0 :         AVCRawBinSetFileDataSize(psFile, psHeader->nLength * 2 + 256);
     476             :     else
     477          14 :         AVCRawBinSetFileDataSize(psFile, psHeader->nLength * 2);
     478             : 
     479             :     /* Move the pointer at the end of the 100 bytes header
     480             :      */
     481          14 :     AVCRawBinFSeek(psFile, 72, SEEK_CUR);
     482             : 
     483          14 :     return nStatus;
     484             : }
     485             : 
     486             : /**********************************************************************
     487             :  *                          AVCBinReadRewind()
     488             :  *
     489             :  * Rewind the read pointer, and read/skip the header if necessary so
     490             :  * that we are ready to read the data objects from the file after
     491             :  * this call.
     492             :  *
     493             :  * Returns 0 on success, -1 on error, and -2 if file has an invalid
     494             :  * signature and is possibly corrupted.
     495             :  **********************************************************************/
     496          17 : int AVCBinReadRewind(AVCBinFile *psFile)
     497             : {
     498             :     AVCBinHeader sHeader;
     499          17 :     int nStatus = 0;
     500             : 
     501             :     /*-----------------------------------------------------------------
     502             :      * For AVCCoverPC coverages, there is a first 256 bytes header
     503             :      * that we just skip and that precedes the 100 bytes header block.
     504             :      *
     505             :      * In AVCCoverV7, AVCCoverPC2 and AVCCoverWeird, we only find the
     506             :      * 100 bytes header.
     507             :      *
     508             :      * Note: it is the call to _AVCBinReadHeader() that takes care
     509             :      * of skipping the first 256 bytes header if necessary.
     510             :      *----------------------------------------------------------------*/
     511             : 
     512          17 :     AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET);
     513             : 
     514          17 :     if (psFile->eFileType == AVCFileARC || psFile->eFileType == AVCFilePAL ||
     515           9 :         psFile->eFileType == AVCFileRPL || psFile->eFileType == AVCFileCNT ||
     516           8 :         psFile->eFileType == AVCFileLAB || psFile->eFileType == AVCFileTXT ||
     517           3 :         psFile->eFileType == AVCFileTX6)
     518             :     {
     519          14 :         nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader,
     520             :                                     psFile->eCoverType);
     521             : 
     522             :         /* Store the precision information inside the file handle.
     523             :          *
     524             :          * Of course, there had to be an exception...
     525             :          * At least PAL and TXT files in PC Arc/Info coverages sometimes
     526             :          * have a negative precision flag even if they contain single
     527             :          * precision data... why is that????  A PC Arc bug?
     528             :          *
     529             :          * 2000-06-05: Found a double-precision PAL file with a signature
     530             :          *             of 1011 (should have been -11).  So we'll assume
     531             :          *             that signature > 1000 also means double precision.
     532             :          */
     533          14 :         if ((sHeader.nPrecision < 0 || sHeader.nPrecision > 1000) &&
     534           0 :             psFile->eCoverType != AVCCoverPC)
     535           0 :             psFile->nPrecision = AVC_DOUBLE_PREC;
     536             :         else
     537          14 :             psFile->nPrecision = AVC_SINGLE_PREC;
     538             : 
     539             :         /* Validate the signature value... this will allow us to detect
     540             :          * corrupted files or files that do not belong in the coverage.
     541             :          */
     542          14 :         if (sHeader.nSignature != 9993 && sHeader.nSignature != 9994)
     543             :         {
     544           0 :             CPLError(CE_Warning, CPLE_AssertionFailed,
     545             :                      "%s appears to have an invalid file header.",
     546             :                      psFile->pszFilename);
     547           0 :             return -2;
     548             :         }
     549             : 
     550             :         /* In Weird coverages, TXT files can be stored in the PC or the V7
     551             :          * format.  Look at the 'precision' field in the header to tell which
     552             :          * type we have.
     553             :          *   Weird TXT in PC format: nPrecision = 16
     554             :          *   Weird TXT in V7 format: nPrecision = +/-67
     555             :          * Use AVCFileTXT for PC type, and AVCFileTX6 for V7 type.
     556             :          */
     557          14 :         if (psFile->eCoverType == AVCCoverWeird &&
     558           0 :             psFile->eFileType == AVCFileTXT &&
     559           0 :             (sHeader.nPrecision == 67 || sHeader.nPrecision == -67))
     560             :         {
     561             :             /* TXT file will be processed as V7 TXT/TX6/TX7 */
     562           0 :             psFile->eFileType = AVCFileTX6;
     563             :         }
     564             :     }
     565           3 :     else if (psFile->eFileType == AVCFileTOL)
     566             :     {
     567             :         /*-------------------------------------------------------------
     568             :          * For some reason, the tolerance files do not follow the
     569             :          * general rules!
     570             :          * Single precision "tol.adf" have no header
     571             :          * Double precision "par.adf" have the usual 100 bytes header,
     572             :          *  but the 3rd field, which usually defines the precision has
     573             :          *  a positive value, even if the file is double precision!
     574             :          *
     575             :          * Also, we have a problem with PC Arc/Info TOL files since they
     576             :          * do not contain the first 256 bytes header either... so we will
     577             :          * just assume that double precision TOL files cannot exist in
     578             :          * PC Arc/Info coverages... this should be OK.
     579             :          *------------------------------------------------------------*/
     580           3 :         int nSignature = 0;
     581           3 :         nSignature = AVCRawBinReadInt32(psFile->psRawBinFile);
     582             : 
     583           3 :         if (nSignature == 9993)
     584             :         {
     585             :             /* We have a double precision par.adf... read the 100 bytes
     586             :              * header and set the precision information inside the file
     587             :              * handle.
     588             :              */
     589           0 :             nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader,
     590             :                                         psFile->eCoverType);
     591             : 
     592           0 :             psFile->nPrecision = AVC_DOUBLE_PREC;
     593             :         }
     594             :         else
     595             :         {
     596             :             /* It's a single precision tol.adf ... just set the
     597             :              * precision field.
     598             :              */
     599           3 :             AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET);
     600           3 :             psFile->nPrecision = AVC_SINGLE_PREC;
     601             :         }
     602             :     }
     603             : 
     604          17 :     return nStatus;
     605             : }
     606             : 
     607             : /**********************************************************************
     608             :  *                          AVCBinReadObject()
     609             :  *
     610             :  * Read the object with a particular index.  For fixed length record
     611             :  * files we seek directly to the object.  For variable files we try to
     612             :  * get the offset from the corresponding index file.
     613             :  *
     614             :  * NOTE: Currently only implemented for ARC, PAL and TABLE files.
     615             :  *
     616             :  * Returns the read object on success or nullptr on error.
     617             :  **********************************************************************/
     618         196 : void *AVCBinReadObject(AVCBinFile *psFile, int iObjIndex)
     619             : {
     620         196 :     int bIndexed = FALSE;
     621         196 :     int nObjectOffset, nRecordSize = 0, nRecordStart = 0, nLen;
     622             :     /* cppcheck-suppress unreadVariable */
     623         196 :     char szExt[4] = {0, 0, 0, 0};
     624         196 :     char *pszExt = szExt;
     625             : 
     626         196 :     if (iObjIndex < 0)
     627           0 :         return nullptr;
     628             : 
     629             :     /*-----------------------------------------------------------------
     630             :      * Determine some information from based on the coverage type.
     631             :      *----------------------------------------------------------------*/
     632         196 :     nLen = (int)strlen(psFile->pszFilename);
     633         224 :     if (psFile->eFileType == AVCFileARC &&
     634          28 :         ((nLen >= 3 &&
     635          28 :           STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 3), "arc")) ||
     636          28 :          (nLen >= 7 && STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 7),
     637             :                                       "arc.adf"))))
     638             :     {
     639          28 :         bIndexed = TRUE;
     640             :     }
     641         168 :     else if (psFile->eFileType == AVCFilePAL &&
     642           0 :              ((nLen >= 3 &&
     643           0 :                STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 3),
     644           0 :                               "pal")) ||
     645           0 :               (nLen >= 7 &&
     646           0 :                STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 7),
     647             :                               "pal.adf"))))
     648             :     {
     649           0 :         bIndexed = TRUE;
     650             :     }
     651         168 :     else if (psFile->eFileType == AVCFileTABLE)
     652             :     {
     653         168 :         bIndexed = FALSE;
     654         168 :         nRecordSize = psFile->hdr.psTableDef->nRecSize;
     655         168 :         nRecordStart = 0;
     656             :     }
     657             :     else
     658           0 :         return nullptr;
     659             : 
     660             :     /*-----------------------------------------------------------------
     661             :      * Ensure the index file is opened if an index file is required.
     662             :      *----------------------------------------------------------------*/
     663             : 
     664         196 :     if (bIndexed && psFile->psIndexFile == nullptr)
     665             :     {
     666             :         char chOrig;
     667             : 
     668           1 :         chOrig = pszExt[2];
     669           1 :         if (chOrig > 'A' && chOrig < 'Z')
     670           0 :             pszExt[2] = 'X';
     671             :         else
     672           1 :             pszExt[2] = 'x';
     673             : 
     674           2 :         psFile->psIndexFile = AVCRawBinOpen(psFile->pszFilename, "rb",
     675           1 :                                             psFile->psRawBinFile->eByteOrder,
     676           1 :                                             psFile->psRawBinFile->psDBCSInfo);
     677           1 :         pszExt[2] = chOrig;
     678             : 
     679           1 :         if (psFile->psIndexFile == nullptr)
     680           0 :             return nullptr;
     681             :     }
     682             : 
     683             :     /*-----------------------------------------------------------------
     684             :      * Establish the offset to read the object from.
     685             :      *----------------------------------------------------------------*/
     686         196 :     if (bIndexed)
     687             :     {
     688             :         GIntBig nIndexOffsetBig;
     689             : 
     690          28 :         if (psFile->eCoverType == AVCCoverPC)
     691           0 :             nIndexOffsetBig = 356 + static_cast<GIntBig>(iObjIndex - 1) * 8;
     692             :         else
     693          28 :             nIndexOffsetBig = 100 + static_cast<GIntBig>(iObjIndex - 1) * 8;
     694          28 :         if (nIndexOffsetBig < INT_MIN || nIndexOffsetBig > INT_MAX)
     695           0 :             return nullptr;
     696             : 
     697          28 :         const int nIndexOffset = static_cast<int>(nIndexOffsetBig);
     698          28 :         AVCRawBinFSeek(psFile->psIndexFile, nIndexOffset, SEEK_SET);
     699          28 :         if (AVCRawBinEOF(psFile->psIndexFile))
     700           0 :             return nullptr;
     701             : 
     702          28 :         nObjectOffset = AVCRawBinReadInt32(psFile->psIndexFile);
     703          28 :         if (nObjectOffset < INT_MIN / 2 || nObjectOffset > (INT_MAX - 256) / 2)
     704           0 :             return nullptr;
     705          28 :         nObjectOffset *= 2;
     706             : 
     707          28 :         if (psFile->eCoverType == AVCCoverPC)
     708           0 :             nObjectOffset += 256;
     709             :     }
     710             :     else
     711             :     {
     712         168 :         GIntBig nObjectOffsetBig =
     713         168 :             nRecordStart + nRecordSize * static_cast<GIntBig>(iObjIndex - 1);
     714         168 :         if (nObjectOffsetBig < INT_MIN || nObjectOffsetBig > INT_MAX)
     715           0 :             return nullptr;
     716         168 :         nObjectOffset = static_cast<int>(nObjectOffsetBig);
     717             :     }
     718             : 
     719             :     /*-----------------------------------------------------------------
     720             :      * Seek to the start of the object in the data file.
     721             :      *----------------------------------------------------------------*/
     722         196 :     AVCRawBinFSeek(psFile->psRawBinFile, nObjectOffset, SEEK_SET);
     723         196 :     if (AVCRawBinEOF(psFile->psRawBinFile))
     724           0 :         return nullptr;
     725             : 
     726             :     /*-----------------------------------------------------------------
     727             :      * Read and return the object.
     728             :      *----------------------------------------------------------------*/
     729         196 :     return AVCBinReadNextObject(psFile);
     730             : }
     731             : 
     732             : /**********************************************************************
     733             :  *                          AVCBinReadNextObject()
     734             :  *
     735             :  * Read the next structure from the file.  This function is just a generic
     736             :  * cover on top of the AVCBinReadNextArc/Lab/Pal/Cnt() functions.
     737             :  *
     738             :  * Returns a (void*) to a static structure with the contents of the object
     739             :  * that was read.  The contents of the structure will be valid only until
     740             :  * the next call.
     741             :  * If you use the returned value, then make sure that you cast it to
     742             :  * the right type for the current file! (AVCArc, AVCPal, AVCCnt, ...)
     743             :  *
     744             :  * Returns nullptr if an error happened or if EOF was reached.
     745             :  **********************************************************************/
     746         377 : void *AVCBinReadNextObject(AVCBinFile *psFile)
     747             : {
     748         377 :     void *psObj = nullptr;
     749             : 
     750         377 :     switch (psFile->eFileType)
     751             :     {
     752          37 :         case AVCFileARC:
     753          37 :             psObj = (void *)AVCBinReadNextArc(psFile);
     754          37 :             break;
     755          10 :         case AVCFilePAL:
     756             :         case AVCFileRPL:
     757          10 :             psObj = (void *)AVCBinReadNextPal(psFile);
     758          10 :             break;
     759           0 :         case AVCFileCNT:
     760           0 :             psObj = (void *)AVCBinReadNextCnt(psFile);
     761           0 :             break;
     762         162 :         case AVCFileLAB:
     763         162 :             psObj = (void *)AVCBinReadNextLab(psFile);
     764         162 :             break;
     765           0 :         case AVCFileTOL:
     766           0 :             psObj = (void *)AVCBinReadNextTol(psFile);
     767           0 :             break;
     768           0 :         case AVCFileTXT:
     769             :         case AVCFileTX6:
     770           0 :             psObj = (void *)AVCBinReadNextTxt(psFile);
     771           0 :             break;
     772           0 :         case AVCFileRXP:
     773           0 :             psObj = (void *)AVCBinReadNextRxp(psFile);
     774           0 :             break;
     775         168 :         case AVCFileTABLE:
     776         168 :             psObj = (void *)AVCBinReadNextTableRec(psFile);
     777         168 :             break;
     778           0 :         default:
     779           0 :             CPLError(CE_Failure, CPLE_IllegalArg,
     780             :                      "AVCBinReadNextObject(): Unsupported file type!");
     781             :     }
     782             : 
     783         377 :     return psObj;
     784             : }
     785             : 
     786             : /**********************************************************************
     787             :  *                          AVCBinReadNextTableRec()
     788             :  *
     789             :  * Reads the next record from an attribute table.
     790             :  *
     791             :  * Returns a pointer to an array of static AVCField structure whose
     792             :  * contents will be valid only until the next call,
     793             :  * or nullptr if an error happened or if EOF was reached.
     794             :  **********************************************************************/
     795         168 : AVCField *AVCBinReadNextTableRec(AVCBinFile *psFile)
     796             : {
     797         168 :     if (psFile->eCoverType != AVCCoverPC && psFile->eCoverType != AVCCoverPC2 &&
     798         168 :         psFile->eFileType == AVCFileTABLE &&
     799         168 :         psFile->hdr.psTableDef->numRecords > 0 &&
     800         504 :         !AVCRawBinEOF(psFile->psRawBinFile) &&
     801         168 :         _AVCBinReadNextTableRec(
     802         168 :             psFile->psRawBinFile, psFile->hdr.psTableDef->numFields,
     803         168 :             psFile->hdr.psTableDef->pasFieldDef, psFile->cur.pasFields,
     804         168 :             psFile->hdr.psTableDef->nRecSize) == 0)
     805             :     {
     806         168 :         return psFile->cur.pasFields;
     807             :     }
     808           0 :     else if ((psFile->eCoverType == AVCCoverPC ||
     809           0 :               psFile->eCoverType == AVCCoverPC2) &&
     810           0 :              psFile->eFileType == AVCFileTABLE &&
     811           0 :              psFile->hdr.psTableDef->numRecords > 0 &&
     812           0 :              _AVCBinReadNextDBFTableRec(psFile->hDBFFile,
     813             :                                         &(psFile->nCurDBFRecord),
     814           0 :                                         psFile->hdr.psTableDef->numFields,
     815           0 :                                         psFile->hdr.psTableDef->pasFieldDef,
     816             :                                         psFile->cur.pasFields) == 0)
     817             :     {
     818           0 :         return psFile->cur.pasFields;
     819             :     }
     820             : 
     821           0 :     return nullptr;
     822             : }
     823             : 
     824             : /*=====================================================================
     825             :  *                              ARC
     826             :  *====================================================================*/
     827             : 
     828             : /**********************************************************************
     829             :  *                          _AVCBinReadNextArc()
     830             :  *
     831             :  * (This function is for internal library use... external calls should
     832             :  * go to AVCBinReadNextArc() instead)
     833             :  *
     834             :  * Read the next Arc structure from the file.
     835             :  *
     836             :  * The contents of the psArc structure is assumed to be valid, and the
     837             :  * psArc->pasVertices buffer may be reallocated or free()'d if it is not
     838             :  * nullptr.
     839             :  *
     840             :  * Returns 0 on success or -1 on error.
     841             :  **********************************************************************/
     842          36 : static int _AVCBinReadNextArc(AVCRawBinFile *psFile, AVCArc *psArc,
     843             :                               int nPrecision)
     844             : {
     845             :     int i, numVertices;
     846             :     int nRecordSize, nStartPos, nBytesRead;
     847             : 
     848          36 :     psArc->nArcId = AVCRawBinReadInt32(psFile);
     849          36 :     if (AVCRawBinEOF(psFile))
     850           0 :         return -1;
     851             : 
     852          36 :     nRecordSize = AVCRawBinReadInt32(psFile);
     853          36 :     if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
     854           0 :         return -1;
     855          36 :     nRecordSize *= 2;
     856          36 :     nStartPos = psFile->nCurPos + psFile->nOffset;
     857          36 :     psArc->nUserId = AVCRawBinReadInt32(psFile);
     858          36 :     psArc->nFNode = AVCRawBinReadInt32(psFile);
     859          36 :     psArc->nTNode = AVCRawBinReadInt32(psFile);
     860          36 :     psArc->nLPoly = AVCRawBinReadInt32(psFile);
     861          36 :     psArc->nRPoly = AVCRawBinReadInt32(psFile);
     862          36 :     numVertices = AVCRawBinReadInt32(psFile);
     863          36 :     if (numVertices < 0 || numVertices > 100 * 1024 * 1024)
     864           0 :         return -1;
     865          36 :     if (numVertices > 10 * 1024 * 1024 &&
     866           0 :         !AVCRawBinIsFileGreaterThan(
     867             :             psFile,
     868           0 :             cpl::fits_on<int>(numVertices *
     869           0 :                               ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
     870             :     {
     871           0 :         return -1;
     872             :     }
     873             : 
     874             :     /* Realloc the vertices array only if it needs to grow...
     875             :      * do not realloc to a smaller size.
     876             :      * Note that for simplicity reasons, we always store the vertices as
     877             :      * double values in memory, even for single precision coverages.
     878             :      */
     879          36 :     if (psArc->pasVertices == nullptr || numVertices > psArc->numVertices)
     880             :     {
     881          28 :         AVCVertex *pasNewVertices = (AVCVertex *)VSIRealloc(
     882          14 :             psArc->pasVertices, numVertices * sizeof(AVCVertex));
     883          14 :         if (pasNewVertices == nullptr)
     884           0 :             return -1;
     885          14 :         psArc->pasVertices = pasNewVertices;
     886             :     }
     887             : 
     888          36 :     psArc->numVertices = numVertices;
     889             : 
     890          36 :     if (nPrecision == AVC_SINGLE_PREC)
     891             :     {
     892         130 :         for (i = 0; i < numVertices; i++)
     893             :         {
     894          94 :             psArc->pasVertices[i].x = AVCRawBinReadFloat(psFile);
     895          94 :             psArc->pasVertices[i].y = AVCRawBinReadFloat(psFile);
     896          94 :             if (psFile->nCurSize == 0)
     897           0 :                 return -1;
     898             :         }
     899             :     }
     900             :     else
     901             :     {
     902           0 :         for (i = 0; i < numVertices; i++)
     903             :         {
     904           0 :             psArc->pasVertices[i].x = AVCRawBinReadDouble(psFile);
     905           0 :             psArc->pasVertices[i].y = AVCRawBinReadDouble(psFile);
     906           0 :             if (psFile->nCurSize == 0)
     907           0 :                 return -1;
     908             :         }
     909             :     }
     910             : 
     911             :     /*-----------------------------------------------------------------
     912             :      * Record size may be larger than number of vertices.  Skip up to
     913             :      * start of next object.
     914             :      *----------------------------------------------------------------*/
     915          36 :     nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
     916          36 :     if (nBytesRead < nRecordSize)
     917           0 :         AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
     918             : 
     919          36 :     return 0;
     920             : }
     921             : 
     922             : /**********************************************************************
     923             :  *                          AVCBinReadNextArc()
     924             :  *
     925             :  * Read the next Arc structure from the file.
     926             :  *
     927             :  * Returns a pointer to a static AVCArc structure whose contents will be
     928             :  * valid only until the next call or nullptr if an error happened or if EOF
     929             :  * was reached.
     930             :  **********************************************************************/
     931          37 : AVCArc *AVCBinReadNextArc(AVCBinFile *psFile)
     932             : {
     933          73 :     if (psFile->eFileType != AVCFileARC || AVCRawBinEOF(psFile->psRawBinFile) ||
     934          36 :         _AVCBinReadNextArc(psFile->psRawBinFile, psFile->cur.psArc,
     935             :                            psFile->nPrecision) != 0)
     936             :     {
     937           1 :         return nullptr;
     938             :     }
     939             : 
     940          36 :     return psFile->cur.psArc;
     941             : }
     942             : 
     943             : /*=====================================================================
     944             :  *                              PAL
     945             :  *====================================================================*/
     946             : 
     947             : /**********************************************************************
     948             :  *                          _AVCBinReadNextPal()
     949             :  *
     950             :  * (This function is for internal library use... external calls should
     951             :  * go to AVCBinReadNextPal() instead)
     952             :  *
     953             :  * Read the next PAL (Polygon Arc List) structure from the file.
     954             :  *
     955             :  * The contents of the psPal structure is assumed to be valid, and the
     956             :  * psPal->paVertices buffer may be reallocated or free()'d if it is not
     957             :  * nullptr.
     958             :  *
     959             :  * Returns 0 on success or -1 on error.
     960             :  **********************************************************************/
     961           8 : static int _AVCBinReadNextPal(AVCRawBinFile *psFile, AVCPal *psPal,
     962             :                               int nPrecision)
     963             : {
     964             :     int i, numArcs;
     965             :     int nRecordSize, nStartPos, nBytesRead;
     966             : 
     967           8 :     psPal->nPolyId = AVCRawBinReadInt32(psFile);
     968           8 :     nRecordSize = AVCRawBinReadInt32(psFile);
     969           8 :     if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
     970           0 :         return -1;
     971           8 :     nRecordSize *= 2;
     972           8 :     nStartPos = psFile->nCurPos + psFile->nOffset;
     973             : 
     974           8 :     if (AVCRawBinEOF(psFile))
     975           0 :         return -1;
     976             : 
     977           8 :     if (nPrecision == AVC_SINGLE_PREC)
     978             :     {
     979           8 :         psPal->sMin.x = AVCRawBinReadFloat(psFile);
     980           8 :         psPal->sMin.y = AVCRawBinReadFloat(psFile);
     981           8 :         psPal->sMax.x = AVCRawBinReadFloat(psFile);
     982           8 :         psPal->sMax.y = AVCRawBinReadFloat(psFile);
     983             :     }
     984             :     else
     985             :     {
     986           0 :         psPal->sMin.x = AVCRawBinReadDouble(psFile);
     987           0 :         psPal->sMin.y = AVCRawBinReadDouble(psFile);
     988           0 :         psPal->sMax.x = AVCRawBinReadDouble(psFile);
     989           0 :         psPal->sMax.y = AVCRawBinReadDouble(psFile);
     990             :     }
     991             : 
     992           8 :     numArcs = AVCRawBinReadInt32(psFile);
     993           8 :     if (numArcs < 0 || numArcs > 100 * 1024 * 1024)
     994           0 :         return -1;
     995           8 :     if (numArcs > 10 * 1024 * 1024 &&
     996           0 :         !AVCRawBinIsFileGreaterThan(psFile, numArcs * sizeof(int) * 3))
     997             :     {
     998           0 :         return -1;
     999             :     }
    1000             : 
    1001             :     /* Realloc the arc list array only if it needs to grow...
    1002             :      * do not realloc to a smaller size.
    1003             :      */
    1004           8 :     if (psPal->pasArcs == nullptr || numArcs > psPal->numArcs)
    1005             :     {
    1006           4 :         AVCPalArc *pasNewArcs = (AVCPalArc *)VSIRealloc(
    1007           2 :             psPal->pasArcs, numArcs * sizeof(AVCPalArc));
    1008           2 :         if (pasNewArcs == nullptr)
    1009           0 :             return -1;
    1010           2 :         psPal->pasArcs = pasNewArcs;
    1011             :     }
    1012             : 
    1013           8 :     psPal->numArcs = numArcs;
    1014             : 
    1015          38 :     for (i = 0; i < numArcs; i++)
    1016             :     {
    1017          30 :         psPal->pasArcs[i].nArcId = AVCRawBinReadInt32(psFile);
    1018          30 :         psPal->pasArcs[i].nFNode = AVCRawBinReadInt32(psFile);
    1019          30 :         psPal->pasArcs[i].nAdjPoly = AVCRawBinReadInt32(psFile);
    1020          30 :         if (psFile->nCurSize == 0)
    1021           0 :             return -1;
    1022             :     }
    1023             : 
    1024             :     /*-----------------------------------------------------------------
    1025             :      * Record size may be larger than number of vertices.  Skip up to
    1026             :      * start of next object.
    1027             :      *----------------------------------------------------------------*/
    1028           8 :     nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
    1029           8 :     if (nBytesRead < nRecordSize)
    1030           0 :         AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
    1031             : 
    1032           8 :     return 0;
    1033             : }
    1034             : 
    1035             : /**********************************************************************
    1036             :  *                          AVCBinReadNextPal()
    1037             :  *
    1038             :  * Read the next PAL structure from the file.
    1039             :  *
    1040             :  * Returns a pointer to a static AVCPal structure whose contents will be
    1041             :  * valid only until the next call or nullptr if an error happened or if EOF
    1042             :  * was reached.
    1043             :  **********************************************************************/
    1044          10 : AVCPal *AVCBinReadNextPal(AVCBinFile *psFile)
    1045             : {
    1046           0 :     if ((psFile->eFileType != AVCFilePAL && psFile->eFileType != AVCFileRPL) ||
    1047          18 :         AVCRawBinEOF(psFile->psRawBinFile) ||
    1048           8 :         _AVCBinReadNextPal(psFile->psRawBinFile, psFile->cur.psPal,
    1049             :                            psFile->nPrecision) != 0)
    1050             :     {
    1051           2 :         return nullptr;
    1052             :     }
    1053             : 
    1054           8 :     return psFile->cur.psPal;
    1055             : }
    1056             : 
    1057             : /*=====================================================================
    1058             :  *                              CNT
    1059             :  *====================================================================*/
    1060             : 
    1061             : /**********************************************************************
    1062             :  *                          _AVCBinReadNextCnt()
    1063             :  *
    1064             :  * (This function is for internal library use... external calls should
    1065             :  * go to AVCBinReadNextCnt() instead)
    1066             :  *
    1067             :  * Read the next CNT (Polygon Centroid) structure from the file.
    1068             :  *
    1069             :  * Returns 0 on success or -1 on error.
    1070             :  **********************************************************************/
    1071           0 : static int _AVCBinReadNextCnt(AVCRawBinFile *psFile, AVCCnt *psCnt,
    1072             :                               int nPrecision)
    1073             : {
    1074             :     int i, numLabels;
    1075             :     int nRecordSize, nStartPos, nBytesRead;
    1076             : 
    1077           0 :     psCnt->nPolyId = AVCRawBinReadInt32(psFile);
    1078           0 :     nRecordSize = AVCRawBinReadInt32(psFile);
    1079           0 :     if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
    1080           0 :         return -1;
    1081           0 :     nRecordSize *= 2;
    1082           0 :     nStartPos = psFile->nCurPos + psFile->nOffset;
    1083             : 
    1084           0 :     if (AVCRawBinEOF(psFile))
    1085           0 :         return -1;
    1086             : 
    1087           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1088             :     {
    1089           0 :         psCnt->sCoord.x = AVCRawBinReadFloat(psFile);
    1090           0 :         psCnt->sCoord.y = AVCRawBinReadFloat(psFile);
    1091             :     }
    1092             :     else
    1093             :     {
    1094           0 :         psCnt->sCoord.x = AVCRawBinReadDouble(psFile);
    1095           0 :         psCnt->sCoord.y = AVCRawBinReadDouble(psFile);
    1096             :     }
    1097             : 
    1098           0 :     numLabels = AVCRawBinReadInt32(psFile);
    1099           0 :     if (numLabels < 0 || numLabels > 100 * 1024 * 1024)
    1100           0 :         return -1;
    1101           0 :     if (numLabels > 10 * 1024 * 1024 &&
    1102           0 :         !AVCRawBinIsFileGreaterThan(psFile, numLabels * sizeof(int)))
    1103             :     {
    1104           0 :         return -1;
    1105             :     }
    1106             : 
    1107             :     /* Realloc the LabelIds array only if it needs to grow...
    1108             :      * do not realloc to a smaller size.
    1109             :      */
    1110           0 :     if (psCnt->panLabelIds == nullptr || numLabels > psCnt->numLabels)
    1111             :     {
    1112           0 :         GInt32 *panIds = (GInt32 *)VSIRealloc(psCnt->panLabelIds,
    1113           0 :                                               numLabels * sizeof(GInt32));
    1114           0 :         if (panIds == nullptr)
    1115           0 :             return -1;
    1116           0 :         psCnt->panLabelIds = panIds;
    1117             :     }
    1118             : 
    1119           0 :     psCnt->numLabels = numLabels;
    1120             : 
    1121           0 :     for (i = 0; i < numLabels; i++)
    1122             :     {
    1123           0 :         psCnt->panLabelIds[i] = AVCRawBinReadInt32(psFile);
    1124           0 :         if (psFile->nCurSize == 0)
    1125           0 :             return -1;
    1126             :     }
    1127             : 
    1128             :     /*-----------------------------------------------------------------
    1129             :      * Record size may be larger than number of vertices.  Skip up to
    1130             :      * start of next object.
    1131             :      *----------------------------------------------------------------*/
    1132           0 :     nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
    1133           0 :     if (nBytesRead < nRecordSize)
    1134           0 :         AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
    1135             : 
    1136           0 :     return 0;
    1137             : }
    1138             : 
    1139             : /**********************************************************************
    1140             :  *                          AVCBinReadNextCnt()
    1141             :  *
    1142             :  * Read the next CNT structure from the file.
    1143             :  *
    1144             :  * Returns a pointer to a static AVCCnt structure whose contents will be
    1145             :  * valid only until the next call or nullptr if an error happened or if EOF
    1146             :  * was reached.
    1147             :  **********************************************************************/
    1148           0 : AVCCnt *AVCBinReadNextCnt(AVCBinFile *psFile)
    1149             : {
    1150           0 :     if (psFile->eFileType != AVCFileCNT || AVCRawBinEOF(psFile->psRawBinFile) ||
    1151           0 :         _AVCBinReadNextCnt(psFile->psRawBinFile, psFile->cur.psCnt,
    1152             :                            psFile->nPrecision) != 0)
    1153             :     {
    1154           0 :         return nullptr;
    1155             :     }
    1156             : 
    1157           0 :     return psFile->cur.psCnt;
    1158             : }
    1159             : 
    1160             : /*=====================================================================
    1161             :  *                              LAB
    1162             :  *====================================================================*/
    1163             : 
    1164             : /**********************************************************************
    1165             :  *                          _AVCBinReadNextLab()
    1166             :  *
    1167             :  * (This function is for internal library use... external calls should
    1168             :  * go to AVCBinReadNextLab() instead)
    1169             :  *
    1170             :  * Read the next LAB (Centroid Label) structure from the file.
    1171             :  *
    1172             :  * Returns 0 on success or -1 on error.
    1173             :  **********************************************************************/
    1174         160 : static int _AVCBinReadNextLab(AVCRawBinFile *psFile, AVCLab *psLab,
    1175             :                               int nPrecision)
    1176             : {
    1177             : 
    1178         160 :     psLab->nValue = AVCRawBinReadInt32(psFile);
    1179         160 :     psLab->nPolyId = AVCRawBinReadInt32(psFile);
    1180             : 
    1181         160 :     if (AVCRawBinEOF(psFile))
    1182           0 :         return -1;
    1183             : 
    1184         160 :     if (nPrecision == AVC_SINGLE_PREC)
    1185             :     {
    1186         160 :         psLab->sCoord1.x = AVCRawBinReadFloat(psFile);
    1187         160 :         psLab->sCoord1.y = AVCRawBinReadFloat(psFile);
    1188         160 :         psLab->sCoord2.x = AVCRawBinReadFloat(psFile);
    1189         160 :         psLab->sCoord2.y = AVCRawBinReadFloat(psFile);
    1190         160 :         psLab->sCoord3.x = AVCRawBinReadFloat(psFile);
    1191         160 :         psLab->sCoord3.y = AVCRawBinReadFloat(psFile);
    1192             :     }
    1193             :     else
    1194             :     {
    1195           0 :         psLab->sCoord1.x = AVCRawBinReadDouble(psFile);
    1196           0 :         psLab->sCoord1.y = AVCRawBinReadDouble(psFile);
    1197           0 :         psLab->sCoord2.x = AVCRawBinReadDouble(psFile);
    1198           0 :         psLab->sCoord2.y = AVCRawBinReadDouble(psFile);
    1199           0 :         psLab->sCoord3.x = AVCRawBinReadDouble(psFile);
    1200           0 :         psLab->sCoord3.y = AVCRawBinReadDouble(psFile);
    1201             :     }
    1202             : 
    1203         160 :     return 0;
    1204             : }
    1205             : 
    1206             : /**********************************************************************
    1207             :  *                          AVCBinReadNextLab()
    1208             :  *
    1209             :  * Read the next LAB structure from the file.
    1210             :  *
    1211             :  * Returns a pointer to a static AVCLab structure whose contents will be
    1212             :  * valid only until the next call or nullptr if an error happened or if EOF
    1213             :  * was reached.
    1214             :  **********************************************************************/
    1215         162 : AVCLab *AVCBinReadNextLab(AVCBinFile *psFile)
    1216             : {
    1217         322 :     if (psFile->eFileType != AVCFileLAB || AVCRawBinEOF(psFile->psRawBinFile) ||
    1218         160 :         _AVCBinReadNextLab(psFile->psRawBinFile, psFile->cur.psLab,
    1219             :                            psFile->nPrecision) != 0)
    1220             :     {
    1221           2 :         return nullptr;
    1222             :     }
    1223             : 
    1224         160 :     return psFile->cur.psLab;
    1225             : }
    1226             : 
    1227             : /*=====================================================================
    1228             :  *                              TOL
    1229             :  *====================================================================*/
    1230             : 
    1231             : /**********************************************************************
    1232             :  *                          _AVCBinReadNextTol()
    1233             :  *
    1234             :  * (This function is for internal library use... external calls should
    1235             :  * go to AVCBinReadNextTol() instead)
    1236             :  *
    1237             :  * Read the next TOL (tolerance) structure from the file.
    1238             :  *
    1239             :  * Returns 0 on success or -1 on error.
    1240             :  **********************************************************************/
    1241           0 : static int _AVCBinReadNextTol(AVCRawBinFile *psFile, AVCTol *psTol,
    1242             :                               int nPrecision)
    1243             : {
    1244             : 
    1245           0 :     psTol->nIndex = AVCRawBinReadInt32(psFile);
    1246           0 :     psTol->nFlag = AVCRawBinReadInt32(psFile);
    1247             : 
    1248           0 :     if (AVCRawBinEOF(psFile))
    1249           0 :         return -1;
    1250             : 
    1251           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1252             :     {
    1253           0 :         psTol->dValue = AVCRawBinReadFloat(psFile);
    1254             :     }
    1255             :     else
    1256             :     {
    1257           0 :         psTol->dValue = AVCRawBinReadDouble(psFile);
    1258             :     }
    1259             : 
    1260           0 :     return 0;
    1261             : }
    1262             : 
    1263             : /**********************************************************************
    1264             :  *                          AVCBinReadNextTol()
    1265             :  *
    1266             :  * Read the next TOL structure from the file.
    1267             :  *
    1268             :  * Returns a pointer to a static AVCTol structure whose contents will be
    1269             :  * valid only until the next call or nullptr if an error happened or if EOF
    1270             :  * was reached.
    1271             :  **********************************************************************/
    1272           0 : AVCTol *AVCBinReadNextTol(AVCBinFile *psFile)
    1273             : {
    1274           0 :     if (psFile->eFileType != AVCFileTOL || AVCRawBinEOF(psFile->psRawBinFile) ||
    1275           0 :         _AVCBinReadNextTol(psFile->psRawBinFile, psFile->cur.psTol,
    1276             :                            psFile->nPrecision) != 0)
    1277             :     {
    1278           0 :         return nullptr;
    1279             :     }
    1280             : 
    1281           0 :     return psFile->cur.psTol;
    1282             : }
    1283             : 
    1284             : /*=====================================================================
    1285             :  *                              PRJ
    1286             :  *====================================================================*/
    1287             : 
    1288             : /**********************************************************************
    1289             :  *                          _AVCBinReadOpenPrj()
    1290             :  *
    1291             :  * (This function is for internal library use... external calls should
    1292             :  * go to AVCBinReadOpen() with type AVCFilePRJ instead)
    1293             :  *
    1294             :  * Open a PRJ file.
    1295             :  *
    1296             :  * This call will actually read the whole PRJ file in memory since PRJ
    1297             :  * files are small text files.
    1298             :  **********************************************************************/
    1299           2 : AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath, const char *pszName)
    1300             : {
    1301             :     AVCBinFile *psFile;
    1302             :     char *pszFname, **papszPrj;
    1303             : 
    1304             :     /*-----------------------------------------------------------------
    1305             :      * Load the PRJ file contents into a stringlist.
    1306             :      *----------------------------------------------------------------*/
    1307           2 :     pszFname = (char *)CPLMalloc(strlen(pszPath) + strlen(pszName) + 1);
    1308           2 :     snprintf(pszFname, strlen(pszPath) + strlen(pszName) + 1, "%s%s", pszPath,
    1309             :              pszName);
    1310             : 
    1311           2 :     papszPrj = CSLLoad2(pszFname, 50, 160, nullptr);
    1312             : 
    1313           2 :     CPLFree(pszFname);
    1314             : 
    1315           2 :     if (papszPrj == nullptr)
    1316             :     {
    1317             :         /* Failed to open file... just return nullptr since an error message
    1318             :          * has already been issued by CSLLoad()
    1319             :          */
    1320           0 :         return nullptr;
    1321             :     }
    1322             : 
    1323             :     /*-----------------------------------------------------------------
    1324             :      * Alloc and init the AVCBinFile handle.
    1325             :      *----------------------------------------------------------------*/
    1326           2 :     psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
    1327             : 
    1328           2 :     psFile->eFileType = AVCFilePRJ;
    1329           2 :     psFile->psRawBinFile = nullptr;
    1330           2 :     psFile->cur.papszPrj = papszPrj;
    1331           2 :     psFile->pszFilename = nullptr;
    1332             : 
    1333           2 :     return psFile;
    1334             : }
    1335             : 
    1336             : /**********************************************************************
    1337             :  *                          AVCBinReadPrj()
    1338             :  *
    1339             :  * Return the contents of the previously opened PRJ (projection) file.
    1340             :  *
    1341             :  * PRJ files are simple text files with variable length lines, so we
    1342             :  * don't use the AVCRawBin*() functions for this case.
    1343             :  *
    1344             :  * Returns a reference to a static stringlist with the whole file
    1345             :  * contents, or nullptr in case of error.
    1346             :  *
    1347             :  * The returned stringlist should NOT be freed by the caller.
    1348             :  **********************************************************************/
    1349           2 : char **AVCBinReadNextPrj(AVCBinFile *psFile)
    1350             : {
    1351             :     /*-----------------------------------------------------------------
    1352             :      * The file should have already been loaded by AVCBinFileOpen(),
    1353             :      * so there is not much to do here!
    1354             :      *----------------------------------------------------------------*/
    1355           2 :     return psFile->cur.papszPrj;
    1356             : }
    1357             : 
    1358             : /*=====================================================================
    1359             :  *                              TXT/TX6/TX7
    1360             :  *====================================================================*/
    1361             : 
    1362             : /**********************************************************************
    1363             :  *                          _AVCBinReadNextTxt()
    1364             :  *
    1365             :  * (This function is for internal library use... external calls should
    1366             :  * go to AVCBinReadNextTxt() instead)
    1367             :  *
    1368             :  * Read the next TXT/TX6/TX7 (Annotation) structure from the file.
    1369             :  *
    1370             :  * Returns 0 on success or -1 on error.
    1371             :  **********************************************************************/
    1372           0 : static int _AVCBinReadNextTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
    1373             :                               int nPrecision)
    1374             : {
    1375             :     int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize;
    1376             :     int numBytesRead;
    1377             : 
    1378           0 :     numVerticesBefore =
    1379           0 :         ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
    1380             : 
    1381           0 :     psTxt->nTxtId = AVCRawBinReadInt32(psFile);
    1382           0 :     if (AVCRawBinEOF(psFile))
    1383           0 :         return -1;
    1384             : 
    1385           0 :     nRecordSize = AVCRawBinReadInt32(psFile);
    1386           0 :     if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
    1387           0 :         return -1;
    1388           0 :     nRecordSize = nRecordSize * 2 + 8;
    1389             : 
    1390           0 :     psTxt->nUserId = AVCRawBinReadInt32(psFile);
    1391           0 :     psTxt->nLevel = AVCRawBinReadInt32(psFile);
    1392             : 
    1393           0 :     psTxt->f_1e2 = AVCRawBinReadFloat(psFile);
    1394           0 :     psTxt->nSymbol = AVCRawBinReadInt32(psFile);
    1395           0 :     psTxt->numVerticesLine = AVCRawBinReadInt32(psFile);
    1396           0 :     psTxt->n28 = AVCRawBinReadInt32(psFile);
    1397           0 :     psTxt->numChars = AVCRawBinReadInt32(psFile);
    1398           0 :     if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024)
    1399           0 :         return -1;
    1400           0 :     psTxt->numVerticesArrow = AVCRawBinReadInt32(psFile);
    1401             : 
    1402           0 :     for (i = 0; i < 20; i++)
    1403             :     {
    1404           0 :         psTxt->anJust1[i] = AVCRawBinReadInt16(psFile);
    1405             :     }
    1406           0 :     for (i = 0; i < 20; i++)
    1407             :     {
    1408           0 :         psTxt->anJust2[i] = AVCRawBinReadInt16(psFile);
    1409             :     }
    1410             : 
    1411           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1412             :     {
    1413           0 :         psTxt->dHeight = AVCRawBinReadFloat(psFile);
    1414           0 :         psTxt->dV2 = AVCRawBinReadFloat(psFile);
    1415           0 :         psTxt->dV3 = AVCRawBinReadFloat(psFile);
    1416             :     }
    1417             :     else
    1418             :     {
    1419           0 :         psTxt->dHeight = AVCRawBinReadDouble(psFile);
    1420           0 :         psTxt->dV2 = AVCRawBinReadDouble(psFile);
    1421           0 :         psTxt->dV3 = AVCRawBinReadDouble(psFile);
    1422             :     }
    1423             : 
    1424           0 :     numCharsToRead = ((int)(psTxt->numChars + 3) / 4) * 4;
    1425           0 :     if (psTxt->pszText == nullptr ||
    1426           0 :         ((int)(strlen((char *)psTxt->pszText) + 3) / 4) * 4 < numCharsToRead)
    1427             :     {
    1428           0 :         GByte *pszNewText = (GByte *)VSIRealloc(
    1429           0 :             psTxt->pszText, (numCharsToRead + 1) * sizeof(char));
    1430           0 :         if (pszNewText == nullptr)
    1431           0 :             return -1;
    1432           0 :         psTxt->pszText = pszNewText;
    1433             :     }
    1434             : 
    1435           0 :     AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText);
    1436           0 :     psTxt->pszText[psTxt->numChars] = '\0';
    1437             : 
    1438             :     /* Realloc the vertices array only if it needs to grow...
    1439             :      * do not realloc to a smaller size.
    1440             :      */
    1441           0 :     if (psTxt->numVerticesLine == INT_MIN ||
    1442           0 :         psTxt->numVerticesArrow == INT_MIN ||
    1443           0 :         ABS(psTxt->numVerticesLine) >
    1444           0 :             100 * 1024 * 1024 - ABS(psTxt->numVerticesArrow))
    1445           0 :         return -1;
    1446           0 :     numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
    1447           0 :     if (numVertices > 10 * 1024 * 1024 &&
    1448           0 :         !AVCRawBinIsFileGreaterThan(
    1449             :             psFile,
    1450           0 :             cpl::fits_on<int>(numVertices *
    1451           0 :                               ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
    1452             :     {
    1453           0 :         return -1;
    1454             :     }
    1455             : 
    1456           0 :     if (psTxt->pasVertices == nullptr || numVertices > numVerticesBefore)
    1457           0 :         psTxt->pasVertices = (AVCVertex *)CPLRealloc(
    1458           0 :             psTxt->pasVertices, numVertices * sizeof(AVCVertex));
    1459             : 
    1460           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1461             :     {
    1462           0 :         for (i = 0; i < numVertices; i++)
    1463             :         {
    1464           0 :             psTxt->pasVertices[i].x = AVCRawBinReadFloat(psFile);
    1465           0 :             psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile);
    1466           0 :             if (psFile->nCurSize == 0)
    1467           0 :                 return -1;
    1468             :         }
    1469             :     }
    1470             :     else
    1471             :     {
    1472           0 :         for (i = 0; i < numVertices; i++)
    1473             :         {
    1474           0 :             psTxt->pasVertices[i].x = AVCRawBinReadDouble(psFile);
    1475           0 :             psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile);
    1476           0 :             if (psFile->nCurSize == 0)
    1477           0 :                 return -1;
    1478             :         }
    1479             :     }
    1480             : 
    1481             :     /* In V7 Coverages, we always have 8 bytes of junk at end of record.
    1482             :      * In Weird coverages, these 8 bytes are sometimes present, and
    1483             :      * sometimes not!!! (Probably another AI "random feature"! ;-)
    1484             :      * So we use the record size to establish if there is any junk to skip
    1485             :      */
    1486           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1487           0 :         numBytesRead = 132 + numCharsToRead + numVertices * 2 * 4;
    1488             :     else
    1489           0 :         numBytesRead = 144 + numCharsToRead + numVertices * 2 * 8;
    1490             : 
    1491           0 :     if (numBytesRead < nRecordSize)
    1492           0 :         AVCRawBinFSeek(psFile, nRecordSize - numBytesRead, SEEK_CUR);
    1493             : 
    1494           0 :     return 0;
    1495             : }
    1496             : 
    1497             : /**********************************************************************
    1498             :  *                          _AVCBinReadNextPCCoverageTxt()
    1499             :  *
    1500             :  * (This function is for internal library use... external calls should
    1501             :  * go to AVCBinReadNextTxt() instead)
    1502             :  *
    1503             :  * Read the next TXT (Annotation) structure from a PC Coverage file.
    1504             :  * Note that it is assumed that PC Coverage files are always single
    1505             :  * precision.
    1506             :  *
    1507             :  * Returns 0 on success or -1 on error.
    1508             :  **********************************************************************/
    1509           0 : static int _AVCBinReadNextPCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
    1510             :                                         int nPrecision)
    1511             : {
    1512             :     int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize;
    1513             : 
    1514           0 :     numVerticesBefore =
    1515           0 :         ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
    1516             : 
    1517           0 :     psTxt->nTxtId = AVCRawBinReadInt32(psFile);
    1518           0 :     if (AVCRawBinEOF(psFile))
    1519           0 :         return -1;
    1520             : 
    1521           0 :     nRecordSize = AVCRawBinReadInt32(psFile);
    1522           0 :     if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
    1523           0 :         return -1;
    1524           0 :     nRecordSize = nRecordSize * 2 + 8;
    1525             : 
    1526           0 :     psTxt->nUserId = 0;
    1527           0 :     psTxt->nLevel = AVCRawBinReadInt32(psFile);
    1528             : 
    1529           0 :     psTxt->numVerticesLine = AVCRawBinReadInt32(psFile);
    1530             :     /* We are not expecting more than 4 vertices */
    1531           0 :     psTxt->numVerticesLine = MIN(psTxt->numVerticesLine, 4);
    1532             : 
    1533           0 :     psTxt->numVerticesArrow = 0;
    1534             : 
    1535             :     /* Realloc the vertices array only if it needs to grow...
    1536             :      * do not realloc to a smaller size.
    1537             :      *
    1538             :      * Note that because of the way V7 binary TXT files work, the rest of the
    1539             :      * lib expects to receive duplicate coords for the first vertex, so
    1540             :      * we have to include an additional vertex for that.
    1541             :      */
    1542           0 :     psTxt->numVerticesLine += 1;
    1543           0 :     if (psTxt->numVerticesLine == INT_MIN ||
    1544           0 :         ABS(psTxt->numVerticesLine) > 100 * 1024 * 1024)
    1545           0 :         return -1;
    1546           0 :     numVertices = ABS(psTxt->numVerticesLine);
    1547           0 :     if (numVertices < 2)
    1548           0 :         return -1;
    1549           0 :     if (numVertices > 10 * 1024 * 1024 &&
    1550           0 :         !AVCRawBinIsFileGreaterThan(
    1551             :             psFile,
    1552           0 :             cpl::fits_on<int>(numVertices *
    1553           0 :                               ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
    1554             :     {
    1555           0 :         return -1;
    1556             :     }
    1557             : 
    1558           0 :     if (psTxt->pasVertices == nullptr || numVertices > numVerticesBefore)
    1559           0 :         psTxt->pasVertices = (AVCVertex *)CPLRealloc(
    1560           0 :             psTxt->pasVertices, numVertices * sizeof(AVCVertex));
    1561             : 
    1562           0 :     for (i = 1; i < numVertices; i++)
    1563             :     {
    1564           0 :         if (nPrecision == AVC_SINGLE_PREC)
    1565             :         {
    1566           0 :             psTxt->pasVertices[i].x = AVCRawBinReadFloat(psFile);
    1567           0 :             psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile);
    1568           0 :             if (psFile->nCurSize == 0)
    1569           0 :                 return -1;
    1570             :         }
    1571             :         else
    1572             :         {
    1573           0 :             psTxt->pasVertices[i].x = AVCRawBinReadDouble(psFile);
    1574           0 :             psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile);
    1575           0 :             if (psFile->nCurSize == 0)
    1576           0 :                 return -1;
    1577             :         }
    1578             :     }
    1579             :     /* Duplicate the first vertex because that's the way the other binary TXT
    1580             :      * files work and that's what the lib expects to generate the E00.
    1581             :      */
    1582           0 :     psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
    1583           0 :     psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
    1584             : 
    1585             :     /* Skip the other floats (vertices) that are unused */
    1586           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1587           0 :         AVCRawBinFSeek(psFile, 4 * (15 - 2 * (numVertices - 1)), SEEK_CUR);
    1588             :     else
    1589           0 :         AVCRawBinFSeek(psFile, 8 * (15 - 2 * (numVertices - 1)), SEEK_CUR);
    1590             : 
    1591           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1592             :     {
    1593           0 :         psTxt->dHeight = AVCRawBinReadFloat(psFile);
    1594             :     }
    1595             :     else
    1596             :     {
    1597           0 :         psTxt->dHeight = AVCRawBinReadDouble(psFile);
    1598             :     }
    1599           0 :     psTxt->f_1e2 = AVCRawBinReadFloat(psFile);
    1600           0 :     psTxt->nSymbol = AVCRawBinReadInt32(psFile);
    1601           0 :     psTxt->numChars = AVCRawBinReadInt32(psFile);
    1602           0 :     if (psTxt->numChars < 0)
    1603           0 :         return -1;
    1604             : 
    1605             :     /* In some cases, we may need to skip additional spaces after the
    1606             :      * text string... more than should be required to simply align with
    1607             :      * a 4 bytes boundary... include that in numCharsToRead
    1608             :      */
    1609           0 :     if (nPrecision == AVC_SINGLE_PREC)
    1610             :     {
    1611           0 :         numCharsToRead = nRecordSize - (28 + 16 * 4);
    1612             :     }
    1613             :     else
    1614             :     {
    1615           0 :         numCharsToRead = nRecordSize - (28 + 16 * 8);
    1616             :     }
    1617           0 :     if (numCharsToRead < 0)
    1618           0 :         return -1;
    1619             : 
    1620             :     /* Do a quick check in case file is corrupt! */
    1621           0 :     psTxt->numChars = MIN(psTxt->numChars, numCharsToRead);
    1622             : 
    1623           0 :     if (psTxt->pszText == nullptr ||
    1624           0 :         ((int)(strlen((char *)psTxt->pszText) + 3) / 4) * 4 < numCharsToRead)
    1625             :     {
    1626           0 :         psTxt->pszText = (GByte *)CPLRealloc(
    1627           0 :             psTxt->pszText, (numCharsToRead + 5) * sizeof(char));
    1628             :     }
    1629             : 
    1630           0 :     AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText);
    1631           0 :     psTxt->pszText[psTxt->numChars] = '\0';
    1632             : 
    1633             :     /* Set unused members to default values...
    1634             :      */
    1635           0 :     psTxt->dV2 = 0.0;
    1636           0 :     psTxt->dV3 = 0.0;
    1637           0 :     psTxt->n28 = 0;
    1638           0 :     for (i = 0; i < 20; i++)
    1639             :     {
    1640           0 :         psTxt->anJust1[i] = 0;
    1641           0 :         psTxt->anJust2[i] = 0;
    1642             :     }
    1643             : 
    1644           0 :     return 0;
    1645             : }
    1646             : 
    1647             : /**********************************************************************
    1648             :  *                          AVCBinReadNextTxt()
    1649             :  *
    1650             :  * Read the next TXT/TX6/TX7 structure from the file.
    1651             :  *
    1652             :  * Returns a pointer to a static AVCTxt structure whose contents will be
    1653             :  * valid only until the next call or nullptr if an error happened or if EOF
    1654             :  * was reached.
    1655             :  **********************************************************************/
    1656           0 : AVCTxt *AVCBinReadNextTxt(AVCBinFile *psFile)
    1657             : {
    1658           0 :     int nStatus = 0;
    1659             : 
    1660           0 :     if ((psFile->eFileType != AVCFileTXT && psFile->eFileType != AVCFileTX6) ||
    1661           0 :         AVCRawBinEOF(psFile->psRawBinFile))
    1662             :     {
    1663           0 :         return nullptr;
    1664             :     }
    1665             : 
    1666             :     /* AVCCoverPC have a different TXT format than AVCCoverV7
    1667             :      *
    1668             :      * Note: Some Weird coverages use the PC TXT structure, and some use the
    1669             :      *       V7 structure.  We distinguish them using the header's precision
    1670             :      *       field in AVCBinReadRewind().
    1671             :      */
    1672           0 :     if (psFile->eFileType == AVCFileTXT &&
    1673           0 :         (psFile->eCoverType == AVCCoverPC ||
    1674           0 :          psFile->eCoverType == AVCCoverWeird))
    1675             :     {
    1676             :         /* TXT file in PC Coverages (and some Weird Coverages)
    1677             :          */
    1678           0 :         nStatus = _AVCBinReadNextPCCoverageTxt(
    1679             :             psFile->psRawBinFile, psFile->cur.psTxt, psFile->nPrecision);
    1680             :     }
    1681             :     else
    1682             :     {
    1683             :         /* TXT in V7 Coverages (and some Weird Coverages), and TX6/TX7 in
    1684             :          * all coverage types
    1685             :          */
    1686           0 :         nStatus = _AVCBinReadNextTxt(psFile->psRawBinFile, psFile->cur.psTxt,
    1687             :                                      psFile->nPrecision);
    1688             :     }
    1689             : 
    1690           0 :     if (nStatus != 0)
    1691             :     {
    1692           0 :         return nullptr;
    1693             :     }
    1694             : 
    1695           0 :     return psFile->cur.psTxt;
    1696             : }
    1697             : 
    1698             : /*=====================================================================
    1699             :  *                              RXP
    1700             :  *====================================================================*/
    1701             : 
    1702             : /**********************************************************************
    1703             :  *                          _AVCBinReadNextRxp()
    1704             :  *
    1705             :  * (This function is for internal library use... external calls should
    1706             :  * go to AVCBinReadNextRxp() instead)
    1707             :  *
    1708             :  * Read the next RXP (Region something...) structure from the file.
    1709             :  *
    1710             :  * Returns 0 on success or -1 on error.
    1711             :  **********************************************************************/
    1712           0 : static int _AVCBinReadNextRxp(AVCRawBinFile *psFile, AVCRxp *psRxp,
    1713             :                               CPL_UNUSED int nPrecision)
    1714             : {
    1715             : 
    1716           0 :     psRxp->n1 = AVCRawBinReadInt32(psFile);
    1717           0 :     if (AVCRawBinEOF(psFile))
    1718           0 :         return -1;
    1719           0 :     psRxp->n2 = AVCRawBinReadInt32(psFile);
    1720             : 
    1721           0 :     return 0;
    1722             : }
    1723             : 
    1724             : /**********************************************************************
    1725             :  *                          AVCBinReadNextRxp()
    1726             :  *
    1727             :  * Read the next RXP structure from the file.
    1728             :  *
    1729             :  * Returns a pointer to a static AVCRxp structure whose contents will be
    1730             :  * valid only until the next call or nullptr if an error happened or if EOF
    1731             :  * was reached.
    1732             :  **********************************************************************/
    1733           0 : AVCRxp *AVCBinReadNextRxp(AVCBinFile *psFile)
    1734             : {
    1735           0 :     if (psFile->eFileType != AVCFileRXP || AVCRawBinEOF(psFile->psRawBinFile) ||
    1736           0 :         _AVCBinReadNextRxp(psFile->psRawBinFile, psFile->cur.psRxp,
    1737             :                            psFile->nPrecision) != 0)
    1738             :     {
    1739           0 :         return nullptr;
    1740             :     }
    1741             : 
    1742           0 :     return psFile->cur.psRxp;
    1743             : }
    1744             : 
    1745             : /*=====================================================================
    1746             :  *                         NATIVE (V7.x) TABLEs
    1747             :  *
    1748             :  * Note: Also applies to AVCCoverWeird
    1749             :  *====================================================================*/
    1750             : 
    1751             : /**********************************************************************
    1752             :  *                          _AVCBinReadNextArcDir()
    1753             :  *
    1754             :  * (This function is for internal library use... external calls should
    1755             :  * go to AVCBinReadOpen() with type AVCFileTABLE instead)
    1756             :  *
    1757             :  * Read the next record from an arc.dir (or "arcdr9") file.
    1758             :  *
    1759             :  * Note that arc.dir files have no header... they start with the
    1760             :  * first record immediately.
    1761             :  *
    1762             :  * Returns 0 on success or -1 on error.
    1763             :  **********************************************************************/
    1764             : 
    1765          32 : int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir)
    1766             : {
    1767             :     int i;
    1768             : 
    1769             :     /* Arc/Info Table name
    1770             :      */
    1771          32 :     AVCRawBinReadString(psFile, 32, (GByte *)psArcDir->szTableName);
    1772          32 :     psArcDir->szTableName[32] = '\0';
    1773             : 
    1774          32 :     if (AVCRawBinEOF(psFile))
    1775           0 :         return -1;
    1776             : 
    1777             :     /* "ARC####" basename for .DAT and .NIT files
    1778             :      */
    1779          32 :     AVCRawBinReadString(psFile, 8, (GByte *)psArcDir->szInfoFile);
    1780          32 :     psArcDir->szInfoFile[7] = '\0';
    1781          32 :     for (i = 6; i > 0 && psArcDir->szInfoFile[i] == ' '; i--)
    1782           0 :         psArcDir->szInfoFile[i] = '\0';
    1783             : 
    1784          32 :     psArcDir->numFields = AVCRawBinReadInt16(psFile);
    1785          32 :     psArcDir->nRecSize = AVCRawBinReadInt16(psFile);
    1786             : 
    1787          32 :     AVCRawBinFSeek(psFile, 18, SEEK_CUR); /* Skip 18 bytes */
    1788             : 
    1789          32 :     psArcDir->bDeletedFlag = AVCRawBinReadInt16(psFile);
    1790          32 :     psArcDir->numRecords = AVCRawBinReadInt32(psFile);
    1791             : 
    1792          32 :     AVCRawBinFSeek(psFile, 10, SEEK_CUR); /* Skip 10 bytes */
    1793             : 
    1794          32 :     AVCRawBinReadBytes(psFile, 2, (GByte *)psArcDir->szExternal);
    1795          32 :     psArcDir->szExternal[2] = '\0';
    1796             : 
    1797          32 :     AVCRawBinFSeek(psFile, 300, SEEK_CUR); /* Skip the remaining 300 bytes */
    1798             : 
    1799          32 :     return 0;
    1800             : }
    1801             : 
    1802             : /**********************************************************************
    1803             :  *                          _AVCBinReadNextNit()
    1804             :  *
    1805             :  * (This function is for internal library use... external calls should
    1806             :  * go to AVCBinReadOpen() with type AVCFileTABLE instead)
    1807             :  *
    1808             :  * Read the next record from an arc####.nit file.
    1809             :  *
    1810             :  * Note that arc####.nit files have no header... they start with the
    1811             :  * first record immediately.
    1812             :  *
    1813             :  * Returns 0 on success or -1 on error.
    1814             :  **********************************************************************/
    1815          31 : static int _AVCBinReadNextArcNit(AVCRawBinFile *psFile, AVCFieldInfo *psField)
    1816             : {
    1817          31 :     AVCRawBinReadString(psFile, 16, (GByte *)psField->szName);
    1818          31 :     psField->szName[16] = '\0';
    1819             : 
    1820          31 :     if (AVCRawBinEOF(psFile))
    1821           0 :         return -1;
    1822             : 
    1823          31 :     psField->nSize = AVCRawBinReadInt16(psFile);
    1824          31 :     if (psField->nSize < 0)
    1825           0 :         return -1;
    1826          31 :     psField->v2 = AVCRawBinReadInt16(psFile); /* Always -1 ? */
    1827          31 :     psField->nOffset = AVCRawBinReadInt16(psFile);
    1828          31 :     psField->v4 = AVCRawBinReadInt16(psFile); /* Always 4 ?  */
    1829          31 :     psField->v5 = AVCRawBinReadInt16(psFile); /* Always -1 ? */
    1830          31 :     psField->nFmtWidth = AVCRawBinReadInt16(psFile);
    1831          31 :     psField->nFmtPrec = AVCRawBinReadInt16(psFile);
    1832          31 :     psField->nType1 = AVCRawBinReadInt16(psFile);
    1833          31 :     psField->nType2 = AVCRawBinReadInt16(psFile); /* Always 0 ? */
    1834          31 :     psField->v10 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
    1835          31 :     psField->v11 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
    1836          31 :     psField->v12 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
    1837          31 :     psField->v13 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
    1838             : 
    1839          31 :     AVCRawBinReadString(psFile, 16,
    1840          31 :                         (GByte *)psField->szAltName); /* Always Blank ? */
    1841          31 :     psField->szAltName[16] = '\0';
    1842             : 
    1843          31 :     AVCRawBinFSeek(psFile, 56, SEEK_CUR); /* Skip 56 bytes */
    1844             : 
    1845          31 :     psField->nIndex = AVCRawBinReadInt16(psFile);
    1846             : 
    1847          31 :     AVCRawBinFSeek(psFile, 28, SEEK_CUR); /* Skip the remaining 28 bytes */
    1848             : 
    1849          31 :     return 0;
    1850             : }
    1851             : 
    1852             : /**********************************************************************
    1853             :  *                          _AVCBinReadGetInfoFilename()
    1854             :  *
    1855             :  * Look for the DAT or NIT files for a given table... returns TRUE if
    1856             :  * they exist, or FALSE otherwise.
    1857             :  *
    1858             :  * If pszRetFnmae/pszRetNitFile != nullptr then the filename with full path
    1859             :  * will be copied to the specified buffer.
    1860             :  **********************************************************************/
    1861          44 : static GBool _AVCBinReadGetInfoFilename(const char *pszInfoPath,
    1862             :                                         const char *pszBasename,
    1863             :                                         const char *pszDatOrNit,
    1864             :                                         AVCCoverType eCoverType,
    1865             :                                         char *pszRetFname, size_t nRetFnameLen)
    1866             : {
    1867          44 :     GBool bFilesExist = FALSE;
    1868          44 :     char *pszBuf = nullptr;
    1869             :     VSIStatBufL sStatBuf;
    1870             :     size_t nBufLen;
    1871             : 
    1872          44 :     if (pszRetFname)
    1873             :     {
    1874          14 :         pszBuf = pszRetFname;
    1875          14 :         nBufLen = nRetFnameLen;
    1876             :     }
    1877             :     else
    1878             :     {
    1879          30 :         nBufLen = strlen(pszInfoPath) + strlen(pszBasename) + 10;
    1880          30 :         pszBuf = (char *)CPLMalloc(nBufLen);
    1881             :     }
    1882             : 
    1883          44 :     if (eCoverType == AVCCoverWeird)
    1884             :     {
    1885           0 :         snprintf(pszBuf, nBufLen, "%s%s%s", pszInfoPath, pszBasename,
    1886             :                  pszDatOrNit);
    1887             :     }
    1888             :     else
    1889             :     {
    1890          44 :         snprintf(pszBuf, nBufLen, "%s%s.%s", pszInfoPath, pszBasename,
    1891             :                  pszDatOrNit);
    1892             :     }
    1893             : 
    1894          44 :     AVCAdjustCaseSensitiveFilename(pszBuf);
    1895             : 
    1896          44 :     if (VSIStatL(pszBuf, &sStatBuf) == 0)
    1897          44 :         bFilesExist = TRUE;
    1898             : 
    1899          44 :     if (eCoverType == AVCCoverWeird && !bFilesExist)
    1900             :     {
    1901             :         /* In some cases, the filename can be truncated to 8 chars
    1902             :          * and we end up with "ARC000DA"... check that possibility.
    1903             :          */
    1904           0 :         pszBuf[strlen(pszBuf) - 1] = '\0';
    1905             : 
    1906           0 :         AVCAdjustCaseSensitiveFilename(pszBuf);
    1907             : 
    1908           0 :         if (VSIStatL(pszBuf, &sStatBuf) == 0)
    1909           0 :             bFilesExist = TRUE;
    1910             :     }
    1911             : 
    1912          44 :     if (pszRetFname == nullptr)
    1913          30 :         CPLFree(pszBuf);
    1914             : 
    1915          44 :     return bFilesExist;
    1916             : }
    1917             : 
    1918             : /**********************************************************************
    1919             :  *                          _AVCBinReadInfoFilesExist()
    1920             :  *
    1921             :  * Look for the DAT and NIT files for a given table... returns TRUE if
    1922             :  * they exist, or FALSE otherwise.
    1923             :  *
    1924             :  * If pszRetDatFile/pszRetNitFile != nullptr then the .DAT and .NIT filename
    1925             :  * without the info path will be copied to the specified buffers.
    1926             :  **********************************************************************/
    1927          15 : static GBool _AVCBinReadInfoFileExists(const char *pszInfoPath,
    1928             :                                        const char *pszBasename,
    1929             :                                        AVCCoverType eCoverType)
    1930             : {
    1931             : 
    1932          15 :     return (_AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "dat",
    1933          30 :                                        eCoverType, nullptr, 0) == TRUE &&
    1934          15 :             _AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "nit",
    1935          15 :                                        eCoverType, nullptr, 0) == TRUE);
    1936             : }
    1937             : 
    1938             : /**********************************************************************
    1939             :  *                          AVCBinReadListTables()
    1940             :  *
    1941             :  * Scan the arc.dir file and return stringlist with one entry for the
    1942             :  * Arc/Info name of each table that belongs to the specified coverage.
    1943             :  * Pass pszCoverName = nullptr to get the list of all tables.
    1944             :  *
    1945             :  * ppapszArcDatFiles if not nullptr will be set to point to a stringlist
    1946             :  * with the corresponding "ARC????" info file basenames corresponding
    1947             :  * to each table found.
    1948             :  *
    1949             :  * Note that arc.dir files have no header... they start with the
    1950             :  * first record immediately.
    1951             :  *
    1952             :  * In AVCCoverWeird, the file is called "arcdr9"
    1953             :  *
    1954             :  * Returns a stringlist that should be deallocated by the caller
    1955             :  * with CSLDestroy(), or nullptr on error.
    1956             :  **********************************************************************/
    1957           3 : char **AVCBinReadListTables(const char *pszInfoPath, const char *pszCoverName,
    1958             :                             char ***ppapszArcDatFiles, AVCCoverType eCoverType,
    1959             :                             AVCDBCSInfo *psDBCSInfo)
    1960             : {
    1961           3 :     char **papszList = nullptr;
    1962             :     char *pszFname;
    1963           3 :     char szNameToFind[33] = "";
    1964             :     int nLen;
    1965             :     AVCRawBinFile *hFile;
    1966             :     AVCTableDef sEntry;
    1967             : 
    1968           3 :     if (ppapszArcDatFiles)
    1969           3 :         *ppapszArcDatFiles = nullptr;
    1970             : 
    1971             :     /*-----------------------------------------------------------------
    1972             :      * For AVCCoverV7Tables type we do not look for tables for a specific
    1973             :      * coverage, we return all tables from the info dir.
    1974             :      *----------------------------------------------------------------*/
    1975           3 :     if (eCoverType == AVCCoverV7Tables)
    1976           0 :         pszCoverName = nullptr;
    1977             : 
    1978             :     /*-----------------------------------------------------------------
    1979             :      * All tables that belong to a given coverage have their name starting
    1980             :      * with the coverage name (in uppercase letters), followed by a 3
    1981             :      * letters extension.
    1982             :      *----------------------------------------------------------------*/
    1983           3 :     if (pszCoverName != nullptr)
    1984             :         // cppcheck-suppress bufferAccessOutOfBounds
    1985           3 :         snprintf(szNameToFind, sizeof(szNameToFind), "%-.28s.", pszCoverName);
    1986           3 :     nLen = (int)strlen(szNameToFind);
    1987             : 
    1988             :     /*-----------------------------------------------------------------
    1989             :      * Open the arc.dir and add all entries that match the criteria
    1990             :      * to our list.
    1991             :      * In AVCCoverWeird, the file is called "arcdr9"
    1992             :      *----------------------------------------------------------------*/
    1993           3 :     pszFname = (char *)CPLMalloc(strlen(pszInfoPath) + 9);
    1994           3 :     if (eCoverType == AVCCoverWeird)
    1995           0 :         snprintf(pszFname, strlen(pszInfoPath) + 9, "%sarcdr9", pszInfoPath);
    1996             :     else
    1997           3 :         snprintf(pszFname, strlen(pszInfoPath) + 9, "%sarc.dir", pszInfoPath);
    1998             : 
    1999           3 :     AVCAdjustCaseSensitiveFilename(pszFname);
    2000             : 
    2001           3 :     hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
    2002             :                           psDBCSInfo);
    2003             : 
    2004           3 :     if (hFile)
    2005             :     {
    2006          31 :         while (!AVCRawBinEOF(hFile) &&
    2007          14 :                _AVCBinReadNextArcDir(hFile, &sEntry) == 0)
    2008             :         {
    2009          14 :             if (/* sEntry.numRecords > 0 && (DO NOT skip empty tables) */
    2010          14 :                 !sEntry.bDeletedFlag &&
    2011          14 :                 (pszCoverName == nullptr ||
    2012          36 :                  EQUALN(szNameToFind, sEntry.szTableName, nLen)) &&
    2013           8 :                 _AVCBinReadInfoFileExists(pszInfoPath, sEntry.szInfoFile,
    2014             :                                           eCoverType))
    2015             :             {
    2016           8 :                 papszList = CSLAddString(papszList, sEntry.szTableName);
    2017             : 
    2018           8 :                 if (ppapszArcDatFiles)
    2019           8 :                     *ppapszArcDatFiles =
    2020           8 :                         CSLAddString(*ppapszArcDatFiles, sEntry.szInfoFile);
    2021             :             }
    2022             :         }
    2023           3 :         AVCRawBinClose(hFile);
    2024             :     }
    2025             : 
    2026           3 :     CPLFree(pszFname);
    2027             : 
    2028           3 :     return papszList;
    2029             : }
    2030             : 
    2031             : /**********************************************************************
    2032             :  *                         _AVCBinReadOpenTable()
    2033             :  *
    2034             :  * (This function is for internal library use... external calls should
    2035             :  * go to AVCBinReadOpen() with type AVCFileTABLE instead)
    2036             :  *
    2037             :  * Open a INFO table, read the header file (.NIT), and finally open
    2038             :  * the associated data file to be ready to read records from it.
    2039             :  *
    2040             :  * Returns a valid AVCBinFile handle, or nullptr if the file could
    2041             :  * not be opened.
    2042             :  *
    2043             :  * _AVCBinReadCloseTable() will eventually have to be called to release the
    2044             :  * resources used by the AVCBinFile structure.
    2045             :  **********************************************************************/
    2046           7 : AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath,
    2047             :                                  const char *pszTableName,
    2048             :                                  AVCCoverType eCoverType,
    2049             :                                  AVCDBCSInfo *psDBCSInfo)
    2050             : {
    2051             :     AVCBinFile *psFile;
    2052             :     AVCRawBinFile *hFile;
    2053             :     AVCTableDef sTableDef;
    2054             :     AVCFieldInfo *pasFieldDef;
    2055             :     char *pszFname;
    2056             :     GBool bFound;
    2057             :     int i;
    2058             :     size_t nFnameLen;
    2059             : 
    2060           7 :     memset(&sTableDef, 0, sizeof(sTableDef));
    2061           7 :     sTableDef.numFields = 0;
    2062           7 :     sTableDef.pasFieldDef = nullptr;
    2063             : 
    2064             :     /* Alloc a buffer big enough for the longest possible filename...
    2065             :      */
    2066           7 :     nFnameLen = strlen(pszInfoPath) + 81;
    2067           7 :     pszFname = (char *)CPLMalloc(nFnameLen);
    2068             : 
    2069             :     /*-----------------------------------------------------------------
    2070             :      * Fetch info about this table from the "arc.dir"
    2071             :      *----------------------------------------------------------------*/
    2072           7 :     if (eCoverType == AVCCoverWeird)
    2073           0 :         snprintf(pszFname, nFnameLen, "%sarcdr9", pszInfoPath);
    2074             :     else
    2075           7 :         snprintf(pszFname, nFnameLen, "%sarc.dir", pszInfoPath);
    2076             : 
    2077           7 :     AVCAdjustCaseSensitiveFilename(pszFname);
    2078             : 
    2079           7 :     hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
    2080             :                           psDBCSInfo);
    2081           7 :     bFound = FALSE;
    2082             : 
    2083           7 :     if (hFile)
    2084             :     {
    2085          25 :         while (!bFound && _AVCBinReadNextArcDir(hFile, &sTableDef) == 0)
    2086             :         {
    2087          54 :             if (!sTableDef.bDeletedFlag &&
    2088          18 :                 EQUALN(sTableDef.szTableName, pszTableName,
    2089          36 :                        strlen(pszTableName)) &&
    2090           7 :                 _AVCBinReadInfoFileExists(pszInfoPath, sTableDef.szInfoFile,
    2091             :                                           eCoverType))
    2092             :             {
    2093           7 :                 bFound = TRUE;
    2094             :             }
    2095             :         }
    2096           7 :         AVCRawBinClose(hFile);
    2097             :     }
    2098             : 
    2099             :     /* Hummm... quite likely that this table does not exist!
    2100             :      */
    2101           7 :     if (!bFound)
    2102             :     {
    2103           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open table %s",
    2104             :                  pszTableName);
    2105           0 :         CPLFree(pszFname);
    2106           0 :         return nullptr;
    2107             :     }
    2108             :     /* To please Coverity */
    2109           7 :     if (sTableDef.numFields < 0 || sTableDef.numFields >= 32767)
    2110             :     {
    2111           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Invalid numFields in %s",
    2112             :                  pszTableName);
    2113           0 :         CPLFree(pszFname);
    2114           0 :         return nullptr;
    2115             :     }
    2116             : 
    2117             :     /*-----------------------------------------------------------------
    2118             :      * Establish the location of the data file... depends on the
    2119             :      * szExternal[] field.
    2120             :      *----------------------------------------------------------------*/
    2121           7 :     if (EQUAL(sTableDef.szExternal, "XX"))
    2122             :     {
    2123             :         /*-------------------------------------------------------------
    2124             :          * The data file is located outside of the INFO directory.
    2125             :          * Read the path to the data file from the arc####.dat file
    2126             :          *------------------------------------------------------------*/
    2127           7 :         _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat",
    2128             :                                    eCoverType, pszFname, nFnameLen);
    2129           7 :         AVCAdjustCaseSensitiveFilename(pszFname);
    2130             : 
    2131           7 :         hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
    2132             :                               psDBCSInfo);
    2133             : 
    2134           7 :         if (hFile)
    2135             :         {
    2136             :             /* Read the relative file path, and remove trailing spaces.
    2137             :              */
    2138           7 :             AVCRawBinReadBytes(hFile, 80, (GByte *)sTableDef.szDataFile);
    2139           7 :             sTableDef.szDataFile[80] = '\0';
    2140             : 
    2141           7 :             for (i = (int)strlen(sTableDef.szDataFile) - 1;
    2142         410 :                  i >= 0 && isspace((unsigned char)sTableDef.szDataFile[i]); i--)
    2143             :             {
    2144         403 :                 sTableDef.szDataFile[i] = '\0';
    2145             :             }
    2146             : 
    2147           7 :             AVCRawBinClose(hFile);
    2148             :         }
    2149             :         else
    2150             :         {
    2151           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
    2152             :                      pszFname);
    2153           0 :             CPLFree(pszFname);
    2154           0 :             return nullptr;
    2155             :         }
    2156             :     }
    2157             :     else
    2158             :     {
    2159             :         /*-------------------------------------------------------------
    2160             :          * The data file IS the arc####.dat file
    2161             :          * Note: sTableDef.szDataFile must be relative to info directory
    2162             :          *------------------------------------------------------------*/
    2163           0 :         _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat",
    2164             :                                    eCoverType, pszFname, nFnameLen);
    2165           0 :         snprintf(sTableDef.szDataFile, sizeof(sTableDef.szDataFile), "%s",
    2166           0 :                  pszFname + strlen(pszInfoPath));
    2167             :     }
    2168             : 
    2169             :     /*-----------------------------------------------------------------
    2170             :      * Read the table field definitions from the "arc####.nit" file.
    2171             :      *----------------------------------------------------------------*/
    2172           7 :     _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "nit",
    2173             :                                eCoverType, pszFname, nFnameLen);
    2174           7 :     AVCAdjustCaseSensitiveFilename(pszFname);
    2175             : 
    2176           7 :     hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
    2177             :                           psDBCSInfo);
    2178             : 
    2179           7 :     if (hFile)
    2180             :     {
    2181             :         int iField;
    2182             : 
    2183           7 :         pasFieldDef = (AVCFieldInfo *)CPLCalloc(sTableDef.numFields,
    2184             :                                                 sizeof(AVCFieldInfo));
    2185             : 
    2186             :         /*-------------------------------------------------------------
    2187             :          * There must be at least sTableDef.numFields valid entries
    2188             :          * in the .NIT file...
    2189             :          *
    2190             :          * Note that we ignore any deleted field entries (entries with
    2191             :          * index=-1)... I don't see any use for these deleted fields...
    2192             :          * and I don't understand why Arc/Info includes them in their
    2193             :          * E00 table headers...
    2194             :          *------------------------------------------------------------*/
    2195          38 :         for (i = 0, iField = 0; iField < sTableDef.numFields; i++)
    2196             :         {
    2197          31 :             if (_AVCBinReadNextArcNit(hFile, &(pasFieldDef[iField])) != 0)
    2198             :             {
    2199             :                 /* Problems.... is the NIT file corrupt???
    2200             :                  */
    2201           0 :                 AVCRawBinClose(hFile);
    2202           0 :                 CPLFree(pszFname);
    2203           0 :                 CPLFree(pasFieldDef);
    2204           0 :                 CPLError(CE_Failure, CPLE_FileIO,
    2205             :                          "Failed reading table field info for table %s "
    2206             :                          "File may be corrupt?",
    2207             :                          pszTableName);
    2208           0 :                 return nullptr;
    2209             :             }
    2210             : 
    2211             :             /*---------------------------------------------------------
    2212             :              * Check if the field has been deleted (nIndex == -1).
    2213             :              * We just ignore deleted fields
    2214             :              *--------------------------------------------------------*/
    2215          31 :             if (pasFieldDef[iField].nIndex > 0)
    2216          31 :                 iField++;
    2217             :         }
    2218             : 
    2219           7 :         AVCRawBinClose(hFile);
    2220             :     }
    2221             :     else
    2222             :     {
    2223           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
    2224             :                  pszFname);
    2225           0 :         CPLFree(pszFname);
    2226           0 :         return nullptr;
    2227             :     }
    2228             : 
    2229             :     /*-----------------------------------------------------------------
    2230             :      * Open the data file... ready to read records from it.
    2231             :      * If the header says that table has 0 records, then we don't
    2232             :      * try to open the file... but we don't consider that as an error.
    2233             :      *----------------------------------------------------------------*/
    2234          14 :     if (sTableDef.numRecords > 0 &&
    2235           7 :         AVCFileExists(pszInfoPath, sTableDef.szDataFile))
    2236             :     {
    2237             :         VSIStatBufL sStatBuf;
    2238             : 
    2239           7 :         snprintf(pszFname, nFnameLen, "%s%s", pszInfoPath,
    2240             :                  sTableDef.szDataFile);
    2241           7 :         AVCAdjustCaseSensitiveFilename(pszFname);
    2242             : 
    2243           7 :         hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
    2244             :                               psDBCSInfo);
    2245             : 
    2246             :         /* OOPS... data file does not exist!
    2247             :          */
    2248           7 :         if (hFile == nullptr)
    2249             :         {
    2250           0 :             CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
    2251             :                      pszFname);
    2252           0 :             CPLFree(pszFname);
    2253           0 :             return nullptr;
    2254             :         }
    2255             : 
    2256             :         /*-------------------------------------------------------------
    2257             :          * In some cases, the number of records field for a table in the
    2258             :          * arc.dir does not correspond to the real number of records
    2259             :          * in the data file.  In this kind of situation, the number of
    2260             :          * records returned by Arc/Info in an E00 file will be based
    2261             :          * on the real data file size, and not on the value from the arc.dir.
    2262             :          *
    2263             :          * Fetch the data file size, and correct the number of record
    2264             :          * field in the table header if necessary.
    2265             :          *------------------------------------------------------------*/
    2266          14 :         if (VSIStatL(pszFname, &sStatBuf) != -1 && sTableDef.nRecSize > 0 &&
    2267           7 :             sStatBuf.st_size / sTableDef.nRecSize != sTableDef.numRecords)
    2268             :         {
    2269           0 :             sTableDef.numRecords = (int)(sStatBuf.st_size / sTableDef.nRecSize);
    2270             :         }
    2271             :     }
    2272             :     else
    2273             :     {
    2274           0 :         hFile = nullptr;
    2275           0 :         sTableDef.numRecords = 0;
    2276             :     }
    2277             : 
    2278             :     /*-----------------------------------------------------------------
    2279             :      * Alloc. and init. the AVCBinFile structure.
    2280             :      *----------------------------------------------------------------*/
    2281           7 :     psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
    2282             : 
    2283           7 :     psFile->psRawBinFile = hFile;
    2284           7 :     psFile->eCoverType = AVCCoverV7;
    2285           7 :     psFile->eFileType = AVCFileTABLE;
    2286           7 :     psFile->pszFilename = pszFname;
    2287             : 
    2288           7 :     psFile->hdr.psTableDef = (AVCTableDef *)CPLMalloc(sizeof(AVCTableDef));
    2289           7 :     *(psFile->hdr.psTableDef) = sTableDef;
    2290             : 
    2291           7 :     psFile->hdr.psTableDef->pasFieldDef = pasFieldDef;
    2292             : 
    2293             :     /* We can't really tell the precision from a Table header...
    2294             :      * just set an arbitrary value... it probably won't be used anyways!
    2295             :      */
    2296           7 :     psFile->nPrecision = AVC_SINGLE_PREC;
    2297             : 
    2298             :     /*-----------------------------------------------------------------
    2299             :      * Allocate temp. structures to use to read records from the file
    2300             :      * And allocate buffers for those fields that are stored as strings.
    2301             :      *----------------------------------------------------------------*/
    2302           7 :     psFile->cur.pasFields =
    2303           7 :         (AVCField *)CPLCalloc(sTableDef.numFields, sizeof(AVCField));
    2304             : 
    2305          38 :     for (i = 0; i < sTableDef.numFields; i++)
    2306             :     {
    2307          31 :         if (pasFieldDef[i].nType1 * 10 == AVC_FT_DATE ||
    2308          31 :             pasFieldDef[i].nType1 * 10 == AVC_FT_CHAR ||
    2309          28 :             pasFieldDef[i].nType1 * 10 == AVC_FT_FIXINT ||
    2310          28 :             pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM)
    2311             :         {
    2312           6 :             psFile->cur.pasFields[i].pszStr =
    2313           3 :                 (GByte *)CPLCalloc(pasFieldDef[i].nSize + 1, sizeof(char));
    2314             :         }
    2315             :     }
    2316             : 
    2317           7 :     return psFile;
    2318             : }
    2319             : 
    2320             : /**********************************************************************
    2321             :  *                         _AVCBinReadNextTableRec()
    2322             :  *
    2323             :  * (This function is for internal library use... external calls should
    2324             :  * go to AVCBinReadNextTableRec() instead)
    2325             :  *
    2326             :  * Reads the next record from an attribute table and fills the
    2327             :  * pasFields[] array.
    2328             :  *
    2329             :  * Note that it is assumed that the pasFields[] array has been properly
    2330             :  * initialized, re the allocation of buffers for fields stored as
    2331             :  * strings.
    2332             :  *
    2333             :  * Returns 0 on success or -1 on error.
    2334             :  **********************************************************************/
    2335         168 : static int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields,
    2336             :                                    AVCFieldInfo *pasDef, AVCField *pasFields,
    2337             :                                    int nRecordSize)
    2338             : {
    2339         168 :     int i, nType, nBytesRead = 0;
    2340             : 
    2341         168 :     if (psFile == nullptr)
    2342           0 :         return -1;
    2343             : 
    2344        1000 :     for (i = 0; i < nFields; i++)
    2345             :     {
    2346         832 :         if (AVCRawBinEOF(psFile))
    2347           0 :             return -1;
    2348             : 
    2349         832 :         nType = pasDef[i].nType1 * 10;
    2350             : 
    2351         832 :         if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
    2352         672 :             nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
    2353             :         {
    2354             :             /*---------------------------------------------------------
    2355             :              * Values stored as strings
    2356             :              *--------------------------------------------------------*/
    2357         160 :             AVCRawBinReadString(psFile, pasDef[i].nSize, pasFields[i].pszStr);
    2358         160 :             pasFields[i].pszStr[pasDef[i].nSize] = '\0';
    2359             :         }
    2360         672 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
    2361             :         {
    2362             :             /*---------------------------------------------------------
    2363             :              * 32 bit binary integers
    2364             :              *--------------------------------------------------------*/
    2365         336 :             pasFields[i].nInt32 = AVCRawBinReadInt32(psFile);
    2366             :         }
    2367         336 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
    2368             :         {
    2369             :             /*---------------------------------------------------------
    2370             :              * 16 bit binary integers
    2371             :              *--------------------------------------------------------*/
    2372           0 :             pasFields[i].nInt16 = AVCRawBinReadInt16(psFile);
    2373             :         }
    2374         336 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
    2375             :         {
    2376             :             /*---------------------------------------------------------
    2377             :              * Single precision floats
    2378             :              *--------------------------------------------------------*/
    2379         336 :             pasFields[i].fFloat = AVCRawBinReadFloat(psFile);
    2380             :         }
    2381           0 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
    2382             :         {
    2383             :             /*---------------------------------------------------------
    2384             :              * Double precision floats
    2385             :              *--------------------------------------------------------*/
    2386           0 :             pasFields[i].dDouble = AVCRawBinReadDouble(psFile);
    2387             :         }
    2388             :         else
    2389             :         {
    2390             :             /*---------------------------------------------------------
    2391             :              * Hummm... unsupported field type...
    2392             :              *--------------------------------------------------------*/
    2393           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2394             :                      "Unsupported field type: (type=%d, size=%d)", nType,
    2395           0 :                      pasDef[i].nSize);
    2396           0 :             return -1;
    2397             :         }
    2398             : 
    2399         832 :         nBytesRead += pasDef[i].nSize;
    2400             :     }
    2401             : 
    2402             :     /*-----------------------------------------------------------------
    2403             :      * Record size is rounded to a multiple of 2 bytes.
    2404             :      * Check the number of bytes read, and move the read pointer if
    2405             :      * necessary.
    2406             :      *----------------------------------------------------------------*/
    2407         168 :     if (nBytesRead < nRecordSize)
    2408           0 :         AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
    2409             : 
    2410         168 :     return 0;
    2411             : }
    2412             : 
    2413             : /*=====================================================================
    2414             :  *                         PC Arc/Info DBF TABLEs
    2415             :  *====================================================================*/
    2416             : 
    2417             : void _AVCBinReadRepairDBFFieldName(char *pszFieldName);
    2418             : 
    2419             : /**********************************************************************
    2420             :  *                         _AVCBinReadOpenDBFTable()
    2421             :  *
    2422             :  * (This function is for internal library use... external calls should
    2423             :  * go to AVCBinReadOpen() with type AVCCoverPC/AVCFileTABLE instead)
    2424             :  *
    2425             :  * Open the DBF table, reads the header information and inits the
    2426             :  * AVCBinFile handle to be ready to read records from it.
    2427             :  *
    2428             :  * Returns a valid AVCBinFile handle, or nullptr if the file could
    2429             :  * not be opened.
    2430             :  *
    2431             :  * _AVCBinReadCloseDBFTable() will eventually have to be called to release the
    2432             :  * resources used by the AVCBinFile structure.
    2433             :  **********************************************************************/
    2434           0 : AVCBinFile *_AVCBinReadOpenDBFTable(const char *pszDBFFilename,
    2435             :                                     const char *pszArcInfoTableName)
    2436             : {
    2437             :     AVCBinFile *psFile;
    2438           0 :     DBFHandle hDBFFile = nullptr;
    2439             :     int iField;
    2440             :     AVCTableDef *psTableDef;
    2441             :     AVCFieldInfo *pasFieldDef;
    2442             : 
    2443             :     /*-----------------------------------------------------------------
    2444             :      * Try to open the DBF file
    2445             :      *----------------------------------------------------------------*/
    2446           0 :     if ((hDBFFile = DBFOpen(pszDBFFilename, "rb")) == nullptr)
    2447             :     {
    2448           0 :         CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open table %s",
    2449             :                  pszDBFFilename);
    2450           0 :         return nullptr;
    2451             :     }
    2452             : 
    2453             :     /*-----------------------------------------------------------------
    2454             :      * Alloc. and init. the AVCBinFile structure.
    2455             :      *----------------------------------------------------------------*/
    2456           0 :     psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
    2457             : 
    2458           0 :     psFile->hDBFFile = hDBFFile;
    2459             : 
    2460           0 :     psFile->eCoverType = AVCCoverPC;
    2461           0 :     psFile->eFileType = AVCFileTABLE;
    2462           0 :     psFile->pszFilename = CPLStrdup(pszDBFFilename);
    2463             : 
    2464           0 :     psFile->hdr.psTableDef = nullptr;
    2465             : 
    2466             :     /* nCurDBFRecord is used to keep track of the 0-based index of the
    2467             :      * last record we read from the DBF file... this is to emulate
    2468             :      * sequential access which is assumed by the rest of the lib.
    2469             :      * Since the first record (record 0) has not been read yet, then
    2470             :      * we init the index at -1.
    2471             :      */
    2472           0 :     psFile->nCurDBFRecord = -1;
    2473             : 
    2474             :     /* We can't really tell the precision from a Table header...
    2475             :      * just set an arbitrary value... it probably won't be used anyways!
    2476             :      */
    2477           0 :     psFile->nPrecision = AVC_SINGLE_PREC;
    2478             : 
    2479             :     /*-----------------------------------------------------------------
    2480             :      * Build TableDef from the info in the DBF header
    2481             :      *----------------------------------------------------------------*/
    2482             :     /* Use calloc() to init some unused struct members */
    2483           0 :     psTableDef = (AVCTableDef *)CPLCalloc(1, sizeof(AVCTableDef));
    2484           0 :     psFile->hdr.psTableDef = psTableDef;
    2485             : 
    2486           0 :     snprintf(psTableDef->szTableName, sizeof(psTableDef->szTableName),
    2487             :              "%-32.32s", pszArcInfoTableName);
    2488             : 
    2489           0 :     psTableDef->numFields = (GInt16)DBFGetFieldCount(hDBFFile);
    2490             : 
    2491             :     /* We'll compute nRecSize value when we read fields info later */
    2492           0 :     psTableDef->nRecSize = 0;
    2493             : 
    2494           0 :     psTableDef->numRecords = DBFGetRecordCount(hDBFFile);
    2495             : 
    2496             :     /* All DBF tables are considered External */
    2497           0 :     strcpy(psTableDef->szExternal, "XX");
    2498             : 
    2499             :     /*-----------------------------------------------------------------
    2500             :      * Build Field definitions
    2501             :      *----------------------------------------------------------------*/
    2502             :     pasFieldDef =
    2503           0 :         (AVCFieldInfo *)CPLCalloc(psTableDef->numFields, sizeof(AVCFieldInfo));
    2504             : 
    2505           0 :     psTableDef->pasFieldDef = pasFieldDef;
    2506             : 
    2507           0 :     for (iField = 0; iField < psTableDef->numFields; iField++)
    2508             :     {
    2509           0 :         int nWidth = 0, nDecimals = 0;
    2510             :         /* DBFFieldType eDBFType; */
    2511             : 
    2512             :         /*-------------------------------------------------------------
    2513             :          * Fetch DBF Field info and convert to Arc/Info type...
    2514             :          * Note that since DBF fields names are limited to 10 chars,
    2515             :          * we do not have to worry about field name length in the process.
    2516             :          *------------------------------------------------------------*/
    2517             :         /* eDBFType = */
    2518           0 :         DBFGetFieldInfo(hDBFFile, iField, pasFieldDef[iField].szName, &nWidth,
    2519             :                         &nDecimals);
    2520           0 :         const char cNativeType = DBFGetNativeFieldType(hDBFFile, iField);
    2521             : 
    2522           0 :         pasFieldDef[iField].nFmtWidth = (GInt16)nWidth;
    2523           0 :         pasFieldDef[iField].nFmtPrec = (GInt16)nDecimals;
    2524             : 
    2525             :         /* nIndex is the 1-based field index that we see in the E00 header */
    2526           0 :         pasFieldDef[iField].nIndex = (GInt16)(iField + 1);
    2527             : 
    2528           0 :         if (cNativeType == 'F' || (cNativeType == 'N' && nDecimals > 0))
    2529             :         {
    2530             :             /*---------------------------------------------------------
    2531             :              * BINARY FLOAT
    2532             :              *--------------------------------------------------------*/
    2533           0 :             pasFieldDef[iField].nType1 = AVC_FT_BINFLOAT / 10;
    2534           0 :             pasFieldDef[iField].nSize = 4;
    2535           0 :             pasFieldDef[iField].nFmtWidth = 12; /* PC Arc/Info ignores the */
    2536           0 :             pasFieldDef[iField].nFmtPrec = 3;   /* DBF width/precision     */
    2537             :         }
    2538           0 :         else if (cNativeType == 'N')
    2539             :         {
    2540             :             /*---------------------------------------------------------
    2541             :              * BINARY INTEGER
    2542             :              *--------------------------------------------------------*/
    2543           0 :             pasFieldDef[iField].nType1 = AVC_FT_BININT / 10;
    2544           0 :             pasFieldDef[iField].nSize = 4;
    2545           0 :             pasFieldDef[iField].nFmtWidth = 5; /* PC Arc/Info ignores the */
    2546           0 :             pasFieldDef[iField].nFmtPrec = -1; /* DBF width/precision     */
    2547             : 
    2548             :             /*---------------------------------------------------------
    2549             :              * Some special integer fields need to have their names
    2550             :              * repaired because DBF does not support special characters.
    2551             :              *--------------------------------------------------------*/
    2552           0 :             _AVCBinReadRepairDBFFieldName(pasFieldDef[iField].szName);
    2553             :         }
    2554           0 :         else if (cNativeType == 'D')
    2555             :         {
    2556             :             /*---------------------------------------------------------
    2557             :              * DATE - Actually handled as a string internally
    2558             :              *--------------------------------------------------------*/
    2559           0 :             pasFieldDef[iField].nType1 = AVC_FT_DATE / 10;
    2560           0 :             pasFieldDef[iField].nSize = (GInt16)nWidth;
    2561           0 :             pasFieldDef[iField].nFmtPrec = -1;
    2562             :         }
    2563             :         else /* (cNativeType == 'C' || cNativeType == 'L') */
    2564             :         {
    2565             :             /*---------------------------------------------------------
    2566             :              * CHAR STRINGS ... and all unknown types also handled as strings
    2567             :              *--------------------------------------------------------*/
    2568           0 :             pasFieldDef[iField].nType1 = AVC_FT_CHAR / 10;
    2569           0 :             pasFieldDef[iField].nSize = (GInt16)nWidth;
    2570           0 :             pasFieldDef[iField].nFmtPrec = -1;
    2571             :         }
    2572             : 
    2573             :         /*---------------------------------------------------------
    2574             :          * Keep track of position of field in record... first one always
    2575             :          * starts at offset=1
    2576             :          *--------------------------------------------------------*/
    2577           0 :         if (iField == 0)
    2578           0 :             pasFieldDef[iField].nOffset = 1;
    2579             :         else
    2580           0 :             pasFieldDef[iField].nOffset = (pasFieldDef[iField - 1].nOffset +
    2581           0 :                                            pasFieldDef[iField - 1].nSize);
    2582             : 
    2583             :         /*---------------------------------------------------------
    2584             :          * Set default values for all other unused members in the struct
    2585             :          *--------------------------------------------------------*/
    2586           0 :         pasFieldDef[iField].v2 = -1;    /* Always -1 ? */
    2587           0 :         pasFieldDef[iField].v4 = 4;     /* Always 4 ?  */
    2588           0 :         pasFieldDef[iField].v5 = -1;    /* Always -1 ? */
    2589           0 :         pasFieldDef[iField].nType2 = 0; /* Always 0 ?  */
    2590           0 :         pasFieldDef[iField].v10 = -1;   /* Always -1 ? */
    2591           0 :         pasFieldDef[iField].v11 = -1;   /* Always -1 ? */
    2592           0 :         pasFieldDef[iField].v12 = -1;   /* Always -1 ? */
    2593           0 :         pasFieldDef[iField].v13 = -1;   /* Always -1 ? */
    2594             :     }
    2595             : 
    2596             :     /*-----------------------------------------------------------------
    2597             :      * Compute record size...
    2598             :      * Record size has to be rounded to a multiple of 2 bytes.
    2599             :      *----------------------------------------------------------------*/
    2600           0 :     if (psTableDef->numFields > 0)
    2601             :     {
    2602           0 :         psTableDef->nRecSize =
    2603           0 :             (pasFieldDef[psTableDef->numFields - 1].nOffset - 1 +
    2604           0 :              pasFieldDef[psTableDef->numFields - 1].nSize);
    2605           0 :         psTableDef->nRecSize = ((psTableDef->nRecSize + 1) / 2) * 2;
    2606             :     }
    2607             :     else
    2608           0 :         psTableDef->nRecSize = 0;
    2609             : 
    2610             :     /*-----------------------------------------------------------------
    2611             :      * Allocate temp. structures to use to read records from the file
    2612             :      * And allocate buffers for those fields that are stored as strings.
    2613             :      *----------------------------------------------------------------*/
    2614           0 :     psFile->cur.pasFields =
    2615           0 :         (AVCField *)CPLCalloc(psTableDef->numFields, sizeof(AVCField));
    2616             : 
    2617           0 :     for (iField = 0; iField < psTableDef->numFields; iField++)
    2618             :     {
    2619           0 :         if (pasFieldDef[iField].nType1 * 10 == AVC_FT_DATE ||
    2620           0 :             pasFieldDef[iField].nType1 * 10 == AVC_FT_CHAR ||
    2621           0 :             pasFieldDef[iField].nType1 * 10 == AVC_FT_FIXINT ||
    2622           0 :             pasFieldDef[iField].nType1 * 10 == AVC_FT_FIXNUM)
    2623             :         {
    2624           0 :             psFile->cur.pasFields[iField].pszStr = (GByte *)CPLCalloc(
    2625           0 :                 pasFieldDef[iField].nSize + 1, sizeof(GByte));
    2626             :         }
    2627             :     }
    2628             : 
    2629           0 :     return psFile;
    2630             : }
    2631             : 
    2632             : /**********************************************************************
    2633             :  *                         _AVCBinReadNextDBFTableRec()
    2634             :  *
    2635             :  * (This function is for internal library use... external calls should
    2636             :  * go to AVCBinReadNextTableRec() instead)
    2637             :  *
    2638             :  * Reads the next record from a AVCCoverPC DBF attribute table and fills the
    2639             :  * pasFields[] array.
    2640             :  *
    2641             :  * Note that it is assumed that the pasFields[] array has been properly
    2642             :  * initialized, re the allocation of buffers for fields stored as
    2643             :  * strings.
    2644             :  *
    2645             :  * Returns 0 on success or -1 on error.
    2646             :  **********************************************************************/
    2647           0 : static int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex,
    2648             :                                       int nFields, AVCFieldInfo *pasDef,
    2649             :                                       AVCField *pasFields)
    2650             : {
    2651             :     int i, nType;
    2652             : 
    2653             :     /*-----------------------------------------------------------------
    2654             :      * Increment current record index.
    2655             :      * We use nCurDBFRecord to keep track of the 0-based index of the
    2656             :      * last record we read from the DBF file... this is to emulate
    2657             :      * sequential access which is assumed by the rest of the lib.
    2658             :      *----------------------------------------------------------------*/
    2659           0 :     if (hDBFFile == nullptr || piRecordIndex == nullptr || pasDef == nullptr ||
    2660             :         pasFields == nullptr)
    2661           0 :         return -1;
    2662             : 
    2663           0 :     (*piRecordIndex)++;
    2664             : 
    2665           0 :     if (*piRecordIndex >= DBFGetRecordCount(hDBFFile))
    2666           0 :         return -1; /* Reached EOF */
    2667             : 
    2668             :     /*-----------------------------------------------------------------
    2669             :      * Read/convert each field based on type
    2670             :      *----------------------------------------------------------------*/
    2671           0 :     for (i = 0; i < nFields; i++)
    2672             :     {
    2673           0 :         nType = pasDef[i].nType1 * 10;
    2674             : 
    2675           0 :         if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
    2676           0 :             nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
    2677             :         {
    2678             :             /*---------------------------------------------------------
    2679             :              * Values stored as strings
    2680             :              *--------------------------------------------------------*/
    2681             :             const char *pszValue;
    2682           0 :             pszValue = DBFReadStringAttribute(hDBFFile, *piRecordIndex, i);
    2683           0 :             strncpy((char *)pasFields[i].pszStr, pszValue, pasDef[i].nSize);
    2684           0 :             pasFields[i].pszStr[pasDef[i].nSize] = '\0';
    2685             :         }
    2686           0 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
    2687             :         {
    2688             :             /*---------------------------------------------------------
    2689             :              * 32 bit binary integers
    2690             :              *--------------------------------------------------------*/
    2691           0 :             pasFields[i].nInt32 =
    2692           0 :                 DBFReadIntegerAttribute(hDBFFile, *piRecordIndex, i);
    2693             :         }
    2694           0 :         else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
    2695             :         {
    2696             :             /*---------------------------------------------------------
    2697             :              * 16 bit binary integers
    2698             :              *--------------------------------------------------------*/
    2699           0 :             pasFields[i].nInt16 =
    2700           0 :                 (GInt16)DBFReadIntegerAttribute(hDBFFile, *piRecordIndex, i);
    2701             :         }
    2702           0 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
    2703             :         {
    2704             :             /*---------------------------------------------------------
    2705             :              * Single precision floats
    2706             :              *--------------------------------------------------------*/
    2707           0 :             pasFields[i].fFloat =
    2708           0 :                 (float)DBFReadDoubleAttribute(hDBFFile, *piRecordIndex, i);
    2709             :         }
    2710           0 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
    2711             :         {
    2712             :             /*---------------------------------------------------------
    2713             :              * Double precision floats
    2714             :              *--------------------------------------------------------*/
    2715           0 :             pasFields[i].dDouble =
    2716           0 :                 DBFReadDoubleAttribute(hDBFFile, *piRecordIndex, i);
    2717             :         }
    2718             :         else
    2719             :         {
    2720             :             /*---------------------------------------------------------
    2721             :              * Hummm... unsupported field type...
    2722             :              *--------------------------------------------------------*/
    2723           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2724             :                      "Unsupported field type: (type=%d, size=%d)", nType,
    2725           0 :                      pasDef[i].nSize);
    2726           0 :             return -1;
    2727             :         }
    2728             :     }
    2729             : 
    2730           0 :     return 0;
    2731             : }
    2732             : 
    2733             : /**********************************************************************
    2734             :  *                         _AVCBinReadRepairDBFFieldName()
    2735             :  *
    2736             :  * Attempt to repair some special integer field names that usually
    2737             :  * carry special chars such as '#' or '-' but that are lost because of
    2738             :  * DBF limitations and are replaced by '_'.
    2739             :  *
    2740             :  **********************************************************************/
    2741           0 : void _AVCBinReadRepairDBFFieldName(char *pszFieldName)
    2742             : {
    2743             :     char *pszTmp;
    2744             : 
    2745           0 :     if ((pszTmp = strrchr(pszFieldName, '_')) == nullptr)
    2746           0 :         return; /* No special char to process */
    2747             : 
    2748             :     /*-----------------------------------------------------------------
    2749             :      * Replace '_' at end of field name by a '#', as in:
    2750             :      *   COVER# , FNODE#, TNODE#, LPOLY#, RPOLY#
    2751             :      *
    2752             :      * and replace names that end with "_ID" with "-ID" as in COVER-ID
    2753             :      *----------------------------------------------------------------*/
    2754           0 :     if (EQUAL(pszTmp, "_"))
    2755           0 :         *pszTmp = '#';
    2756           0 :     else if (EQUAL(pszTmp, "_ID"))
    2757           0 :         *pszTmp = '-';
    2758             : }

Generated by: LCOV version 1.14