Coverage Report

Created: 2025-11-15 08:43

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