LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/avc - avc_bin.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 806 309 38.3 %
Date: 2010-01-09 Functions: 34 17 50.0 %

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

Generated by: LCOV version 1.7