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

Generated by: LCOV version 1.14