Coverage Report

Created: 2025-12-31 08:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/avc/avc_e00parse.cpp
Line
Count
Source
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
74.5M
{
94
74.5M
    int nValue = 0;
95
96
74.5M
    if (pszStr && numChars >= (int)strlen(pszStr))
97
2.98M
        return atoi(pszStr);
98
71.5M
    else if (pszStr)
99
71.5M
    {
100
71.5M
        char cNextDigit;
101
71.5M
        char *pszTmp;
102
103
        /* Get rid of const */
104
71.5M
        pszTmp = (char *)pszStr;
105
106
71.5M
        cNextDigit = pszTmp[numChars];
107
71.5M
        pszTmp[numChars] = '\0';
108
71.5M
        nValue = atoi(pszTmp);
109
71.5M
        pszTmp[numChars] = cNextDigit;
110
71.5M
    }
111
112
71.5M
    return nValue;
113
74.5M
}
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
82.5k
{
127
82.5k
    AVCE00ParseInfo *psInfo;
128
129
82.5k
    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
82.5k
    psInfo->nBufSize = 2048;
136
82.5k
    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
82.5k
    psInfo->nPrecision = AVC_SINGLE_PREC;
142
143
82.5k
    return psInfo;
144
82.5k
}
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
23.6M
{
154
23.6M
    if (psInfo->eFileType == AVCFileUnknown)
155
11.9M
        return;
156
157
11.7M
    if (psInfo->eFileType == AVCFileARC)
158
947k
    {
159
947k
        CPLFree(psInfo->cur.psArc->pasVertices);
160
947k
        CPLFree(psInfo->cur.psArc);
161
947k
        psInfo->cur.psArc = nullptr;
162
947k
    }
163
10.8M
    else if (psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileRPL)
164
3.59M
    {
165
3.59M
        CPLFree(psInfo->cur.psPal->pasArcs);
166
3.59M
        CPLFree(psInfo->cur.psPal);
167
3.59M
        psInfo->cur.psPal = nullptr;
168
3.59M
    }
169
7.22M
    else if (psInfo->eFileType == AVCFileCNT)
170
118k
    {
171
118k
        CPLFree(psInfo->cur.psCnt->panLabelIds);
172
118k
        CPLFree(psInfo->cur.psCnt);
173
118k
        psInfo->cur.psCnt = nullptr;
174
118k
    }
175
7.10M
    else if (psInfo->eFileType == AVCFileLAB)
176
3.42M
    {
177
3.42M
        CPLFree(psInfo->cur.psLab);
178
3.42M
        psInfo->cur.psLab = nullptr;
179
3.42M
    }
180
3.68M
    else if (psInfo->eFileType == AVCFileTOL)
181
3.39k
    {
182
3.39k
        CPLFree(psInfo->cur.psTol);
183
3.39k
        psInfo->cur.psTol = nullptr;
184
3.39k
    }
185
3.68M
    else if (psInfo->eFileType == AVCFilePRJ)
186
1.32M
    {
187
1.32M
        psInfo->aosPrj.Clear();
188
1.32M
    }
189
2.35M
    else if (psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6)
190
17.2k
    {
191
17.2k
        CPLFree(psInfo->cur.psTxt->pasVertices);
192
17.2k
        CPLFree(psInfo->cur.psTxt->pszText);
193
17.2k
        CPLFree(psInfo->cur.psTxt);
194
17.2k
        psInfo->cur.psTxt = nullptr;
195
17.2k
    }
196
2.33M
    else if (psInfo->eFileType == AVCFileRXP)
197
2.26k
    {
198
2.26k
        CPLFree(psInfo->cur.psRxp);
199
2.26k
        psInfo->cur.psRxp = nullptr;
200
2.26k
    }
201
2.33M
    else if (psInfo->eFileType == AVCFileTABLE)
202
2.33M
    {
203
2.33M
        _AVCDestroyTableFields(psInfo->hdr.psTableDef, psInfo->cur.pasFields);
204
2.33M
        _AVCDestroyTableDef(psInfo->hdr.psTableDef);
205
2.33M
        psInfo->hdr.psTableDef = nullptr;
206
2.33M
        psInfo->cur.pasFields = nullptr;
207
2.33M
        psInfo->bTableHdrComplete = FALSE;
208
2.33M
    }
209
0
    else
210
0
    {
211
0
        CPLError(CE_Failure, CPLE_NotSupported,
212
0
                 "_AVCE00ParseDestroyCurObject(): Unsupported file type!");
213
0
    }
214
215
11.7M
    psInfo->eFileType = AVCFileUnknown;
216
11.7M
}
217
218
/**********************************************************************
219
 *                          AVCE00ParseInfoFree()
220
 *
221
 * Free any memory associated with a AVCE00ParseInfo structure.
222
 **********************************************************************/
223
void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo)
224
82.5k
{
225
82.5k
    if (psInfo)
226
82.5k
    {
227
82.5k
        CPLFree(psInfo->pszSectionHdrLine);
228
82.5k
        psInfo->pszSectionHdrLine = nullptr;
229
82.5k
        CPLFree(psInfo->pszBuf);
230
82.5k
        _AVCE00ParseDestroyCurObject(psInfo);
231
82.5k
    }
232
233
82.5k
    delete psInfo;
234
82.5k
}
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
11.8M
{
244
11.8M
    psInfo->iCurItem = psInfo->numItems = 0;
245
11.8M
    psInfo->bForceEndOfSection = FALSE;
246
11.8M
}
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
43.1M
{
267
    /*-----------------------------------------------------------------
268
     * If we're already inside a supersection or a section, then
269
     * return AVCFileUnknown right away.
270
     *----------------------------------------------------------------*/
271
43.1M
    if (psInfo == nullptr || psInfo->eSuperSectionType != AVCFileUnknown ||
272
40.7M
        psInfo->eFileType != AVCFileUnknown)
273
2.41M
    {
274
2.41M
        return AVCFileUnknown;
275
2.41M
    }
276
277
    /*-----------------------------------------------------------------
278
     * Check if pszLine is a valid supersection header line.
279
     *----------------------------------------------------------------*/
280
40.7M
    if (STARTS_WITH_CI(pszLine, "RPL  "))
281
6.46k
        psInfo->eSuperSectionType = AVCFileRPL;
282
40.7M
    else if (STARTS_WITH_CI(pszLine, "TX6  ") ||
283
40.7M
             STARTS_WITH_CI(pszLine, "TX7  "))
284
3.25k
        psInfo->eSuperSectionType = AVCFileTX6;
285
40.7M
    else if (STARTS_WITH_CI(pszLine, "RXP  "))
286
540
        psInfo->eSuperSectionType = AVCFileRXP;
287
40.7M
    else if (STARTS_WITH_CI(pszLine, "IFO  "))
288
2.32M
        psInfo->eSuperSectionType = AVCFileTABLE;
289
38.3M
    else
290
38.3M
        return AVCFileUnknown;
291
292
    /*-----------------------------------------------------------------
293
     * Record the start of the supersection (for faster seeking)
294
     *----------------------------------------------------------------*/
295
2.33M
    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
2.33M
    if (atoi(pszLine + 4) == 2)
302
598k
        psInfo->nPrecision = AVC_SINGLE_PREC;
303
1.73M
    else if (atoi(pszLine + 4) == 3)
304
1.73M
        psInfo->nPrecision = AVC_DOUBLE_PREC;
305
63
    else
306
63
    {
307
63
        CPLError(CE_Failure, CPLE_AppDefined,
308
63
                 "Parse Error: Invalid section header line (\"%s\")!", pszLine);
309
63
        psInfo->eSuperSectionType = AVCFileUnknown;
310
        /* psInfo->nStartLineNum = -1; */
311
63
    }
312
313
2.33M
    return psInfo->eSuperSectionType;
314
40.7M
}
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
103M
{
327
103M
    if (psInfo->eFileType == AVCFileUnknown &&
328
45.4M
        psInfo->eSuperSectionType != AVCFileUnknown &&
329
4.70M
        (STARTS_WITH_CI(pszLine, "JABBERWOCKY") ||
330
2.41M
         (psInfo->eSuperSectionType == AVCFileTABLE &&
331
2.41M
          STARTS_WITH_CI(pszLine, "EOI"))))
332
2.29M
    {
333
2.29M
        psInfo->eSuperSectionType = AVCFileUnknown;
334
        /* psInfo->nStartLineNum = -1; */
335
2.29M
        return TRUE;
336
2.29M
    }
337
338
101M
    return FALSE;
339
103M
}
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
40.8M
{
355
40.8M
    AVCFileType eNewType = AVCFileUnknown;
356
357
40.8M
    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
40.8M
    if (psInfo->eSuperSectionType == AVCFileUnknown)
366
38.3M
    {
367
        /*-------------------------------------------------------------
368
         * We're looking for a top-level section...
369
         *------------------------------------------------------------*/
370
38.3M
        if (STARTS_WITH_CI(pszLine, "ARC  "))
371
947k
            eNewType = AVCFileARC;
372
37.4M
        else if (STARTS_WITH_CI(pszLine, "PAL  "))
373
3.58M
            eNewType = AVCFilePAL;
374
33.8M
        else if (STARTS_WITH_CI(pszLine, "CNT  "))
375
118k
            eNewType = AVCFileCNT;
376
33.7M
        else if (STARTS_WITH_CI(pszLine, "LAB  "))
377
3.42M
            eNewType = AVCFileLAB;
378
30.3M
        else if (STARTS_WITH_CI(pszLine, "TOL  "))
379
3.39k
            eNewType = AVCFileTOL;
380
30.3M
        else if (STARTS_WITH_CI(pszLine, "PRJ  "))
381
1.32M
            eNewType = AVCFilePRJ;
382
28.9M
        else if (STARTS_WITH_CI(pszLine, "TXT  "))
383
10.0k
            eNewType = AVCFileTXT;
384
28.9M
        else
385
28.9M
        {
386
28.9M
            return AVCFileUnknown;
387
28.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
9.41M
        if (atoi(pszLine + 4) == 2)
394
7.47M
            psInfo->nPrecision = AVC_SINGLE_PREC;
395
1.93M
        else if (atoi(pszLine + 4) == 3)
396
1.93M
            psInfo->nPrecision = AVC_DOUBLE_PREC;
397
74
        else
398
74
        {
399
74
            CPLError(CE_Failure, CPLE_AppDefined,
400
74
                     "Parse Error: Invalid section header line (\"%s\")!",
401
74
                     pszLine);
402
74
            return AVCFileUnknown;
403
74
        }
404
9.41M
    }
405
2.41M
    else
406
2.41M
    {
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
2.41M
        if (psInfo->eSuperSectionType == AVCFileTX6 && strlen(pszLine) == 0)
421
3.33k
        {
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
3.33k
            eNewType = psInfo->eSuperSectionType;
427
3.33k
        }
428
2.40M
        else if (strlen(pszLine) > 0 && !isspace((unsigned char)pszLine[0]) &&
429
2.40M
                 !STARTS_WITH_CI(pszLine, "JABBERWOCKY") &&
430
2.40M
                 !STARTS_WITH_CI(pszLine, "EOI") &&
431
2.34M
                 !(psInfo->eSuperSectionType == AVCFileRPL &&
432
2.34M
                   STARTS_WITH_CI(pszLine, " 0.00000")))
433
2.34M
        {
434
2.34M
            eNewType = psInfo->eSuperSectionType;
435
2.34M
        }
436
60.2k
        else
437
60.2k
        {
438
60.2k
            return AVCFileUnknown;
439
60.2k
        }
440
2.41M
    }
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
11.7M
    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
11.7M
    _AVCE00ParseDestroyCurObject(psInfo);
454
455
11.7M
    if (eNewType == AVCFileARC)
456
947k
    {
457
947k
        psInfo->cur.psArc = (AVCArc *)CPLCalloc(1, sizeof(AVCArc));
458
947k
    }
459
10.8M
    else if (eNewType == AVCFilePAL || eNewType == AVCFileRPL)
460
3.59M
    {
461
3.59M
        psInfo->cur.psPal = (AVCPal *)CPLCalloc(1, sizeof(AVCPal));
462
3.59M
    }
463
7.22M
    else if (eNewType == AVCFileCNT)
464
118k
    {
465
118k
        psInfo->cur.psCnt = (AVCCnt *)CPLCalloc(1, sizeof(AVCCnt));
466
118k
    }
467
7.10M
    else if (eNewType == AVCFileLAB)
468
3.42M
    {
469
3.42M
        psInfo->cur.psLab = (AVCLab *)CPLCalloc(1, sizeof(AVCLab));
470
3.42M
    }
471
3.68M
    else if (eNewType == AVCFileTOL)
472
3.39k
    {
473
3.39k
        psInfo->cur.psTol = (AVCTol *)CPLCalloc(1, sizeof(AVCTol));
474
3.39k
    }
475
3.68M
    else if (eNewType == AVCFilePRJ)
476
1.32M
    {
477
1.32M
        psInfo->aosPrj.Clear();
478
1.32M
    }
479
2.35M
    else if (eNewType == AVCFileTXT || eNewType == AVCFileTX6)
480
17.2k
    {
481
17.2k
        psInfo->cur.psTxt = (AVCTxt *)CPLCalloc(1, sizeof(AVCTxt));
482
17.2k
    }
483
2.33M
    else if (eNewType == AVCFileRXP)
484
2.26k
    {
485
2.26k
        psInfo->cur.psRxp = (AVCRxp *)CPLCalloc(1, sizeof(AVCRxp));
486
2.26k
    }
487
2.33M
    else if (eNewType == AVCFileTABLE)
488
2.33M
    {
489
2.33M
        psInfo->cur.pasFields = nullptr;
490
2.33M
        psInfo->hdr.psTableDef = nullptr;
491
2.33M
        psInfo->bTableHdrComplete = FALSE;
492
2.33M
    }
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
11.7M
    if (eNewType != AVCFileUnknown)
501
11.7M
    {
502
        /*-----------------------------------------------------------------
503
         * Record the start of the section (for faster seeking)
504
         *----------------------------------------------------------------*/
505
11.7M
        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
11.7M
        CPLFree(psInfo->pszSectionHdrLine);
512
11.7M
        psInfo->pszSectionHdrLine = CPLStrdup(pszLine);
513
11.7M
    }
514
515
11.7M
    psInfo->eFileType = eNewType;
516
517
11.7M
    return psInfo->eFileType;
518
40.8M
}
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
67.7M
{
535
67.7M
    if (psInfo->bForceEndOfSection ||
536
63.9M
        ((psInfo->eFileType == AVCFileARC || psInfo->eFileType == AVCFilePAL ||
537
46.2M
          psInfo->eFileType == AVCFileLAB || psInfo->eFileType == AVCFileRPL ||
538
32.2M
          psInfo->eFileType == AVCFileCNT || psInfo->eFileType == AVCFileTOL ||
539
31.4M
          psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6 ||
540
31.2M
          psInfo->eFileType == AVCFileRXP) &&
541
63.9M
         STARTS_WITH_CI(pszLine, "        -1         0")))
542
19.8M
    {
543
        /* Reset ParseInfo only if explicitly requested.
544
         */
545
19.8M
        if (bResetParseInfo)
546
11.8M
        {
547
11.8M
            _AVCE00ParseDestroyCurObject(psInfo);
548
11.8M
            AVCE00ParseReset(psInfo);
549
11.8M
            psInfo->eFileType = AVCFileUnknown;
550
551
11.8M
            CPLFree(psInfo->pszSectionHdrLine);
552
11.8M
            psInfo->pszSectionHdrLine = nullptr;
553
554
11.8M
            psInfo->bForceEndOfSection = FALSE;
555
11.8M
        }
556
557
19.8M
        return TRUE; /* YES, we reached the end */
558
19.8M
    }
559
560
47.9M
    return FALSE; /* NO, it is not the end of section line */
561
67.7M
}
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
52.5M
{
588
52.5M
    void *psObj = nullptr;
589
590
52.5M
    CPLAssert(psInfo);
591
52.5M
    switch (psInfo->eFileType)
592
52.5M
    {
593
1.30M
        case AVCFileARC:
594
1.30M
            psObj = (void *)AVCE00ParseNextArcLine(psInfo, pszLine);
595
1.30M
            break;
596
7.33M
        case AVCFilePAL:
597
7.36M
        case AVCFileRPL:
598
7.36M
            psObj = (void *)AVCE00ParseNextPalLine(psInfo, pszLine);
599
7.36M
            break;
600
663k
        case AVCFileCNT:
601
663k
            psObj = (void *)AVCE00ParseNextCntLine(psInfo, pszLine);
602
663k
            break;
603
7.17M
        case AVCFileLAB:
604
7.17M
            psObj = (void *)AVCE00ParseNextLabLine(psInfo, pszLine);
605
7.17M
            break;
606
30.5k
        case AVCFileTOL:
607
30.5k
            psObj = (void *)AVCE00ParseNextTolLine(psInfo, pszLine);
608
30.5k
            break;
609
28.8M
        case AVCFilePRJ:
610
28.8M
            psObj = (void *)AVCE00ParseNextPrjLine(psInfo, pszLine);
611
28.8M
            break;
612
89.5k
        case AVCFileTXT:
613
89.5k
            psObj = (void *)AVCE00ParseNextTxtLine(psInfo, pszLine);
614
89.5k
            break;
615
78.9k
        case AVCFileTX6:
616
78.9k
            psObj = (void *)AVCE00ParseNextTx6Line(psInfo, pszLine);
617
78.9k
            break;
618
4.51k
        case AVCFileRXP:
619
4.51k
            psObj = (void *)AVCE00ParseNextRxpLine(psInfo, pszLine);
620
4.51k
            break;
621
6.97M
        case AVCFileTABLE:
622
6.97M
            if (!psInfo->bTableHdrComplete)
623
4.64M
                psObj = (void *)AVCE00ParseNextTableDefLine(psInfo, pszLine);
624
2.33M
            else
625
2.33M
                psObj = (void *)AVCE00ParseNextTableRecLine(psInfo, pszLine);
626
6.97M
            break;
627
0
        default:
628
0
            CPLError(CE_Failure, CPLE_NotSupported,
629
0
                     "AVCE00ParseNextLine(): Unsupported file type!");
630
52.5M
    }
631
632
52.5M
    return psObj;
633
52.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.30M
{
653
1.30M
    AVCArc *psArc;
654
1.30M
    size_t nLen;
655
656
1.30M
    CPLAssert(psInfo->eFileType == AVCFileARC);
657
658
1.30M
    psArc = psInfo->cur.psArc;
659
660
1.30M
    nLen = strlen(pszLine);
661
662
1.30M
    if (psInfo->numItems == 0)
663
1.24M
    {
664
        /*-------------------------------------------------------------
665
         * Begin processing a new object, read header line:
666
         *    ArcId, UserId, FNode, TNode, LPoly, RPoly, numVertices
667
         *------------------------------------------------------------*/
668
1.24M
        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.24M
        else
675
1.24M
        {
676
1.24M
            psArc->nArcId = AVCE00Str2Int(pszLine, 10);
677
1.24M
            psArc->nUserId = AVCE00Str2Int(pszLine + 10, 10);
678
1.24M
            psArc->nFNode = AVCE00Str2Int(pszLine + 20, 10);
679
1.24M
            psArc->nTNode = AVCE00Str2Int(pszLine + 30, 10);
680
1.24M
            psArc->nLPoly = AVCE00Str2Int(pszLine + 40, 10);
681
1.24M
            psArc->nRPoly = AVCE00Str2Int(pszLine + 50, 10);
682
1.24M
            psArc->numVertices = AVCE00Str2Int(pszLine + 60, 10);
683
1.24M
            if (psArc->numVertices < 0 || psArc->numVertices > 10 * 1024 * 1024)
684
18
            {
685
18
                CPLError(CE_Failure, CPLE_AppDefined,
686
18
                         "Error parsing E00 ARC line: \"%s\"", pszLine);
687
18
                psInfo->numItems = psInfo->iCurItem = 0;
688
18
                return nullptr;
689
18
            }
690
691
            /* Realloc the array of vertices
692
             */
693
1.24M
            psArc->pasVertices = (AVCVertex *)CPLRealloc(
694
1.24M
                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.24M
            psInfo->iCurItem = 0;
700
1.24M
            psInfo->numItems = psArc->numVertices;
701
1.24M
        }
702
1.24M
    }
703
61.2k
    else if (psInfo->iCurItem < psInfo->numItems &&
704
61.2k
             psInfo->nPrecision == AVC_SINGLE_PREC &&
705
59.7k
             ((psInfo->iCurItem == psInfo->numItems - 1 && nLen >= 28) ||
706
42.4k
              nLen >= 56))
707
59.6k
    {
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
59.6k
        psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
713
59.6k
        psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 14);
714
59.6k
        if (psInfo->iCurItem < psInfo->numItems && nLen >= 56)
715
42.3k
        {
716
42.3k
            psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine + 28);
717
42.3k
            psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 42);
718
42.3k
        }
719
59.6k
    }
720
1.53k
    else if (psInfo->iCurItem < psInfo->numItems &&
721
1.53k
             psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42)
722
1.50k
    {
723
        /*-------------------------------------------------------------
724
         * Double precision ARCs: 1 pair of X,Y values per line
725
         *------------------------------------------------------------*/
726
1.50k
        psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
727
1.50k
        psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 21);
728
1.50k
    }
729
27
    else
730
27
    {
731
27
        CPLError(CE_Failure, CPLE_AppDefined,
732
27
                 "Error parsing E00 ARC line: \"%s\"", pszLine);
733
27
        psInfo->numItems = psInfo->iCurItem = 0;
734
27
        return nullptr;
735
27
    }
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.30M
    if (psInfo->iCurItem >= psInfo->numItems)
744
1.23M
    {
745
1.23M
        psInfo->numItems = psInfo->iCurItem = 0;
746
1.23M
        return psArc;
747
1.23M
    }
748
749
68.9k
    return nullptr;
750
1.30M
}
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
7.36M
{
770
7.36M
    AVCPal *psPal;
771
7.36M
    size_t nLen;
772
773
7.36M
    CPLAssert(psInfo->eFileType == AVCFilePAL ||
774
7.36M
              psInfo->eFileType == AVCFileRPL);
775
776
7.36M
    psPal = psInfo->cur.psPal;
777
778
7.36M
    nLen = strlen(pszLine);
779
780
7.36M
    if (psInfo->numItems == 0)
781
3.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
3.66M
        if (nLen < 52)
788
52
        {
789
52
            CPLError(CE_Failure, CPLE_AppDefined,
790
52
                     "Error parsing E00 PAL line: \"%s\"", pszLine);
791
52
            return nullptr;
792
52
        }
793
3.66M
        else
794
3.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
3.66M
            psPal->nPolyId = ++psInfo->nCurObjectId;
800
801
3.66M
            psPal->numArcs = AVCE00Str2Int(pszLine, 10);
802
3.66M
            if (psPal->numArcs < 0 || psPal->numArcs > 10 * 1024 * 1024)
803
17
            {
804
17
                CPLError(CE_Failure, CPLE_AppDefined,
805
17
                         "Error parsing E00 PAL line: \"%s\"", pszLine);
806
17
                psInfo->numItems = psInfo->iCurItem = 0;
807
17
                return nullptr;
808
17
            }
809
810
            /* If a PAL record has 0 arcs, it really has a single "0 0 0"
811
             * triplet as its data.
812
             */
813
3.66M
            if (psPal->numArcs == 0)
814
3.57M
            {
815
3.57M
                psPal->numArcs = 1;
816
3.57M
            }
817
818
            /* Realloc the array of Arcs
819
             */
820
3.66M
            psPal->pasArcs = (AVCPalArc *)CPLRealloc(
821
3.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
3.66M
            psInfo->iCurItem = 0;
827
3.66M
            psInfo->numItems = psPal->numArcs;
828
829
3.66M
            if (psInfo->nPrecision == AVC_SINGLE_PREC)
830
3.65M
            {
831
3.65M
                psPal->sMin.x = CPLAtof(pszLine + 10);
832
3.65M
                psPal->sMin.y = CPLAtof(pszLine + 24);
833
3.65M
                psPal->sMax.x = CPLAtof(pszLine + 38);
834
3.65M
                psPal->sMax.y = CPLAtof(pszLine + 52);
835
3.65M
            }
836
1.61k
            else
837
1.61k
            {
838
1.61k
                psPal->sMin.x = CPLAtof(pszLine + 10);
839
1.61k
                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
1.61k
                psInfo->iCurItem = -1;
844
1.61k
            }
845
3.66M
        }
846
3.66M
    }
847
3.70M
    else if (psInfo->iCurItem == -1 && nLen >= 42)
848
1.34k
    {
849
1.34k
        psPal->sMax.x = CPLAtof(pszLine);
850
1.34k
        psPal->sMax.y = CPLAtof(pszLine + 21);
851
1.34k
        psInfo->iCurItem++;
852
1.34k
    }
853
3.70M
    else if (psInfo->iCurItem < psPal->numArcs &&
854
3.70M
             (nLen >= 60 ||
855
3.18M
              (psInfo->iCurItem == psPal->numArcs - 1 && nLen >= 30)))
856
3.70M
    {
857
        /*-------------------------------------------------------------
858
         * 2 PAL entries (ArcId, FNode, AdjPoly) per line,
859
         * (Except on the last line with an odd number of vertices)
860
         *------------------------------------------------------------*/
861
3.70M
        psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine, 10);
862
3.70M
        psPal->pasArcs[psInfo->iCurItem].nFNode =
863
3.70M
            AVCE00Str2Int(pszLine + 10, 10);
864
3.70M
        psPal->pasArcs[psInfo->iCurItem++].nAdjPoly =
865
3.70M
            AVCE00Str2Int(pszLine + 20, 10);
866
867
3.70M
        if (psInfo->iCurItem < psInfo->numItems)
868
75.9k
        {
869
75.9k
            psPal->pasArcs[psInfo->iCurItem].nArcId =
870
75.9k
                AVCE00Str2Int(pszLine + 30, 10);
871
75.9k
            psPal->pasArcs[psInfo->iCurItem].nFNode =
872
75.9k
                AVCE00Str2Int(pszLine + 40, 10);
873
75.9k
            psPal->pasArcs[psInfo->iCurItem++].nAdjPoly =
874
75.9k
                AVCE00Str2Int(pszLine + 50, 10);
875
75.9k
        }
876
3.70M
    }
877
62
    else
878
62
    {
879
62
        CPLError(CE_Failure, CPLE_AppDefined,
880
62
                 "Error parsing E00 PAL line: \"%s\"", pszLine);
881
62
        psInfo->numItems = psInfo->iCurItem = 0;
882
62
        return nullptr;
883
62
    }
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
7.36M
    if (psInfo->iCurItem >= psInfo->numItems)
892
3.64M
    {
893
3.64M
        psInfo->numItems = psInfo->iCurItem = 0;
894
3.64M
        return psPal;
895
3.64M
    }
896
897
3.72M
    return nullptr;
898
7.36M
}
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
663k
{
918
663k
    AVCCnt *psCnt;
919
663k
    size_t nLen;
920
921
663k
    CPLAssert(psInfo->eFileType == AVCFileCNT);
922
923
663k
    psCnt = psInfo->cur.psCnt;
924
925
663k
    nLen = strlen(pszLine);
926
927
663k
    if (psInfo->numItems == 0)
928
221k
    {
929
        /*-------------------------------------------------------------
930
         * Begin processing a new object, read header line:
931
         *    numLabels, X, Y
932
         *------------------------------------------------------------*/
933
221k
        if (nLen < 38)
934
110
        {
935
110
            CPLError(CE_Failure, CPLE_AppDefined,
936
110
                     "Error parsing E00 CNT line: \"%s\"", pszLine);
937
110
            return nullptr;
938
110
        }
939
221k
        else
940
221k
        {
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
221k
            psCnt->nPolyId = ++psInfo->nCurObjectId;
946
947
221k
            psCnt->numLabels = AVCE00Str2Int(pszLine, 10);
948
221k
            if (psCnt->numLabels < 0 || psCnt->numLabels > 10 * 1024 * 1024)
949
30
            {
950
30
                CPLError(CE_Failure, CPLE_AppDefined,
951
30
                         "Error parsing E00 CNT line: \"%s\"", pszLine);
952
30
                psInfo->numItems = psInfo->iCurItem = 0;
953
30
                return nullptr;
954
30
            }
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
221k
            if (psCnt->numLabels > 0)
961
33.0k
                psCnt->panLabelIds = (GInt32 *)CPLRealloc(
962
33.0k
                    psCnt->panLabelIds, psCnt->numLabels * sizeof(GInt32));
963
964
221k
            if (psInfo->nPrecision == AVC_SINGLE_PREC)
965
133k
            {
966
133k
                psCnt->sCoord.x = CPLAtof(pszLine + 10);
967
133k
                psCnt->sCoord.y = CPLAtof(pszLine + 24);
968
133k
            }
969
88.1k
            else
970
88.1k
            {
971
88.1k
                psCnt->sCoord.x = CPLAtof(pszLine + 10);
972
88.1k
                psCnt->sCoord.y = CPLAtof(pszLine + 31);
973
88.1k
            }
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
221k
            psInfo->iCurItem = 0;
979
221k
            psInfo->numItems = psCnt->numLabels;
980
221k
        }
981
221k
    }
982
441k
    else if (psInfo->iCurItem < psInfo->numItems)
983
441k
    {
984
        /*-------------------------------------------------------------
985
         * Each line can contain up to 8 label ids (10 chars each)
986
         *------------------------------------------------------------*/
987
441k
        size_t i = 0;
988
1.65M
        while (psInfo->iCurItem < psInfo->numItems && nLen >= (i + 1) * 10)
989
1.21M
        {
990
1.21M
            psCnt->panLabelIds[psInfo->iCurItem++] =
991
1.21M
                AVCE00Str2Int(pszLine + i * 10, 10);
992
1.21M
            i++;
993
1.21M
        }
994
441k
    }
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
662k
    if (psInfo->iCurItem >= psInfo->numItems)
1010
199k
    {
1011
199k
        psInfo->numItems = psInfo->iCurItem = 0;
1012
199k
        return psCnt;
1013
199k
    }
1014
1015
463k
    return nullptr;
1016
662k
}
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
7.17M
{
1036
7.17M
    AVCLab *psLab;
1037
7.17M
    size_t nLen;
1038
1039
7.17M
    CPLAssert(psInfo->eFileType == AVCFileLAB);
1040
1041
7.17M
    psLab = psInfo->cur.psLab;
1042
1043
7.17M
    nLen = strlen(pszLine);
1044
1045
7.17M
    if (psInfo->numItems == 0)
1046
3.71M
    {
1047
        /*-------------------------------------------------------------
1048
         * Begin processing a new object, read header line:
1049
         *    LabelValue, PolyId, X1, Y1
1050
         *------------------------------------------------------------*/
1051
3.71M
        if (nLen < 48)
1052
18
        {
1053
18
            CPLError(CE_Failure, CPLE_AppDefined,
1054
18
                     "Error parsing E00 LAB line: \"%s\"", pszLine);
1055
18
            return nullptr;
1056
18
        }
1057
3.71M
        else
1058
3.71M
        {
1059
3.71M
            psLab->nValue = AVCE00Str2Int(pszLine, 10);
1060
3.71M
            psLab->nPolyId = AVCE00Str2Int(pszLine + 10, 10);
1061
1062
3.71M
            if (psInfo->nPrecision == AVC_SINGLE_PREC)
1063
3.71M
            {
1064
3.71M
                psLab->sCoord1.x = CPLAtof(pszLine + 20);
1065
3.71M
                psLab->sCoord1.y = CPLAtof(pszLine + 34);
1066
3.71M
            }
1067
4.92k
            else
1068
4.92k
            {
1069
4.92k
                psLab->sCoord1.x = CPLAtof(pszLine + 20);
1070
4.92k
                psLab->sCoord1.y = CPLAtof(pszLine + 41);
1071
4.92k
            }
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
3.71M
            psInfo->iCurItem = 1;
1077
3.71M
            psInfo->numItems = 3;
1078
3.71M
        }
1079
3.71M
    }
1080
3.45M
    else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC &&
1081
3.44M
             nLen >= 56)
1082
3.44M
    {
1083
3.44M
        psLab->sCoord2.x = CPLAtof(pszLine);
1084
3.44M
        psLab->sCoord2.y = CPLAtof(pszLine + 14);
1085
3.44M
        psLab->sCoord3.x = CPLAtof(pszLine + 28);
1086
3.44M
        psLab->sCoord3.y = CPLAtof(pszLine + 42);
1087
3.44M
        psInfo->iCurItem += 2;
1088
3.44M
    }
1089
8.95k
    else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
1090
4.64k
             nLen >= 42)
1091
4.60k
    {
1092
4.60k
        psLab->sCoord2.x = CPLAtof(pszLine);
1093
4.60k
        psLab->sCoord2.y = CPLAtof(pszLine + 21);
1094
4.60k
        psInfo->iCurItem++;
1095
4.60k
    }
1096
4.34k
    else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
1097
4.30k
             nLen >= 42)
1098
4.29k
    {
1099
4.29k
        psLab->sCoord3.x = CPLAtof(pszLine);
1100
4.29k
        psLab->sCoord3.y = CPLAtof(pszLine + 21);
1101
4.29k
        psInfo->iCurItem++;
1102
4.29k
    }
1103
51
    else
1104
51
    {
1105
51
        CPLError(CE_Failure, CPLE_AppDefined,
1106
51
                 "Error parsing E00 LAB line: \"%s\"", pszLine);
1107
51
        psInfo->numItems = psInfo->iCurItem = 0;
1108
51
        return nullptr;
1109
51
    }
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
7.17M
    if (psInfo->iCurItem >= psInfo->numItems)
1118
3.45M
    {
1119
3.45M
        psInfo->numItems = psInfo->iCurItem = 0;
1120
3.45M
        return psLab;
1121
3.45M
    }
1122
1123
3.72M
    return nullptr;
1124
7.17M
}
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
30.5k
{
1144
30.5k
    AVCTol *psTol;
1145
30.5k
    size_t nLen;
1146
1147
30.5k
    CPLAssert(psInfo->eFileType == AVCFileTOL);
1148
1149
30.5k
    psTol = psInfo->cur.psTol;
1150
1151
30.5k
    nLen = strlen(pszLine);
1152
1153
30.5k
    if (nLen >= 34)
1154
30.5k
    {
1155
        /*-------------------------------------------------------------
1156
         * TOL Entries are only one line each:
1157
         *   TolIndex, TolFlag, TolValue
1158
         *------------------------------------------------------------*/
1159
30.5k
        psTol->nIndex = AVCE00Str2Int(pszLine, 10);
1160
30.5k
        psTol->nFlag = AVCE00Str2Int(pszLine + 10, 10);
1161
1162
30.5k
        psTol->dValue = CPLAtof(pszLine + 20);
1163
30.5k
    }
1164
22
    else
1165
22
    {
1166
22
        CPLError(CE_Failure, CPLE_AppDefined,
1167
22
                 "Error parsing E00 TOL line: \"%s\"", pszLine);
1168
22
        psInfo->numItems = psInfo->iCurItem = 0;
1169
22
        return nullptr;
1170
22
    }
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
30.5k
    if (psInfo->iCurItem >= psInfo->numItems)
1179
30.5k
    {
1180
30.5k
        psInfo->numItems = psInfo->iCurItem = 0;
1181
30.5k
        return psTol;
1182
30.5k
    }
1183
1184
0
    return nullptr;
1185
30.5k
}
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.8M
{
1211
28.8M
    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.8M
    if (STARTS_WITH_CI(pszLine, "EOP"))
1222
1.32M
    {
1223
        /*-------------------------------------------------------------
1224
         * We reached end of section... return the PRJ.
1225
         *------------------------------------------------------------*/
1226
1.32M
        psInfo->bForceEndOfSection = TRUE;
1227
1.32M
        return psInfo->aosPrj.List();
1228
1.32M
    }
1229
1230
27.5M
    if (pszLine[0] != '~')
1231
25.7M
    {
1232
        /*-------------------------------------------------------------
1233
         * This is a new line... add it to the papszPrj stringlist.
1234
         *------------------------------------------------------------*/
1235
25.7M
        psInfo->aosPrj.AddString(pszLine);
1236
25.7M
    }
1237
1.80M
    else if (strlen(pszLine) > 1)
1238
701k
    {
1239
        /*-------------------------------------------------------------
1240
         * '~' is a line continuation char.  Append what follows the '~'
1241
         * to the end of the previous line.
1242
         *------------------------------------------------------------*/
1243
701k
        if (!psInfo->aosPrj.empty())
1244
699k
        {
1245
699k
            size_t nOldLen =
1246
699k
                strlen(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1]);
1247
699k
            size_t nAddLen = strlen(pszLine + 1);
1248
699k
            psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] =
1249
699k
                static_cast<char *>(
1250
699k
                    CPLRealloc(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1],
1251
699k
                               nOldLen + nAddLen + 1));
1252
699k
            memcpy(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] + nOldLen,
1253
699k
                   pszLine + 1, nAddLen + 1);
1254
699k
        }
1255
701k
    }
1256
1257
27.5M
    return nullptr;
1258
28.8M
}
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
89.5k
{
1278
89.5k
    AVCTxt *psTxt;
1279
89.5k
    int i, numFixedLines;
1280
89.5k
    size_t nLen;
1281
1282
89.5k
    CPLAssert(psInfo->eFileType == AVCFileTXT);
1283
1284
89.5k
    psTxt = psInfo->cur.psTxt;
1285
1286
89.5k
    nLen = strlen(pszLine);
1287
1288
    /* numFixedLines is the number of lines to expect before the line(s)
1289
     * with the text string
1290
     */
1291
89.5k
    if (psInfo->nPrecision == AVC_SINGLE_PREC)
1292
15.3k
        numFixedLines = 4;
1293
74.2k
    else
1294
74.2k
        numFixedLines = 6;
1295
1296
89.5k
    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
38
        {
1303
38
            CPLError(CE_Failure, CPLE_AppDefined,
1304
38
                     "Error parsing E00 TXT line: \"%s\"", pszLine);
1305
38
            return nullptr;
1306
38
        }
1307
12.9k
        else
1308
12.9k
        {
1309
12.9k
            int numVertices;
1310
            /*---------------------------------------------------------
1311
             * With TXT, there are several unused fields that have to be
1312
             * set to default values... usually 0.
1313
             *--------------------------------------------------------*/
1314
12.9k
            psTxt->nUserId = 0;
1315
12.9k
            psTxt->n28 = 0;
1316
272k
            for (i = 0; i < 20; i++)
1317
259k
                psTxt->anJust1[i] = psTxt->anJust2[i] = 0;
1318
12.9k
            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
12.9k
            psTxt->nTxtId = ++psInfo->nCurObjectId;
1326
1327
12.9k
            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
12.9k
            psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 10, 10);
1333
12.9k
            if (psTxt->numVerticesLine < 0 ||
1334
12.9k
                psTxt->numVerticesLine > 10 * 1024 * 1024)
1335
29
            {
1336
29
                CPLError(CE_Failure, CPLE_AppDefined,
1337
29
                         "Error parsing E00 TXT line: \"%s\"", pszLine);
1338
29
                psInfo->numItems = psInfo->iCurItem = 0;
1339
29
                return nullptr;
1340
29
            }
1341
12.9k
            psTxt->numVerticesLine++;
1342
1343
12.9k
            psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 20, 10);
1344
12.9k
            if (psTxt->numVerticesArrow < -10 * 1024 * 1024 ||
1345
12.9k
                psTxt->numVerticesArrow > 10 * 1024 * 1024)
1346
11
            {
1347
11
                CPLError(CE_Failure, CPLE_AppDefined,
1348
11
                         "Error parsing E00 TXT line: \"%s\"", pszLine);
1349
11
                psInfo->numItems = psInfo->iCurItem = 0;
1350
11
                return nullptr;
1351
11
            }
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.8k
            psTxt->pszText = (GByte *)CPLRealloc(
1366
12.8k
                psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte));
1367
12.8k
            numVertices =
1368
12.8k
                ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
1369
12.8k
            if (numVertices > 0)
1370
12.8k
                psTxt->pasVertices = (AVCVertex *)CPLRealloc(
1371
12.8k
                    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.8k
            memset(psTxt->pszText, ' ', psTxt->numChars);
1378
12.8k
            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.8k
            psInfo->iCurItem = 0;
1385
12.8k
            psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1);
1386
12.8k
        }
1387
13.0k
    }
1388
76.5k
    else if (psInfo->iCurItem < psInfo->numItems &&
1389
76.5k
             psInfo->iCurItem < numFixedLines - 1 && nLen >= 63)
1390
39.3k
    {
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
39.3k
        int iCurCoord = 0, numCoordPerLine, nItemSize, iVertex;
1405
39.3k
        if (psInfo->nPrecision == AVC_SINGLE_PREC)
1406
6.19k
        {
1407
6.19k
            numCoordPerLine = 5;
1408
6.19k
            nItemSize = 14; /* Num of chars for single precision float*/
1409
6.19k
        }
1410
33.1k
        else
1411
33.1k
        {
1412
33.1k
            numCoordPerLine = 3;
1413
33.1k
            nItemSize = 21; /* Num of chars for double precision float*/
1414
33.1k
        }
1415
39.3k
        iCurCoord = psInfo->iCurItem * numCoordPerLine;
1416
1417
39.3k
        for (i = 0;
1418
169k
             i < numCoordPerLine && nLen > static_cast<size_t>(i) * nItemSize;
1419
130k
             i++, iCurCoord++)
1420
130k
        {
1421
130k
            if (iCurCoord < 4 &&
1422
40.4k
                (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1)
1423
6.96k
            {
1424
6.96k
                psTxt->pasVertices[iVertex + 1].x =
1425
6.96k
                    CPLAtof(pszLine + i * nItemSize);
1426
                /* The first vertex is always duplicated */
1427
6.96k
                if (iVertex == 0)
1428
1.80k
                    psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
1429
6.96k
            }
1430
123k
            else if (iCurCoord >= 4 && iCurCoord < 8 &&
1431
33.8k
                     (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1)
1432
6.58k
            {
1433
6.58k
                psTxt->pasVertices[iVertex + 1].y =
1434
6.58k
                    CPLAtof(pszLine + i * nItemSize);
1435
                /* The first vertex is always duplicated */
1436
6.58k
                if (iVertex == 0)
1437
1.79k
                    psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
1438
6.58k
            }
1439
116k
            else if (iCurCoord >= 8 && iCurCoord < 11 &&
1440
24.4k
                     (iVertex = (iCurCoord - 8) % 3) <
1441
24.4k
                         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
23.8k
                     (iVertex = (iCurCoord - 8) % 3) <
1448
23.8k
                         ABS(psTxt->numVerticesArrow))
1449
3.86k
            {
1450
3.86k
                psTxt->pasVertices[iVertex + psTxt->numVerticesLine].y =
1451
3.86k
                    CPLAtof(pszLine + i * nItemSize);
1452
3.86k
            }
1453
109k
            else if (iCurCoord == 14)
1454
7.89k
            {
1455
7.89k
                psTxt->dHeight = CPLAtof(pszLine + i * nItemSize);
1456
7.89k
            }
1457
130k
        }
1458
1459
39.3k
        psInfo->iCurItem++;
1460
39.3k
    }
1461
37.1k
    else if (psInfo->iCurItem < psInfo->numItems &&
1462
37.1k
             psInfo->iCurItem == numFixedLines - 1 && nLen >= 14)
1463
5.45k
    {
1464
        /*-------------------------------------------------------------
1465
         * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
1466
         *------------------------------------------------------------*/
1467
5.45k
        psTxt->f_1e2 = (float)CPLAtof(pszLine);
1468
1469
5.45k
        psInfo->iCurItem++;
1470
5.45k
    }
1471
31.7k
    else if (psInfo->iCurItem < psInfo->numItems &&
1472
31.7k
             psInfo->iCurItem >= numFixedLines)
1473
31.6k
    {
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
31.6k
        int numLines, iLine;
1480
31.6k
        numLines = (psTxt->numChars - 1) / 80 + 1;
1481
31.6k
        iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1482
1483
31.6k
        if (iLine == numLines - 1)
1484
4.09k
        {
1485
4.09k
            memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
1486
4.09k
                   MIN((int)nLen, (psTxt->numChars - (iLine * 80))));
1487
4.09k
        }
1488
27.5k
        else
1489
27.5k
        {
1490
27.5k
            memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
1491
27.5k
                   MIN(nLen, 80));
1492
27.5k
        }
1493
1494
31.6k
        psInfo->iCurItem++;
1495
31.6k
    }
1496
63
    else
1497
63
    {
1498
63
        CPLError(CE_Failure, CPLE_AppDefined,
1499
63
                 "Error parsing E00 TXT line: \"%s\"", pszLine);
1500
63
        psInfo->numItems = psInfo->iCurItem = 0;
1501
63
        return nullptr;
1502
63
    }
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
89.3k
    if (psInfo->iCurItem >= psInfo->numItems)
1511
4.09k
    {
1512
4.09k
        psInfo->numItems = psInfo->iCurItem = 0;
1513
4.09k
        return psTxt;
1514
4.09k
    }
1515
1516
85.2k
    return nullptr;
1517
89.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
78.9k
{
1537
78.9k
    AVCTxt *psTxt;
1538
78.9k
    int i;
1539
78.9k
    size_t nLen;
1540
1541
78.9k
    CPLAssert(psInfo->eFileType == AVCFileTX6);
1542
1543
78.9k
    psTxt = psInfo->cur.psTxt;
1544
1545
78.9k
    nLen = strlen(pszLine);
1546
1547
78.9k
    if (psInfo->numItems == 0)
1548
6.19k
    {
1549
        /*-------------------------------------------------------------
1550
         * Begin processing a new object, read header line:
1551
         *------------------------------------------------------------*/
1552
6.19k
        if (nLen < 70)
1553
20
        {
1554
20
            CPLError(CE_Failure, CPLE_AppDefined,
1555
20
                     "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1556
20
            return nullptr;
1557
20
        }
1558
6.17k
        else
1559
6.17k
        {
1560
6.17k
            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
6.17k
            psTxt->nTxtId = ++psInfo->nCurObjectId;
1567
1568
6.17k
            psTxt->nUserId = AVCE00Str2Int(pszLine, 10);
1569
6.17k
            psTxt->nLevel = AVCE00Str2Int(pszLine + 10, 10);
1570
6.17k
            psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 20, 10);
1571
6.17k
            if (psTxt->numVerticesLine < 0 ||
1572
6.15k
                psTxt->numVerticesLine > 10 * 1024 * 1024)
1573
28
            {
1574
28
                CPLError(CE_Failure, CPLE_AppDefined,
1575
28
                         "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1576
28
                psInfo->numItems = psInfo->iCurItem = 0;
1577
28
                return nullptr;
1578
28
            }
1579
6.14k
            psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 30, 10);
1580
6.14k
            if (psTxt->numVerticesArrow < -10 * 1024 * 1024 ||
1581
6.14k
                psTxt->numVerticesArrow > 10 * 1024 * 1024)
1582
11
            {
1583
11
                CPLError(CE_Failure, CPLE_AppDefined,
1584
11
                         "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1585
11
                psInfo->numItems = psInfo->iCurItem = 0;
1586
11
                return nullptr;
1587
11
            }
1588
6.13k
            psTxt->nSymbol = AVCE00Str2Int(pszLine + 40, 10);
1589
6.13k
            psTxt->n28 = AVCE00Str2Int(pszLine + 50, 10);
1590
6.13k
            psTxt->numChars = AVCE00Str2Int(pszLine + 60, 10);
1591
6.13k
            if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024)
1592
11
            {
1593
11
                CPLError(CE_Failure, CPLE_AppDefined,
1594
11
                         "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1595
11
                psInfo->numItems = psInfo->iCurItem = 0;
1596
11
                return nullptr;
1597
11
            }
1598
1599
            /*---------------------------------------------------------
1600
             * Realloc the string buffer and array of vertices
1601
             *--------------------------------------------------------*/
1602
6.12k
            psTxt->pszText = (GByte *)CPLRealloc(
1603
6.12k
                psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte));
1604
1605
6.12k
            numVertices =
1606
6.12k
                ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
1607
6.12k
            if (numVertices > 0)
1608
1.02k
                psTxt->pasVertices = (AVCVertex *)CPLRealloc(
1609
1.02k
                    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
6.12k
            memset(psTxt->pszText, ' ', psTxt->numChars);
1616
6.12k
            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
6.12k
            psInfo->iCurItem = 0;
1623
6.12k
            psInfo->numItems =
1624
6.12k
                8 + numVertices + ((psTxt->numChars - 1) / 80 + 1);
1625
6.12k
        }
1626
6.19k
    }
1627
72.7k
    else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6 &&
1628
19.9k
             nLen >= 60)
1629
19.8k
    {
1630
        /*-------------------------------------------------------------
1631
         * Text Justification stuff... 2 sets of 20 int16 values.
1632
         *------------------------------------------------------------*/
1633
19.8k
        GInt16 *pValue;
1634
19.8k
        int numValPerLine;
1635
1636
19.8k
        if (psInfo->iCurItem == 0 || psInfo->iCurItem == 1)
1637
9.44k
        {
1638
9.44k
            pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
1639
9.44k
            numValPerLine = 7;
1640
9.44k
        }
1641
10.4k
        else if (psInfo->iCurItem == 2)
1642
2.97k
        {
1643
2.97k
            pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
1644
            /* Last line of each set contains only 6 values instead of 7 */
1645
2.97k
            numValPerLine = 6;
1646
2.97k
        }
1647
7.44k
        else if (psInfo->iCurItem == 3 || psInfo->iCurItem == 4)
1648
5.13k
        {
1649
5.13k
            pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
1650
5.13k
            numValPerLine = 7;
1651
5.13k
        }
1652
2.31k
        else /* if (psInfo->iCurItem == 5) */
1653
2.31k
        {
1654
2.31k
            pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
1655
            /* Last line of each set contains only 6 values instead of 7 */
1656
2.31k
            numValPerLine = 6;
1657
2.31k
        }
1658
1659
19.8k
        for (i = 0;
1660
151k
             i < numValPerLine && nLen >= static_cast<size_t>(i) * 10 + 10; i++)
1661
132k
            pValue[i] = (GInt16)AVCE00Str2Int(pszLine + i * 10, 10);
1662
1663
19.8k
        psInfo->iCurItem++;
1664
19.8k
    }
1665
52.8k
    else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6 &&
1666
2.28k
             nLen >= 14)
1667
2.28k
    {
1668
        /*-------------------------------------------------------------
1669
         * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
1670
         *------------------------------------------------------------*/
1671
2.28k
        psTxt->f_1e2 = (float)CPLAtof(pszLine);
1672
2.28k
        psInfo->iCurItem++;
1673
2.28k
    }
1674
50.6k
    else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7 &&
1675
2.25k
             nLen >= 42)
1676
2.25k
    {
1677
        /*-------------------------------------------------------------
1678
         * Line with 3 values, 1st value is text height.
1679
         *------------------------------------------------------------*/
1680
2.25k
        psTxt->dHeight = CPLAtof(pszLine);
1681
2.25k
        if (psInfo->nPrecision == AVC_SINGLE_PREC)
1682
1.98k
        {
1683
1.98k
            psTxt->dV2 = CPLAtof(pszLine + 14);
1684
1.98k
            psTxt->dV3 = CPLAtof(pszLine + 28);
1685
1.98k
        }
1686
268
        else
1687
268
        {
1688
268
            psTxt->dV2 = CPLAtof(pszLine + 21);
1689
268
            psTxt->dV3 = CPLAtof(pszLine + 42);
1690
268
        }
1691
1692
2.25k
        psInfo->iCurItem++;
1693
2.25k
    }
1694
48.3k
    else if (psInfo->iCurItem >= 8 &&
1695
48.2k
             psInfo->iCurItem < (8 + ABS(psTxt->numVerticesLine) +
1696
48.2k
                                 ABS(psTxt->numVerticesArrow)) &&
1697
2.71k
             nLen >= 28)
1698
2.69k
    {
1699
        /*-------------------------------------------------------------
1700
         * One line for each pair of X,Y coordinates
1701
         * (Lines 8 to 8+numVertices-1)
1702
         *------------------------------------------------------------*/
1703
2.69k
        psTxt->pasVertices[psInfo->iCurItem - 8].x = CPLAtof(pszLine);
1704
2.69k
        if (psInfo->nPrecision == AVC_SINGLE_PREC)
1705
2.19k
            psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 14);
1706
502
        else
1707
502
            psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 21);
1708
1709
2.69k
        psInfo->iCurItem++;
1710
2.69k
    }
1711
45.6k
    else if (psInfo->iCurItem >= (8 + ABS(psTxt->numVerticesLine) +
1712
45.6k
                                  ABS(psTxt->numVerticesArrow)) &&
1713
45.5k
             psInfo->iCurItem < psInfo->numItems &&
1714
45.5k
             (psTxt->numChars - 1) / 80 + 1 -
1715
45.5k
                     (psInfo->numItems - psInfo->iCurItem) >=
1716
45.5k
                 0)
1717
45.5k
    {
1718
        /*-------------------------------------------------------------
1719
         * Last line, contains the text string
1720
         * Note that text can be split in 80 chars chunk and that buffer
1721
         * has been previously initialized with spaces and '\0'-terminated
1722
         *------------------------------------------------------------*/
1723
45.5k
        int numLines, iLine;
1724
45.5k
        numLines = (psTxt->numChars - 1) / 80 + 1;
1725
45.5k
        iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1726
1727
45.5k
        if (iLine == numLines - 1)
1728
1.78k
        {
1729
1.78k
            memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
1730
1.78k
                   MIN((int)nLen, (psTxt->numChars - (iLine * 80))));
1731
1.78k
        }
1732
43.7k
        else
1733
43.7k
        {
1734
43.7k
            memcpy((char *)psTxt->pszText + (iLine * 80), pszLine,
1735
43.7k
                   MIN(nLen, 80));
1736
43.7k
        }
1737
1738
45.5k
        psInfo->iCurItem++;
1739
45.5k
    }
1740
78
    else
1741
78
    {
1742
78
        CPLError(CE_Failure, CPLE_AppDefined,
1743
78
                 "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1744
78
        psInfo->numItems = psInfo->iCurItem = 0;
1745
78
        return nullptr;
1746
78
    }
1747
1748
    /*-----------------------------------------------------------------
1749
     * If we're done parsing this TX6/TX7, then reset the ParseInfo,
1750
     * and return a reference to the TXT structure
1751
     * Otherwise return nullptr, which means that we are expecting more
1752
     * more lines of input.
1753
     *----------------------------------------------------------------*/
1754
78.8k
    if (psInfo->iCurItem >= psInfo->numItems)
1755
1.78k
    {
1756
1.78k
        psInfo->numItems = psInfo->iCurItem = 0;
1757
1.78k
        return psTxt;
1758
1.78k
    }
1759
1760
77.0k
    return nullptr;
1761
78.8k
}
1762
1763
/**********************************************************************
1764
 *                          AVCE00ParseNextRxpLine()
1765
 *
1766
 * Take the next line of E00 input for an RXP object and parse it.
1767
 *
1768
 * Returns nullptr if the current object is not complete yet (expecting
1769
 * more lines of input) or a reference to a complete object if it
1770
 * is complete.
1771
 *
1772
 * The returned object is a reference to an internal data structure.
1773
 * It should not be modified or freed by the caller.
1774
 *
1775
 * If the input is invalid or other problems happen, then a CPLError()
1776
 * will be generated.  CPLGetLastErrorNo() should be called to check
1777
 * that the line was parsed successfully.
1778
 **********************************************************************/
1779
AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1780
4.51k
{
1781
4.51k
    AVCRxp *psRxp;
1782
4.51k
    size_t nLen;
1783
1784
4.51k
    CPLAssert(psInfo->eFileType == AVCFileRXP);
1785
1786
4.51k
    psRxp = psInfo->cur.psRxp;
1787
1788
4.51k
    nLen = strlen(pszLine);
1789
1790
4.51k
    if (nLen >= 20)
1791
4.49k
    {
1792
        /*-------------------------------------------------------------
1793
         * RXP Entries are only one line each:
1794
         *   Value1, Value2 (meaning of the value??? Don't know!!!)
1795
         *------------------------------------------------------------*/
1796
4.49k
        psRxp->n1 = AVCE00Str2Int(pszLine, 10);
1797
4.49k
        psRxp->n2 = AVCE00Str2Int(pszLine + 10, 10);
1798
4.49k
    }
1799
27
    else
1800
27
    {
1801
27
        CPLError(CE_Failure, CPLE_AppDefined,
1802
27
                 "Error parsing E00 RXP line: \"%s\"", pszLine);
1803
27
        psInfo->numItems = psInfo->iCurItem = 0;
1804
27
        return nullptr;
1805
27
    }
1806
1807
    /*-----------------------------------------------------------------
1808
     * If we're done parsing this RXP, then reset the ParseInfo,
1809
     * and return a reference to the RXP structure
1810
     * Otherwise return nullptr, which means that we are expecting more
1811
     * more lines of input.
1812
     *----------------------------------------------------------------*/
1813
4.49k
    if (psInfo->iCurItem >= psInfo->numItems)
1814
4.49k
    {
1815
4.49k
        psInfo->numItems = psInfo->iCurItem = 0;
1816
4.49k
        return psRxp;
1817
4.49k
    }
1818
1819
0
    return nullptr;
1820
4.49k
}
1821
1822
/*=====================================================================
1823
                            TABLE stuff
1824
 =====================================================================*/
1825
1826
/**********************************************************************
1827
 *                          AVCE00ParseNextTableDefLine()
1828
 *
1829
 * Take the next line of E00 input for an TableDef object and parse it.
1830
 *
1831
 * Returns nullptr if the current object is not complete yet (expecting
1832
 * more lines of input) or a reference to a complete object if it
1833
 * is complete.
1834
 *
1835
 * The returned object is a reference to an internal data structure.
1836
 * It should not be modified or freed by the caller.
1837
 *
1838
 * If the input is invalid or other problems happen, then a CPLError()
1839
 * will be generated.  CPLGetLastErrorNo() should be called to check
1840
 * that the line was parsed successfully.
1841
 **********************************************************************/
1842
AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo,
1843
                                         const char *pszLine)
1844
4.64M
{
1845
4.64M
    AVCTableDef *psTableDef;
1846
4.64M
    size_t nLen;
1847
1848
4.64M
    CPLAssert(psInfo->eFileType == AVCFileTABLE);
1849
1850
4.64M
    psTableDef = psInfo->hdr.psTableDef; /* May be nullptr on first call */
1851
1852
4.64M
    nLen = strlen(pszLine);
1853
1854
4.64M
    if (psInfo->numItems == 0)
1855
2.33M
    {
1856
        /*-------------------------------------------------------------
1857
         * Begin processing a new TableDef.  Read header line:
1858
         *    TableName, extFlag, numFields, RecSize, numRecords
1859
         *------------------------------------------------------------*/
1860
2.33M
        if (nLen < 56)
1861
71
        {
1862
71
            CPLError(CE_Failure, CPLE_AppDefined,
1863
71
                     "Error parsing E00 Table Definition line: \"%s\"",
1864
71
                     pszLine);
1865
71
            return nullptr;
1866
71
        }
1867
2.33M
        else
1868
2.33M
        {
1869
            /*---------------------------------------------------------
1870
             * Parse header line and alloc and init. a new psTableDef struct
1871
             *--------------------------------------------------------*/
1872
2.33M
            psTableDef = psInfo->hdr.psTableDef =
1873
2.33M
                (AVCTableDef *)CPLCalloc(1, sizeof(AVCTableDef));
1874
2.33M
            psInfo->bTableHdrComplete = FALSE;
1875
1876
2.33M
            strncpy(psTableDef->szTableName, pszLine, 32);
1877
2.33M
            psTableDef->szTableName[32] = '\0';
1878
2.33M
            strncpy(psTableDef->szExternal, pszLine + 32, 2);
1879
2.33M
            psTableDef->szExternal[2] = '\0';
1880
1881
2.33M
            psTableDef->numFields = (GInt16)AVCE00Str2Int(pszLine + 34, 4);
1882
2.33M
            psTableDef->nRecSize = (GInt16)AVCE00Str2Int(pszLine + 42, 4);
1883
2.33M
            psTableDef->numRecords = AVCE00Str2Int(pszLine + 46, 10);
1884
2.33M
            if (psTableDef->numFields < 0 || psTableDef->numFields > 10 * 1024)
1885
1
            {
1886
1
                CPLError(CE_Failure, CPLE_AppDefined,
1887
1
                         "Error parsing E00 Table Definition line: \"%s\"",
1888
1
                         pszLine);
1889
1
                psInfo->numItems = psInfo->iCurItem = 0;
1890
1
                psTableDef->numFields = 0;
1891
1
                return nullptr;
1892
1
            }
1893
1894
            /*---------------------------------------------------------
1895
             * Alloc array of fields defs, will be filled in further calls
1896
             *--------------------------------------------------------*/
1897
2.33M
            psTableDef->pasFieldDef = (AVCFieldInfo *)CPLCalloc(
1898
2.33M
                psTableDef->numFields, sizeof(AVCFieldInfo));
1899
1900
            /*---------------------------------------------------------
1901
             * psInfo->iCurItem is the index of the last field def we read.
1902
             * psInfo->numItems is the number of field defs to read,
1903
             *                     including deleted ones.
1904
             *--------------------------------------------------------*/
1905
2.33M
            psInfo->numItems = AVCE00Str2Int(pszLine + 38, 4);
1906
2.33M
            psInfo->iCurItem = 0;
1907
2.33M
            psInfo->nCurObjectId = 0; /* We'll use it as a field index */
1908
2.33M
        }
1909
2.33M
    }
1910
2.30M
    else if (psInfo->iCurItem < psInfo->numItems && nLen >= 69)
1911
2.30M
    {
1912
        /*-------------------------------------------------------------
1913
         * Read an attribute field definition
1914
         * If field index is -1, then we ignore this line...
1915
         *------------------------------------------------------------*/
1916
2.30M
        int nIndex;
1917
1918
2.30M
        nIndex = AVCE00Str2Int(pszLine + 65, 4);
1919
1920
2.30M
        if (nIndex > 0 && psInfo->nCurObjectId >= psTableDef->numFields)
1921
2
        {
1922
2
            CPLError(CE_Failure, CPLE_AppDefined,
1923
2
                     "Error parsing E00 INFO Table Header: "
1924
2
                     "number of fields is invalid "
1925
2
                     "(expected %d, got at least %d)",
1926
2
                     psTableDef->numFields, psInfo->nCurObjectId + 1);
1927
2
            psInfo->numItems = psInfo->iCurItem = psInfo->nCurObjectId;
1928
2
            return nullptr;
1929
2
        }
1930
1931
2.30M
        if (nIndex > 0)
1932
2.30M
        {
1933
2.30M
            AVCFieldInfo *psDef;
1934
2.30M
            psDef = &(psTableDef->pasFieldDef[psInfo->nCurObjectId]);
1935
1936
2.30M
            psDef->nIndex = (GInt16)nIndex;
1937
1938
2.30M
            strncpy(psDef->szName, pszLine, 16);
1939
2.30M
            psDef->szName[16] = '\0';
1940
1941
2.30M
            psDef->nSize = (GInt16)AVCE00Str2Int(pszLine + 16, 3);
1942
2.30M
            psDef->v2 = (GInt16)AVCE00Str2Int(pszLine + 19, 2);
1943
1944
2.30M
            psDef->nOffset = (GInt16)AVCE00Str2Int(pszLine + 21, 4);
1945
1946
2.30M
            psDef->v4 = (GInt16)AVCE00Str2Int(pszLine + 25, 1);
1947
2.30M
            psDef->v5 = (GInt16)AVCE00Str2Int(pszLine + 26, 2);
1948
2.30M
            psDef->nFmtWidth = (GInt16)AVCE00Str2Int(pszLine + 28, 4);
1949
2.30M
            psDef->nFmtPrec = (GInt16)AVCE00Str2Int(pszLine + 32, 2);
1950
2.30M
            psDef->nType1 = (GInt16)AVCE00Str2Int(pszLine + 34, 3) / 10;
1951
2.30M
            psDef->nType2 = AVCE00Str2Int(pszLine + 34, 3) % 10;
1952
2.30M
            psDef->v10 = (GInt16)AVCE00Str2Int(pszLine + 37, 2);
1953
2.30M
            psDef->v11 = (GInt16)AVCE00Str2Int(pszLine + 39, 4);
1954
2.30M
            psDef->v12 = (GInt16)AVCE00Str2Int(pszLine + 43, 4);
1955
2.30M
            psDef->v13 = (GInt16)AVCE00Str2Int(pszLine + 47, 2);
1956
2.30M
            strncpy(psDef->szAltName, pszLine + 49, 16);
1957
2.30M
            psDef->szAltName[16] = '\0';
1958
1959
2.30M
            if (psDef->nSize < 0)
1960
1
            {
1961
1
                CPLError(CE_Failure, CPLE_AppDefined,
1962
1
                         "Error parsing E00 Table Definition line: \"%s\"",
1963
1
                         pszLine);
1964
1
                psInfo->numItems = psInfo->iCurItem = 0;
1965
1
                return nullptr;
1966
1
            }
1967
1968
2.30M
            psInfo->nCurObjectId++;
1969
2.30M
        }
1970
2.30M
        psInfo->iCurItem++;
1971
2.30M
    }
1972
26
    else
1973
26
    {
1974
26
        CPLError(CE_Failure, CPLE_AppDefined,
1975
26
                 "Error parsing E00 Table Definition line: \"%s\"", pszLine);
1976
26
        psInfo->numItems = psInfo->iCurItem = 0;
1977
26
        return nullptr;
1978
26
    }
1979
1980
    /*-----------------------------------------------------------------
1981
     * If we're done parsing this TableDef, then reset the ParseInfo,
1982
     * and return a reference to the TableDef structure.
1983
     * Next calls should go to AVCE00ParseNextTableRecLine() to
1984
     * read data records.
1985
     * Otherwise return nullptr, which means that we are expecting more
1986
     * more lines of input.
1987
     *----------------------------------------------------------------*/
1988
4.64M
    if (psInfo->iCurItem >= psInfo->numItems)
1989
2.33M
    {
1990
2.33M
        psInfo->numItems = psInfo->iCurItem = 0;
1991
2.33M
        psInfo->nCurObjectId = 0;
1992
1993
2.33M
        psInfo->bTableHdrComplete = TRUE;
1994
1995
        /*---------------------------------------------------------
1996
         * It is possible to have a table with 0 records... in this
1997
         * case we are already at the end of the section for that table.
1998
         *--------------------------------------------------------*/
1999
2.33M
        if (psTableDef->numRecords == 0)
2000
64.7k
            psInfo->bForceEndOfSection = TRUE;
2001
2002
2.33M
        return psTableDef;
2003
2.33M
    }
2004
2005
2.30M
    return nullptr;
2006
4.64M
}
2007
2008
/**********************************************************************
2009
 *                         _AVCE00ParseTableRecord()
2010
 *
2011
 * Parse the record data present inside psInfo->pszBuf and fill and
2012
 * return the psInfo->cur.pasFields[].
2013
 *
2014
 * This function should not be called directly... it is used by
2015
 * AVCE00ParseNextTableRecLine().
2016
 **********************************************************************/
2017
static AVCField *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
2018
2.31M
{
2019
2.31M
    AVCField *pasFields;
2020
2.31M
    AVCFieldInfo *pasDef;
2021
2.31M
    AVCTableDef *psTableDef;
2022
2.31M
    int i, nType, nSize;
2023
2.31M
    char szFormat[20];
2024
2.31M
    char *pszBuf, szTmp[30];
2025
2026
2.31M
    pasFields = psInfo->cur.pasFields;
2027
2.31M
    psTableDef = psInfo->hdr.psTableDef;
2028
2.31M
    pasDef = psTableDef->pasFieldDef;
2029
2030
2.31M
    pszBuf = psInfo->pszBuf;
2031
2.31M
    CPLAssert(pszBuf);
2032
2033
4.79M
    for (i = 0; i < psTableDef->numFields; i++)
2034
2.48M
    {
2035
2.48M
        nType = pasDef[i].nType1 * 10;
2036
2.48M
        nSize = pasDef[i].nSize;
2037
2038
2.48M
        if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
2039
2.41M
            nType == AVC_FT_FIXINT)
2040
1.76M
        {
2041
1.76M
            strncpy((char *)pasFields[i].pszStr, pszBuf, nSize);
2042
1.76M
            pasFields[i].pszStr[nSize] = '\0';
2043
1.76M
            pszBuf += nSize;
2044
1.76M
        }
2045
717k
        else if (nType == AVC_FT_FIXNUM)
2046
592k
        {
2047
            /* TYPE 40 attributes are stored with 1 byte per digit
2048
             * in binary format, and as single precision floats in
2049
             * E00 tables, even in double precision coverages.
2050
             */
2051
592k
            const char *pszTmpStr;
2052
592k
            strncpy(szTmp, pszBuf, 14);
2053
592k
            szTmp[14] = '\0';
2054
592k
            pszBuf += 14;
2055
2056
            /* Compensate for a very odd behavior observed in some E00 files.
2057
             * A type 40 field can be written in decimal format instead of
2058
             * exponent format, but in this case the decimal point is shifted
2059
             * one position to the right, resulting in a value 10 times bigger
2060
             * than expected.  So if the value is not in exponent format then
2061
             * we should shift the decimal point to the left before we
2062
             * interpret it.  (bug 599)
2063
             */
2064
592k
            if (!strchr(szTmp, 'E') && !strchr(szTmp, 'e'))
2065
589k
            {
2066
589k
                char *pszTmp;
2067
589k
                if ((pszTmp = strchr(szTmp, '.')) != nullptr && pszTmp != szTmp)
2068
571k
                {
2069
571k
                    *pszTmp = *(pszTmp - 1);
2070
571k
                    *(pszTmp - 1) = '.';
2071
571k
                }
2072
589k
            }
2073
2074
            /* We use nSize and nFmtPrec for the format because nFmtWidth can
2075
             * be different from nSize, but nSize has priority since it
2076
             * is the actual size of the field in memory.
2077
             */
2078
592k
            snprintf(szFormat, sizeof(szFormat), "%%%d.%df", nSize,
2079
592k
                     pasDef[i].nFmtPrec);
2080
592k
            pszTmpStr = CPLSPrintf(szFormat, CPLAtof(szTmp));
2081
2082
            /* If value is bigger than size, then it is too bad... we
2083
             * truncate it... but this should never happen in clean datasets.
2084
             */
2085
592k
            if ((int)strlen(pszTmpStr) > nSize)
2086
589k
                pszTmpStr = pszTmpStr + strlen(pszTmpStr) - nSize;
2087
592k
            strncpy((char *)pasFields[i].pszStr, pszTmpStr, nSize);
2088
592k
            pasFields[i].pszStr[nSize] = '\0';
2089
592k
        }
2090
124k
        else if (nType == AVC_FT_BININT && nSize == 4)
2091
39.3k
        {
2092
39.3k
            pasFields[i].nInt32 = AVCE00Str2Int(pszBuf, 11);
2093
39.3k
            pszBuf += 11;
2094
39.3k
        }
2095
85.5k
        else if (nType == AVC_FT_BININT && nSize == 2)
2096
11.3k
        {
2097
11.3k
            pasFields[i].nInt16 = (GInt16)AVCE00Str2Int(pszBuf, 6);
2098
11.3k
            pszBuf += 6;
2099
11.3k
        }
2100
74.2k
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
2101
57.3k
        {
2102
            /* NOTE: The E00 representation for a binary float is
2103
             * defined by its binary size, not by the coverage's
2104
             * precision.
2105
             */
2106
57.3k
            strncpy(szTmp, pszBuf, 14);
2107
57.3k
            szTmp[14] = '\0';
2108
57.3k
            pasFields[i].fFloat = (float)CPLAtof(szTmp);
2109
57.3k
            pszBuf += 14;
2110
57.3k
        }
2111
16.9k
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
2112
16.9k
        {
2113
            /* NOTE: The E00 representation for a binary float is
2114
             * defined by its binary size, not by the coverage's
2115
             * precision.
2116
             */
2117
16.9k
            strncpy(szTmp, pszBuf, 24);
2118
16.9k
            szTmp[24] = '\0';
2119
16.9k
            pasFields[i].dDouble = CPLAtof(szTmp);
2120
16.9k
            pszBuf += 24;
2121
16.9k
        }
2122
0
        else
2123
0
        {
2124
            /*-----------------------------------------------------
2125
             * Hummm... unsupported field type...
2126
             *----------------------------------------------------*/
2127
0
            CPLError(CE_Failure, CPLE_NotSupported,
2128
0
                     "_AVCE00ParseTableRecord(): Unsupported field type "
2129
0
                     "(type=%d, size=%d)",
2130
0
                     nType, pasDef[i].nSize);
2131
0
            return nullptr;
2132
0
        }
2133
2.48M
    }
2134
2135
2.31M
    CPLAssert(pszBuf == psInfo->pszBuf + psInfo->nTableE00RecLength);
2136
2137
2.31M
    return pasFields;
2138
2.31M
}
2139
2140
/**********************************************************************
2141
 *                          AVCE00ParseNextTableRecLine()
2142
 *
2143
 * Take the next line of E00 input for an Table data record and parse it.
2144
 *
2145
 * Returns nullptr if the current record is not complete yet (expecting
2146
 * more lines of input) or a reference to a complete record if it
2147
 * is complete.
2148
 *
2149
 * The returned record is a reference to an internal data structure.
2150
 * It should not be modified or freed by the caller.
2151
 *
2152
 * If the input is invalid or other problems happen, then a CPLError()
2153
 * will be generated.  CPLGetLastErrorNo() should be called to check
2154
 * that the line was parsed successfully.
2155
 **********************************************************************/
2156
AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo,
2157
                                      const char *pszLine)
2158
2.33M
{
2159
2.33M
    AVCField *pasFields = nullptr;
2160
2.33M
    AVCTableDef *psTableDef;
2161
2.33M
    int i;
2162
2163
2.33M
    CPLAssert(psInfo->eFileType == AVCFileTABLE);
2164
2165
2.33M
    psTableDef = psInfo->hdr.psTableDef;
2166
2167
2.33M
    if (psInfo->bForceEndOfSection || psTableDef->numFields == 0 ||
2168
2.33M
        psTableDef->numRecords == 0)
2169
1.23k
    {
2170
1.23k
        psInfo->bForceEndOfSection = TRUE;
2171
1.23k
        return nullptr;
2172
1.23k
    }
2173
2174
    /*-----------------------------------------------------------------
2175
     * On the first call for a new table, we have some allocations to
2176
     * do:
2177
     * - make sure the psInfo->szBuf is big enough to hold one complete
2178
     *   E00 data record.
2179
     * - Alloc the array of Field values (psInfo->cur.pasFields[])
2180
     *   for the number of fields in this table.
2181
     *----------------------------------------------------------------*/
2182
2.33M
    if (psInfo->numItems == 0 && psInfo->nCurObjectId == 0)
2183
2.26M
    {
2184
        /*-------------------------------------------------------------
2185
         * Realloc E00 buffer
2186
         *------------------------------------------------------------*/
2187
2.26M
        psInfo->nTableE00RecLength = _AVCE00ComputeRecSize(
2188
2.26M
            psTableDef->numFields, psTableDef->pasFieldDef, FALSE);
2189
2.26M
        if (psInfo->nTableE00RecLength < 0)
2190
34
        {
2191
34
            return nullptr;
2192
34
        }
2193
2194
2.26M
        if (psInfo->nBufSize < psInfo->nTableE00RecLength + 1)
2195
0
        {
2196
0
            psInfo->nBufSize = psInfo->nTableE00RecLength + 1;
2197
0
            psInfo->pszBuf =
2198
0
                (char *)CPLRealloc(psInfo->pszBuf, psInfo->nBufSize);
2199
0
        }
2200
2201
        /*---------------------------------------------------------
2202
         * Alloc psInfo->cur.pasFields[]
2203
         * Also alloc buffers for string attributes.
2204
         *--------------------------------------------------------*/
2205
2.26M
        psInfo->cur.pasFields =
2206
2.26M
            (AVCField *)CPLCalloc(psTableDef->numFields, sizeof(AVCField));
2207
4.56M
        for (i = 0; i < psTableDef->numFields; i++)
2208
2.30M
        {
2209
2.30M
            if (psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_DATE ||
2210
2.28M
                psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_CHAR ||
2211
2.27M
                psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXINT ||
2212
599k
                psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM)
2213
2.27M
            {
2214
2.27M
                psInfo->cur.pasFields[i].pszStr = (GByte *)CPLCalloc(
2215
2.27M
                    psTableDef->pasFieldDef[i].nSize + 1, sizeof(GByte));
2216
2.27M
            }
2217
2.30M
        }
2218
2.26M
    }
2219
2220
2.33M
    if (psInfo->numItems == 0)
2221
2.31M
    {
2222
        /*-----------------------------------------------------------------
2223
         * Begin processing a new record... we'll accumulate the 80
2224
         * chars lines until we have the whole record in our buffer
2225
         * and parse it only at the end.
2226
         * Lines shorter than 80 chars are legal, and in this case
2227
         * they will be padded with spaces up to 80 chars.
2228
         *----------------------------------------------------------------*/
2229
2230
        /*---------------------------------------------------------
2231
         * First fill the whole record buffer with spaces we'll just
2232
         * paste lines in it using strncpy()
2233
         *--------------------------------------------------------*/
2234
2.31M
        memset(psInfo->pszBuf, ' ', psInfo->nTableE00RecLength);
2235
2.31M
        psInfo->pszBuf[psInfo->nTableE00RecLength] = '\0';
2236
2237
        /*---------------------------------------------------------
2238
         * psInfo->iCurItem is the number of chars buffered so far.
2239
         * psInfo->numItems is the number of chars to expect in one record.
2240
         *--------------------------------------------------------*/
2241
2.31M
        psInfo->numItems = psInfo->nTableE00RecLength;
2242
2.31M
        psInfo->iCurItem = 0;
2243
2.31M
    }
2244
2245
2.33M
    if (psInfo->iCurItem < psInfo->numItems)
2246
633k
    {
2247
        /*-------------------------------------------------------------
2248
         * Continue to accumulate the 80 chars lines until we have
2249
         * the whole record in our buffer.  We'll parse it only at the end.
2250
         * Lines shorter than 80 chars are legal, and in this case
2251
         * they padded with spaces up to 80 chars.
2252
         *------------------------------------------------------------*/
2253
633k
        int nSrcLen, nLenToCopy;
2254
2255
633k
        nSrcLen = (int)strlen(pszLine);
2256
633k
        nLenToCopy =
2257
633k
            MIN(80, MIN(nSrcLen, (psInfo->numItems - psInfo->iCurItem)));
2258
633k
        strncpy(psInfo->pszBuf + psInfo->iCurItem, pszLine, nLenToCopy);
2259
2260
633k
        psInfo->iCurItem += 80;
2261
633k
    }
2262
2263
2.33M
    if (psInfo->iCurItem >= psInfo->numItems)
2264
2.31M
    {
2265
        /*-------------------------------------------------------------
2266
         * OK, we've got one full record in the buffer... parse it and
2267
         * return the pasFields[]
2268
         *------------------------------------------------------------*/
2269
2.31M
        pasFields = _AVCE00ParseTableRecord(psInfo);
2270
2271
2.31M
        if (pasFields == nullptr)
2272
0
        {
2273
0
            CPLError(CE_Failure, CPLE_AppDefined,
2274
0
                     "Error parsing E00 Table Record: \"%s\"", psInfo->pszBuf);
2275
0
            return nullptr;
2276
0
        }
2277
2278
2.31M
        psInfo->numItems = psInfo->iCurItem = 0;
2279
2.31M
        psInfo->nCurObjectId++;
2280
2.31M
    }
2281
2282
    /*-----------------------------------------------------------------
2283
     * Since there is no explicit "end of table" line, we set the
2284
     * bForceEndOfSection flag when the last record is read.
2285
     *----------------------------------------------------------------*/
2286
2.33M
    if (psInfo->nCurObjectId >= psTableDef->numRecords)
2287
2.26M
    {
2288
2.26M
        psInfo->bForceEndOfSection = TRUE;
2289
2.26M
    }
2290
2291
2.33M
    return pasFields;
2292
2.33M
}