LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/avc - avc_e00gen.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 11 435 2.5 %
Date: 2026-03-05 10:33:42 Functions: 2 17 11.8 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     avc_e00gen.c
       4             :  * Project:  Arc/Info vector coverage (AVC)  BIN->E00 conversion library
       5             :  * Language: ANSI C
       6             :  * Purpose:  Functions to generate ASCII E00 lines form binary structures.
       7             :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       8             :  *
       9             :  **********************************************************************
      10             :  * Copyright (c) 1999-2005, Daniel Morissette
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  **********************************************************************
      14             :  *
      15             :  * $Log: avc_e00gen.c,v $
      16             :  * Revision 1.18  2008/07/23 20:51:38  dmorissette
      17             :  * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
      18             :  * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
      19             :  *
      20             :  * Revision 1.17  2006/06/14 15:01:33  daniel
      21             :  * Remove any embedded '\0' from data line in AVCE00GenTableRec()
      22             :  *
      23             :  * Revision 1.16  2005/06/03 03:49:58  daniel
      24             :  * Update email address, website url, and copyright dates
      25             :  *
      26             :  * Revision 1.15  2004/08/19 17:48:20  warmerda
      27             :  * Avoid uninitialized variable warnings.
      28             :  *
      29             :  * Revision 1.14  2001/11/25 21:15:23  daniel
      30             :  * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
      31             :  * digits to double precision as we generate E00 output (bug599)
      32             :  *
      33             :  * Revision 1.13  2001/11/19 20:39:48  daniel
      34             :  * Change to correctly format 0-arc PAL records, so that they have a
      35             :  * single "filler" arc record
      36             :  *
      37             :  * Revision 1.12  2000/09/26 20:21:04  daniel
      38             :  * Added AVCCoverPC write
      39             :  *
      40             :  * Revision 1.11  2000/09/22 19:45:20  daniel
      41             :  * Switch to MIT-style license
      42             :  *
      43             :  * Revision 1.10  2000/02/04 04:54:03  daniel
      44             :  * Fixed warnings
      45             :  *
      46             :  * Revision 1.9  2000/02/03 07:21:02  daniel
      47             :  * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks
      48             :  *
      49             :  * Revision 1.8  2000/02/02 04:28:00  daniel
      50             :  * Fixed support of TX6/RXP/RPL coming from "weird" coverages
      51             :  *
      52             :  * Revision 1.7  1999/08/23 18:20:49  daniel
      53             :  * Fixed support for attribute fields type 40
      54             :  *
      55             :  * Revision 1.6  1999/05/17 16:19:39  daniel
      56             :  * Made sure ACVE00GenTableRec() removes all spaces at the end of a
      57             :  * table record line (it used to leave one space)
      58             :  *
      59             :  * Revision 1.5  1999/05/11 02:08:17  daniel
      60             :  * Simple changes related to the addition of coverage write support.
      61             :  *
      62             :  * Revision 1.4  1999/03/03 02:06:38  daniel
      63             :  * Properly handle 8 bytes floats inside single precision tables.
      64             :  *
      65             :  * Revision 1.3  1999/02/25 17:01:58  daniel
      66             :  * Added support for 16 bit integers in INFO tables (type=50, size=2)
      67             :  *
      68             :  * Revision 1.2  1999/02/25 04:17:51  daniel
      69             :  * Added TXT, TX6/TX7, RXP and RPL support + some minor changes
      70             :  *
      71             :  * Revision 1.1  1999/01/29 16:28:52  daniel
      72             :  * Initial revision
      73             :  *
      74             :  **********************************************************************/
      75             : 
      76             : #include "avc.h"
      77             : 
      78             : #include <algorithm>
      79             : #include <cassert>
      80             : #include <cmath>
      81             : #include <ctype.h> /* toupper() */
      82             : 
      83             : /**********************************************************************
      84             :  *                          AVCE00GenInfoAlloc()
      85             :  *
      86             :  * Allocate and initialize a new AVCE00GenInfo structure.
      87             :  *
      88             :  * The structure will eventually have to be freed with AVCE00GenInfoFree().
      89             :  **********************************************************************/
      90           3 : AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision)
      91             : {
      92             :     AVCE00GenInfo *psInfo;
      93             : 
      94           3 :     psInfo = (AVCE00GenInfo *)CPLCalloc(1, sizeof(AVCE00GenInfo));
      95             : 
      96             :     /* Allocate output buffer.
      97             :      * 2k should be enough... the biggest thing we'll need to store
      98             :      * in it will be 1 complete INFO table record.
      99             :      */
     100           3 :     psInfo->nBufSize = 2048;
     101           3 :     psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize * sizeof(char));
     102             : 
     103           3 :     psInfo->nPrecision = nCoverPrecision;
     104             : 
     105           3 :     return psInfo;
     106             : }
     107             : 
     108             : /**********************************************************************
     109             :  *                          AVCE00GenInfoFree()
     110             :  *
     111             :  * Free any memory associated with a AVCE00GenInfo structure.
     112             :  **********************************************************************/
     113           3 : void AVCE00GenInfoFree(AVCE00GenInfo *psInfo)
     114             : {
     115           3 :     if (psInfo)
     116           3 :         CPLFree(psInfo->pszBuf);
     117           3 :     CPLFree(psInfo);
     118           3 : }
     119             : 
     120             : /**********************************************************************
     121             :  *                          AVCE00GenReset()
     122             :  *
     123             :  * Reset the fields in the AVCE00GenInfo structure so that further calls
     124             :  * with bCont = TRUE (ex: AVCE00GenArc(psInfo, TRUE)) would return nullptr.
     125             :  **********************************************************************/
     126           0 : void AVCE00GenReset(AVCE00GenInfo *psInfo)
     127             : {
     128             :     /* Reinitialize counters so that further calls with bCont = TRUE,
     129             :      * like AVCE00GenArc(psInfo, TRUE) would return nullptr.
     130             :      */
     131           0 :     psInfo->iCurItem = psInfo->numItems = 0;
     132           0 : }
     133             : 
     134             : /**********************************************************************
     135             :  *                          AVCE00GenStartSection()
     136             :  *
     137             :  * Generate the first line of an E00 section.
     138             :  *
     139             :  * pszClassName applies only to JABBERWOCKY type of sections.
     140             :  **********************************************************************/
     141           0 : const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType,
     142             :                                   const char *pszClassName)
     143             : {
     144           0 :     const char *pszName = "UNK";
     145             : 
     146           0 :     AVCE00GenReset(psInfo);
     147             : 
     148           0 :     if (eType == AVCFileTX6 || eType == AVCFileRXP || eType == AVCFileRPL)
     149             :     {
     150             :         /* TX6/RXP/RPL sections start with the class name (the basename
     151             :          * of the file) in uppercase.
     152             :          * ex:  The section for "cities.txt" would start with "CITIES"
     153             :          */
     154             :         int i;
     155           0 :         for (i = 0; pszClassName[i] != '\0'; i++)
     156             :         {
     157           0 :             psInfo->pszBuf[i] =
     158           0 :                 (char)CPLToupper(static_cast<unsigned char>(pszClassName[i]));
     159             :         }
     160           0 :         psInfo->pszBuf[i] = '\0';
     161             :     }
     162             :     else
     163             :     {
     164             :         /* In most cases, the section starts with a 3 letters code followed
     165             :          * by the precision code (2 or 3)
     166             :          */
     167           0 :         switch (eType)
     168             :         {
     169           0 :             case AVCFileARC:
     170           0 :                 pszName = "ARC";
     171           0 :                 break;
     172           0 :             case AVCFilePAL:
     173           0 :                 pszName = "PAL";
     174           0 :                 break;
     175           0 :             case AVCFileCNT:
     176           0 :                 pszName = "CNT";
     177           0 :                 break;
     178           0 :             case AVCFileLAB:
     179           0 :                 pszName = "LAB";
     180           0 :                 break;
     181           0 :             case AVCFileTOL:
     182           0 :                 pszName = "TOL";
     183           0 :                 break;
     184           0 :             case AVCFilePRJ:
     185           0 :                 pszName = "PRJ";
     186           0 :                 break;
     187           0 :             case AVCFileTXT:
     188           0 :                 pszName = "TXT";
     189           0 :                 break;
     190           0 :             default:
     191           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     192             :                          "Unsupported E00 section type!");
     193             :         }
     194             : 
     195           0 :         if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     196           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s  3", pszName);
     197             :         else
     198           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s  2", pszName);
     199             :     }
     200             : 
     201           0 :     return psInfo->pszBuf;
     202             : }
     203             : 
     204             : /**********************************************************************
     205             :  *                          AVCE00GenEndSection()
     206             :  *
     207             :  * Generate the last line(s) of an E00 section.
     208             :  *
     209             :  * This function should be called once with bCont=FALSE to get the
     210             :  * first "end of section" line for the current section, and then call
     211             :  * with bCont=TRUE to get all the other lines.
     212             :  *
     213             :  * The function returns nullptr when there are no more lines to generate
     214             :  * for this "end of section".
     215             :  **********************************************************************/
     216           0 : const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType,
     217             :                                 GBool bCont)
     218             : {
     219           0 :     if (bCont == FALSE)
     220             :     {
     221             :         /*-------------------------------------------------------------
     222             :          * Most section types end with only 1 line.
     223             :          *------------------------------------------------------------*/
     224           0 :         AVCE00GenReset(psInfo);
     225           0 :         psInfo->iCurItem = 0;
     226             : 
     227           0 :         if (eType == AVCFileARC || eType == AVCFilePAL || eType == AVCFileRPL ||
     228           0 :             eType == AVCFileCNT || eType == AVCFileTOL || eType == AVCFileTXT ||
     229             :             eType == AVCFileTX6)
     230             :         {
     231           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
     232             :                      "        -1         0         0         0         0       "
     233             :                      "  0         0");
     234             :         }
     235           0 :         else if (eType == AVCFileLAB)
     236             :         {
     237           0 :             if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     238           0 :                 snprintf(psInfo->pszBuf, psInfo->nBufSize,
     239             :                          "        -1         0 0.00000000000000E+00 "
     240             :                          "0.00000000000000E+00");
     241             :             else
     242           0 :                 snprintf(psInfo->pszBuf, psInfo->nBufSize,
     243             :                          "        -1         0 0.0000000E+00 0.0000000E+00");
     244             :         }
     245           0 :         else if (eType == AVCFilePRJ)
     246             :         {
     247           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "EOP");
     248             :         }
     249           0 :         else if (eType == AVCFileRXP)
     250             :         {
     251           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "        -1         0");
     252             :         }
     253             :         else
     254             :         {
     255           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     256             :                      "Unsupported E00 section type!");
     257           0 :             return nullptr;
     258             :         }
     259             :     }
     260           0 :     else if (psInfo->iCurItem == 0 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
     261           0 :              (eType == AVCFilePAL || eType == AVCFileRPL))
     262             :     {
     263             :         /*---------------------------------------------------------
     264             :          * Return the 2nd line for the end of a PAL or RPL section.
     265             :          *--------------------------------------------------------*/
     266           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize,
     267             :                  " 0.00000000000000E+00 0.00000000000000E+00");
     268             : 
     269           0 :         psInfo->iCurItem++;
     270             :     }
     271             :     else
     272             :     {
     273             :         /*-----------------------------------------------------
     274             :          * All other section types end with only one line, and thus
     275             :          * we return nullptr when bCont==TRUE
     276             :          *----------------------------------------------------*/
     277           0 :         return nullptr;
     278             :     }
     279             : 
     280           0 :     return psInfo->pszBuf;
     281             : }
     282             : 
     283             : /**********************************************************************
     284             :  *                          AVCE00GenObject()
     285             :  *
     286             :  * Cover function on top of AVCE00GenArc/Pal/Cnt/Lab() that will
     287             :  * call the right function according to argument eType.
     288             :  *
     289             :  * Since there is no compiler type checking on psObj, you have to
     290             :  * be very careful to make sure you pass an object of the right type
     291             :  * when you use this function!
     292             :  *
     293             :  * The function returns nullptr when there are no more lines to generate
     294             :  * for this ARC.
     295             :  **********************************************************************/
     296           0 : const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType,
     297             :                             void *psObj, GBool bCont)
     298             : {
     299           0 :     const char *pszLine = nullptr;
     300             : 
     301           0 :     switch (eType)
     302             :     {
     303           0 :         case AVCFileARC:
     304           0 :             pszLine = AVCE00GenArc(psInfo, (AVCArc *)psObj, bCont);
     305           0 :             break;
     306           0 :         case AVCFilePAL:
     307             :         case AVCFileRPL:
     308           0 :             pszLine = AVCE00GenPal(psInfo, (AVCPal *)psObj, bCont);
     309           0 :             break;
     310           0 :         case AVCFileCNT:
     311           0 :             pszLine = AVCE00GenCnt(psInfo, (AVCCnt *)psObj, bCont);
     312           0 :             break;
     313           0 :         case AVCFileLAB:
     314           0 :             pszLine = AVCE00GenLab(psInfo, (AVCLab *)psObj, bCont);
     315           0 :             break;
     316           0 :         case AVCFileTOL:
     317           0 :             pszLine = AVCE00GenTol(psInfo, (AVCTol *)psObj, bCont);
     318           0 :             break;
     319           0 :         case AVCFileTXT:
     320           0 :             pszLine = AVCE00GenTxt(psInfo, (AVCTxt *)psObj, bCont);
     321           0 :             break;
     322           0 :         case AVCFileTX6:
     323           0 :             pszLine = AVCE00GenTx6(psInfo, (AVCTxt *)psObj, bCont);
     324           0 :             break;
     325           0 :         case AVCFilePRJ:
     326           0 :             pszLine = AVCE00GenPrj(psInfo, (char **)psObj, bCont);
     327           0 :             break;
     328           0 :         case AVCFileRXP:
     329           0 :             pszLine = AVCE00GenRxp(psInfo, (AVCRxp *)psObj, bCont);
     330           0 :             break;
     331           0 :         default:
     332           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     333             :                      "AVCE00GenObject(): Unsupported file type!");
     334             :     }
     335             : 
     336           0 :     return pszLine;
     337             : }
     338             : 
     339             : /*=====================================================================
     340             :                             ARC stuff
     341             :  =====================================================================*/
     342             : 
     343             : /**********************************************************************
     344             :  *                          AVCE00GenArc()
     345             :  *
     346             :  * Generate the next line of an E00 ARC.
     347             :  *
     348             :  * This function should be called once with bCont=FALSE to get the
     349             :  * first E00 line for the current ARC, and then call with bCont=TRUE
     350             :  * to get all the other lines for this ARC.
     351             :  *
     352             :  * The function returns nullptr when there are no more lines to generate
     353             :  * for this ARC.
     354             :  **********************************************************************/
     355           0 : const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont)
     356             : {
     357           0 :     if (bCont == FALSE)
     358             :     {
     359             :         /* Initialize the psInfo structure with info about the
     360             :          * current ARC.
     361             :          */
     362           0 :         psInfo->iCurItem = 0;
     363           0 :         if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     364           0 :             psInfo->numItems = psArc->numVertices;
     365             :         else
     366           0 :             psInfo->numItems = (psArc->numVertices + 1) / 2;
     367             : 
     368             :         /* And return the ARC header line
     369             :          */
     370           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize,
     371             :                  "%10d%10d%10d%10d%10d%10d%10d", psArc->nArcId, psArc->nUserId,
     372             :                  psArc->nFNode, psArc->nTNode, psArc->nLPoly, psArc->nRPoly,
     373             :                  psArc->numVertices);
     374             :     }
     375           0 :     else if (psInfo->iCurItem < psInfo->numItems)
     376             :     {
     377             :         int iVertex;
     378             : 
     379             :         /* return the next set of vertices for the ARC.
     380             :          */
     381           0 :         if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     382             :         {
     383           0 :             iVertex = psInfo->iCurItem;
     384             : 
     385           0 :             psInfo->pszBuf[0] = '\0';
     386           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     387             :                               psInfo->nPrecision, AVCFileARC,
     388           0 :                               psArc->pasVertices[iVertex].x);
     389           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     390             :                               psInfo->nPrecision, AVCFileARC,
     391           0 :                               psArc->pasVertices[iVertex].y);
     392             :         }
     393             :         else
     394             :         {
     395           0 :             iVertex = psInfo->iCurItem * 2;
     396             : 
     397           0 :             psInfo->pszBuf[0] = '\0';
     398           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     399             :                               psInfo->nPrecision, AVCFileARC,
     400           0 :                               psArc->pasVertices[iVertex].x);
     401           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     402             :                               psInfo->nPrecision, AVCFileARC,
     403           0 :                               psArc->pasVertices[iVertex].y);
     404             : 
     405             :             /* Check because if we have a odd number of vertices then
     406             :              * the last line contains only one pair of vertices.
     407             :              */
     408           0 :             if (iVertex + 1 < psArc->numVertices)
     409             :             {
     410           0 :                 AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     411             :                                   psInfo->nPrecision, AVCFileARC,
     412           0 :                                   psArc->pasVertices[iVertex + 1].x);
     413           0 :                 AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     414             :                                   psInfo->nPrecision, AVCFileARC,
     415           0 :                                   psArc->pasVertices[iVertex + 1].y);
     416             :             }
     417             :         }
     418           0 :         psInfo->iCurItem++;
     419             :     }
     420             :     else
     421             :     {
     422             :         /* No more lines to generate for this ARC.
     423             :          */
     424           0 :         return nullptr;
     425             :     }
     426             : 
     427           0 :     return psInfo->pszBuf;
     428             : }
     429             : 
     430             : /*=====================================================================
     431             :                             PAL stuff
     432             :  =====================================================================*/
     433             : 
     434             : /**********************************************************************
     435             :  *                          AVCE00GenPal()
     436             :  *
     437             :  * Generate the next line of an E00 PAL (Polygon Arc List) entry.
     438             :  *
     439             :  * This function should be called once with bCont=FALSE to get the
     440             :  * first E00 line for the current PAL, and then call with bCont=TRUE
     441             :  * to get all the other lines for this PAL.
     442             :  *
     443             :  * The function returns nullptr when there are no more lines to generate
     444             :  * for this PAL entry.
     445             :  **********************************************************************/
     446           0 : const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont)
     447             : {
     448           0 :     if (bCont == FALSE)
     449             :     {
     450             :         /* Initialize the psInfo structure with info about the
     451             :          * current PAL.  (Number of lines excluding header)
     452             :          */
     453           0 :         psInfo->numItems = (psPal->numArcs + 1) / 2;
     454             : 
     455             :         /* And return the PAL header line.
     456             :          */
     457           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psPal->numArcs);
     458             : 
     459           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     460             :                           AVCFilePAL, psPal->sMin.x);
     461           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     462             :                           AVCFilePAL, psPal->sMin.y);
     463             : 
     464             :         /* Double precision PAL entries have their header on 2 lines!
     465             :          */
     466           0 :         if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     467             :         {
     468           0 :             psInfo->iCurItem = -1; /* Means 1 line left in header */
     469             :         }
     470             :         else
     471             :         {
     472           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     473             :                               psInfo->nPrecision, AVCFilePAL, psPal->sMax.x);
     474           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     475             :                               psInfo->nPrecision, AVCFilePAL, psPal->sMax.y);
     476           0 :             psInfo->iCurItem = 0; /* Next thing = first Arc entry */
     477             :         }
     478             :     }
     479           0 :     else if (psInfo->iCurItem == -1)
     480             :     {
     481             :         /* Second (and last) header line for double precision coverages
     482             :          */
     483           0 :         psInfo->pszBuf[0] = '\0';
     484           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     485             :                           AVCFilePAL, psPal->sMax.x);
     486           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     487             :                           AVCFilePAL, psPal->sMax.y);
     488             : 
     489           0 :         if (psInfo->numItems == 0)
     490             :         {
     491           0 :             psInfo->iCurItem = -2; /* We have a 0-arc polygon, which needs
     492             :                                       an arc list with one "0 0 0" element */
     493             :         }
     494             :         else
     495             :         {
     496           0 :             psInfo->iCurItem = 0; /* Next thing = first Arc entry */
     497             :         }
     498             :     }
     499           0 :     else if (psInfo->iCurItem == -2)
     500             :     {
     501           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", 0, 0, 0);
     502           0 :         psInfo->iCurItem = 0; /* Next thing = first Arc entry */
     503             :     }
     504           0 :     else if (psInfo->iCurItem < psInfo->numItems)
     505             :     {
     506             :         /* Return PAL Arc entries...
     507             :          */
     508             :         int iArc;
     509             : 
     510           0 :         iArc = psInfo->iCurItem * 2;
     511             : 
     512             :         /* If we have a odd number of arcs then
     513             :          * the last line contains only one arc entry.
     514             :          */
     515           0 :         if (iArc + 1 < psPal->numArcs)
     516             :         {
     517           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
     518           0 :                      "%10d%10d%10d%10d%10d%10d", psPal->pasArcs[iArc].nArcId,
     519           0 :                      psPal->pasArcs[iArc].nFNode, psPal->pasArcs[iArc].nAdjPoly,
     520           0 :                      psPal->pasArcs[iArc + 1].nArcId,
     521           0 :                      psPal->pasArcs[iArc + 1].nFNode,
     522           0 :                      psPal->pasArcs[iArc + 1].nAdjPoly);
     523             :         }
     524             :         else
     525             :         {
     526           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d",
     527           0 :                      psPal->pasArcs[iArc].nArcId, psPal->pasArcs[iArc].nFNode,
     528           0 :                      psPal->pasArcs[iArc].nAdjPoly);
     529             :         }
     530           0 :         psInfo->iCurItem++;
     531             :     }
     532             :     else
     533             :     {
     534             :         /* No more lines to generate for this PAL.
     535             :          */
     536           0 :         return nullptr;
     537             :     }
     538             : 
     539           0 :     return psInfo->pszBuf;
     540             : }
     541             : 
     542             : /*=====================================================================
     543             :                             CNT stuff
     544             :  =====================================================================*/
     545             : 
     546             : /**********************************************************************
     547             :  *                          AVCE00GenCnt()
     548             :  *
     549             :  * Generate the next line of an E00 CNT (Polygon Centroid) entry.
     550             :  *
     551             :  * This function should be called once with bCont=FALSE to get the
     552             :  * first E00 line for the current CNT, and then call with bCont=TRUE
     553             :  * to get all the other lines for this CNT.
     554             :  *
     555             :  * The function returns nullptr when there are no more lines to generate
     556             :  * for this CNT entry.
     557             :  **********************************************************************/
     558           0 : const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont)
     559             : {
     560           0 :     if (bCont == FALSE)
     561             :     {
     562             :         /* Initialize the psInfo structure with info about the
     563             :          * current CNT.
     564             :          */
     565           0 :         psInfo->iCurItem = 0;
     566           0 :         psInfo->numItems = (psCnt->numLabels + 7) / 8;
     567             : 
     568             :         /* And return the CNT header line.
     569             :          */
     570           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psCnt->numLabels);
     571             : 
     572           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     573             :                           AVCFileCNT, psCnt->sCoord.x);
     574           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     575             :                           AVCFileCNT, psCnt->sCoord.y);
     576             :     }
     577           0 :     else if (psInfo->iCurItem < psInfo->numItems)
     578             :     {
     579             :         /* Return CNT Label Ids, 8 label Ids per line...
     580             :          */
     581             :         int i, nFirstLabel, numLabels;
     582             : 
     583           0 :         nFirstLabel = psInfo->iCurItem * 8;
     584           0 :         numLabels = std::min(8, (psCnt->numLabels - nFirstLabel));
     585             : 
     586           0 :         psInfo->pszBuf[0] = '\0';
     587           0 :         for (i = 0; i < numLabels; i++)
     588             :         {
     589           0 :             snprintf(psInfo->pszBuf + strlen(psInfo->pszBuf),
     590           0 :                      psInfo->nBufSize - strlen(psInfo->pszBuf), "%10d",
     591           0 :                      psCnt->panLabelIds[nFirstLabel + i]);
     592             :         }
     593             : 
     594           0 :         psInfo->iCurItem++;
     595             :     }
     596             :     else
     597             :     {
     598             :         /* No more lines to generate for this CNT.
     599             :          */
     600           0 :         return nullptr;
     601             :     }
     602             : 
     603           0 :     return psInfo->pszBuf;
     604             : }
     605             : 
     606             : /*=====================================================================
     607             :                             LAB stuff
     608             :  =====================================================================*/
     609             : 
     610             : /**********************************************************************
     611             :  *                          AVCE00GenLab()
     612             :  *
     613             :  * Generate the next line of an E00 LAB (Label) entry.
     614             :  *
     615             :  * This function should be called once with bCont=FALSE to get the
     616             :  * first E00 line for the current LAB, and then call with bCont=TRUE
     617             :  * to get all the other lines for this LAB.
     618             :  *
     619             :  * The function returns nullptr when there are no more lines to generate
     620             :  * for this LAB entry.
     621             :  **********************************************************************/
     622           0 : const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont)
     623             : {
     624           0 :     if (bCont == FALSE)
     625             :     {
     626             :         /* Initialize the psInfo structure with info about the
     627             :          * current LAB. (numItems = Number of lines excluding header)
     628             :          */
     629           0 :         psInfo->iCurItem = 0;
     630           0 :         if (psInfo->nPrecision == AVC_DOUBLE_PREC)
     631           0 :             psInfo->numItems = 2;
     632             :         else
     633           0 :             psInfo->numItems = 1;
     634             : 
     635             :         /* And return the LAB header line.
     636             :          */
     637           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psLab->nValue,
     638             :                  psLab->nPolyId);
     639             : 
     640           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     641             :                           AVCFileLAB, psLab->sCoord1.x);
     642           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     643             :                           AVCFileLAB, psLab->sCoord1.y);
     644             :     }
     645           0 :     else if (psInfo->iCurItem < psInfo->numItems)
     646             :     {
     647             :         /* Return next Label coordinates...
     648             :          */
     649           0 :         if (psInfo->nPrecision != AVC_DOUBLE_PREC)
     650             :         {
     651             :             /* Single precision, all on the same line
     652             :              */
     653           0 :             psInfo->pszBuf[0] = '\0';
     654           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     655             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x);
     656           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     657             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y);
     658           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     659             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x);
     660           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     661             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y);
     662             :         }
     663           0 :         else if (psInfo->iCurItem == 0)
     664             :         {
     665             :             /* 2nd line, in a double precision coverage
     666             :              */
     667           0 :             psInfo->pszBuf[0] = '\0';
     668           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     669             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x);
     670           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     671             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y);
     672             :         }
     673             :         else
     674             :         {
     675             :             /* 3rd line, in a double precision coverage
     676             :              */
     677           0 :             psInfo->pszBuf[0] = '\0';
     678           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     679             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x);
     680           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     681             :                               psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y);
     682             :         }
     683             : 
     684           0 :         psInfo->iCurItem++;
     685             :     }
     686             :     else
     687             :     {
     688             :         /* No more lines to generate for this LAB.
     689             :          */
     690           0 :         return nullptr;
     691             :     }
     692             : 
     693           0 :     return psInfo->pszBuf;
     694             : }
     695             : 
     696             : /*=====================================================================
     697             :                             TOL stuff
     698             :  =====================================================================*/
     699             : 
     700             : /**********************************************************************
     701             :  *                          AVCE00GenTol()
     702             :  *
     703             :  * Generate the next line of an E00 TOL (Tolerance) entry.
     704             :  *
     705             :  * This function should be called once with bCont=FALSE to get the
     706             :  * first E00 line for the current TOL, and then call with bCont=TRUE
     707             :  * to get all the other lines for this TOL.
     708             :  *
     709             :  * The function returns nullptr when there are no more lines to generate
     710             :  * for this TOL entry.
     711             :  **********************************************************************/
     712           0 : const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont)
     713             : {
     714           0 :     if (bCont == TRUE)
     715             :     {
     716             :         /*---------------------------------------------------------
     717             :          * TOL entries are only 1 line, we support the bCont flag
     718             :          * only for compatibility with the other AVCE00Gen*() functions.
     719             :          *--------------------------------------------------------*/
     720           0 :         return nullptr;
     721             :     }
     722             : 
     723           0 :     snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psTol->nIndex,
     724             :              psTol->nFlag);
     725           0 :     AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
     726             :                       AVCFileTOL, psTol->dValue);
     727             : 
     728           0 :     return psInfo->pszBuf;
     729             : }
     730             : 
     731             : /*=====================================================================
     732             :                             PRJ stuff
     733             :  =====================================================================*/
     734             : 
     735             : /**********************************************************************
     736             :  *                          AVCE00GenPrj()
     737             :  *
     738             :  * Generate the next line of an E00 PRJ (Projection) section.
     739             :  *
     740             :  * This function should be called once with bCont=FALSE to get the
     741             :  * first E00 line for the current PRJ, and then call with bCont=TRUE
     742             :  * to get all the other lines for this PRJ.
     743             :  *
     744             :  * The function returns nullptr when there are no more lines to generate
     745             :  * for this PRJ entry.
     746             :  **********************************************************************/
     747           0 : const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont)
     748             : {
     749           0 :     if (bCont == FALSE)
     750             :     {
     751             :         /*---------------------------------------------------------
     752             :          * Initialize the psInfo structure with info about the
     753             :          * current PRJ. (numItems = Number of lines to output)
     754             :          *--------------------------------------------------------*/
     755           0 :         psInfo->iCurItem = 0;
     756           0 :         psInfo->numItems = CSLCount(papszPrj) * 2;
     757             :     }
     758             : 
     759           0 :     if (psInfo->iCurItem < psInfo->numItems)
     760             :     {
     761             :         /*---------------------------------------------------------
     762             :          * Return the next PRJ section line.  Note that every
     763             :          * second line of the output is only a "~".
     764             :          *--------------------------------------------------------*/
     765             : 
     766           0 :         if (psInfo->iCurItem % 2 == 0)
     767             :         {
     768             :             /*-----------------------------------------------------
     769             :              * In theory we should split lines longer than 80 chars on
     770             :              * several lines, but I won't do it for now since I never
     771             :              * saw any projection line longer than 80 chars.
     772             :              *----------------------------------------------------*/
     773           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s",
     774           0 :                      papszPrj[psInfo->iCurItem / 2]);
     775             :         }
     776             :         else
     777             :         {
     778             :             /*-----------------------------------------------------
     779             :              * Every second line in a PRJ section contains only a "~",
     780             :              * this is a way to tell that the previous line was complete.
     781             :              *----------------------------------------------------*/
     782           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "~");
     783             :         }
     784             : 
     785           0 :         psInfo->iCurItem++;
     786             :     }
     787             :     else
     788             :     {
     789             :         /* No more lines to generate for this PRJ.
     790             :          */
     791           0 :         return nullptr;
     792             :     }
     793             : 
     794           0 :     return psInfo->pszBuf;
     795             : }
     796             : 
     797             : /*=====================================================================
     798             :                             TXT stuff
     799             :  =====================================================================*/
     800             : 
     801             : /**********************************************************************
     802             :  *                          AVCE00GenTxt()
     803             :  *
     804             :  * Generate the next line of an E00 TXT (Annotation) entry.
     805             :  *
     806             :  * This function should be called once with bCont=FALSE to get the
     807             :  * first E00 line for the current TXT, and then call with bCont=TRUE
     808             :  * to get all the other lines for this TXT.
     809             :  *
     810             :  * The function returns nullptr when there are no more lines to generate
     811             :  * for this TXT entry.
     812             :  **********************************************************************/
     813           0 : const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
     814             : {
     815             :     int numFixedLines;
     816             : 
     817             :     /* numFixedLines is the number of lines to generate before the line(s)
     818             :      * with the text string
     819             :      */
     820           0 :     if (psInfo->nPrecision == AVC_SINGLE_PREC)
     821           0 :         numFixedLines = 4;
     822             :     else
     823           0 :         numFixedLines = 6;
     824             : 
     825           0 :     if (bCont == FALSE)
     826             :     {
     827             :         /*-------------------------------------------------------------
     828             :          * Initialize the psInfo structure with info about the
     829             :          * current TXT. (numItems = Number of lines excluding header)
     830             :          *------------------------------------------------------------*/
     831           0 :         psInfo->iCurItem = 0;
     832           0 :         psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1);
     833             : 
     834             :         /* And return the TXT header line.
     835             :          */
     836           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d%10d%10d",
     837           0 :                  psTxt->nLevel, psTxt->numVerticesLine - 1,
     838             :                  psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars);
     839             :     }
     840           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
     841           0 :              psInfo->iCurItem < numFixedLines - 1)
     842             :     {
     843             :         /*-------------------------------------------------------------
     844             :          * Return next line of coordinates... start by placing the coord.
     845             :          * values in the order that they should appear, and then generate the
     846             :          * current line
     847             :          * (This is a little bit less efficient, but will give much easier
     848             :          *  code to read ;-)
     849             :          *------------------------------------------------------------*/
     850           0 :         double dXY[15] = {0.0};
     851             :         int i, nFirstValue, numValuesPerLine;
     852             : 
     853           0 :         dXY[14] = psTxt->dHeight;
     854             : 
     855             :         /* note that the first vertex in the vertices list is never exported
     856             :          */
     857           0 :         for (i = 0; i < 4 && i < (psTxt->numVerticesLine - 1); i++)
     858             :         {
     859           0 :             dXY[i] = psTxt->pasVertices[i + 1].x;
     860           0 :             dXY[i + 4] = psTxt->pasVertices[i + 1].y;
     861             :         }
     862           0 :         for (i = 0; i < 3 && i < std::abs(psTxt->numVerticesArrow); i++)
     863             :         {
     864           0 :             dXY[i + 8] = psTxt->pasVertices[i + psTxt->numVerticesLine].x;
     865           0 :             dXY[i + 11] = psTxt->pasVertices[i + psTxt->numVerticesLine].y;
     866             :         }
     867             : 
     868             :         /* OK, now that we prepared the coord. values, return the next line
     869             :          * of coordinates.  The only difference between double and single
     870             :          * precision is the number of coordinates per line.
     871             :          */
     872           0 :         if (psInfo->nPrecision != AVC_DOUBLE_PREC)
     873             :         {
     874             :             /* Single precision
     875             :              */
     876           0 :             numValuesPerLine = 5;
     877             :         }
     878             :         else
     879             :         {
     880             :             /* Double precision
     881             :              */
     882           0 :             numValuesPerLine = 3;
     883             :         }
     884             : 
     885           0 :         nFirstValue = psInfo->iCurItem * numValuesPerLine;
     886           0 :         psInfo->pszBuf[0] = '\0';
     887           0 :         for (i = 0; i < numValuesPerLine; i++)
     888             :         {
     889           0 :             AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
     890             :                               psInfo->nPrecision, AVCFileTXT,
     891           0 :                               dXY[nFirstValue + i]);
     892             :         }
     893             : 
     894           0 :         psInfo->iCurItem++;
     895             :     }
     896           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
     897           0 :              psInfo->iCurItem == numFixedLines - 1)
     898             :     {
     899             :         /*-------------------------------------------------------------
     900             :          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
     901             :          *------------------------------------------------------------*/
     902           0 :         psInfo->pszBuf[0] = '\0';
     903           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC,
     904           0 :                           AVCFileTXT, psTxt->f_1e2);
     905           0 :         psInfo->iCurItem++;
     906             :     }
     907           0 :     else if (psInfo->iCurItem < psInfo->numItems &&
     908           0 :              psInfo->iCurItem >= numFixedLines)
     909             :     {
     910             :         /*-------------------------------------------------------------
     911             :          * Last line, contains the text string
     912             :          * Strings longer than 80 chars have to be in 80 chars chunks
     913             :          *------------------------------------------------------------*/
     914             :         int numLines, iLine;
     915           0 :         numLines = (psTxt->numChars - 1) / 80 + 1;
     916           0 :         iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
     917             : 
     918           0 :         if ((int)strlen((char *)psTxt->pszText) > (iLine * 80))
     919           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s",
     920           0 :                      psTxt->pszText + (iLine * 80));
     921             :         else
     922           0 :             psInfo->pszBuf[0] = '\0';
     923             : 
     924           0 :         psInfo->iCurItem++;
     925             :     }
     926             :     else
     927             :     {
     928             :         /* No more lines to generate for this TXT.
     929             :          */
     930           0 :         return nullptr;
     931             :     }
     932             : 
     933           0 :     return psInfo->pszBuf;
     934             : }
     935             : 
     936             : /*=====================================================================
     937             :                             TX6 stuff
     938             :  =====================================================================*/
     939             : 
     940             : /**********************************************************************
     941             :  *                          AVCE00GenTx6()
     942             :  *
     943             :  * Generate the next line of an E00 TX6 (Annotation) entry.
     944             :  *
     945             :  * This function should be called once with bCont=FALSE to get the
     946             :  * first E00 line for the current TX6, and then call with bCont=TRUE
     947             :  * to get all the other lines for this TX6.
     948             :  *
     949             :  * Note that E00 files can also contain TX7 sections, they seem identical
     950             :  * to TX6 sections, except for one value in each entry, and it was
     951             :  * impossible to find where this value comes from... so we will always
     952             :  * generate TX6 sections and not bother with TX7.
     953             :  *
     954             :  * The function returns nullptr when there are no more lines to generate
     955             :  * for this TX6 entry.
     956             :  **********************************************************************/
     957           0 : const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
     958             : {
     959           0 :     if (bCont == FALSE)
     960             :     {
     961             :         /*-------------------------------------------------------------
     962             :          * Initialize the psInfo structure with info about the
     963             :          * current TX6. (numItems = Number of lines excluding header)
     964             :          *------------------------------------------------------------*/
     965           0 :         psInfo->iCurItem = 0;
     966           0 :         psInfo->numItems = 8 + psTxt->numVerticesLine +
     967           0 :                            std::abs(psTxt->numVerticesArrow) +
     968           0 :                            ((psTxt->numChars - 1) / 80 + 1);
     969             : 
     970             :         /* And return the TX6 header line.
     971             :          */
     972           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize,
     973             :                  "%10d%10d%10d%10d%10d%10d%10d", psTxt->nUserId, psTxt->nLevel,
     974             :                  psTxt->numVerticesLine, psTxt->numVerticesArrow,
     975             :                  psTxt->nSymbol, psTxt->n28, psTxt->numChars);
     976             :     }
     977           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6)
     978             :     {
     979             :         /*-------------------------------------------------------------
     980             :          * Text Justification stuff... 2 sets of 20 int16 values.
     981             :          *------------------------------------------------------------*/
     982             :         GInt16 *pValue;
     983             : 
     984           0 :         if (psInfo->iCurItem == 0 || psInfo->iCurItem == 1)
     985             :         {
     986           0 :             pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
     987           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
     988           0 :                      "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
     989           0 :                      pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]);
     990             :         }
     991           0 :         else if (psInfo->iCurItem == 2)
     992             :         {
     993           0 :             pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
     994           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
     995           0 :                      "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
     996           0 :                      pValue[2], pValue[3], pValue[4], pValue[5]);
     997             :         }
     998           0 :         else if (psInfo->iCurItem == 3)
     999             :         {
    1000           0 :             pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
    1001           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
    1002           0 :                      "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
    1003           0 :                      pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]);
    1004             :         }
    1005           0 :         else if (psInfo->iCurItem == 4)
    1006             :         {
    1007           0 :             pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
    1008           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
    1009           0 :                      "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
    1010           0 :                      pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]);
    1011             :         }
    1012             :         else
    1013             :         {
    1014           0 :             assert(psInfo->iCurItem == 5);
    1015           0 :             pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
    1016           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize,
    1017           0 :                      "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
    1018           0 :                      pValue[2], pValue[3], pValue[4], pValue[5]);
    1019             :         }
    1020             : 
    1021           0 :         psInfo->iCurItem++;
    1022             :     }
    1023           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6)
    1024             :     {
    1025             :         /*-------------------------------------------------------------
    1026             :          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
    1027             :          *------------------------------------------------------------*/
    1028           0 :         psInfo->pszBuf[0] = '\0';
    1029           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC,
    1030           0 :                           AVCFileTX6, psTxt->f_1e2);
    1031           0 :         psInfo->iCurItem++;
    1032             :     }
    1033           0 :     else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7)
    1034             :     {
    1035             :         /*-------------------------------------------------------------
    1036             :          * Line with 3 values, 1st value is probably text height.
    1037             :          *------------------------------------------------------------*/
    1038           0 :         psInfo->pszBuf[0] = '\0';
    1039           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
    1040             :                           AVCFileTX6, psTxt->dHeight);
    1041           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
    1042             :                           AVCFileTX6, psTxt->dV2);
    1043           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
    1044             :                           AVCFileTX6, psTxt->dV3);
    1045           0 :         psInfo->iCurItem++;
    1046             :     }
    1047           0 :     else if (psInfo->iCurItem <
    1048           0 :              psInfo->numItems - ((psTxt->numChars - 1) / 80 + 1))
    1049             :     {
    1050             :         /*-------------------------------------------------------------
    1051             :          * One line for each pair of X,Y coordinates
    1052             :          *------------------------------------------------------------*/
    1053           0 :         psInfo->pszBuf[0] = '\0';
    1054             : 
    1055           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
    1056             :                           AVCFileTX6,
    1057           0 :                           psTxt->pasVertices[psInfo->iCurItem - 8].x);
    1058           0 :         AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
    1059             :                           AVCFileTX6,
    1060           0 :                           psTxt->pasVertices[psInfo->iCurItem - 8].y);
    1061             : 
    1062           0 :         psInfo->iCurItem++;
    1063             :     }
    1064           0 :     else if (psInfo->iCurItem < psInfo->numItems /* &&
    1065             :              psInfo->iCurItem >= psInfo->numItems-((psTxt->numChars-1)/80 + 1) */ )
    1066             :     {
    1067             :         /*-------------------------------------------------------------
    1068             :          * Last line, contains the text string
    1069             :          * Strings longer than 80 chars have to be in 80 chars chunks
    1070             :          *------------------------------------------------------------*/
    1071             :         int numLines, iLine;
    1072           0 :         numLines = (psTxt->numChars - 1) / 80 + 1;
    1073           0 :         iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
    1074             : 
    1075           0 :         if ((int)strlen((char *)psTxt->pszText) > (iLine * 80))
    1076           0 :             snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s",
    1077           0 :                      psTxt->pszText + (iLine * 80));
    1078             :         else
    1079           0 :             psInfo->pszBuf[0] = '\0';
    1080             : 
    1081           0 :         psInfo->iCurItem++;
    1082             :     }
    1083             :     else
    1084             :     {
    1085             :         /* No more lines to generate for this TX6.
    1086             :          */
    1087           0 :         return nullptr;
    1088             :     }
    1089             : 
    1090           0 :     return psInfo->pszBuf;
    1091             : }
    1092             : 
    1093             : /*=====================================================================
    1094             :                             RXP stuff
    1095             :  =====================================================================*/
    1096             : 
    1097             : /**********************************************************************
    1098             :  *                          AVCE00GenRxp()
    1099             :  *
    1100             :  * Generate the next line of an E00 RXP entry (RXPs are related to regions).
    1101             :  *
    1102             :  * This function should be called once with bCont=FALSE to get the
    1103             :  * first E00 line for the current RXP, and then call with bCont=TRUE
    1104             :  * to get all the other lines for this RXP.
    1105             :  *
    1106             :  * The function returns nullptr when there are no more lines to generate
    1107             :  * for this RXP entry.
    1108             :  **********************************************************************/
    1109           0 : const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont)
    1110             : {
    1111           0 :     if (bCont == TRUE)
    1112             :     {
    1113             :         /*---------------------------------------------------------
    1114             :          * RXP entries are only 1 line, we support the bCont flag
    1115             :          * only for compatibility with the other AVCE00Gen*() functions.
    1116             :          *--------------------------------------------------------*/
    1117           0 :         return nullptr;
    1118             :     }
    1119             : 
    1120           0 :     snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psRxp->n1,
    1121             :              psRxp->n2);
    1122             : 
    1123           0 :     return psInfo->pszBuf;
    1124             : }
    1125             : 
    1126             : /*=====================================================================
    1127             :                             TABLE stuff
    1128             :  =====================================================================*/
    1129             : 
    1130             : /**********************************************************************
    1131             :  *                          AVCE00GenTableHdr()
    1132             :  *
    1133             :  * Generate the next line of an E00 Table header.
    1134             :  *
    1135             :  * This function should be called once with bCont=FALSE to get the
    1136             :  * first E00 line for the current table header, and then call with
    1137             :  * bCont=TRUE to get all the other lines.
    1138             :  *
    1139             :  * The function returns nullptr when there are no more lines to generate.
    1140             :  **********************************************************************/
    1141           0 : const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef,
    1142             :                               GBool bCont)
    1143             : {
    1144           0 :     if (bCont == FALSE)
    1145             :     {
    1146             :         int nRecSize;
    1147             :         /* Initialize the psInfo structure with info about the
    1148             :          * current Table Header
    1149             :          */
    1150           0 :         psInfo->iCurItem = 0;
    1151           0 :         psInfo->numItems = psDef->numFields;
    1152             : 
    1153           0 :         nRecSize = psDef->nRecSize;
    1154             : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
    1155             :         {
    1156             :             /* Adjust Table record size if we're remapping type 40 fields */
    1157             :             int i;
    1158             :             for (i = 0; i < psDef->numFields; i++)
    1159             :             {
    1160             :                 if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM &&
    1161             :                     psDef->pasFieldDef[i].nSize > 8)
    1162             :                 {
    1163             :                     nRecSize -= psDef->pasFieldDef[i].nSize;
    1164             :                     nRecSize += 8;
    1165             :                 }
    1166             :             }
    1167             :             nRecSize = ((nRecSize + 1) / 2) * 2;
    1168             :         }
    1169             : #endif
    1170             : 
    1171             :         /* And return the header's header line(!).
    1172             :          */
    1173           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-32.32s%s%4d%4d%4d%10d",
    1174           0 :                  psDef->szTableName, psDef->szExternal, psDef->numFields,
    1175           0 :                  psDef->numFields, nRecSize, psDef->numRecords);
    1176             :     }
    1177           0 :     else if (psInfo->iCurItem < psInfo->numItems)
    1178             :     {
    1179             :         int nSize, nType, nOffset;
    1180             : 
    1181           0 :         nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize;
    1182           0 :         nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10;
    1183           0 :         nOffset = psDef->pasFieldDef[psInfo->iCurItem].nOffset;
    1184             : 
    1185             : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
    1186             :         /* Type 40 fields with more than 12 digits written to E00 by Arc/Info
    1187             :          * will lose some digits of precision (and we starts losing them at 8
    1188             :          * with the way AVC lib writes type 40).  This (optional) hack will
    1189             :          * remap type 40 fields with more than 8 digits to double precision
    1190             :          * floats which can carry up to 18 digits of precision.  (bug 599)
    1191             :          */
    1192             :         if (nType == AVC_FT_FIXNUM && nSize > 8)
    1193             :         {
    1194             :             /* Remap to double-precision float */
    1195             :             nType = AVC_FT_BINFLOAT;
    1196             :             nSize = 8;
    1197             :         }
    1198             : 
    1199             :         /* Adjust field offset if this field is preceded by any type40 fields
    1200             :          * that were remapped.
    1201             :          */
    1202             :         {
    1203             :             int i;
    1204             :             for (i = 0; i < psInfo->iCurItem; i++)
    1205             :             {
    1206             :                 if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM &&
    1207             :                     psDef->pasFieldDef[i].nSize > 8)
    1208             :                 {
    1209             :                     nOffset -= psDef->pasFieldDef[i].nSize;
    1210             :                     nOffset += 8;
    1211             :                 }
    1212             :             }
    1213             :         }
    1214             : #endif
    1215             :         /* Return next Field definition line
    1216             :          */
    1217           0 :         snprintf(psInfo->pszBuf, psInfo->nBufSize,
    1218             :                  "%-16.16s%3d%2d%4d%1d%2d%4d%2d%3d%2d%4d%4d%2d%-16.16s%4d-",
    1219           0 :                  psDef->pasFieldDef[psInfo->iCurItem].szName, nSize,
    1220           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v2, nOffset,
    1221           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v4,
    1222           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v5,
    1223           0 :                  psDef->pasFieldDef[psInfo->iCurItem].nFmtWidth,
    1224           0 :                  psDef->pasFieldDef[psInfo->iCurItem].nFmtPrec, nType,
    1225           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v10,
    1226           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v11,
    1227           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v12,
    1228           0 :                  psDef->pasFieldDef[psInfo->iCurItem].v13,
    1229           0 :                  psDef->pasFieldDef[psInfo->iCurItem].szAltName,
    1230           0 :                  psDef->pasFieldDef[psInfo->iCurItem].nIndex);
    1231             : 
    1232           0 :         psInfo->iCurItem++;
    1233             :     }
    1234             :     else
    1235             :     {
    1236             :         /* No more lines to generate.
    1237             :          */
    1238           0 :         return nullptr;
    1239             :     }
    1240             : 
    1241           0 :     return psInfo->pszBuf;
    1242             : }
    1243             : 
    1244             : /**********************************************************************
    1245             :  *                          AVCE00GenTableRec()
    1246             :  *
    1247             :  * Generate the next line of an E00 Table Data Record.
    1248             :  *
    1249             :  * This function should be called once with bCont=FALSE to get the
    1250             :  * first E00 line for the current table record, and then call with
    1251             :  * bCont=TRUE to get all the other lines.
    1252             :  *
    1253             :  * The function returns nullptr when there are no more lines to generate.
    1254             :  **********************************************************************/
    1255           0 : const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields,
    1256             :                               AVCFieldInfo *pasDef, AVCField *pasFields,
    1257             :                               GBool bCont)
    1258             : {
    1259             :     int i, nSize, nType, nLen;
    1260             :     char *pszBuf2;
    1261             : 
    1262           0 :     if (bCont == FALSE)
    1263             :     {
    1264             :         /*-------------------------------------------------------------
    1265             :          * Initialize the psInfo structure to be ready to process this
    1266             :          * new Table Record
    1267             :          *------------------------------------------------------------*/
    1268           0 :         psInfo->iCurItem = 0;
    1269             : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
    1270             :         psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE);
    1271             : #else
    1272           0 :         psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, FALSE);
    1273             : #endif
    1274             : 
    1275             :         /*-------------------------------------------------------------
    1276             :          * First, we need to make sure that the output buffer is big
    1277             :          * enough to hold the whole record, plus 81 chars to hold
    1278             :          * the line that we'll return to the caller.
    1279             :          *------------------------------------------------------------*/
    1280           0 :         nSize = psInfo->numItems + 1 + 81;
    1281             : 
    1282           0 :         if (psInfo->nBufSize < nSize)
    1283             :         {
    1284           0 :             psInfo->pszBuf =
    1285           0 :                 (char *)CPLRealloc(psInfo->pszBuf, nSize * sizeof(char));
    1286           0 :             psInfo->nBufSize = nSize;
    1287             :         }
    1288             : 
    1289             :         /*-------------------------------------------------------------
    1290             :          * Generate the whole record now, and we'll return it to the
    1291             :          * caller by chunks of 80 chars.
    1292             :          * The first 80 chars of the buffer will be used to return
    1293             :          * one line at a time, and the rest of the buffer is used to
    1294             :          * hold the whole record.
    1295             :          *------------------------------------------------------------*/
    1296           0 :         pszBuf2 = psInfo->pszBuf + 81;
    1297             : 
    1298           0 :         for (i = 0; i < numFields; i++)
    1299             :         {
    1300           0 :             nType = pasDef[i].nType1 * 10;
    1301           0 :             nSize = pasDef[i].nSize;
    1302             : 
    1303           0 :             if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
    1304             :                 nType == AVC_FT_FIXINT)
    1305             :             {
    1306           0 :                 memcpy(pszBuf2, pasFields[i].pszStr, nSize * sizeof(char));
    1307           0 :                 pszBuf2 += nSize;
    1308             :             }
    1309             : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
    1310             :             /* See explanation in AVCE00GenTableHdr() about this hack to remap
    1311             :              * type 40 fields to double precision floats.
    1312             :              */
    1313             :             else if (nType == AVC_FT_FIXNUM && nSize > 8)
    1314             :             {
    1315             :                 pszBuf2[0] = '\0';
    1316             :                 /* NOTE: The E00 representation for a binary float is
    1317             :                  * defined by its binary size, not by the coverage's
    1318             :                  * precision.
    1319             :                  */
    1320             :                 nLen = AVCPrintRealValue(
    1321             :                     pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1322             :                     AVC_DOUBLE_PREC, AVCFileTABLE,
    1323             :                     CPLAtof((char *)pasFields[i].pszStr));
    1324             :                 pszBuf2 += nLen;
    1325             :             }
    1326             : #endif
    1327           0 :             else if (nType == AVC_FT_FIXNUM)
    1328             :             {
    1329             :                 /* TYPE 40 attributes are stored with 1 byte per digit
    1330             :                  * in binary format, and as single precision floats in
    1331             :                  * E00 tables, even in double precision coverages.
    1332             :                  */
    1333           0 :                 pszBuf2[0] = '\0';
    1334           0 :                 nLen = AVCPrintRealValue(
    1335           0 :                     pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1336             :                     AVC_SINGLE_PREC, AVCFileTABLE,
    1337           0 :                     CPLAtof((char *)pasFields[i].pszStr));
    1338           0 :                 pszBuf2 += nLen;
    1339             :             }
    1340           0 :             else if (nType == AVC_FT_BININT && nSize == 4)
    1341             :             {
    1342           0 :                 snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1343           0 :                          "%11d", pasFields[i].nInt32);
    1344           0 :                 pszBuf2 += 11;
    1345             :             }
    1346           0 :             else if (nType == AVC_FT_BININT && nSize == 2)
    1347             :             {
    1348           0 :                 snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1349           0 :                          "%6d", pasFields[i].nInt16);
    1350           0 :                 pszBuf2 += 6;
    1351             :             }
    1352           0 :             else if (nType == AVC_FT_BINFLOAT && nSize == 4)
    1353             :             {
    1354           0 :                 pszBuf2[0] = '\0';
    1355             :                 /* NOTE: The E00 representation for a binary float is
    1356             :                  * defined by its binary size, not by the coverage's
    1357             :                  * precision.
    1358             :                  */
    1359           0 :                 nLen = AVCPrintRealValue(
    1360           0 :                     pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1361           0 :                     AVC_SINGLE_PREC, AVCFileTABLE, pasFields[i].fFloat);
    1362           0 :                 pszBuf2 += nLen;
    1363             :             }
    1364           0 :             else if (nType == AVC_FT_BINFLOAT && nSize == 8)
    1365             :             {
    1366           0 :                 pszBuf2[0] = '\0';
    1367             :                 /* NOTE: The E00 representation for a binary float is
    1368             :                  * defined by its binary size, not by the coverage's
    1369             :                  * precision.
    1370             :                  */
    1371           0 :                 nLen = AVCPrintRealValue(
    1372           0 :                     pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
    1373           0 :                     AVC_DOUBLE_PREC, AVCFileTABLE, pasFields[i].dDouble);
    1374           0 :                 pszBuf2 += nLen;
    1375             :             }
    1376             :             else
    1377             :             {
    1378             :                 /*-----------------------------------------------------
    1379             :                  * Hummm... unsupported field type...
    1380             :                  *----------------------------------------------------*/
    1381           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    1382             :                          "Unsupported field type: (type=%d, size=%d)", nType,
    1383             :                          nSize);
    1384           0 :                 return nullptr;
    1385             :             }
    1386             :         }
    1387             : 
    1388           0 :         *pszBuf2 = '\0';
    1389             : 
    1390             :         /* Make sure that we remove any embedded NUL characters from the
    1391             :          * data line before returning it, otherwise we may be accidentally
    1392             :          * truncating results.
    1393             :          */
    1394           0 :         while (--pszBuf2 >= psInfo->pszBuf + 81)
    1395             :         {
    1396           0 :             if (*pszBuf2 == '\0')
    1397             :             {
    1398           0 :                 *pszBuf2 = ' ';
    1399             :             }
    1400             :         }
    1401             :     }
    1402             : 
    1403           0 :     if (psInfo->iCurItem < psInfo->numItems)
    1404             :     {
    1405             :         /*-------------------------------------------------------------
    1406             :          * Return the next 80 chars chunk.
    1407             :          * The first 80 chars of the buffer is used to return
    1408             :          * one line at a time, and the rest of the buffer (chars 81+)
    1409             :          * is used to hold the whole record.
    1410             :          *------------------------------------------------------------*/
    1411           0 :         nLen = psInfo->numItems - psInfo->iCurItem;
    1412             : 
    1413           0 :         if (nLen > 80)
    1414           0 :             nLen = 80;
    1415             : 
    1416           0 :         strncpy(psInfo->pszBuf, psInfo->pszBuf + (81 + psInfo->iCurItem), nLen);
    1417           0 :         psInfo->pszBuf[nLen] = '\0';
    1418             : 
    1419           0 :         psInfo->iCurItem += nLen;
    1420             : 
    1421             :         /*-------------------------------------------------------------
    1422             :          * Arc/Info removes spaces at the end of the lines... let's
    1423             :          * remove them as well since it can reduce the E00 file size.
    1424             :          *------------------------------------------------------------*/
    1425           0 :         nLen--;
    1426           0 :         while (nLen >= 0 && psInfo->pszBuf[nLen] == ' ')
    1427             :         {
    1428           0 :             psInfo->pszBuf[nLen] = '\0';
    1429           0 :             nLen--;
    1430             :         }
    1431             :     }
    1432             :     else
    1433             :     {
    1434             :         /* No more lines to generate.
    1435             :          */
    1436           0 :         return nullptr;
    1437             :     }
    1438             : 
    1439           0 :     return psInfo->pszBuf;
    1440             : }

Generated by: LCOV version 1.14