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