LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/avc - avc_e00parse.c (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 718 350 48.7 %
Date: 2011-12-18 Functions: 22 17 77.3 %

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

Generated by: LCOV version 1.7