Coverage Report

Created: 2025-08-11 09:23

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