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

Generated by: LCOV version 1.14