Coverage Report

Created: 2026-11-12 08:28

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