Coverage Report

Created: 2025-06-09 08:44

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