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

Generated by: LCOV version 1.14