Coverage Report

Created: 2026-05-16 08:20

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