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

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

Generated by: LCOV version 1.14