LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - avc_e00parse.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 440 802 54.9 %
Date: 2024-11-21 22:18:42 Functions: 19 22 86.4 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Name:     avc_e00parse.c
       5             :  * Project:  Arc/Info vector coverage (AVC)  E00->BIN conversion library
       6             :  * Language: ANSI C
       7             :  * Purpose:  Functions to parse ASCII E00 lines and fill binary structures.
       8             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9             :  *
      10             :  **********************************************************************
      11             :  * Copyright (c) 1999-2005, Daniel Morissette
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  **********************************************************************
      15             :  *
      16             :  * $Log: avc_e00parse.c,v $
      17             :  * Revision 1.19  2008/07/23 20:51:38  dmorissette
      18             :  * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
      19             :  * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
      20             :  *
      21             :  * Revision 1.18  2006/06/27 18:06:34  dmorissette
      22             :  * Applied patch for EOP processing from James F. (bug 1497)
      23             :  *
      24             :  * Revision 1.17  2006/06/19 14:35:47  dmorissette
      25             :  * New patch from James F. for E00 read support in OGR (bug 1497)
      26             :  *
      27             :  * Revision 1.16  2006/06/16 11:48:11  daniel
      28             :  * New functions to read E00 files directly as opposed to translating to
      29             :  * binary coverage. Used in the implementation of E00 read support in OGR.
      30             :  * Contributed by James E. Flemer. (bug 1497)
      31             :  *
      32             :  * Revision 1.15  2006/03/02 22:46:26  daniel
      33             :  * Accept empty subclass names for TX6/TX7 sections (bug 1261)
      34             :  *
      35             :  * Revision 1.14  2005/06/03 03:49:58  daniel
      36             :  * Update email address, website url, and copyright dates
      37             :  *
      38             :  * Revision 1.13  2002/08/27 15:43:02  daniel
      39             :  * Small typo in type 40 fix (forgot to commit to CVS on 2002-08-05)
      40             :  *
      41             :  * Revision 1.12  2002/08/05 20:20:17  daniel
      42             :  * Fixed parsing type 40 fields to properly detect negative exp. (bug 1272)
      43             :  *
      44             :  * Revision 1.11  2001/11/25 21:15:23  daniel
      45             :  * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
      46             :  * digits to double precision as we generate E00 output (bug599)
      47             :  *
      48             :  * Revision 1.10  2001/11/25 19:45:32  daniel
      49             :  * Fixed reading of type 40 when not in exponent format (bug599)
      50             :  *
      51             :  * Revision 1.9  2001/07/12 20:59:34  daniel
      52             :  * Properly handle PAL entries with 0 arcs
      53             :  *
      54             :  * Revision 1.8  2000/09/22 19:45:20  daniel
      55             :  * Switch to MIT-style license
      56             :  *
      57             :  * Revision 1.7  2000/03/16 03:48:00  daniel
      58             :  * Accept 0-length text strings in TX6/TX7 objects
      59             :  *
      60             :  * Revision 1.6  2000/02/03 07:21:40  daniel
      61             :  * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks
      62             :  *
      63             :  * Revision 1.5  1999/12/05 03:40:13  daniel
      64             :  * Fixed signed/unsigned mismatch compile warning
      65             :  *
      66             :  * Revision 1.4  1999/11/23 05:27:58  daniel
      67             :  * Added AVCE00Str2Int() to extract integer values in E00 lines
      68             :  *
      69             :  * Revision 1.3  1999/08/23 18:20:49  daniel
      70             :  * Fixed support for attribute fields type 40
      71             :  *
      72             :  * Revision 1.2  1999/05/17 16:20:48  daniel
      73             :  * Added RXP + TXT/TX6/TX7 write support + some simple problems fixed
      74             :  *
      75             :  * Revision 1.1  1999/05/11 02:34:46  daniel
      76             :  * Initial revision
      77             :  *
      78             :  **********************************************************************/
      79             : 
      80             : #include "avc.h"
      81             : 
      82             : #include <ctype.h> /* toupper() */
      83             : 
      84             : /**********************************************************************
      85             :  *                          AVCE00Str2Int()
      86             :  *
      87             :  * Convert a portion of a string to an integer value.
      88             :  * The difference between this function and atoi() is that this version
      89             :  * takes only the specified number of characters... so it can handle the
      90             :  * case of 2 numbers that are part of the same string but are not separated
      91             :  * by a space.
      92             :  **********************************************************************/
      93        8001 : static int AVCE00Str2Int(const char *pszStr, int numChars)
      94             : {
      95        8001 :     int nValue = 0;
      96             : 
      97        8001 :     if (pszStr && numChars >= (int)strlen(pszStr))
      98         314 :         return atoi(pszStr);
      99        7687 :     else if (pszStr)
     100             :     {
     101             :         char cNextDigit;
     102             :         char *pszTmp;
     103             : 
     104             :         /* Get rid of const */
     105        7687 :         pszTmp = (char *)pszStr;
     106             : 
     107        7687 :         cNextDigit = pszTmp[numChars];
     108        7687 :         pszTmp[numChars] = '\0';
     109        7687 :         nValue = atoi(pszTmp);
     110        7687 :         pszTmp[numChars] = cNextDigit;
     111             :     }
     112             : 
     113        7687 :     return nValue;
     114             : }
     115             : 
     116             : /**********************************************************************
     117             :  *                          AVCE00ParseInfoAlloc()
     118             :  *
     119             :  * Allocate and initialize a new AVCE00ParseInfo structure.
     120             :  *
     121             :  * AVCE00ParseStartSection() will have to be called at least once
     122             :  * to specify the type of objects to parse.
     123             :  *
     124             :  * The structure will eventually have to be freed with AVCE00ParseInfoFree().
     125             :  **********************************************************************/
     126          11 : AVCE00ParseInfo *AVCE00ParseInfoAlloc(void)
     127             : {
     128             :     AVCE00ParseInfo *psInfo;
     129             : 
     130          11 :     psInfo = new AVCE00ParseInfo();
     131             : 
     132             :     /* Allocate output buffer.
     133             :      * 2k should be enough... the biggest thing we'll need to store
     134             :      * in it will be 1 complete INFO table record.
     135             :      */
     136          11 :     psInfo->nBufSize = 2048;
     137          11 :     psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize * sizeof(char));
     138             : 
     139             :     /* Set a default precision, but this value will be set on a section
     140             :      * by section basis inside AVCE00ParseStartSection()
     141             :      */
     142          11 :     psInfo->nPrecision = AVC_SINGLE_PREC;
     143             : 
     144          11 :     return psInfo;
     145             : }
     146             : 
     147             : /**********************************************************************
     148             :  *                         _AVCE00ParseDestroyCurObject()
     149             :  *
     150             :  * Release mem. associated with the psInfo->cur.* object we are
     151             :  * currently using.
     152             :  **********************************************************************/
     153         314 : static void _AVCE00ParseDestroyCurObject(AVCE00ParseInfo *psInfo)
     154             : {
     155         314 :     if (psInfo->eFileType == AVCFileUnknown)
     156         169 :         return;
     157             : 
     158         145 :     if (psInfo->eFileType == AVCFileARC)
     159             :     {
     160          22 :         CPLFree(psInfo->cur.psArc->pasVertices);
     161          22 :         CPLFree(psInfo->cur.psArc);
     162          22 :         psInfo->cur.psArc = nullptr;
     163             :     }
     164         123 :     else if (psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileRPL)
     165             :     {
     166          10 :         CPLFree(psInfo->cur.psPal->pasArcs);
     167          10 :         CPLFree(psInfo->cur.psPal);
     168          10 :         psInfo->cur.psPal = nullptr;
     169             :     }
     170         113 :     else if (psInfo->eFileType == AVCFileCNT)
     171             :     {
     172          10 :         CPLFree(psInfo->cur.psCnt->panLabelIds);
     173          10 :         CPLFree(psInfo->cur.psCnt);
     174          10 :         psInfo->cur.psCnt = nullptr;
     175             :     }
     176         103 :     else if (psInfo->eFileType == AVCFileLAB)
     177             :     {
     178          19 :         CPLFree(psInfo->cur.psLab);
     179          19 :         psInfo->cur.psLab = nullptr;
     180             :     }
     181          84 :     else if (psInfo->eFileType == AVCFileTOL)
     182             :     {
     183          17 :         CPLFree(psInfo->cur.psTol);
     184          17 :         psInfo->cur.psTol = nullptr;
     185             :     }
     186          67 :     else if (psInfo->eFileType == AVCFilePRJ)
     187             :     {
     188          12 :         psInfo->aosPrj.Clear();
     189             :     }
     190          55 :     else if (psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6)
     191             :     {
     192           0 :         CPLFree(psInfo->cur.psTxt->pasVertices);
     193           0 :         CPLFree(psInfo->cur.psTxt->pszText);
     194           0 :         CPLFree(psInfo->cur.psTxt);
     195           0 :         psInfo->cur.psTxt = nullptr;
     196             :     }
     197          55 :     else if (psInfo->eFileType == AVCFileRXP)
     198             :     {
     199           0 :         CPLFree(psInfo->cur.psRxp);
     200           0 :         psInfo->cur.psRxp = nullptr;
     201             :     }
     202          55 :     else if (psInfo->eFileType == AVCFileTABLE)
     203             :     {
     204          55 :         _AVCDestroyTableFields(psInfo->hdr.psTableDef, psInfo->cur.pasFields);
     205          55 :         _AVCDestroyTableDef(psInfo->hdr.psTableDef);
     206          55 :         psInfo->hdr.psTableDef = nullptr;
     207          55 :         psInfo->cur.pasFields = nullptr;
     208          55 :         psInfo->bTableHdrComplete = FALSE;
     209             :     }
     210             :     else
     211             :     {
     212           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     213             :                  "_AVCE00ParseDestroyCurObject(): Unsupported file type!");
     214             :     }
     215             : 
     216         145 :     psInfo->eFileType = AVCFileUnknown;
     217             : }
     218             : 
     219             : /**********************************************************************
     220             :  *                          AVCE00ParseInfoFree()
     221             :  *
     222             :  * Free any memory associated with a AVCE00ParseInfo structure.
     223             :  **********************************************************************/
     224          11 : void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo)
     225             : {
     226          11 :     if (psInfo)
     227             :     {
     228          11 :         CPLFree(psInfo->pszSectionHdrLine);
     229          11 :         psInfo->pszSectionHdrLine = nullptr;
     230          11 :         CPLFree(psInfo->pszBuf);
     231          11 :         _AVCE00ParseDestroyCurObject(psInfo);
     232             :     }
     233             : 
     234          11 :     delete psInfo;
     235          11 : }
     236             : 
     237             : /**********************************************************************
     238             :  *                          AVCE00ParseReset()
     239             :  *
     240             :  * Reset the fields in a AVCE00ParseInfo structure so that further calls
     241             :  * to the API will be ready to process a new object.
     242             :  **********************************************************************/
     243         158 : void AVCE00ParseReset(AVCE00ParseInfo *psInfo)
     244             : {
     245         158 :     psInfo->iCurItem = psInfo->numItems = 0;
     246         158 :     psInfo->bForceEndOfSection = FALSE;
     247         158 : }
     248             : 
     249             : /**********************************************************************
     250             :  *                          AVCE00ParseSuperSectionHeader()
     251             :  *
     252             :  * Check if pszLine is a valid "supersection" header line, if it is one
     253             :  * then store the supersection type in the ParseInfo structure.
     254             :  *
     255             :  * What I call a "supersection" is a section that contains several
     256             :  * files, such as the TX6/TX7, RPL, RXP, ... and also the IFO (TABLEs).
     257             :  *
     258             :  * The ParseInfo structure won't be ready to read objects until
     259             :  * a call to AVCE00ParseSectionHeader() (see below) successfully
     260             :  * recognizes the beginning of a subsection of this type.
     261             :  *
     262             :  * Returns the new supersection type, or AVCFileUnknown if the line is
     263             :  * not recognized.
     264             :  **********************************************************************/
     265         276 : AVCFileType AVCE00ParseSuperSectionHeader(AVCE00ParseInfo *psInfo,
     266             :                                           const char *pszLine)
     267             : {
     268             :     /*-----------------------------------------------------------------
     269             :      * If we're already inside a supersection or a section, then
     270             :      * return AVCFileUnknown right away.
     271             :      *----------------------------------------------------------------*/
     272         276 :     if (psInfo == nullptr || psInfo->eSuperSectionType != AVCFileUnknown ||
     273         221 :         psInfo->eFileType != AVCFileUnknown)
     274             :     {
     275          55 :         return AVCFileUnknown;
     276             :     }
     277             : 
     278             :     /*-----------------------------------------------------------------
     279             :      * Check if pszLine is a valid supersection header line.
     280             :      *----------------------------------------------------------------*/
     281         221 :     if (STARTS_WITH_CI(pszLine, "RPL  "))
     282           0 :         psInfo->eSuperSectionType = AVCFileRPL;
     283         221 :     else if (STARTS_WITH_CI(pszLine, "TX6  ") ||
     284         221 :              STARTS_WITH_CI(pszLine, "TX7  "))
     285           0 :         psInfo->eSuperSectionType = AVCFileTX6;
     286         221 :     else if (STARTS_WITH_CI(pszLine, "RXP  "))
     287           0 :         psInfo->eSuperSectionType = AVCFileRXP;
     288         221 :     else if (STARTS_WITH_CI(pszLine, "IFO  "))
     289          15 :         psInfo->eSuperSectionType = AVCFileTABLE;
     290             :     else
     291         206 :         return AVCFileUnknown;
     292             : 
     293             :     /*-----------------------------------------------------------------
     294             :      * Record the start of the supersection (for faster seeking)
     295             :      *----------------------------------------------------------------*/
     296          15 :     psInfo->nStartLineNum = psInfo->nCurLineNum;
     297             : 
     298             :     /*-----------------------------------------------------------------
     299             :      * OK, we have a valid new section header. Set the precision and
     300             :      * get ready to read objects from it.
     301             :      *----------------------------------------------------------------*/
     302          15 :     if (atoi(pszLine + 4) == 2)
     303          15 :         psInfo->nPrecision = AVC_SINGLE_PREC;
     304           0 :     else if (atoi(pszLine + 4) == 3)
     305           0 :         psInfo->nPrecision = AVC_DOUBLE_PREC;
     306             :     else
     307             :     {
     308           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     309             :                  "Parse Error: Invalid section header line (\"%s\")!", pszLine);
     310           0 :         psInfo->eSuperSectionType = AVCFileUnknown;
     311             :         /* psInfo->nStartLineNum = -1; */
     312             :     }
     313             : 
     314          15 :     return psInfo->eSuperSectionType;
     315             : }
     316             : 
     317             : /**********************************************************************
     318             :  *                          AVCE00ParseSuperSectionEnd()
     319             :  *
     320             :  * Check if pszLine marks the end of a supersection, and if it is the
     321             :  * case, then reset the supersection flag in the ParseInfo.
     322             :  *
     323             :  * Supersections always end with the line "JABBERWOCKY", except for
     324             :  * the IFO section.
     325             :  **********************************************************************/
     326        3121 : GBool AVCE00ParseSuperSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine)
     327             : {
     328        3121 :     if (psInfo->eFileType == AVCFileUnknown &&
     329         286 :         psInfo->eSuperSectionType != AVCFileUnknown &&
     330          65 :         (STARTS_WITH_CI(pszLine, "JABBERWOCKY") ||
     331          65 :          (psInfo->eSuperSectionType == AVCFileTABLE &&
     332          65 :           STARTS_WITH_CI(pszLine, "EOI"))))
     333             :     {
     334          10 :         psInfo->eSuperSectionType = AVCFileUnknown;
     335             :         /* psInfo->nStartLineNum = -1; */
     336          10 :         return TRUE;
     337             :     }
     338             : 
     339        3111 :     return FALSE;
     340             : }
     341             : 
     342             : /**********************************************************************
     343             :  *                          AVCE00ParseSectionHeader()
     344             :  *
     345             :  * Check if pszLine is a valid section header line, then initialize the
     346             :  * ParseInfo structure to be ready to parse of object from that section.
     347             :  *
     348             :  * Returns the new section type, or AVCFileUnknown if the line is
     349             :  * not recognized as a valid section header.
     350             :  *
     351             :  * Note: by section header lines, we mean the "ARC  2", "PAL  2", etc.
     352             :  **********************************************************************/
     353         261 : AVCFileType AVCE00ParseSectionHeader(AVCE00ParseInfo *psInfo,
     354             :                                      const char *pszLine)
     355             : {
     356         261 :     AVCFileType eNewType = AVCFileUnknown;
     357             : 
     358         261 :     if (psInfo == nullptr || psInfo->eFileType != AVCFileUnknown)
     359             :     {
     360           0 :         return AVCFileUnknown;
     361             :     }
     362             : 
     363             :     /*-----------------------------------------------------------------
     364             :      * Check if pszLine is a valid section header line.
     365             :      *----------------------------------------------------------------*/
     366         261 :     if (psInfo->eSuperSectionType == AVCFileUnknown)
     367             :     {
     368             :         /*-------------------------------------------------------------
     369             :          * We're looking for a top-level section...
     370             :          *------------------------------------------------------------*/
     371         206 :         if (STARTS_WITH_CI(pszLine, "ARC  "))
     372          22 :             eNewType = AVCFileARC;
     373         184 :         else if (STARTS_WITH_CI(pszLine, "PAL  "))
     374          10 :             eNewType = AVCFilePAL;
     375         174 :         else if (STARTS_WITH_CI(pszLine, "CNT  "))
     376          10 :             eNewType = AVCFileCNT;
     377         164 :         else if (STARTS_WITH_CI(pszLine, "LAB  "))
     378          19 :             eNewType = AVCFileLAB;
     379         145 :         else if (STARTS_WITH_CI(pszLine, "TOL  "))
     380          17 :             eNewType = AVCFileTOL;
     381         128 :         else if (STARTS_WITH_CI(pszLine, "PRJ  "))
     382          12 :             eNewType = AVCFilePRJ;
     383         116 :         else if (STARTS_WITH_CI(pszLine, "TXT  "))
     384           0 :             eNewType = AVCFileTXT;
     385             :         else
     386             :         {
     387         116 :             return AVCFileUnknown;
     388             :         }
     389             : 
     390             :         /*-------------------------------------------------------------
     391             :          * OK, we have a valid new section header. Set the precision and
     392             :          * get ready to read objects from it.
     393             :          *------------------------------------------------------------*/
     394          90 :         if (atoi(pszLine + 4) == 2)
     395          90 :             psInfo->nPrecision = AVC_SINGLE_PREC;
     396           0 :         else if (atoi(pszLine + 4) == 3)
     397           0 :             psInfo->nPrecision = AVC_DOUBLE_PREC;
     398             :         else
     399             :         {
     400           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     401             :                      "Parse Error: Invalid section header line (\"%s\")!",
     402             :                      pszLine);
     403           0 :             return AVCFileUnknown;
     404             :         }
     405             :     }
     406             :     else
     407             :     {
     408             :         /*-------------------------------------------------------------
     409             :          * We're looking for a section inside a super-section...
     410             :          * in this case, the header line contains the subclass name,
     411             :          * so any non-empty line is acceptable!
     412             :          * Note: the precision is already set from the previous call to
     413             :          *       AVCE00ParseSuperSectionHeader()
     414             :          * Note2: Inside a double precision RPL supersection, the end of
     415             :          *        each sub-section is marked by 2 lines, just like what
     416             :          *        happens with double precision PALs... we have to make
     417             :          *        sure we don't catch that second line as the beginning
     418             :          *        of a new RPL sub-section.
     419             :          *------------------------------------------------------------*/
     420             : 
     421          55 :         if (psInfo->eSuperSectionType == AVCFileTX6 && strlen(pszLine) == 0)
     422             :         {
     423             :             /* See bug 1261: It seems that empty subclass names are valid
     424             :              * for TX7. We don't know if that's valid for other supersection
     425             :              * types, so we'll handle this as a specific case just for TX7
     426             :              */
     427           0 :             eNewType = psInfo->eSuperSectionType;
     428             :         }
     429          55 :         else if (strlen(pszLine) > 0 && !isspace((unsigned char)pszLine[0]) &&
     430          55 :                  !STARTS_WITH_CI(pszLine, "JABBERWOCKY") &&
     431          55 :                  !STARTS_WITH_CI(pszLine, "EOI") &&
     432          55 :                  !(psInfo->eSuperSectionType == AVCFileRPL &&
     433           0 :                    STARTS_WITH_CI(pszLine, " 0.00000")))
     434             :         {
     435          55 :             eNewType = psInfo->eSuperSectionType;
     436             :         }
     437             :         else
     438             :         {
     439           0 :             return AVCFileUnknown;
     440             :         }
     441             :     }
     442             : 
     443             :     /*-----------------------------------------------------------------
     444             :      * nCurObjectId is used to keep track of sequential ids that are
     445             :      * not explicitly stored in E00.  e.g. polygon Id in a PAL section.
     446             :      *----------------------------------------------------------------*/
     447         145 :     psInfo->nCurObjectId = 0;
     448             : 
     449             :     /*-----------------------------------------------------------------
     450             :      * Allocate a temp. structure to use to store the objects we read
     451             :      * (Using Calloc() will automatically initialize the struct contents
     452             :      *  to nullptr... this is very important for ARCs and PALs)
     453             :      *----------------------------------------------------------------*/
     454         145 :     _AVCE00ParseDestroyCurObject(psInfo);
     455             : 
     456         145 :     if (eNewType == AVCFileARC)
     457             :     {
     458          22 :         psInfo->cur.psArc = (AVCArc *)CPLCalloc(1, sizeof(AVCArc));
     459             :     }
     460         123 :     else if (eNewType == AVCFilePAL || eNewType == AVCFileRPL)
     461             :     {
     462          10 :         psInfo->cur.psPal = (AVCPal *)CPLCalloc(1, sizeof(AVCPal));
     463             :     }
     464         113 :     else if (eNewType == AVCFileCNT)
     465             :     {
     466          10 :         psInfo->cur.psCnt = (AVCCnt *)CPLCalloc(1, sizeof(AVCCnt));
     467             :     }
     468         103 :     else if (eNewType == AVCFileLAB)
     469             :     {
     470          19 :         psInfo->cur.psLab = (AVCLab *)CPLCalloc(1, sizeof(AVCLab));
     471             :     }
     472          84 :     else if (eNewType == AVCFileTOL)
     473             :     {
     474          17 :         psInfo->cur.psTol = (AVCTol *)CPLCalloc(1, sizeof(AVCTol));
     475             :     }
     476          67 :     else if (eNewType == AVCFilePRJ)
     477             :     {
     478          12 :         psInfo->aosPrj.Clear();
     479             :     }
     480          55 :     else if (eNewType == AVCFileTXT || eNewType == AVCFileTX6)
     481             :     {
     482           0 :         psInfo->cur.psTxt = (AVCTxt *)CPLCalloc(1, sizeof(AVCTxt));
     483             :     }
     484          55 :     else if (eNewType == AVCFileRXP)
     485             :     {
     486           0 :         psInfo->cur.psRxp = (AVCRxp *)CPLCalloc(1, sizeof(AVCRxp));
     487             :     }
     488          55 :     else if (eNewType == AVCFileTABLE)
     489             :     {
     490          55 :         psInfo->cur.pasFields = nullptr;
     491          55 :         psInfo->hdr.psTableDef = nullptr;
     492          55 :         psInfo->bTableHdrComplete = FALSE;
     493             :     }
     494             :     else
     495             :     {
     496           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     497             :                  "AVCE00ParseSectionHeader(): Unsupported file type!");
     498           0 :         eNewType = AVCFileUnknown;
     499             :     }
     500             : 
     501         145 :     if (eNewType != AVCFileUnknown)
     502             :     {
     503             :         /*-----------------------------------------------------------------
     504             :          * Record the start of the section (for faster seeking)
     505             :          *----------------------------------------------------------------*/
     506         145 :         psInfo->nStartLineNum = psInfo->nCurLineNum;
     507             : 
     508             :         /*-----------------------------------------------------------------
     509             :          * Keep track of section header line... this is used for some file
     510             :          * types, specially the ones enclosed inside supersections.
     511             :          *----------------------------------------------------------------*/
     512         145 :         CPLFree(psInfo->pszSectionHdrLine);
     513         145 :         psInfo->pszSectionHdrLine = CPLStrdup(pszLine);
     514             :     }
     515             : 
     516         145 :     psInfo->eFileType = eNewType;
     517             : 
     518         145 :     return psInfo->eFileType;
     519             : }
     520             : 
     521             : /**********************************************************************
     522             :  *                          AVCE00ParseSectionEnd()
     523             :  *
     524             :  * Check if pszLine marks the end of the current section.
     525             :  *
     526             :  * Passing bResetParseInfo=TRUE will reset the parser struct if an end of
     527             :  * section is found.  Passing FALSE simply tests for the end of section
     528             :  * without affecting the parse info struct.
     529             :  *
     530             :  * Return TRUE if this is the end of the section (and reset the
     531             :  * ParseInfo structure) , or FALSE otherwise.
     532             :  **********************************************************************/
     533        2710 : GBool AVCE00ParseSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine,
     534             :                             GBool bResetParseInfo)
     535             : {
     536        2710 :     if (psInfo->bForceEndOfSection ||
     537        2622 :         ((psInfo->eFileType == AVCFileARC || psInfo->eFileType == AVCFilePAL ||
     538        2132 :           psInfo->eFileType == AVCFileLAB || psInfo->eFileType == AVCFileRPL ||
     539        1082 :           psInfo->eFileType == AVCFileCNT || psInfo->eFileType == AVCFileTOL ||
     540         798 :           psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6 ||
     541         798 :           psInfo->eFileType == AVCFileRXP) &&
     542        1824 :          STARTS_WITH_CI(pszLine, "        -1         0")))
     543             :     {
     544             :         /* Reset ParseInfo only if explicitly requested.
     545             :          */
     546         228 :         if (bResetParseInfo)
     547             :         {
     548         158 :             _AVCE00ParseDestroyCurObject(psInfo);
     549         158 :             AVCE00ParseReset(psInfo);
     550         158 :             psInfo->eFileType = AVCFileUnknown;
     551             : 
     552         158 :             CPLFree(psInfo->pszSectionHdrLine);
     553         158 :             psInfo->pszSectionHdrLine = nullptr;
     554             : 
     555         158 :             psInfo->bForceEndOfSection = FALSE;
     556             :         }
     557             : 
     558         228 :         return TRUE; /* YES, we reached the end */
     559             :     }
     560             : 
     561        2482 :     return FALSE; /* NO, it is not the end of section line */
     562             : }
     563             : 
     564             : /**********************************************************************
     565             :  *                          AVCE00ParseNextLine()
     566             :  *
     567             :  * Take the next line of E00 input and parse it.
     568             :  *
     569             :  * Returns nullptr if the current object is not complete yet (expecting
     570             :  * more lines of input) or a reference to a complete object if it
     571             :  * is complete.
     572             :  *
     573             :  * The returned object is a reference to an internal data structure.
     574             :  * It should not be modified or freed by the caller.
     575             :  *
     576             :  * If the input is invalid or other problems happen, then a CPLError()
     577             :  * will be generated.  CPLGetLastErrorNo() should be called to check
     578             :  * that the line was parsed successfully.
     579             :  *
     580             :  * Note for TABLES:
     581             :  * When parsing input from info tables, the first valid object that
     582             :  * will be returned will be the AVCTableDef, and then the data records
     583             :  * will follow.  When all the records have been read, then the
     584             :  * psInfo->bForceEndOfSection flag will be set to TRUE since there is
     585             :  * no explicit "end of table" line in E00.
     586             :  **********************************************************************/
     587        2820 : void *AVCE00ParseNextLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     588             : {
     589        2820 :     void *psObj = nullptr;
     590             : 
     591        2820 :     CPLAssert(psInfo);
     592        2820 :     switch (psInfo->eFileType)
     593             :     {
     594         322 :         case AVCFileARC:
     595         322 :             psObj = (void *)AVCE00ParseNextArcLine(psInfo, pszLine);
     596         322 :             break;
     597         120 :         case AVCFilePAL:
     598             :         case AVCFileRPL:
     599         120 :             psObj = (void *)AVCE00ParseNextPalLine(psInfo, pszLine);
     600         120 :             break;
     601          60 :         case AVCFileCNT:
     602          60 :             psObj = (void *)AVCE00ParseNextCntLine(psInfo, pszLine);
     603          60 :             break;
     604        1012 :         case AVCFileLAB:
     605        1012 :             psObj = (void *)AVCE00ParseNextLabLine(psInfo, pszLine);
     606        1012 :             break;
     607         170 :         case AVCFileTOL:
     608         170 :             psObj = (void *)AVCE00ParseNextTolLine(psInfo, pszLine);
     609         170 :             break;
     610         228 :         case AVCFilePRJ:
     611         228 :             psObj = (void *)AVCE00ParseNextPrjLine(psInfo, pszLine);
     612         228 :             break;
     613           0 :         case AVCFileTXT:
     614           0 :             psObj = (void *)AVCE00ParseNextTxtLine(psInfo, pszLine);
     615           0 :             break;
     616           0 :         case AVCFileTX6:
     617           0 :             psObj = (void *)AVCE00ParseNextTx6Line(psInfo, pszLine);
     618           0 :             break;
     619           0 :         case AVCFileRXP:
     620           0 :             psObj = (void *)AVCE00ParseNextRxpLine(psInfo, pszLine);
     621           0 :             break;
     622         908 :         case AVCFileTABLE:
     623         908 :             if (!psInfo->bTableHdrComplete)
     624         338 :                 psObj = (void *)AVCE00ParseNextTableDefLine(psInfo, pszLine);
     625             :             else
     626         570 :                 psObj = (void *)AVCE00ParseNextTableRecLine(psInfo, pszLine);
     627         908 :             break;
     628           0 :         default:
     629           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     630             :                      "AVCE00ParseNextLine(): Unsupported file type!");
     631             :     }
     632             : 
     633        2820 :     return psObj;
     634             : }
     635             : 
     636             : /**********************************************************************
     637             :  *                          AVCE00ParseNextArcLine()
     638             :  *
     639             :  * Take the next line of E00 input for an ARC object and parse it.
     640             :  *
     641             :  * Returns nullptr if the current object is not complete yet (expecting
     642             :  * more lines of input) or a reference to a complete object if it
     643             :  * is complete.
     644             :  *
     645             :  * The returned object is a reference to an internal data structure.
     646             :  * It should not be modified or freed by the caller.
     647             :  *
     648             :  * If the input is invalid or other problems happen, then a CPLError()
     649             :  * will be generated.  CPLGetLastErrorNo() should be called to check
     650             :  * that the line was parsed successfully.
     651             :  **********************************************************************/
     652         322 : AVCArc *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     653             : {
     654             :     AVCArc *psArc;
     655             :     size_t nLen;
     656             : 
     657         322 :     CPLAssert(psInfo->eFileType == AVCFileARC);
     658             : 
     659         322 :     psArc = psInfo->cur.psArc;
     660             : 
     661         322 :     nLen = strlen(pszLine);
     662             : 
     663         322 :     if (psInfo->numItems == 0)
     664             :     {
     665             :         /*-------------------------------------------------------------
     666             :          * Begin processing a new object, read header line:
     667             :          *    ArcId, UserId, FNode, TNode, LPoly, RPoly, numVertices
     668             :          *------------------------------------------------------------*/
     669         133 :         if (nLen < 70)
     670             :         {
     671           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     672             :                      "Error parsing E00 ARC line: \"%s\"", pszLine);
     673           0 :             return nullptr;
     674             :         }
     675             :         else
     676             :         {
     677         133 :             psArc->nArcId = AVCE00Str2Int(pszLine, 10);
     678         133 :             psArc->nUserId = AVCE00Str2Int(pszLine + 10, 10);
     679         133 :             psArc->nFNode = AVCE00Str2Int(pszLine + 20, 10);
     680         133 :             psArc->nTNode = AVCE00Str2Int(pszLine + 30, 10);
     681         133 :             psArc->nLPoly = AVCE00Str2Int(pszLine + 40, 10);
     682         133 :             psArc->nRPoly = AVCE00Str2Int(pszLine + 50, 10);
     683         133 :             psArc->numVertices = AVCE00Str2Int(pszLine + 60, 10);
     684         133 :             if (psArc->numVertices < 0 || psArc->numVertices > 10 * 1024 * 1024)
     685             :             {
     686           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     687             :                          "Error parsing E00 ARC line: \"%s\"", pszLine);
     688           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
     689           0 :                 return nullptr;
     690             :             }
     691             : 
     692             :             /* Realloc the array of vertices
     693             :              */
     694         266 :             psArc->pasVertices = (AVCVertex *)CPLRealloc(
     695         133 :                 psArc->pasVertices, psArc->numVertices * sizeof(AVCVertex));
     696             : 
     697             :             /* psInfo->iCurItem is the last vertex that was read.
     698             :              * psInfo->numItems is the number of vertices to read.
     699             :              */
     700         133 :             psInfo->iCurItem = 0;
     701         133 :             psInfo->numItems = psArc->numVertices;
     702             :         }
     703             :     }
     704         189 :     else if (psInfo->iCurItem < psInfo->numItems &&
     705         189 :              psInfo->nPrecision == AVC_SINGLE_PREC &&
     706         189 :              ((psInfo->iCurItem == psInfo->numItems - 1 && nLen >= 28) ||
     707             :               nLen >= 56))
     708             :     {
     709             :         /*-------------------------------------------------------------
     710             :          * Single precision ARCs: 2 pairs of X,Y values per line
     711             :          * Except on the last line with an odd number of vertices)
     712             :          *------------------------------------------------------------*/
     713         189 :         psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
     714         189 :         psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 14);
     715         189 :         if (psInfo->iCurItem < psInfo->numItems && nLen >= 56)
     716             :         {
     717         154 :             psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine + 28);
     718         154 :             psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 42);
     719             :         }
     720             :     }
     721           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
     722           0 :              psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42)
     723             :     {
     724             :         /*-------------------------------------------------------------
     725             :          * Double precision ARCs: 1 pair of X,Y values per line
     726             :          *------------------------------------------------------------*/
     727           0 :         psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
     728           0 :         psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 21);
     729             :     }
     730             :     else
     731             :     {
     732           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     733             :                  "Error parsing E00 ARC line: \"%s\"", pszLine);
     734           0 :         psInfo->numItems = psInfo->iCurItem = 0;
     735           0 :         return nullptr;
     736             :     }
     737             : 
     738             :     /*-----------------------------------------------------------------
     739             :      * If we're done parsing this ARC, then reset the ParseInfo,
     740             :      * and return a reference to the ARC structure
     741             :      * Otherwise return nullptr, which means that we are expecting more
     742             :      * more lines of input.
     743             :      *----------------------------------------------------------------*/
     744         322 :     if (psInfo->iCurItem >= psInfo->numItems)
     745             :     {
     746         133 :         psInfo->numItems = psInfo->iCurItem = 0;
     747         133 :         return psArc;
     748             :     }
     749             : 
     750         189 :     return nullptr;
     751             : }
     752             : 
     753             : /**********************************************************************
     754             :  *                          AVCE00ParseNextPalLine()
     755             :  *
     756             :  * Take the next line of E00 input for an PAL object and parse it.
     757             :  *
     758             :  * Returns nullptr if the current object is not complete yet (expecting
     759             :  * more lines of input) or a reference to a complete object if it
     760             :  * is complete.
     761             :  *
     762             :  * The returned object is a reference to an internal data structure.
     763             :  * It should not be modified or freed by the caller.
     764             :  *
     765             :  * If the input is invalid or other problems happen, then a CPLError()
     766             :  * will be generated.  CPLGetLastErrorNo() should be called to check
     767             :  * that the line was parsed successfully.
     768             :  **********************************************************************/
     769         120 : AVCPal *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     770             : {
     771             :     AVCPal *psPal;
     772             :     size_t nLen;
     773             : 
     774         120 :     CPLAssert(psInfo->eFileType == AVCFilePAL ||
     775             :               psInfo->eFileType == AVCFileRPL);
     776             : 
     777         120 :     psPal = psInfo->cur.psPal;
     778             : 
     779         120 :     nLen = strlen(pszLine);
     780             : 
     781         120 :     if (psInfo->numItems == 0)
     782             :     {
     783             :         /*-------------------------------------------------------------
     784             :          * Begin processing a new object, read header line:
     785             :          *    numArcs, MinX, MinY, MaxX, MaxY
     786             :          * For Double precision, MaxX, MaxY are on a separate line.
     787             :          *------------------------------------------------------------*/
     788          40 :         if (nLen < 52)
     789             :         {
     790           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     791             :                      "Error parsing E00 PAL line: \"%s\"", pszLine);
     792           0 :             return nullptr;
     793             :         }
     794             :         else
     795             :         {
     796             :             /* Polygon Id is not stored in the E00 file.  Polygons are
     797             :              * stored in increasing order, starting at 1... so we just
     798             :              * increment the previous value.
     799             :              */
     800          40 :             psPal->nPolyId = ++psInfo->nCurObjectId;
     801             : 
     802          40 :             psPal->numArcs = AVCE00Str2Int(pszLine, 10);
     803          40 :             if (psPal->numArcs < 0 || psPal->numArcs > 10 * 1024 * 1024)
     804             :             {
     805           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     806             :                          "Error parsing E00 PAL line: \"%s\"", pszLine);
     807           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
     808           0 :                 return nullptr;
     809             :             }
     810             : 
     811             :             /* If a PAL record has 0 arcs, it really has a single "0 0 0"
     812             :              * triplet as its data.
     813             :              */
     814          40 :             if (psPal->numArcs == 0)
     815             :             {
     816           0 :                 psPal->numArcs = 1;
     817             :             }
     818             : 
     819             :             /* Realloc the array of Arcs
     820             :              */
     821          80 :             psPal->pasArcs = (AVCPalArc *)CPLRealloc(
     822          40 :                 psPal->pasArcs, psPal->numArcs * sizeof(AVCPalArc));
     823             : 
     824             :             /* psInfo->iCurItem is the index of the last arc that was read.
     825             :              * psInfo->numItems is the number of arcs to read.
     826             :              */
     827          40 :             psInfo->iCurItem = 0;
     828          40 :             psInfo->numItems = psPal->numArcs;
     829             : 
     830          40 :             if (psInfo->nPrecision == AVC_SINGLE_PREC)
     831             :             {
     832          40 :                 psPal->sMin.x = CPLAtof(pszLine + 10);
     833          40 :                 psPal->sMin.y = CPLAtof(pszLine + 24);
     834          40 :                 psPal->sMax.x = CPLAtof(pszLine + 38);
     835          40 :                 psPal->sMax.y = CPLAtof(pszLine + 52);
     836             :             }
     837             :             else
     838             :             {
     839           0 :                 psPal->sMin.x = CPLAtof(pszLine + 10);
     840           0 :                 psPal->sMin.y = CPLAtof(pszLine + 31);
     841             :                 /* Set psInfo->iCurItem = -1 since we still have 2 values
     842             :                  * from the header to read on the next line.
     843             :                  */
     844           0 :                 psInfo->iCurItem = -1;
     845             :             }
     846             :         }
     847             :     }
     848          80 :     else if (psInfo->iCurItem == -1 && nLen >= 42)
     849             :     {
     850           0 :         psPal->sMax.x = CPLAtof(pszLine);
     851           0 :         psPal->sMax.y = CPLAtof(pszLine + 21);
     852           0 :         psInfo->iCurItem++;
     853             :     }
     854          80 :     else if (psInfo->iCurItem < psPal->numArcs &&
     855          10 :              (nLen >= 60 ||
     856          10 :               (psInfo->iCurItem == psPal->numArcs - 1 && nLen >= 30)))
     857             :     {
     858             :         /*-------------------------------------------------------------
     859             :          * 2 PAL entries (ArcId, FNode, AdjPoly) per line,
     860             :          * (Except on the last line with an odd number of vertices)
     861             :          *------------------------------------------------------------*/
     862          80 :         psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine, 10);
     863         160 :         psPal->pasArcs[psInfo->iCurItem].nFNode =
     864          80 :             AVCE00Str2Int(pszLine + 10, 10);
     865          80 :         psPal->pasArcs[psInfo->iCurItem++].nAdjPoly =
     866          80 :             AVCE00Str2Int(pszLine + 20, 10);
     867             : 
     868          80 :         if (psInfo->iCurItem < psInfo->numItems)
     869             :         {
     870         140 :             psPal->pasArcs[psInfo->iCurItem].nArcId =
     871          70 :                 AVCE00Str2Int(pszLine + 30, 10);
     872         140 :             psPal->pasArcs[psInfo->iCurItem].nFNode =
     873          70 :                 AVCE00Str2Int(pszLine + 40, 10);
     874          70 :             psPal->pasArcs[psInfo->iCurItem++].nAdjPoly =
     875          70 :                 AVCE00Str2Int(pszLine + 50, 10);
     876             :         }
     877             :     }
     878             :     else
     879             :     {
     880           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     881             :                  "Error parsing E00 PAL line: \"%s\"", pszLine);
     882           0 :         psInfo->numItems = psInfo->iCurItem = 0;
     883           0 :         return nullptr;
     884             :     }
     885             : 
     886             :     /*-----------------------------------------------------------------
     887             :      * If we're done parsing this PAL, then reset the ParseInfo,
     888             :      * and return a reference to the PAL structure
     889             :      * Otherwise return nullptr, which means that we are expecting more
     890             :      * more lines of input.
     891             :      *----------------------------------------------------------------*/
     892         120 :     if (psInfo->iCurItem >= psInfo->numItems)
     893             :     {
     894          40 :         psInfo->numItems = psInfo->iCurItem = 0;
     895          40 :         return psPal;
     896             :     }
     897             : 
     898          80 :     return nullptr;
     899             : }
     900             : 
     901             : /**********************************************************************
     902             :  *                          AVCE00ParseNextCntLine()
     903             :  *
     904             :  * Take the next line of E00 input for an CNT object and parse it.
     905             :  *
     906             :  * Returns nullptr if the current object is not complete yet (expecting
     907             :  * more lines of input) or a reference to a complete object if it
     908             :  * is complete.
     909             :  *
     910             :  * The returned object is a reference to an internal data structure.
     911             :  * It should not be modified or freed by the caller.
     912             :  *
     913             :  * If the input is invalid or other problems happen, then a CPLError()
     914             :  * will be generated.  CPLGetLastErrorNo() should be called to check
     915             :  * that the line was parsed successfully.
     916             :  **********************************************************************/
     917          60 : AVCCnt *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     918             : {
     919             :     AVCCnt *psCnt;
     920             :     size_t nLen;
     921             : 
     922          60 :     CPLAssert(psInfo->eFileType == AVCFileCNT);
     923             : 
     924          60 :     psCnt = psInfo->cur.psCnt;
     925             : 
     926          60 :     nLen = strlen(pszLine);
     927             : 
     928          60 :     if (psInfo->numItems == 0)
     929             :     {
     930             :         /*-------------------------------------------------------------
     931             :          * Begin processing a new object, read header line:
     932             :          *    numLabels, X, Y
     933             :          *------------------------------------------------------------*/
     934          40 :         if (nLen < 38)
     935             :         {
     936           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     937             :                      "Error parsing E00 CNT line: \"%s\"", pszLine);
     938           0 :             return nullptr;
     939             :         }
     940             :         else
     941             :         {
     942             :             /* Polygon Id is not stored in the E00 file.  Centroids are
     943             :              * stored in increasing order of Polygon Id, starting at 1...
     944             :              * so we just increment the previous value.
     945             :              */
     946          40 :             psCnt->nPolyId = ++psInfo->nCurObjectId;
     947             : 
     948          40 :             psCnt->numLabels = AVCE00Str2Int(pszLine, 10);
     949          40 :             if (psCnt->numLabels < 0 || psCnt->numLabels > 10 * 1024 * 1024)
     950             :             {
     951           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     952             :                          "Error parsing E00 CNT line: \"%s\"", pszLine);
     953           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
     954           0 :                 return nullptr;
     955             :             }
     956             : 
     957             :             /* Realloc the array of Labels Ids
     958             :              * Avoid allocating a 0-length segment since centroids can have
     959             :              * 0 labels attached to them.
     960             :              */
     961          40 :             if (psCnt->numLabels > 0)
     962          20 :                 psCnt->panLabelIds = (GInt32 *)CPLRealloc(
     963          20 :                     psCnt->panLabelIds, psCnt->numLabels * sizeof(GInt32));
     964             : 
     965          40 :             if (psInfo->nPrecision == AVC_SINGLE_PREC)
     966             :             {
     967          40 :                 psCnt->sCoord.x = CPLAtof(pszLine + 10);
     968          40 :                 psCnt->sCoord.y = CPLAtof(pszLine + 24);
     969             :             }
     970             :             else
     971             :             {
     972           0 :                 psCnt->sCoord.x = CPLAtof(pszLine + 10);
     973           0 :                 psCnt->sCoord.y = CPLAtof(pszLine + 31);
     974             :             }
     975             : 
     976             :             /* psInfo->iCurItem is the index of the last label that was read.
     977             :              * psInfo->numItems is the number of label ids to read.
     978             :              */
     979          40 :             psInfo->iCurItem = 0;
     980          40 :             psInfo->numItems = psCnt->numLabels;
     981             :         }
     982             :     }
     983          20 :     else if (psInfo->iCurItem < psInfo->numItems)
     984             :     {
     985             :         /*-------------------------------------------------------------
     986             :          * Each line can contain up to 8 label ids (10 chars each)
     987             :          *------------------------------------------------------------*/
     988          20 :         size_t i = 0;
     989          40 :         while (psInfo->iCurItem < psInfo->numItems && nLen >= (i + 1) * 10)
     990             :         {
     991          20 :             psCnt->panLabelIds[psInfo->iCurItem++] =
     992          20 :                 AVCE00Str2Int(pszLine + i * 10, 10);
     993          20 :             i++;
     994             :         }
     995             :     }
     996             :     else
     997             :     {
     998           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     999             :                  "Error parsing E00 CNT line: \"%s\"", pszLine);
    1000           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1001           0 :         return nullptr;
    1002             :     }
    1003             : 
    1004             :     /*-----------------------------------------------------------------
    1005             :      * If we're done parsing this CNT, then reset the ParseInfo,
    1006             :      * and return a reference to the CNT structure
    1007             :      * Otherwise return nullptr, which means that we are expecting more
    1008             :      * more lines of input.
    1009             :      *----------------------------------------------------------------*/
    1010          60 :     if (psInfo->iCurItem >= psInfo->numItems)
    1011             :     {
    1012          40 :         psInfo->numItems = psInfo->iCurItem = 0;
    1013          40 :         return psCnt;
    1014             :     }
    1015             : 
    1016          20 :     return nullptr;
    1017             : }
    1018             : 
    1019             : /**********************************************************************
    1020             :  *                          AVCE00ParseNextLabLine()
    1021             :  *
    1022             :  * Take the next line of E00 input for an LAB object and parse it.
    1023             :  *
    1024             :  * Returns nullptr if the current object is not complete yet (expecting
    1025             :  * more lines of input) or a reference to a complete object if it
    1026             :  * is complete.
    1027             :  *
    1028             :  * The returned object is a reference to an internal data structure.
    1029             :  * It should not be modified or freed by the caller.
    1030             :  *
    1031             :  * If the input is invalid or other problems happen, then a CPLError()
    1032             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1033             :  * that the line was parsed successfully.
    1034             :  **********************************************************************/
    1035        1012 : AVCLab *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine)
    1036             : {
    1037             :     AVCLab *psLab;
    1038             :     size_t nLen;
    1039             : 
    1040        1012 :     CPLAssert(psInfo->eFileType == AVCFileLAB);
    1041             : 
    1042        1012 :     psLab = psInfo->cur.psLab;
    1043             : 
    1044        1012 :     nLen = strlen(pszLine);
    1045             : 
    1046        1012 :     if (psInfo->numItems == 0)
    1047             :     {
    1048             :         /*-------------------------------------------------------------
    1049             :          * Begin processing a new object, read header line:
    1050             :          *    LabelValue, PolyId, X1, Y1
    1051             :          *------------------------------------------------------------*/
    1052         506 :         if (nLen < 48)
    1053             :         {
    1054           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1055             :                      "Error parsing E00 LAB line: \"%s\"", pszLine);
    1056           0 :             return nullptr;
    1057             :         }
    1058             :         else
    1059             :         {
    1060         506 :             psLab->nValue = AVCE00Str2Int(pszLine, 10);
    1061         506 :             psLab->nPolyId = AVCE00Str2Int(pszLine + 10, 10);
    1062             : 
    1063         506 :             if (psInfo->nPrecision == AVC_SINGLE_PREC)
    1064             :             {
    1065         506 :                 psLab->sCoord1.x = CPLAtof(pszLine + 20);
    1066         506 :                 psLab->sCoord1.y = CPLAtof(pszLine + 34);
    1067             :             }
    1068             :             else
    1069             :             {
    1070           0 :                 psLab->sCoord1.x = CPLAtof(pszLine + 20);
    1071           0 :                 psLab->sCoord1.y = CPLAtof(pszLine + 41);
    1072             :             }
    1073             : 
    1074             :             /* psInfo->iCurItem is the index of the last X,Y pair we read.
    1075             :              * psInfo->numItems is the number of X,Y pairs to read.
    1076             :              */
    1077         506 :             psInfo->iCurItem = 1;
    1078         506 :             psInfo->numItems = 3;
    1079             :         }
    1080             :     }
    1081         506 :     else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC &&
    1082             :              nLen >= 56)
    1083             :     {
    1084         506 :         psLab->sCoord2.x = CPLAtof(pszLine);
    1085         506 :         psLab->sCoord2.y = CPLAtof(pszLine + 14);
    1086         506 :         psLab->sCoord3.x = CPLAtof(pszLine + 28);
    1087         506 :         psLab->sCoord3.y = CPLAtof(pszLine + 42);
    1088         506 :         psInfo->iCurItem += 2;
    1089             :     }
    1090           0 :     else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
    1091             :              nLen >= 42)
    1092             :     {
    1093           0 :         psLab->sCoord2.x = CPLAtof(pszLine);
    1094           0 :         psLab->sCoord2.y = CPLAtof(pszLine + 21);
    1095           0 :         psInfo->iCurItem++;
    1096             :     }
    1097           0 :     else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
    1098             :              nLen >= 42)
    1099             :     {
    1100           0 :         psLab->sCoord3.x = CPLAtof(pszLine);
    1101           0 :         psLab->sCoord3.y = CPLAtof(pszLine + 21);
    1102           0 :         psInfo->iCurItem++;
    1103             :     }
    1104             :     else
    1105             :     {
    1106           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1107             :                  "Error parsing E00 LAB line: \"%s\"", pszLine);
    1108           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1109           0 :         return nullptr;
    1110             :     }
    1111             : 
    1112             :     /*-----------------------------------------------------------------
    1113             :      * If we're done parsing this LAB, then reset the ParseInfo,
    1114             :      * and return a reference to the LAB structure
    1115             :      * Otherwise return nullptr, which means that we are expecting more
    1116             :      * more lines of input.
    1117             :      *----------------------------------------------------------------*/
    1118        1012 :     if (psInfo->iCurItem >= psInfo->numItems)
    1119             :     {
    1120         506 :         psInfo->numItems = psInfo->iCurItem = 0;
    1121         506 :         return psLab;
    1122             :     }
    1123             : 
    1124         506 :     return nullptr;
    1125             : }
    1126             : 
    1127             : /**********************************************************************
    1128             :  *                          AVCE00ParseNextTolLine()
    1129             :  *
    1130             :  * Take the next line of E00 input for an TOL object and parse it.
    1131             :  *
    1132             :  * Returns nullptr if the current object is not complete yet (expecting
    1133             :  * more lines of input) or a reference to a complete object if it
    1134             :  * is complete.
    1135             :  *
    1136             :  * The returned object is a reference to an internal data structure.
    1137             :  * It should not be modified or freed by the caller.
    1138             :  *
    1139             :  * If the input is invalid or other problems happen, then a CPLError()
    1140             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1141             :  * that the line was parsed successfully.
    1142             :  **********************************************************************/
    1143         170 : AVCTol *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine)
    1144             : {
    1145             :     AVCTol *psTol;
    1146             :     size_t nLen;
    1147             : 
    1148         170 :     CPLAssert(psInfo->eFileType == AVCFileTOL);
    1149             : 
    1150         170 :     psTol = psInfo->cur.psTol;
    1151             : 
    1152         170 :     nLen = strlen(pszLine);
    1153             : 
    1154         170 :     if (nLen >= 34)
    1155             :     {
    1156             :         /*-------------------------------------------------------------
    1157             :          * TOL Entries are only one line each:
    1158             :          *   TolIndex, TolFlag, TolValue
    1159             :          *------------------------------------------------------------*/
    1160         170 :         psTol->nIndex = AVCE00Str2Int(pszLine, 10);
    1161         170 :         psTol->nFlag = AVCE00Str2Int(pszLine + 10, 10);
    1162             : 
    1163         170 :         psTol->dValue = CPLAtof(pszLine + 20);
    1164             :     }
    1165             :     else
    1166             :     {
    1167           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1168             :                  "Error parsing E00 TOL line: \"%s\"", pszLine);
    1169           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1170           0 :         return nullptr;
    1171             :     }
    1172             : 
    1173             :     /*-----------------------------------------------------------------
    1174             :      * If we're done parsing this TOL, then reset the ParseInfo,
    1175             :      * and return a reference to the TOL structure
    1176             :      * Otherwise return nullptr, which means that we are expecting more
    1177             :      * more lines of input.
    1178             :      *----------------------------------------------------------------*/
    1179         170 :     if (psInfo->iCurItem >= psInfo->numItems)
    1180             :     {
    1181         170 :         psInfo->numItems = psInfo->iCurItem = 0;
    1182         170 :         return psTol;
    1183             :     }
    1184             : 
    1185           0 :     return nullptr;
    1186             : }
    1187             : 
    1188             : /**********************************************************************
    1189             :  *                          AVCE00ParseNextPrjLine()
    1190             :  *
    1191             :  * Take the next line of E00 input for a PRJ object and parse it.
    1192             :  *
    1193             :  * Returns nullptr if the current object is not complete yet (expecting
    1194             :  * more lines of input) or a reference to a complete object if it
    1195             :  * is complete.
    1196             :  *
    1197             :  * Since a PRJ section contains only ONE projection, the function will
    1198             :  * always return nullptr, until it reaches the end-of-section (EOP) line.
    1199             :  * This is behavior is a bit different from the other section types that
    1200             :  * will usually return a valid object immediately before the last line
    1201             :  * of the section (the end-of-section line).
    1202             :  *
    1203             :  * The returned object is a reference to an internal data structure.
    1204             :  * It should not be modified or freed by the caller.
    1205             :  *
    1206             :  * If the input is invalid or other problems happen, then a CPLError()
    1207             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1208             :  * that the line was parsed successfully.
    1209             :  **********************************************************************/
    1210         228 : char **AVCE00ParseNextPrjLine(AVCE00ParseInfo *psInfo, const char *pszLine)
    1211             : {
    1212         228 :     CPLAssert(psInfo->eFileType == AVCFilePRJ);
    1213             : 
    1214             :     /*-------------------------------------------------------------
    1215             :      * Since a PRJ section contains only ONE projection, this function will
    1216             :      * always return nullptr until it reaches the end-of-section (EOP) line.
    1217             :      * This is behavior is a bit different from the other section types that
    1218             :      * will usually return a valid object immediately before the last line
    1219             :      * of the section (the end-of-section line).
    1220             :      *------------------------------------------------------------*/
    1221             : 
    1222         228 :     if (STARTS_WITH_CI(pszLine, "EOP"))
    1223             :     {
    1224             :         /*-------------------------------------------------------------
    1225             :          * We reached end of section... return the PRJ.
    1226             :          *------------------------------------------------------------*/
    1227          12 :         psInfo->bForceEndOfSection = TRUE;
    1228          12 :         return psInfo->aosPrj.List();
    1229             :     }
    1230             : 
    1231         216 :     if (pszLine[0] != '~')
    1232             :     {
    1233             :         /*-------------------------------------------------------------
    1234             :          * This is a new line... add it to the papszPrj stringlist.
    1235             :          *------------------------------------------------------------*/
    1236         108 :         psInfo->aosPrj.AddString(pszLine);
    1237             :     }
    1238         108 :     else if (strlen(pszLine) > 1)
    1239             :     {
    1240             :         /*-------------------------------------------------------------
    1241             :          * '~' is a line continuation char.  Append what follows the '~'
    1242             :          * to the end of the previous line.
    1243             :          *------------------------------------------------------------*/
    1244           0 :         if (!psInfo->aosPrj.empty())
    1245             :         {
    1246             :             size_t nOldLen =
    1247           0 :                 strlen(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1]);
    1248           0 :             size_t nAddLen = strlen(pszLine + 1);
    1249           0 :             psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] =
    1250             :                 static_cast<char *>(
    1251           0 :                     CPLRealloc(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1],
    1252           0 :                                nOldLen + nAddLen + 1));
    1253           0 :             memcpy(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] + nOldLen,
    1254           0 :                    pszLine + 1, nAddLen + 1);
    1255             :         }
    1256             :     }
    1257             : 
    1258         216 :     return nullptr;
    1259             : }
    1260             : 
    1261             : /**********************************************************************
    1262             :  *                          AVCE00ParseNextTxtLine()
    1263             :  *
    1264             :  * Take the next line of E00 input for an TXT object and parse it.
    1265             :  *
    1266             :  * Returns nullptr if the current object is not complete yet (expecting
    1267             :  * more lines of input) or a reference to a complete object if it
    1268             :  * is complete.
    1269             :  *
    1270             :  * The returned object is a reference to an internal data structure.
    1271             :  * It should not be modified or freed by the caller.
    1272             :  *
    1273             :  * If the input is invalid or other problems happen, then a CPLError()
    1274             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1275             :  * that the line was parsed successfully.
    1276             :  **********************************************************************/
    1277           0 : AVCTxt *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
    1278             : {
    1279             :     AVCTxt *psTxt;
    1280             :     int i, numFixedLines;
    1281             :     size_t nLen;
    1282             : 
    1283           0 :     CPLAssert(psInfo->eFileType == AVCFileTXT);
    1284             : 
    1285           0 :     psTxt = psInfo->cur.psTxt;
    1286             : 
    1287           0 :     nLen = strlen(pszLine);
    1288             : 
    1289             :     /* numFixedLines is the number of lines to expect before the line(s)
    1290             :      * with the text string
    1291             :      */
    1292           0 :     if (psInfo->nPrecision == AVC_SINGLE_PREC)
    1293           0 :         numFixedLines = 4;
    1294             :     else
    1295           0 :         numFixedLines = 6;
    1296             : 
    1297           0 :     if (psInfo->numItems == 0)
    1298             :     {
    1299             :         /*-------------------------------------------------------------
    1300             :          * Begin processing a new object, read header line:
    1301             :          *------------------------------------------------------------*/
    1302           0 :         if (nLen < 50)
    1303             :         {
    1304           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1305             :                      "Error parsing E00 TXT line: \"%s\"", pszLine);
    1306           0 :             return nullptr;
    1307             :         }
    1308             :         else
    1309             :         {
    1310             :             int numVertices;
    1311             :             /*---------------------------------------------------------
    1312             :              * With TXT, there are several unused fields that have to be
    1313             :              * set to default values... usually 0.
    1314             :              *--------------------------------------------------------*/
    1315           0 :             psTxt->nUserId = 0;
    1316           0 :             psTxt->n28 = 0;
    1317           0 :             for (i = 0; i < 20; i++)
    1318           0 :                 psTxt->anJust1[i] = psTxt->anJust2[i] = 0;
    1319           0 :             psTxt->dV2 = psTxt->dV3 = 0.0;
    1320             : 
    1321             :             /*---------------------------------------------------------
    1322             :              * System Id is not stored in the E00 file.  Annotations are
    1323             :              * stored in increasing order of System Id, starting at 1...
    1324             :              * so we just increment the previous value.
    1325             :              *--------------------------------------------------------*/
    1326           0 :             psTxt->nTxtId = ++psInfo->nCurObjectId;
    1327             : 
    1328           0 :             psTxt->nLevel = AVCE00Str2Int(pszLine, 10);
    1329             : 
    1330             :             /* Add 1 to numVerticesLine because the first vertex is
    1331             :              * always duplicated in the TXT binary structure...
    1332             :              */
    1333           0 :             psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 10, 10);
    1334           0 :             if (psTxt->numVerticesLine < 0 ||
    1335           0 :                 psTxt->numVerticesLine > 10 * 1024 * 1024)
    1336             :             {
    1337           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1338             :                          "Error parsing E00 TXT line: \"%s\"", pszLine);
    1339           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1340           0 :                 return nullptr;
    1341             :             }
    1342           0 :             psTxt->numVerticesLine++;
    1343             : 
    1344           0 :             psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 20, 10);
    1345           0 :             if (psTxt->numVerticesArrow < -10 * 1024 * 1024 ||
    1346           0 :                 psTxt->numVerticesArrow > 10 * 1024 * 1024)
    1347             :             {
    1348           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1349             :                          "Error parsing E00 TXT line: \"%s\"", pszLine);
    1350           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1351           0 :                 return nullptr;
    1352             :             }
    1353           0 :             psTxt->nSymbol = AVCE00Str2Int(pszLine + 30, 10);
    1354           0 :             psTxt->numChars = AVCE00Str2Int(pszLine + 40, 10);
    1355           0 :             if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024)
    1356             :             {
    1357           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1358             :                          "Error parsing E00 TXT line: \"%s\"", pszLine);
    1359           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1360           0 :                 return nullptr;
    1361             :             }
    1362             : 
    1363             :             /*---------------------------------------------------------
    1364             :              * Realloc the string buffer and array of vertices
    1365             :              *--------------------------------------------------------*/
    1366           0 :             psTxt->pszText = (GByte *)CPLRealloc(
    1367           0 :                 psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte));
    1368           0 :             numVertices =
    1369           0 :                 ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
    1370           0 :             if (numVertices > 0)
    1371           0 :                 psTxt->pasVertices = (AVCVertex *)CPLRealloc(
    1372           0 :                     psTxt->pasVertices, numVertices * sizeof(AVCVertex));
    1373             : 
    1374             :             /*---------------------------------------------------------
    1375             :              * Fill the whole string buffer with spaces we'll just
    1376             :              * paste lines in it using strncpy()
    1377             :              *--------------------------------------------------------*/
    1378           0 :             memset(psTxt->pszText, ' ', psTxt->numChars);
    1379           0 :             psTxt->pszText[psTxt->numChars] = '\0';
    1380             : 
    1381             :             /*---------------------------------------------------------
    1382             :              * psInfo->iCurItem is the index of the last line that was read.
    1383             :              * psInfo->numItems is the number of lines to read.
    1384             :              *--------------------------------------------------------*/
    1385           0 :             psInfo->iCurItem = 0;
    1386           0 :             psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1);
    1387             :         }
    1388             :     }
    1389           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
    1390           0 :              psInfo->iCurItem < numFixedLines - 1 && nLen >= 63)
    1391             :     {
    1392             :         /*-------------------------------------------------------------
    1393             :          * Then we have a set of 15 coordinate values... unused ones
    1394             :          * are present but are set to 0.00E+00
    1395             :          *
    1396             :          * Vals 1 to 4 are X coords of line along which text is drawn
    1397             :          * Vals 5 to 8 are the corresponding Y coords
    1398             :          * Vals 9 to 11 are the X coords of the text arrow
    1399             :          * Vals 12 to 14 are the corresponding Y coords
    1400             :          * The 15th value is the height
    1401             :          *
    1402             :          * Note that the first vertex (values 1 and 5) is duplicated
    1403             :          * in the TXT structure... go wonder why???
    1404             :          *------------------------------------------------------------*/
    1405           0 :         int iCurCoord = 0, numCoordPerLine, nItemSize, iVertex;
    1406           0 :         if (psInfo->nPrecision == AVC_SINGLE_PREC)
    1407             :         {
    1408           0 :             numCoordPerLine = 5;
    1409           0 :             nItemSize = 14; /* Num of chars for single precision float*/
    1410             :         }
    1411             :         else
    1412             :         {
    1413           0 :             numCoordPerLine = 3;
    1414           0 :             nItemSize = 21; /* Num of chars for double precision float*/
    1415             :         }
    1416           0 :         iCurCoord = psInfo->iCurItem * numCoordPerLine;
    1417             : 
    1418           0 :         for (i = 0;
    1419           0 :              i < numCoordPerLine && nLen > static_cast<size_t>(i) * nItemSize;
    1420             :              i++, iCurCoord++)
    1421             :         {
    1422           0 :             if (iCurCoord < 4 &&
    1423           0 :                 (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1)
    1424             :             {
    1425           0 :                 psTxt->pasVertices[iVertex + 1].x =
    1426           0 :                     CPLAtof(pszLine + i * nItemSize);
    1427             :                 /* The first vertex is always duplicated */
    1428           0 :                 if (iVertex == 0)
    1429           0 :                     psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
    1430             :             }
    1431           0 :             else if (iCurCoord >= 4 && iCurCoord < 8 &&
    1432           0 :                      (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1)
    1433             :             {
    1434           0 :                 psTxt->pasVertices[iVertex + 1].y =
    1435           0 :                     CPLAtof(pszLine + i * nItemSize);
    1436             :                 /* The first vertex is always duplicated */
    1437           0 :                 if (iVertex == 0)
    1438           0 :                     psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
    1439             :             }
    1440           0 :             else if (iCurCoord >= 8 && iCurCoord < 11 &&
    1441           0 :                      (iVertex = (iCurCoord - 8) % 3) <
    1442           0 :                          ABS(psTxt->numVerticesArrow))
    1443             :             {
    1444           0 :                 psTxt->pasVertices[iVertex + psTxt->numVerticesLine].x =
    1445           0 :                     CPLAtof(pszLine + i * nItemSize);
    1446             :             }
    1447           0 :             else if (iCurCoord >= 11 && iCurCoord < 14 &&
    1448           0 :                      (iVertex = (iCurCoord - 8) % 3) <
    1449           0 :                          ABS(psTxt->numVerticesArrow))
    1450             :             {
    1451           0 :                 psTxt->pasVertices[iVertex + psTxt->numVerticesLine].y =
    1452           0 :                     CPLAtof(pszLine + i * nItemSize);
    1453             :             }
    1454           0 :             else if (iCurCoord == 14)
    1455             :             {
    1456           0 :                 psTxt->dHeight = CPLAtof(pszLine + i * nItemSize);
    1457             :             }
    1458             :         }
    1459             : 
    1460           0 :         psInfo->iCurItem++;
    1461             :     }
    1462           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
    1463           0 :              psInfo->iCurItem == numFixedLines - 1 && nLen >= 14)
    1464             :     {
    1465             :         /*-------------------------------------------------------------
    1466             :          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
    1467             :          *------------------------------------------------------------*/
    1468           0 :         psTxt->f_1e2 = (float)CPLAtof(pszLine);
    1469             : 
    1470           0 :         psInfo->iCurItem++;
    1471             :     }
    1472           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
    1473           0 :              psInfo->iCurItem >= numFixedLines)
    1474             :     {
    1475             :         /*-------------------------------------------------------------
    1476             :          * Last line, contains the text string
    1477             :          * Note that text can be split in 80 chars chunk and that buffer
    1478             :          * has been previously initialized with spaces and '\0'-terminated
    1479             :          *------------------------------------------------------------*/
    1480             :         int numLines, iLine;
    1481           0 :         numLines = (psTxt->numChars - 1) / 80 + 1;
    1482           0 :         iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
    1483             : 
    1484           0 :         if (iLine == numLines - 1)
    1485             :         {
    1486           0 :             memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
    1487           0 :                    MIN((int)nLen, (psTxt->numChars - (iLine * 80))));
    1488             :         }
    1489             :         else
    1490             :         {
    1491           0 :             memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
    1492           0 :                    MIN(nLen, 80));
    1493             :         }
    1494             : 
    1495           0 :         psInfo->iCurItem++;
    1496             :     }
    1497             :     else
    1498             :     {
    1499           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1500             :                  "Error parsing E00 TXT line: \"%s\"", pszLine);
    1501           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1502           0 :         return nullptr;
    1503             :     }
    1504             : 
    1505             :     /*-----------------------------------------------------------------
    1506             :      * If we're done parsing this TXT, then reset the ParseInfo,
    1507             :      * and return a reference to the TXT structure
    1508             :      * Otherwise return nullptr, which means that we are expecting more
    1509             :      * more lines of input.
    1510             :      *----------------------------------------------------------------*/
    1511           0 :     if (psInfo->iCurItem >= psInfo->numItems)
    1512             :     {
    1513           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1514           0 :         return psTxt;
    1515             :     }
    1516             : 
    1517           0 :     return nullptr;
    1518             : }
    1519             : 
    1520             : /**********************************************************************
    1521             :  *                          AVCE00ParseNextTx6Line()
    1522             :  *
    1523             :  * Take the next line of E00 input for an TX6/TX7 object and parse it.
    1524             :  *
    1525             :  * Returns nullptr if the current object is not complete yet (expecting
    1526             :  * more lines of input) or a reference to a complete object if it
    1527             :  * is complete.
    1528             :  *
    1529             :  * The returned object is a reference to an internal data structure.
    1530             :  * It should not be modified or freed by the caller.
    1531             :  *
    1532             :  * If the input is invalid or other problems happen, then a CPLError()
    1533             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1534             :  * that the line was parsed successfully.
    1535             :  **********************************************************************/
    1536           0 : AVCTxt *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine)
    1537             : {
    1538             :     AVCTxt *psTxt;
    1539             :     int i;
    1540             :     size_t nLen;
    1541             : 
    1542           0 :     CPLAssert(psInfo->eFileType == AVCFileTX6);
    1543             : 
    1544           0 :     psTxt = psInfo->cur.psTxt;
    1545             : 
    1546           0 :     nLen = strlen(pszLine);
    1547             : 
    1548           0 :     if (psInfo->numItems == 0)
    1549             :     {
    1550             :         /*-------------------------------------------------------------
    1551             :          * Begin processing a new object, read header line:
    1552             :          *------------------------------------------------------------*/
    1553           0 :         if (nLen < 70)
    1554             :         {
    1555           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1556             :                      "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
    1557           0 :             return nullptr;
    1558             :         }
    1559             :         else
    1560             :         {
    1561             :             int numVertices;
    1562             :             /*---------------------------------------------------------
    1563             :              * System Id is not stored in the E00 file.  Annotations are
    1564             :              * stored in increasing order of System Id, starting at 1...
    1565             :              * so we just increment the previous value.
    1566             :              *--------------------------------------------------------*/
    1567           0 :             psTxt->nTxtId = ++psInfo->nCurObjectId;
    1568             : 
    1569           0 :             psTxt->nUserId = AVCE00Str2Int(pszLine, 10);
    1570           0 :             psTxt->nLevel = AVCE00Str2Int(pszLine + 10, 10);
    1571           0 :             psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 20, 10);
    1572           0 :             if (psTxt->numVerticesLine < 0 ||
    1573           0 :                 psTxt->numVerticesLine > 10 * 1024 * 1024)
    1574             :             {
    1575           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1576             :                          "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
    1577           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1578           0 :                 return nullptr;
    1579             :             }
    1580           0 :             psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 30, 10);
    1581           0 :             if (psTxt->numVerticesArrow < -10 * 1024 * 1024 ||
    1582           0 :                 psTxt->numVerticesArrow > 10 * 1024 * 1024)
    1583             :             {
    1584           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1585             :                          "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
    1586           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1587           0 :                 return nullptr;
    1588             :             }
    1589           0 :             psTxt->nSymbol = AVCE00Str2Int(pszLine + 40, 10);
    1590           0 :             psTxt->n28 = AVCE00Str2Int(pszLine + 50, 10);
    1591           0 :             psTxt->numChars = AVCE00Str2Int(pszLine + 60, 10);
    1592           0 :             if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024)
    1593             :             {
    1594           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1595             :                          "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
    1596           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1597           0 :                 return nullptr;
    1598             :             }
    1599             : 
    1600             :             /*---------------------------------------------------------
    1601             :              * Realloc the string buffer and array of vertices
    1602             :              *--------------------------------------------------------*/
    1603           0 :             psTxt->pszText = (GByte *)CPLRealloc(
    1604           0 :                 psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte));
    1605             : 
    1606           0 :             numVertices =
    1607           0 :                 ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
    1608           0 :             if (numVertices > 0)
    1609           0 :                 psTxt->pasVertices = (AVCVertex *)CPLRealloc(
    1610           0 :                     psTxt->pasVertices, numVertices * sizeof(AVCVertex));
    1611             : 
    1612             :             /*---------------------------------------------------------
    1613             :              * Fill the whole string buffer with spaces we'll just
    1614             :              * paste lines in it using strncpy()
    1615             :              *--------------------------------------------------------*/
    1616           0 :             memset(psTxt->pszText, ' ', psTxt->numChars);
    1617           0 :             psTxt->pszText[psTxt->numChars] = '\0';
    1618             : 
    1619             :             /*---------------------------------------------------------
    1620             :              * psInfo->iCurItem is the index of the last line that was read.
    1621             :              * psInfo->numItems is the number of lines to read.
    1622             :              *--------------------------------------------------------*/
    1623           0 :             psInfo->iCurItem = 0;
    1624           0 :             psInfo->numItems =
    1625           0 :                 8 + numVertices + ((psTxt->numChars - 1) / 80 + 1);
    1626             :         }
    1627             :     }
    1628           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6 &&
    1629             :              nLen >= 60)
    1630             :     {
    1631             :         /*-------------------------------------------------------------
    1632             :          * Text Justification stuff... 2 sets of 20 int16 values.
    1633             :          *------------------------------------------------------------*/
    1634             :         GInt16 *pValue;
    1635           0 :         int numValPerLine = 7;
    1636             : 
    1637           0 :         if (psInfo->iCurItem < 3)
    1638           0 :             pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
    1639             :         else
    1640           0 :             pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
    1641             : 
    1642             :         /* Last line of each set contains only 6 values instead of 7 */
    1643           0 :         if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5)
    1644           0 :             numValPerLine = 6;
    1645             : 
    1646           0 :         for (i = 0;
    1647           0 :              i < numValPerLine && nLen >= static_cast<size_t>(i) * 10 + 10; i++)
    1648           0 :             pValue[i] = (GInt16)AVCE00Str2Int(pszLine + i * 10, 10);
    1649             : 
    1650           0 :         psInfo->iCurItem++;
    1651             :     }
    1652           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6 &&
    1653             :              nLen >= 14)
    1654             :     {
    1655             :         /*-------------------------------------------------------------
    1656             :          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
    1657             :          *------------------------------------------------------------*/
    1658           0 :         psTxt->f_1e2 = (float)CPLAtof(pszLine);
    1659           0 :         psInfo->iCurItem++;
    1660             :     }
    1661           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7 &&
    1662             :              nLen >= 42)
    1663             :     {
    1664             :         /*-------------------------------------------------------------
    1665             :          * Line with 3 values, 1st value is text height.
    1666             :          *------------------------------------------------------------*/
    1667           0 :         psTxt->dHeight = CPLAtof(pszLine);
    1668           0 :         if (psInfo->nPrecision == AVC_SINGLE_PREC)
    1669             :         {
    1670           0 :             psTxt->dV2 = CPLAtof(pszLine + 14);
    1671           0 :             psTxt->dV3 = CPLAtof(pszLine + 28);
    1672             :         }
    1673             :         else
    1674             :         {
    1675           0 :             psTxt->dV2 = CPLAtof(pszLine + 21);
    1676           0 :             psTxt->dV3 = CPLAtof(pszLine + 42);
    1677             :         }
    1678             : 
    1679           0 :         psInfo->iCurItem++;
    1680             :     }
    1681           0 :     else if (psInfo->iCurItem >= 8 &&
    1682           0 :              psInfo->iCurItem < (8 + ABS(psTxt->numVerticesLine) +
    1683           0 :                                  ABS(psTxt->numVerticesArrow)) &&
    1684             :              nLen >= 28)
    1685             :     {
    1686             :         /*-------------------------------------------------------------
    1687             :          * One line for each pair of X,Y coordinates
    1688             :          * (Lines 8 to 8+numVertices-1)
    1689             :          *------------------------------------------------------------*/
    1690           0 :         psTxt->pasVertices[psInfo->iCurItem - 8].x = CPLAtof(pszLine);
    1691           0 :         if (psInfo->nPrecision == AVC_SINGLE_PREC)
    1692           0 :             psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 14);
    1693             :         else
    1694           0 :             psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 21);
    1695             : 
    1696           0 :         psInfo->iCurItem++;
    1697             :     }
    1698           0 :     else if (psInfo->iCurItem >= (8 + ABS(psTxt->numVerticesLine) +
    1699           0 :                                   ABS(psTxt->numVerticesArrow)) &&
    1700           0 :              psInfo->iCurItem < psInfo->numItems &&
    1701           0 :              (psTxt->numChars - 1) / 80 + 1 -
    1702           0 :                      (psInfo->numItems - psInfo->iCurItem) >=
    1703             :                  0)
    1704             :     {
    1705             :         /*-------------------------------------------------------------
    1706             :          * Last line, contains the text string
    1707             :          * Note that text can be split in 80 chars chunk and that buffer
    1708             :          * has been previously initialized with spaces and '\0'-terminated
    1709             :          *------------------------------------------------------------*/
    1710             :         int numLines, iLine;
    1711           0 :         numLines = (psTxt->numChars - 1) / 80 + 1;
    1712           0 :         iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
    1713             : 
    1714           0 :         if (iLine == numLines - 1)
    1715             :         {
    1716           0 :             memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
    1717           0 :                    MIN((int)nLen, (psTxt->numChars - (iLine * 80))));
    1718             :         }
    1719             :         else
    1720             :         {
    1721           0 :             memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
    1722           0 :                    MIN(nLen, 80));
    1723             :         }
    1724             : 
    1725           0 :         psInfo->iCurItem++;
    1726             :     }
    1727             :     else
    1728             :     {
    1729           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1730             :                  "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
    1731           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1732           0 :         return nullptr;
    1733             :     }
    1734             : 
    1735             :     /*-----------------------------------------------------------------
    1736             :      * If we're done parsing this TX6/TX7, then reset the ParseInfo,
    1737             :      * and return a reference to the TXT structure
    1738             :      * Otherwise return nullptr, which means that we are expecting more
    1739             :      * more lines of input.
    1740             :      *----------------------------------------------------------------*/
    1741           0 :     if (psInfo->iCurItem >= psInfo->numItems)
    1742             :     {
    1743           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1744           0 :         return psTxt;
    1745             :     }
    1746             : 
    1747           0 :     return nullptr;
    1748             : }
    1749             : 
    1750             : /**********************************************************************
    1751             :  *                          AVCE00ParseNextRxpLine()
    1752             :  *
    1753             :  * Take the next line of E00 input for an RXP object and parse it.
    1754             :  *
    1755             :  * Returns nullptr if the current object is not complete yet (expecting
    1756             :  * more lines of input) or a reference to a complete object if it
    1757             :  * is complete.
    1758             :  *
    1759             :  * The returned object is a reference to an internal data structure.
    1760             :  * It should not be modified or freed by the caller.
    1761             :  *
    1762             :  * If the input is invalid or other problems happen, then a CPLError()
    1763             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1764             :  * that the line was parsed successfully.
    1765             :  **********************************************************************/
    1766           0 : AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine)
    1767             : {
    1768             :     AVCRxp *psRxp;
    1769             :     size_t nLen;
    1770             : 
    1771           0 :     CPLAssert(psInfo->eFileType == AVCFileRXP);
    1772             : 
    1773           0 :     psRxp = psInfo->cur.psRxp;
    1774             : 
    1775           0 :     nLen = strlen(pszLine);
    1776             : 
    1777           0 :     if (nLen >= 20)
    1778             :     {
    1779             :         /*-------------------------------------------------------------
    1780             :          * RXP Entries are only one line each:
    1781             :          *   Value1, Value2 (meaning of the value??? Don't know!!!)
    1782             :          *------------------------------------------------------------*/
    1783           0 :         psRxp->n1 = AVCE00Str2Int(pszLine, 10);
    1784           0 :         psRxp->n2 = AVCE00Str2Int(pszLine + 10, 10);
    1785             :     }
    1786             :     else
    1787             :     {
    1788           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1789             :                  "Error parsing E00 RXP line: \"%s\"", pszLine);
    1790           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1791           0 :         return nullptr;
    1792             :     }
    1793             : 
    1794             :     /*-----------------------------------------------------------------
    1795             :      * If we're done parsing this RXP, then reset the ParseInfo,
    1796             :      * and return a reference to the RXP structure
    1797             :      * Otherwise return nullptr, which means that we are expecting more
    1798             :      * more lines of input.
    1799             :      *----------------------------------------------------------------*/
    1800           0 :     if (psInfo->iCurItem >= psInfo->numItems)
    1801             :     {
    1802           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1803           0 :         return psRxp;
    1804             :     }
    1805             : 
    1806           0 :     return nullptr;
    1807             : }
    1808             : 
    1809             : /*=====================================================================
    1810             :                             TABLE stuff
    1811             :  =====================================================================*/
    1812             : 
    1813             : /**********************************************************************
    1814             :  *                          AVCE00ParseNextTableDefLine()
    1815             :  *
    1816             :  * Take the next line of E00 input for an TableDef object and parse it.
    1817             :  *
    1818             :  * Returns nullptr if the current object is not complete yet (expecting
    1819             :  * more lines of input) or a reference to a complete object if it
    1820             :  * is complete.
    1821             :  *
    1822             :  * The returned object is a reference to an internal data structure.
    1823             :  * It should not be modified or freed by the caller.
    1824             :  *
    1825             :  * If the input is invalid or other problems happen, then a CPLError()
    1826             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    1827             :  * that the line was parsed successfully.
    1828             :  **********************************************************************/
    1829         338 : AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo,
    1830             :                                          const char *pszLine)
    1831             : {
    1832             :     AVCTableDef *psTableDef;
    1833             :     size_t nLen;
    1834             : 
    1835         338 :     CPLAssert(psInfo->eFileType == AVCFileTABLE);
    1836             : 
    1837         338 :     psTableDef = psInfo->hdr.psTableDef; /* May be nullptr on first call */
    1838             : 
    1839         338 :     nLen = strlen(pszLine);
    1840             : 
    1841         338 :     if (psInfo->numItems == 0)
    1842             :     {
    1843             :         /*-------------------------------------------------------------
    1844             :          * Begin processing a new TableDef.  Read header line:
    1845             :          *    TableName, extFlag, numFields, RecSize, numRecords
    1846             :          *------------------------------------------------------------*/
    1847          55 :         if (nLen < 56)
    1848             :         {
    1849           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1850             :                      "Error parsing E00 Table Definition line: \"%s\"",
    1851             :                      pszLine);
    1852           0 :             return nullptr;
    1853             :         }
    1854             :         else
    1855             :         {
    1856             :             /*---------------------------------------------------------
    1857             :              * Parse header line and alloc and init. a new psTableDef struct
    1858             :              *--------------------------------------------------------*/
    1859          55 :             psTableDef = psInfo->hdr.psTableDef =
    1860          55 :                 (AVCTableDef *)CPLCalloc(1, sizeof(AVCTableDef));
    1861          55 :             psInfo->bTableHdrComplete = FALSE;
    1862             : 
    1863          55 :             strncpy(psTableDef->szTableName, pszLine, 32);
    1864          55 :             psTableDef->szTableName[32] = '\0';
    1865          55 :             strncpy(psTableDef->szExternal, pszLine + 32, 2);
    1866          55 :             psTableDef->szExternal[2] = '\0';
    1867             : 
    1868          55 :             psTableDef->numFields = (GInt16)AVCE00Str2Int(pszLine + 34, 4);
    1869          55 :             psTableDef->nRecSize = (GInt16)AVCE00Str2Int(pszLine + 42, 4);
    1870          55 :             psTableDef->numRecords = AVCE00Str2Int(pszLine + 46, 10);
    1871          55 :             if (psTableDef->numFields < 0 || psTableDef->numFields > 10 * 1024)
    1872             :             {
    1873           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1874             :                          "Error parsing E00 Table Definition line: \"%s\"",
    1875             :                          pszLine);
    1876           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1877           0 :                 psTableDef->numFields = 0;
    1878           0 :                 return nullptr;
    1879             :             }
    1880             : 
    1881             :             /*---------------------------------------------------------
    1882             :              * Alloc array of fields defs, will be filled in further calls
    1883             :              *--------------------------------------------------------*/
    1884         110 :             psTableDef->pasFieldDef = (AVCFieldInfo *)CPLCalloc(
    1885          55 :                 psTableDef->numFields, sizeof(AVCFieldInfo));
    1886             : 
    1887             :             /*---------------------------------------------------------
    1888             :              * psInfo->iCurItem is the index of the last field def we read.
    1889             :              * psInfo->numItems is the number of field defs to read,
    1890             :              *                     including deleted ones.
    1891             :              *--------------------------------------------------------*/
    1892          55 :             psInfo->numItems = AVCE00Str2Int(pszLine + 38, 4);
    1893          55 :             psInfo->iCurItem = 0;
    1894          55 :             psInfo->nCurObjectId = 0; /* We'll use it as a field index */
    1895             :         }
    1896             :     }
    1897         283 :     else if (psInfo->iCurItem < psInfo->numItems && nLen >= 69)
    1898             :     {
    1899             :         /*-------------------------------------------------------------
    1900             :          * Read an attribute field definition
    1901             :          * If field index is -1, then we ignore this line...
    1902             :          *------------------------------------------------------------*/
    1903             :         int nIndex;
    1904             : 
    1905         283 :         nIndex = AVCE00Str2Int(pszLine + 65, 4);
    1906             : 
    1907         283 :         if (nIndex > 0 && psInfo->nCurObjectId >= psTableDef->numFields)
    1908             :         {
    1909           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1910             :                      "Error parsing E00 INFO Table Header: "
    1911             :                      "number of fields is invalid "
    1912             :                      "(expected %d, got at least %d)",
    1913           0 :                      psTableDef->numFields, psInfo->nCurObjectId + 1);
    1914           0 :             psInfo->numItems = psInfo->iCurItem = psInfo->nCurObjectId;
    1915           0 :             return nullptr;
    1916             :         }
    1917             : 
    1918         283 :         if (nIndex > 0)
    1919             :         {
    1920             :             AVCFieldInfo *psDef;
    1921         283 :             psDef = &(psTableDef->pasFieldDef[psInfo->nCurObjectId]);
    1922             : 
    1923         283 :             psDef->nIndex = (GInt16)nIndex;
    1924             : 
    1925         283 :             strncpy(psDef->szName, pszLine, 16);
    1926         283 :             psDef->szName[16] = '\0';
    1927             : 
    1928         283 :             psDef->nSize = (GInt16)AVCE00Str2Int(pszLine + 16, 3);
    1929         283 :             psDef->v2 = (GInt16)AVCE00Str2Int(pszLine + 19, 2);
    1930             : 
    1931         283 :             psDef->nOffset = (GInt16)AVCE00Str2Int(pszLine + 21, 4);
    1932             : 
    1933         283 :             psDef->v4 = (GInt16)AVCE00Str2Int(pszLine + 25, 1);
    1934         283 :             psDef->v5 = (GInt16)AVCE00Str2Int(pszLine + 26, 2);
    1935         283 :             psDef->nFmtWidth = (GInt16)AVCE00Str2Int(pszLine + 28, 4);
    1936         283 :             psDef->nFmtPrec = (GInt16)AVCE00Str2Int(pszLine + 32, 2);
    1937         283 :             psDef->nType1 = (GInt16)AVCE00Str2Int(pszLine + 34, 3) / 10;
    1938         283 :             psDef->nType2 = AVCE00Str2Int(pszLine + 34, 3) % 10;
    1939         283 :             psDef->v10 = (GInt16)AVCE00Str2Int(pszLine + 37, 2);
    1940         283 :             psDef->v11 = (GInt16)AVCE00Str2Int(pszLine + 39, 4);
    1941         283 :             psDef->v12 = (GInt16)AVCE00Str2Int(pszLine + 43, 4);
    1942         283 :             psDef->v13 = (GInt16)AVCE00Str2Int(pszLine + 47, 2);
    1943         283 :             strncpy(psDef->szAltName, pszLine + 49, 16);
    1944         283 :             psDef->szAltName[16] = '\0';
    1945             : 
    1946         283 :             if (psDef->nSize < 0)
    1947             :             {
    1948           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1949             :                          "Error parsing E00 Table Definition line: \"%s\"",
    1950             :                          pszLine);
    1951           0 :                 psInfo->numItems = psInfo->iCurItem = 0;
    1952           0 :                 return nullptr;
    1953             :             }
    1954             : 
    1955         283 :             psInfo->nCurObjectId++;
    1956             :         }
    1957         283 :         psInfo->iCurItem++;
    1958             :     }
    1959             :     else
    1960             :     {
    1961           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1962             :                  "Error parsing E00 Table Definition line: \"%s\"", pszLine);
    1963           0 :         psInfo->numItems = psInfo->iCurItem = 0;
    1964           0 :         return nullptr;
    1965             :     }
    1966             : 
    1967             :     /*-----------------------------------------------------------------
    1968             :      * If we're done parsing this TableDef, then reset the ParseInfo,
    1969             :      * and return a reference to the TableDef structure.
    1970             :      * Next calls should go to AVCE00ParseNextTableRecLine() to
    1971             :      * read data records.
    1972             :      * Otherwise return nullptr, which means that we are expecting more
    1973             :      * more lines of input.
    1974             :      *----------------------------------------------------------------*/
    1975         338 :     if (psInfo->iCurItem >= psInfo->numItems)
    1976             :     {
    1977          55 :         psInfo->numItems = psInfo->iCurItem = 0;
    1978          55 :         psInfo->nCurObjectId = 0;
    1979             : 
    1980          55 :         psInfo->bTableHdrComplete = TRUE;
    1981             : 
    1982             :         /*---------------------------------------------------------
    1983             :          * It is possible to have a table with 0 records... in this
    1984             :          * case we are already at the end of the section for that table.
    1985             :          *--------------------------------------------------------*/
    1986          55 :         if (psTableDef->numRecords == 0)
    1987           0 :             psInfo->bForceEndOfSection = TRUE;
    1988             : 
    1989          55 :         return psTableDef;
    1990             :     }
    1991             : 
    1992         283 :     return nullptr;
    1993             : }
    1994             : 
    1995             : /**********************************************************************
    1996             :  *                         _AVCE00ParseTableRecord()
    1997             :  *
    1998             :  * Parse the record data present inside psInfo->pszBuf and fill and
    1999             :  * return the psInfo->cur.pasFields[].
    2000             :  *
    2001             :  * This function should not be called directly... it is used by
    2002             :  * AVCE00ParseNextTableRecLine().
    2003             :  **********************************************************************/
    2004         486 : static AVCField *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
    2005             : {
    2006             :     AVCField *pasFields;
    2007             :     AVCFieldInfo *pasDef;
    2008             :     AVCTableDef *psTableDef;
    2009             :     int i, nType, nSize;
    2010             :     char szFormat[20];
    2011             :     char *pszBuf, szTmp[30];
    2012             : 
    2013         486 :     pasFields = psInfo->cur.pasFields;
    2014         486 :     psTableDef = psInfo->hdr.psTableDef;
    2015         486 :     pasDef = psTableDef->pasFieldDef;
    2016             : 
    2017         486 :     pszBuf = psInfo->pszBuf;
    2018         486 :     CPLAssert(pszBuf);
    2019             : 
    2020        3047 :     for (i = 0; i < psTableDef->numFields; i++)
    2021             :     {
    2022        2561 :         nType = pasDef[i].nType1 * 10;
    2023        2561 :         nSize = pasDef[i].nSize;
    2024             : 
    2025        2561 :         if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
    2026             :             nType == AVC_FT_FIXINT)
    2027             :         {
    2028         405 :             strncpy((char *)pasFields[i].pszStr, pszBuf, nSize);
    2029         405 :             pasFields[i].pszStr[nSize] = '\0';
    2030         405 :             pszBuf += nSize;
    2031             :         }
    2032        2156 :         else if (nType == AVC_FT_FIXNUM)
    2033             :         {
    2034             :             /* TYPE 40 attributes are stored with 1 byte per digit
    2035             :              * in binary format, and as single precision floats in
    2036             :              * E00 tables, even in double precision coverages.
    2037             :              */
    2038             :             const char *pszTmpStr;
    2039           0 :             strncpy(szTmp, pszBuf, 14);
    2040           0 :             szTmp[14] = '\0';
    2041           0 :             pszBuf += 14;
    2042             : 
    2043             :             /* Compensate for a very odd behavior observed in some E00 files.
    2044             :              * A type 40 field can be written in decimal format instead of
    2045             :              * exponent format, but in this case the decimal point is shifted
    2046             :              * one position to the right, resulting in a value 10 times bigger
    2047             :              * than expected.  So if the value is not in exponent format then
    2048             :              * we should shift the decimal point to the left before we
    2049             :              * interpret it.  (bug 599)
    2050             :              */
    2051           0 :             if (!strchr(szTmp, 'E') && !strchr(szTmp, 'e'))
    2052             :             {
    2053             :                 char *pszTmp;
    2054           0 :                 if ((pszTmp = strchr(szTmp, '.')) != nullptr && pszTmp != szTmp)
    2055             :                 {
    2056           0 :                     *pszTmp = *(pszTmp - 1);
    2057           0 :                     *(pszTmp - 1) = '.';
    2058             :                 }
    2059             :             }
    2060             : 
    2061             :             /* We use nSize and nFmtPrec for the format because nFmtWidth can
    2062             :              * be different from nSize, but nSize has priority since it
    2063             :              * is the actual size of the field in memory.
    2064             :              */
    2065           0 :             snprintf(szFormat, sizeof(szFormat), "%%%d.%df", nSize,
    2066           0 :                      pasDef[i].nFmtPrec);
    2067           0 :             pszTmpStr = CPLSPrintf(szFormat, CPLAtof(szTmp));
    2068             : 
    2069             :             /* If value is bigger than size, then it is too bad... we
    2070             :              * truncate it... but this should never happen in clean datasets.
    2071             :              */
    2072           0 :             if ((int)strlen(pszTmpStr) > nSize)
    2073           0 :                 pszTmpStr = pszTmpStr + strlen(pszTmpStr) - nSize;
    2074           0 :             strncpy((char *)pasFields[i].pszStr, pszTmpStr, nSize);
    2075           0 :             pasFields[i].pszStr[nSize] = '\0';
    2076             :         }
    2077        2156 :         else if (nType == AVC_FT_BININT && nSize == 4)
    2078             :         {
    2079         986 :             pasFields[i].nInt32 = AVCE00Str2Int(pszBuf, 11);
    2080         986 :             pszBuf += 11;
    2081             :         }
    2082        1170 :         else if (nType == AVC_FT_BININT && nSize == 2)
    2083             :         {
    2084           0 :             pasFields[i].nInt16 = (GInt16)AVCE00Str2Int(pszBuf, 6);
    2085           0 :             pszBuf += 6;
    2086             :         }
    2087        1170 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
    2088             :         {
    2089             :             /* NOTE: The E00 representation for a binary float is
    2090             :              * defined by its binary size, not by the coverage's
    2091             :              * precision.
    2092             :              */
    2093        1170 :             strncpy(szTmp, pszBuf, 14);
    2094        1170 :             szTmp[14] = '\0';
    2095        1170 :             pasFields[i].fFloat = (float)CPLAtof(szTmp);
    2096        1170 :             pszBuf += 14;
    2097             :         }
    2098           0 :         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
    2099             :         {
    2100             :             /* NOTE: The E00 representation for a binary float is
    2101             :              * defined by its binary size, not by the coverage's
    2102             :              * precision.
    2103             :              */
    2104           0 :             strncpy(szTmp, pszBuf, 24);
    2105           0 :             szTmp[24] = '\0';
    2106           0 :             pasFields[i].dDouble = CPLAtof(szTmp);
    2107           0 :             pszBuf += 24;
    2108             :         }
    2109             :         else
    2110             :         {
    2111             :             /*-----------------------------------------------------
    2112             :              * Hummm... unsupported field type...
    2113             :              *----------------------------------------------------*/
    2114           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    2115             :                      "_AVCE00ParseTableRecord(): Unsupported field type "
    2116             :                      "(type=%d, size=%d)",
    2117           0 :                      nType, pasDef[i].nSize);
    2118           0 :             return nullptr;
    2119             :         }
    2120             :     }
    2121             : 
    2122         486 :     CPLAssert(pszBuf == psInfo->pszBuf + psInfo->nTableE00RecLength);
    2123             : 
    2124         486 :     return pasFields;
    2125             : }
    2126             : 
    2127             : /**********************************************************************
    2128             :  *                          AVCE00ParseNextTableRecLine()
    2129             :  *
    2130             :  * Take the next line of E00 input for an Table data record and parse it.
    2131             :  *
    2132             :  * Returns nullptr if the current record is not complete yet (expecting
    2133             :  * more lines of input) or a reference to a complete record if it
    2134             :  * is complete.
    2135             :  *
    2136             :  * The returned record is a reference to an internal data structure.
    2137             :  * It should not be modified or freed by the caller.
    2138             :  *
    2139             :  * If the input is invalid or other problems happen, then a CPLError()
    2140             :  * will be generated.  CPLGetLastErrorNo() should be called to check
    2141             :  * that the line was parsed successfully.
    2142             :  **********************************************************************/
    2143         570 : AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo,
    2144             :                                       const char *pszLine)
    2145             : {
    2146         570 :     AVCField *pasFields = nullptr;
    2147             :     AVCTableDef *psTableDef;
    2148             :     int i;
    2149             : 
    2150         570 :     CPLAssert(psInfo->eFileType == AVCFileTABLE);
    2151             : 
    2152         570 :     psTableDef = psInfo->hdr.psTableDef;
    2153             : 
    2154         570 :     if (psInfo->bForceEndOfSection || psTableDef->numFields == 0 ||
    2155         570 :         psTableDef->numRecords == 0)
    2156             :     {
    2157           0 :         psInfo->bForceEndOfSection = TRUE;
    2158           0 :         return nullptr;
    2159             :     }
    2160             : 
    2161             :     /*-----------------------------------------------------------------
    2162             :      * On the first call for a new table, we have some allocations to
    2163             :      * do:
    2164             :      * - make sure the psInfo->szBuf is big enough to hold one complete
    2165             :      *   E00 data record.
    2166             :      * - Alloc the array of Field values (psInfo->cur.pasFields[])
    2167             :      *   for the number of fields in this table.
    2168             :      *----------------------------------------------------------------*/
    2169         570 :     if (psInfo->numItems == 0 && psInfo->nCurObjectId == 0)
    2170             :     {
    2171             :         /*-------------------------------------------------------------
    2172             :          * Realloc E00 buffer
    2173             :          *------------------------------------------------------------*/
    2174         110 :         psInfo->nTableE00RecLength = _AVCE00ComputeRecSize(
    2175          55 :             psTableDef->numFields, psTableDef->pasFieldDef, FALSE);
    2176          55 :         if (psInfo->nTableE00RecLength < 0)
    2177             :         {
    2178           0 :             return nullptr;
    2179             :         }
    2180             : 
    2181          55 :         if (psInfo->nBufSize < psInfo->nTableE00RecLength + 1)
    2182             :         {
    2183           0 :             psInfo->nBufSize = psInfo->nTableE00RecLength + 1;
    2184           0 :             psInfo->pszBuf =
    2185           0 :                 (char *)CPLRealloc(psInfo->pszBuf, psInfo->nBufSize);
    2186             :         }
    2187             : 
    2188             :         /*---------------------------------------------------------
    2189             :          * Alloc psInfo->cur.pasFields[]
    2190             :          * Also alloc buffers for string attributes.
    2191             :          *--------------------------------------------------------*/
    2192          55 :         psInfo->cur.pasFields =
    2193          55 :             (AVCField *)CPLCalloc(psTableDef->numFields, sizeof(AVCField));
    2194         338 :         for (i = 0; i < psTableDef->numFields; i++)
    2195             :         {
    2196         283 :             if (psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_DATE ||
    2197         283 :                 psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_CHAR ||
    2198         261 :                 psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXINT ||
    2199         261 :                 psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM)
    2200             :             {
    2201          22 :                 psInfo->cur.pasFields[i].pszStr = (GByte *)CPLCalloc(
    2202          22 :                     psTableDef->pasFieldDef[i].nSize + 1, sizeof(GByte));
    2203             :             }
    2204             :         }
    2205             :     }
    2206             : 
    2207         570 :     if (psInfo->numItems == 0)
    2208             :     {
    2209             :         /*-----------------------------------------------------------------
    2210             :          * Begin processing a new record... we'll accumulate the 80
    2211             :          * chars lines until we have the whole record in our buffer
    2212             :          * and parse it only at the end.
    2213             :          * Lines shorter than 80 chars are legal, and in this case
    2214             :          * they will be padded with spaces up to 80 chars.
    2215             :          *----------------------------------------------------------------*/
    2216             : 
    2217             :         /*---------------------------------------------------------
    2218             :          * First fill the whole record buffer with spaces we'll just
    2219             :          * paste lines in it using strncpy()
    2220             :          *--------------------------------------------------------*/
    2221         486 :         memset(psInfo->pszBuf, ' ', psInfo->nTableE00RecLength);
    2222         486 :         psInfo->pszBuf[psInfo->nTableE00RecLength] = '\0';
    2223             : 
    2224             :         /*---------------------------------------------------------
    2225             :          * psInfo->iCurItem is the number of chars buffered so far.
    2226             :          * psInfo->numItems is the number of chars to expect in one record.
    2227             :          *--------------------------------------------------------*/
    2228         486 :         psInfo->numItems = psInfo->nTableE00RecLength;
    2229         486 :         psInfo->iCurItem = 0;
    2230             :     }
    2231             : 
    2232         570 :     if (psInfo->iCurItem < psInfo->numItems)
    2233             :     {
    2234             :         /*-------------------------------------------------------------
    2235             :          * Continue to accumulate the 80 chars lines until we have
    2236             :          * the whole record in our buffer.  We'll parse it only at the end.
    2237             :          * Lines shorter than 80 chars are legal, and in this case
    2238             :          * they padded with spaces up to 80 chars.
    2239             :          *------------------------------------------------------------*/
    2240             :         int nSrcLen, nLenToCopy;
    2241             : 
    2242         570 :         nSrcLen = (int)strlen(pszLine);
    2243         570 :         nLenToCopy =
    2244         570 :             MIN(80, MIN(nSrcLen, (psInfo->numItems - psInfo->iCurItem)));
    2245         570 :         strncpy(psInfo->pszBuf + psInfo->iCurItem, pszLine, nLenToCopy);
    2246             : 
    2247         570 :         psInfo->iCurItem += 80;
    2248             :     }
    2249             : 
    2250         570 :     if (psInfo->iCurItem >= psInfo->numItems)
    2251             :     {
    2252             :         /*-------------------------------------------------------------
    2253             :          * OK, we've got one full record in the buffer... parse it and
    2254             :          * return the pasFields[]
    2255             :          *------------------------------------------------------------*/
    2256         486 :         pasFields = _AVCE00ParseTableRecord(psInfo);
    2257             : 
    2258         486 :         if (pasFields == nullptr)
    2259             :         {
    2260           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    2261             :                      "Error parsing E00 Table Record: \"%s\"", psInfo->pszBuf);
    2262           0 :             return nullptr;
    2263             :         }
    2264             : 
    2265         486 :         psInfo->numItems = psInfo->iCurItem = 0;
    2266         486 :         psInfo->nCurObjectId++;
    2267             :     }
    2268             : 
    2269             :     /*-----------------------------------------------------------------
    2270             :      * Since there is no explicit "end of table" line, we set the
    2271             :      * bForceEndOfSection flag when the last record is read.
    2272             :      *----------------------------------------------------------------*/
    2273         570 :     if (psInfo->nCurObjectId >= psTableDef->numRecords)
    2274             :     {
    2275          52 :         psInfo->bForceEndOfSection = TRUE;
    2276             :     }
    2277             : 
    2278         570 :     return pasFields;
    2279             : }

Generated by: LCOV version 1.14