Coverage Report

Created: 2026-08-11 08:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/avc/avc_bin.cpp
Line
Count
Source
1
/**********************************************************************
2
 *
3
 * Name:     avc_bin.c
4
 * Project:  Arc/Info vector coverage (AVC)  BIN->E00 conversion library
5
 * Language: ANSI C
6
 * Purpose:  Binary files access functions.
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_bin.c,v $
16
 * Revision 1.30  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.29  2006/08/17 18:56:42  dmorissette
21
 * Support for reading standalone info tables (just tables, no coverage
22
 * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549).
23
 *
24
 * Revision 1.28  2006/06/14 16:31:28  daniel
25
 * Added support for AVCCoverPC2 type (bug 1491)
26
 *
27
 * Revision 1.27  2005/06/03 03:49:58  daniel
28
 * Update email address, website url, and copyright dates
29
 *
30
 * Revision 1.26  2004/02/28 06:35:49  warmerda
31
 * Fixed AVCBinReadObject() index support to use 'x' or 'X' for index
32
 * depending on the case of the original name.
33
 * Fixed so that PC Arc/Info coverages with the extra 256 byte header work
34
 * properly when using indexes to read them.
35
 *   http://bugzilla.remotesensing.org/show_bug.cgi?id=493
36
 *
37
 * Revision 1.25  2004/02/11 05:49:44  daniel
38
 * Added support for deleted flag in arc.dir (bug 2332)
39
 *
40
 * Revision 1.24  2002/08/27 15:26:06  daniel
41
 * Removed C++ style comments for IRIX compiler (GDAL bug 192)
42
 *
43
 * Revision 1.23  2002/04/16 20:04:24  daniel
44
 * Use record size while reading ARC, PAL, CNT to skip junk bytes. (bug940)
45
 *
46
 * Revision 1.22  2002/03/18 19:03:37  daniel
47
 * Fixed AVCBinReadObject() for PAL objects (bug 848)
48
 *
49
 * Revision 1.21  2002/02/14 22:54:13  warmerda
50
 * added polygon and table support for random reading
51
 *
52
 * Revision 1.20  2002/02/13 20:35:24  warmerda
53
 * added AVCBinReadObject
54
 *
55
 * Revision 1.19  2001/11/25 22:01:23  daniel
56
 * Fixed order of args to AVCRawBinFSeek() in _AVCBinReadNextTableRec()
57
 *
58
 * Revision 1.18  2000/10/16 16:16:20  daniel
59
 * Accept TXT files in AVCCoverWeird that use both PC or V7 TXT structure
60
 *
61
 * Revision 1.17  2000/09/26 20:21:04  daniel
62
 * Added AVCCoverPC write
63
 *
64
 * Revision 1.16  2000/09/22 19:45:20  daniel
65
 * Switch to MIT-style license
66
 *
67
 * Revision 1.15  2000/09/20 15:09:34  daniel
68
 * Check for DAT/NIT fnames sometimes truncated to 8 chars in weird coverages
69
 *
70
 * Revision 1.14  2000/06/05 21:38:53  daniel
71
 * Handle precision field > 1000 in cover file header as meaning double prec.
72
 *
73
 * Revision 1.13  2000/05/29 15:31:30  daniel
74
 * Added Japanese DBCS support
75
 *
76
 * Revision 1.12  2000/02/14 17:22:36  daniel
77
 * Check file signature (9993 or 9994) when reading header.
78
 *
79
 * Revision 1.11  2000/02/02 04:24:52  daniel
80
 * Support double precision "weird" coverages
81
 *
82
 * Revision 1.10  2000/01/10 02:54:10  daniel
83
 * Added read support for "weird" coverages
84
 *
85
 * Revision 1.9  2000/01/07 07:11:51  daniel
86
 * Added support for reading PC Coverage TXT files
87
 *
88
 * Revision 1.8  1999/12/24 07:38:10  daniel
89
 * Added missing DBFClose()
90
 *
91
 * Revision 1.7  1999/12/24 07:18:34  daniel
92
 * Added PC Arc/Info coverages support
93
 *
94
 * Revision 1.6  1999/08/23 18:17:16  daniel
95
 * Modified AVCBinReadListTables() to return INFO fnames for DeleteCoverage()
96
 *
97
 * Revision 1.5  1999/05/11 01:49:08  daniel
98
 * Simple changes required by addition of coverage write support
99
 *
100
 * Revision 1.4  1999/03/03 18:42:53  daniel
101
 * Fixed problem with INFO table headers (arc.dir) that sometimes contain an
102
 * invalid number of records.
103
 *
104
 * Revision 1.3  1999/02/25 17:01:53  daniel
105
 * Added support for 16 bit integers in INFO tables (type=50, size=2)
106
 *
107
 * Revision 1.2  1999/02/25 03:41:28  daniel
108
 * Added TXT, TX6/TX7, RXP and RPL support
109
 *
110
 * Revision 1.1  1999/01/29 16:28:52  daniel
111
 * Initial revision
112
 *
113
 **********************************************************************/
114
115
#include "avc.h"
116
117
#include <algorithm>
118
#include <cmath>
119
#include <ctype.h> /* for isspace() */
120
121
#ifdef WITHOUT_SHAPEFILE
122
123
#define SHP_VSI_ONLY_SETUP_HOOKS
124
#define SAOffset vsi_l_offset
125
#define SHPAPI_CAL
126
127
#define DBFAddField OGRAVC_DBFAddField
128
#define DBFAddNativeFieldType OGRAVC_DBFAddNativeFieldType
129
#define DBFAlterFieldDefn OGRAVC_DBFAlterFieldDefn
130
#define DBFCloneEmpty OGRAVC_DBFCloneEmpty
131
#define DBFClose OGRAVC_DBFClose
132
#define DBFCreateEx OGRAVC_DBFCreateEx
133
#define DBFCreate OGRAVC_DBFCreate
134
#define DBFCreateLL OGRAVC_DBFCreateLL
135
#define DBFDeleteField OGRAVC_DBFDeleteField
136
#define DBFFlushRecord OGRAVC_DBFFlushRecord
137
#define DBFGetCodePage OGRAVC_DBFGetCodePage
138
#define DBFGetFieldCount OGRAVC_DBFGetFieldCount
139
#define DBFGetFieldIndex OGRAVC_DBFGetFieldIndex
140
#define DBFGetFieldInfo OGRAVC_DBFGetFieldInfo
141
#define DBFGetLenWithoutExtension OGRAVC_DBFGetLenWithoutExtension
142
#define DBFGetNativeFieldType OGRAVC_DBFGetNativeFieldType
143
#define DBFGetNullCharacter OGRAVC_DBFGetNullCharacter
144
#define DBFGetRecordCount OGRAVC_DBFGetRecordCount
145
#define DBFIsAttributeNULL OGRAVC_DBFIsAttributeNULL
146
#define DBFIsRecordDeleted OGRAVC_DBFIsRecordDeleted
147
#define DBFIsValueNULL OGRAVC_DBFIsValueNULL
148
#define DBFLoadRecord OGRAVC_DBFLoadRecord
149
#define DBFMarkRecordDeleted OGRAVC_DBFMarkRecordDeleted
150
#define DBFOpen OGRAVC_DBFOpen
151
#define DBFOpenLL OGRAVC_DBFOpenLL
152
#define DBFReadAttribute OGRAVC_DBFReadAttribute
153
#define DBFReadDoubleAttribute OGRAVC_DBFReadDoubleAttribute
154
#define DBFReadIntegerAttribute OGRAVC_DBFReadIntegerAttribute
155
#define DBFReadLogicalAttribute OGRAVC_DBFReadLogicalAttribute
156
#define DBFReadStringAttribute OGRAVC_DBFReadStringAttribute
157
#define DBFReadDateAttribute OGRAVC_DBFReadDateAttribute
158
#define DBFReadTuple OGRAVC_DBFReadTuple
159
#define DBFReorderFields OGRAVC_DBFReorderFields
160
#define DBFSetLastModifiedDate OGRAVC_DBFSetLastModifiedDate
161
#define DBFSetWriteEndOfFileChar OGRAVC_DBFSetWriteEndOfFileChar
162
#define DBFUpdateHeader OGRAVC_DBFUpdateHeader
163
#define DBFWriteAttributeDirectly OGRAVC_DBFWriteAttributeDirectly
164
#define DBFWriteAttribute OGRAVC_DBFWriteAttribute
165
#define DBFWriteDoubleAttribute OGRAVC_DBFWriteDoubleAttribute
166
#define DBFWriteHeader OGRAVC_DBFWriteHeader
167
#define DBFWriteIntegerAttribute OGRAVC_DBFWriteIntegerAttribute
168
#define DBFWriteLogicalAttribute OGRAVC_DBFWriteLogicalAttribute
169
#define DBFWriteNULLAttribute OGRAVC_DBFWriteNULLAttribute
170
#define DBFWriteStringAttribute OGRAVC_DBFWriteStringAttribute
171
#define DBFWriteDateAttribute OGRAVC_DBFWriteDateAttribute
172
#define DBFWriteTuple OGRAVC_DBFWriteTuple
173
174
#define VSI_SHP_WriteMoreDataOK OGRAVC_VSI_SHP_WriteMoreDataOK
175
#define SASetupDefaultHooks OGRAVC_SASetupDefaultHooks
176
177
#include "shapefil.h"
178
#include "dbfopen.c"
179
#include "shp_vsi.cpp"
180
181
#else
182
183
#ifdef RENAME_INTERNAL_SHAPELIB_SYMBOLS
184
#include "gdal_shapelib_symbol_rename.h"
185
#endif
186
#include "shapefil.h"
187
188
#endif  // WITHOUT_SHAPEFILE
189
190
/* Used by avc_binwr.c */
191
extern int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir);
192
193
/*=====================================================================
194
 * Prototypes for some static functions
195
 *====================================================================*/
196
197
static AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath,
198
                                        const char *pszTableName,
199
                                        AVCCoverType eCoverType,
200
                                        AVCDBCSInfo *psDBCSInfo);
201
static AVCBinFile *_AVCBinReadOpenDBFTable(const char *pszInfoPath,
202
                                           const char *pszTableName);
203
static AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath, const char *pszName);
204
205
static int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields,
206
                                   AVCFieldInfo *pasDef, AVCField *pasFields,
207
                                   int nRecordSize);
208
static int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex,
209
                                      int nFields, AVCFieldInfo *pasDef,
210
                                      AVCField *pasFields);
211
212
/*=====================================================================
213
 * Stuff related to reading the binary coverage files
214
 *====================================================================*/
215
216
/**********************************************************************
217
 *                          AVCBinReadOpen()
218
 *
219
 * Open a coverage file for reading, read the file header if applicable,
220
 * and initialize a temp. storage structure to be ready to read objects
221
 * from the file.
222
 *
223
 * pszPath is the coverage (or info directory) path, terminated by
224
 *         a '/' or a '\\'
225
 * pszName is the name of the file to open relative to this directory.
226
 *
227
 * Note: For most file types except tables, passing pszPath="" and
228
 * including the coverage path as part of pszName instead would work.
229
 *
230
 * Returns a valid AVCBinFile handle, or nullptr if the file could
231
 * not be opened.
232
 *
233
 * AVCBinClose() will eventually have to be called to release the
234
 * resources used by the AVCBinFile structure.
235
 **********************************************************************/
236
AVCBinFile *AVCBinReadOpen(const char *pszPath, const char *pszName,
237
                           AVCCoverType eCoverType, AVCFileType eFileType,
238
                           AVCDBCSInfo *psDBCSInfo)
239
47.7k
{
240
47.7k
    AVCBinFile *psFile;
241
242
    /*-----------------------------------------------------------------
243
     * The case of INFO tables is a bit more complicated...
244
     * pass the control to a separate function.
245
     *----------------------------------------------------------------*/
246
47.7k
    if (eFileType == AVCFileTABLE)
247
5.62k
    {
248
5.62k
        if (eCoverType == AVCCoverPC || eCoverType == AVCCoverPC2)
249
334
            return _AVCBinReadOpenDBFTable(pszPath, pszName);
250
5.29k
        else
251
5.29k
            return _AVCBinReadOpenTable(pszPath, pszName, eCoverType,
252
5.29k
                                        psDBCSInfo);
253
5.62k
    }
254
255
    /*-----------------------------------------------------------------
256
     * PRJ files are text files... we won't use the AVCRawBin*()
257
     * functions for them...
258
     *----------------------------------------------------------------*/
259
42.1k
    if (eFileType == AVCFilePRJ)
260
14.4k
    {
261
14.4k
        return _AVCBinReadOpenPrj(pszPath, pszName);
262
14.4k
    }
263
264
    /*-----------------------------------------------------------------
265
     * All other file types share a very similar opening method.
266
     *----------------------------------------------------------------*/
267
27.6k
    psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
268
269
27.6k
    psFile->eFileType = eFileType;
270
27.6k
    psFile->eCoverType = eCoverType;
271
272
27.6k
    psFile->pszFilename =
273
27.6k
        (char *)CPLMalloc(strlen(pszPath) + strlen(pszName) + 1);
274
27.6k
    snprintf(psFile->pszFilename, strlen(pszPath) + strlen(pszName) + 1, "%s%s",
275
27.6k
             pszPath, pszName);
276
277
27.6k
    AVCAdjustCaseSensitiveFilename(psFile->pszFilename);
278
279
27.6k
    psFile->psRawBinFile = AVCRawBinOpen(
280
27.6k
        psFile->pszFilename, "r", AVC_COVER_BYTE_ORDER(eCoverType), psDBCSInfo);
281
282
27.6k
    if (psFile->psRawBinFile == nullptr)
283
409
    {
284
        /* Failed to open file... just return nullptr since an error message
285
         * has already been issued by AVCRawBinOpen()
286
         */
287
409
        CPLFree(psFile->pszFilename);
288
409
        CPLFree(psFile);
289
409
        return nullptr;
290
409
    }
291
292
    /*-----------------------------------------------------------------
293
     * Read the header, and set the precision field if applicable
294
     *----------------------------------------------------------------*/
295
27.2k
    if (AVCBinReadRewind(psFile) != 0)
296
2.86k
    {
297
2.86k
        AVCRawBinClose(psFile->psRawBinFile);
298
2.86k
        CPLFree(psFile->pszFilename);
299
2.86k
        CPLFree(psFile);
300
2.86k
        return nullptr;
301
2.86k
    }
302
303
    /*-----------------------------------------------------------------
304
     * Allocate a temp. structure to use to read objects from the file
305
     * (Using Calloc() will automatically initialize the struct contents
306
     *  to nullptr... this is very important for ARCs and PALs)
307
     *----------------------------------------------------------------*/
308
24.3k
    if (psFile->eFileType == AVCFileARC)
309
3.37k
    {
310
3.37k
        psFile->cur.psArc = (AVCArc *)CPLCalloc(1, sizeof(AVCArc));
311
3.37k
    }
312
20.9k
    else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL)
313
12.8k
    {
314
12.8k
        psFile->cur.psPal = (AVCPal *)CPLCalloc(1, sizeof(AVCPal));
315
12.8k
    }
316
8.11k
    else if (psFile->eFileType == AVCFileCNT)
317
389
    {
318
389
        psFile->cur.psCnt = (AVCCnt *)CPLCalloc(1, sizeof(AVCCnt));
319
389
    }
320
7.72k
    else if (psFile->eFileType == AVCFileLAB)
321
2.77k
    {
322
2.77k
        psFile->cur.psLab = (AVCLab *)CPLCalloc(1, sizeof(AVCLab));
323
2.77k
    }
324
4.95k
    else if (psFile->eFileType == AVCFileTOL)
325
32
    {
326
32
        psFile->cur.psTol = (AVCTol *)CPLCalloc(1, sizeof(AVCTol));
327
32
    }
328
4.92k
    else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6)
329
4.80k
    {
330
4.80k
        psFile->cur.psTxt = (AVCTxt *)CPLCalloc(1, sizeof(AVCTxt));
331
4.80k
    }
332
119
    else if (psFile->eFileType == AVCFileRXP)
333
119
    {
334
119
        psFile->cur.psRxp = (AVCRxp *)CPLCalloc(1, sizeof(AVCRxp));
335
119
    }
336
0
    else
337
0
    {
338
0
        CPLError(CE_Failure, CPLE_IllegalArg,
339
0
                 "%s: Unsupported file type or corrupted file.",
340
0
                 psFile->pszFilename);
341
0
        AVCRawBinClose(psFile->psRawBinFile);
342
0
        CPLFree(psFile->pszFilename);
343
0
        CPLFree(psFile);
344
0
        psFile = nullptr;
345
0
    }
346
347
24.3k
    return psFile;
348
27.2k
}
349
350
/**********************************************************************
351
 *                          AVCBinReadClose()
352
 *
353
 * Close a coverage file, and release all memory (object strcut., buffers,
354
 * etc.) associated with this file.
355
 **********************************************************************/
356
void AVCBinReadClose(AVCBinFile *psFile)
357
43.8k
{
358
43.8k
    AVCRawBinClose(psFile->psRawBinFile);
359
43.8k
    psFile->psRawBinFile = nullptr;
360
361
43.8k
    CPLFree(psFile->pszFilename);
362
43.8k
    psFile->pszFilename = nullptr;
363
364
43.8k
    if (psFile->hDBFFile)
365
222
        DBFClose(psFile->hDBFFile);
366
367
43.8k
    if (psFile->psIndexFile != nullptr)
368
1.13k
        AVCRawBinClose(psFile->psIndexFile);
369
370
43.8k
    if (psFile->eFileType == AVCFileARC)
371
3.37k
    {
372
3.37k
        if (psFile->cur.psArc)
373
3.37k
            CPLFree(psFile->cur.psArc->pasVertices);
374
3.37k
        CPLFree(psFile->cur.psArc);
375
3.37k
    }
376
40.4k
    else if (psFile->eFileType == AVCFilePAL || psFile->eFileType == AVCFileRPL)
377
12.8k
    {
378
12.8k
        if (psFile->cur.psPal)
379
12.8k
            CPLFree(psFile->cur.psPal->pasArcs);
380
12.8k
        CPLFree(psFile->cur.psPal);
381
12.8k
    }
382
27.6k
    else if (psFile->eFileType == AVCFileCNT)
383
389
    {
384
389
        if (psFile->cur.psCnt)
385
389
            CPLFree(psFile->cur.psCnt->panLabelIds);
386
389
        CPLFree(psFile->cur.psCnt);
387
389
    }
388
27.2k
    else if (psFile->eFileType == AVCFileLAB)
389
2.77k
    {
390
2.77k
        CPLFree(psFile->cur.psLab);
391
2.77k
    }
392
24.4k
    else if (psFile->eFileType == AVCFileTOL)
393
32
    {
394
32
        CPLFree(psFile->cur.psTol);
395
32
    }
396
24.4k
    else if (psFile->eFileType == AVCFilePRJ)
397
14.2k
    {
398
14.2k
        CSLDestroy(psFile->cur.papszPrj);
399
14.2k
    }
400
10.1k
    else if (psFile->eFileType == AVCFileTXT || psFile->eFileType == AVCFileTX6)
401
4.80k
    {
402
4.80k
        if (psFile->cur.psTxt)
403
4.80k
        {
404
4.80k
            CPLFree(psFile->cur.psTxt->pasVertices);
405
4.80k
            CPLFree(psFile->cur.psTxt->pszText);
406
4.80k
        }
407
4.80k
        CPLFree(psFile->cur.psTxt);
408
4.80k
    }
409
5.37k
    else if (psFile->eFileType == AVCFileRXP)
410
119
    {
411
119
        CPLFree(psFile->cur.psRxp);
412
119
    }
413
5.25k
    else if (psFile->eFileType == AVCFileTABLE)
414
5.25k
    {
415
5.25k
        _AVCDestroyTableFields(psFile->hdr.psTableDef, psFile->cur.pasFields);
416
5.25k
        _AVCDestroyTableDef(psFile->hdr.psTableDef);
417
5.25k
    }
418
0
    else
419
0
    {
420
0
        CPLError(CE_Failure, CPLE_IllegalArg,
421
0
                 "Unsupported file type or invalid file handle!");
422
0
    }
423
424
43.8k
    CPLFree(psFile);
425
43.8k
}
426
427
/**********************************************************************
428
 *                          _AVCBinReadHeader()
429
 *
430
 * (This function is for internal library use... external calls should
431
 * go to AVCBinReadRewind() instead)
432
 *
433
 * Read the first 100 bytes header of the file and fill the AVCHeader
434
 * structure.
435
 *
436
 * Returns 0 on success or -1 on error.
437
 **********************************************************************/
438
static int _AVCBinReadHeader(AVCRawBinFile *psFile, AVCBinHeader *psHeader,
439
                             AVCCoverType eCoverType)
440
27.0k
{
441
27.0k
    int nStatus = 0;
442
443
    /*-----------------------------------------------------------------
444
     * For AVCCoverPC coverages (files without the .adf extension),
445
     * there is a first 256 bytes header that we just skip and that
446
     * precedes the 100 bytes header block.
447
     *
448
     * In AVCCoverV7, we only have the 100 bytes header.
449
     *----------------------------------------------------------------*/
450
27.0k
    if (eCoverType == AVCCoverPC)
451
417
        AVCRawBinFSeek(psFile, 256, SEEK_SET);
452
26.6k
    else
453
26.6k
        AVCRawBinFSeek(psFile, 0, SEEK_SET);
454
455
27.0k
    psHeader->nSignature = AVCRawBinReadInt32(psFile);
456
457
27.0k
    if (AVCRawBinEOF(psFile))
458
221
        nStatus = -1;
459
460
27.0k
    psHeader->nPrecision = AVCRawBinReadInt32(psFile);
461
27.0k
    psHeader->nRecordSize = AVCRawBinReadInt32(psFile);
462
463
    /* Jump to 24th byte in header */
464
27.0k
    AVCRawBinFSeek(psFile, 12, SEEK_CUR);
465
27.0k
    psHeader->nLength = AVCRawBinReadInt32(psFile);
466
27.0k
    if (psHeader->nLength < 0 || psHeader->nLength > (INT_MAX - 256) / 2)
467
1.55k
    {
468
1.55k
        return -1;
469
1.55k
    }
470
471
    /*-----------------------------------------------------------------
472
     * File length, in words (16 bits)... pass the info to the RawBinFile
473
     * to prevent it from trying to read junk bytes at the end of files...
474
     * this problem happens specially with PC Arc/Info files.
475
     *----------------------------------------------------------------*/
476
25.5k
    if (eCoverType == AVCCoverPC)
477
392
        AVCRawBinSetFileDataSize(psFile, psHeader->nLength * 2 + 256);
478
25.1k
    else
479
25.1k
        AVCRawBinSetFileDataSize(psFile, psHeader->nLength * 2);
480
481
    /* Move the pointer at the end of the 100 bytes header
482
     */
483
25.5k
    AVCRawBinFSeek(psFile, 72, SEEK_CUR);
484
485
25.5k
    return nStatus;
486
27.0k
}
487
488
/**********************************************************************
489
 *                          AVCBinReadRewind()
490
 *
491
 * Rewind the read pointer, and read/skip the header if necessary so
492
 * that we are ready to read the data objects from the file after
493
 * this call.
494
 *
495
 * Returns 0 on success, -1 on error, and -2 if file has an invalid
496
 * signature and is possibly corrupted.
497
 **********************************************************************/
498
int AVCBinReadRewind(AVCBinFile *psFile)
499
27.2k
{
500
27.2k
    AVCBinHeader sHeader;
501
27.2k
    int nStatus = 0;
502
503
    /*-----------------------------------------------------------------
504
     * For AVCCoverPC coverages, there is a first 256 bytes header
505
     * that we just skip and that precedes the 100 bytes header block.
506
     *
507
     * In AVCCoverV7, AVCCoverPC2 and AVCCoverWeird, we only find the
508
     * 100 bytes header.
509
     *
510
     * Note: it is the call to _AVCBinReadHeader() that takes care
511
     * of skipping the first 256 bytes header if necessary.
512
     *----------------------------------------------------------------*/
513
514
27.2k
    AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET);
515
516
27.2k
    if (psFile->eFileType == AVCFileARC || psFile->eFileType == AVCFilePAL ||
517
19.5k
        psFile->eFileType == AVCFileRPL || psFile->eFileType == AVCFileCNT ||
518
8.17k
        psFile->eFileType == AVCFileLAB || psFile->eFileType == AVCFileTXT ||
519
4.51k
        psFile->eFileType == AVCFileTX6)
520
27.0k
    {
521
27.0k
        nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader,
522
27.0k
                                    psFile->eCoverType);
523
524
        /* Store the precision information inside the file handle.
525
         *
526
         * Of course, there had to be an exception...
527
         * At least PAL and TXT files in PC Arc/Info coverages sometimes
528
         * have a negative precision flag even if they contain single
529
         * precision data... why is that????  A PC Arc bug?
530
         *
531
         * 2000-06-05: Found a double-precision PAL file with a signature
532
         *             of 1011 (should have been -11).  So we'll assume
533
         *             that signature > 1000 also means double precision.
534
         */
535
27.0k
        if ((sHeader.nPrecision < 0 || sHeader.nPrecision > 1000) &&
536
15.4k
            psFile->eCoverType != AVCCoverPC)
537
15.1k
            psFile->nPrecision = AVC_DOUBLE_PREC;
538
11.9k
        else
539
11.9k
            psFile->nPrecision = AVC_SINGLE_PREC;
540
541
        /* Validate the signature value... this will allow us to detect
542
         * corrupted files or files that do not belong in the coverage.
543
         */
544
27.0k
        if (sHeader.nSignature != 9993 && sHeader.nSignature != 9994)
545
1.90k
        {
546
1.90k
            CPLError(CE_Warning, CPLE_AssertionFailed,
547
1.90k
                     "%s appears to have an invalid file header.",
548
1.90k
                     psFile->pszFilename);
549
1.90k
            return -2;
550
1.90k
        }
551
552
        /* In Weird coverages, TXT files can be stored in the PC or the V7
553
         * format.  Look at the 'precision' field in the header to tell which
554
         * type we have.
555
         *   Weird TXT in PC format: nPrecision = 16
556
         *   Weird TXT in V7 format: nPrecision = +/-67
557
         * Use AVCFileTXT for PC type, and AVCFileTX6 for V7 type.
558
         */
559
25.1k
        if (psFile->eCoverType == AVCCoverWeird &&
560
216
            psFile->eFileType == AVCFileTXT &&
561
48
            (sHeader.nPrecision == 67 || sHeader.nPrecision == -67))
562
6
        {
563
            /* TXT file will be processed as V7 TXT/TX6/TX7 */
564
6
            psFile->eFileType = AVCFileTX6;
565
6
        }
566
25.1k
    }
567
152
    else if (psFile->eFileType == AVCFileTOL)
568
33
    {
569
        /*-------------------------------------------------------------
570
         * For some reason, the tolerance files do not follow the
571
         * general rules!
572
         * Single precision "tol.adf" have no header
573
         * Double precision "par.adf" have the usual 100 bytes header,
574
         *  but the 3rd field, which usually defines the precision has
575
         *  a positive value, even if the file is double precision!
576
         *
577
         * Also, we have a problem with PC Arc/Info TOL files since they
578
         * do not contain the first 256 bytes header either... so we will
579
         * just assume that double precision TOL files cannot exist in
580
         * PC Arc/Info coverages... this should be OK.
581
         *------------------------------------------------------------*/
582
33
        int nSignature = 0;
583
33
        nSignature = AVCRawBinReadInt32(psFile->psRawBinFile);
584
585
33
        if (nSignature == 9993)
586
2
        {
587
            /* We have a double precision par.adf... read the 100 bytes
588
             * header and set the precision information inside the file
589
             * handle.
590
             */
591
2
            nStatus = _AVCBinReadHeader(psFile->psRawBinFile, &sHeader,
592
2
                                        psFile->eCoverType);
593
594
2
            psFile->nPrecision = AVC_DOUBLE_PREC;
595
2
        }
596
31
        else
597
31
        {
598
            /* It's a single precision tol.adf ... just set the
599
             * precision field.
600
             */
601
31
            AVCRawBinFSeek(psFile->psRawBinFile, 0, SEEK_SET);
602
31
            psFile->nPrecision = AVC_SINGLE_PREC;
603
31
        }
604
33
    }
605
606
25.3k
    return nStatus;
607
27.2k
}
608
609
/**********************************************************************
610
 *                          AVCBinReadObject()
611
 *
612
 * Read the object with a particular index.  For fixed length record
613
 * files we seek directly to the object.  For variable files we try to
614
 * get the offset from the corresponding index file.
615
 *
616
 * NOTE: Currently only implemented for ARC, PAL and TABLE files.
617
 *
618
 * Returns the read object on success or nullptr on error.
619
 **********************************************************************/
620
void *AVCBinReadObject(AVCBinFile *psFile, int iObjIndex)
621
224k
{
622
224k
    int bIndexed = FALSE;
623
224k
    int nObjectOffset, nRecordSize = 0, nRecordStart = 0, nLen;
624
    /* cppcheck-suppress unreadVariable */
625
224k
    char szExt[4] = {0, 0, 0, 0};
626
224k
    char *pszExt = szExt;
627
628
224k
    if (iObjIndex < 0)
629
3.54k
        return nullptr;
630
631
    /*-----------------------------------------------------------------
632
     * Determine some information from based on the coverage type.
633
     *----------------------------------------------------------------*/
634
221k
    nLen = (int)strlen(psFile->pszFilename);
635
221k
    if (psFile->eFileType == AVCFileARC &&
636
125k
        ((nLen >= 3 &&
637
125k
          STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 3), "arc")) ||
638
125k
         (nLen >= 7 && STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 7),
639
125k
                                      "arc.adf"))))
640
125k
    {
641
125k
        bIndexed = TRUE;
642
125k
    }
643
95.7k
    else if (psFile->eFileType == AVCFilePAL &&
644
0
             ((nLen >= 3 &&
645
0
               STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 3),
646
0
                              "pal")) ||
647
0
              (nLen >= 7 &&
648
0
               STARTS_WITH_CI((pszExt = psFile->pszFilename + nLen - 7),
649
0
                              "pal.adf"))))
650
0
    {
651
0
        bIndexed = TRUE;
652
0
    }
653
95.7k
    else if (psFile->eFileType == AVCFileTABLE)
654
95.7k
    {
655
95.7k
        bIndexed = FALSE;
656
95.7k
        nRecordSize = psFile->hdr.psTableDef->nRecSize;
657
95.7k
        nRecordStart = 0;
658
95.7k
    }
659
0
    else
660
0
        return nullptr;
661
662
    /*-----------------------------------------------------------------
663
     * Ensure the index file is opened if an index file is required.
664
     *----------------------------------------------------------------*/
665
666
221k
    if (bIndexed && psFile->psIndexFile == nullptr)
667
2.38k
    {
668
2.38k
        char chOrig;
669
670
2.38k
        chOrig = pszExt[2];
671
2.38k
        if (chOrig > 'A' && chOrig < 'Z')
672
300
            pszExt[2] = 'X';
673
2.08k
        else
674
2.08k
            pszExt[2] = 'x';
675
676
2.38k
        psFile->psIndexFile = AVCRawBinOpen(psFile->pszFilename, "rb",
677
2.38k
                                            psFile->psRawBinFile->eByteOrder,
678
2.38k
                                            psFile->psRawBinFile->psDBCSInfo);
679
2.38k
        pszExt[2] = chOrig;
680
681
2.38k
        if (psFile->psIndexFile == nullptr)
682
1.25k
            return nullptr;
683
2.38k
    }
684
685
    /*-----------------------------------------------------------------
686
     * Establish the offset to read the object from.
687
     *----------------------------------------------------------------*/
688
220k
    if (bIndexed)
689
124k
    {
690
124k
        GIntBig nIndexOffsetBig;
691
692
124k
        if (psFile->eCoverType == AVCCoverPC)
693
0
            nIndexOffsetBig = 356 + static_cast<GIntBig>(iObjIndex - 1) * 8;
694
124k
        else
695
124k
            nIndexOffsetBig = 100 + static_cast<GIntBig>(iObjIndex - 1) * 8;
696
124k
        if (nIndexOffsetBig < INT_MIN || nIndexOffsetBig > INT_MAX)
697
814
            return nullptr;
698
699
123k
        const int nIndexOffset = static_cast<int>(nIndexOffsetBig);
700
123k
        AVCRawBinFSeek(psFile->psIndexFile, nIndexOffset, SEEK_SET);
701
123k
        if (AVCRawBinEOF(psFile->psIndexFile))
702
2.81k
            return nullptr;
703
704
120k
        nObjectOffset = AVCRawBinReadInt32(psFile->psIndexFile);
705
120k
        if (nObjectOffset < INT_MIN / 2 || nObjectOffset > (INT_MAX - 256) / 2)
706
811
            return nullptr;
707
119k
        nObjectOffset *= 2;
708
709
119k
        if (psFile->eCoverType == AVCCoverPC)
710
0
            nObjectOffset += 256;
711
119k
    }
712
95.7k
    else
713
95.7k
    {
714
95.7k
        GIntBig nObjectOffsetBig =
715
95.7k
            nRecordStart + nRecordSize * static_cast<GIntBig>(iObjIndex - 1);
716
95.7k
        if (nObjectOffsetBig < INT_MIN || nObjectOffsetBig > INT_MAX)
717
6.64k
            return nullptr;
718
89.0k
        nObjectOffset = static_cast<int>(nObjectOffsetBig);
719
89.0k
    }
720
721
    /*-----------------------------------------------------------------
722
     * Seek to the start of the object in the data file.
723
     *----------------------------------------------------------------*/
724
208k
    AVCRawBinFSeek(psFile->psRawBinFile, nObjectOffset, SEEK_SET);
725
208k
    if (AVCRawBinEOF(psFile->psRawBinFile))
726
17.0k
        return nullptr;
727
728
    /*-----------------------------------------------------------------
729
     * Read and return the object.
730
     *----------------------------------------------------------------*/
731
191k
    return AVCBinReadNextObject(psFile);
732
208k
}
733
734
/**********************************************************************
735
 *                          AVCBinReadNextObject()
736
 *
737
 * Read the next structure from the file.  This function is just a generic
738
 * cover on top of the AVCBinReadNextArc/Lab/Pal/Cnt() functions.
739
 *
740
 * Returns a (void*) to a static structure with the contents of the object
741
 * that was read.  The contents of the structure will be valid only until
742
 * the next call.
743
 * If you use the returned value, then make sure that you cast it to
744
 * the right type for the current file! (AVCArc, AVCPal, AVCCnt, ...)
745
 *
746
 * Returns nullptr if an error happened or if EOF was reached.
747
 **********************************************************************/
748
void *AVCBinReadNextObject(AVCBinFile *psFile)
749
350k
{
750
350k
    void *psObj = nullptr;
751
752
350k
    switch (psFile->eFileType)
753
350k
    {
754
121k
        case AVCFileARC:
755
121k
            psObj = (void *)AVCBinReadNextArc(psFile);
756
121k
            break;
757
5.93k
        case AVCFilePAL:
758
26.4k
        case AVCFileRPL:
759
26.4k
            psObj = (void *)AVCBinReadNextPal(psFile);
760
26.4k
            break;
761
3.31k
        case AVCFileCNT:
762
3.31k
            psObj = (void *)AVCBinReadNextCnt(psFile);
763
3.31k
            break;
764
119k
        case AVCFileLAB:
765
119k
            psObj = (void *)AVCBinReadNextLab(psFile);
766
119k
            break;
767
0
        case AVCFileTOL:
768
0
            psObj = (void *)AVCBinReadNextTol(psFile);
769
0
            break;
770
3.20k
        case AVCFileTXT:
771
7.07k
        case AVCFileTX6:
772
7.07k
            psObj = (void *)AVCBinReadNextTxt(psFile);
773
7.07k
            break;
774
0
        case AVCFileRXP:
775
0
            psObj = (void *)AVCBinReadNextRxp(psFile);
776
0
            break;
777
72.9k
        case AVCFileTABLE:
778
72.9k
            psObj = (void *)AVCBinReadNextTableRec(psFile);
779
72.9k
            break;
780
0
        default:
781
0
            CPLError(CE_Failure, CPLE_IllegalArg,
782
0
                     "AVCBinReadNextObject(): Unsupported file type!");
783
350k
    }
784
785
350k
    return psObj;
786
350k
}
787
788
/**********************************************************************
789
 *                          AVCBinReadNextTableRec()
790
 *
791
 * Reads the next record from an attribute table.
792
 *
793
 * Returns a pointer to an array of static AVCField structure whose
794
 * contents will be valid only until the next call,
795
 * or nullptr if an error happened or if EOF was reached.
796
 **********************************************************************/
797
AVCField *AVCBinReadNextTableRec(AVCBinFile *psFile)
798
72.9k
{
799
72.9k
    if (psFile->eCoverType != AVCCoverPC && psFile->eCoverType != AVCCoverPC2 &&
800
72.9k
        psFile->eFileType == AVCFileTABLE &&
801
72.9k
        psFile->hdr.psTableDef->numRecords > 0 &&
802
72.3k
        !AVCRawBinEOF(psFile->psRawBinFile) &&
803
72.3k
        _AVCBinReadNextTableRec(
804
72.3k
            psFile->psRawBinFile, psFile->hdr.psTableDef->numFields,
805
72.3k
            psFile->hdr.psTableDef->pasFieldDef, psFile->cur.pasFields,
806
72.3k
            psFile->hdr.psTableDef->nRecSize) == 0)
807
69.9k
    {
808
69.9k
        return psFile->cur.pasFields;
809
69.9k
    }
810
2.99k
    else if ((psFile->eCoverType == AVCCoverPC ||
811
2.99k
              psFile->eCoverType == AVCCoverPC2) &&
812
0
             psFile->eFileType == AVCFileTABLE &&
813
0
             psFile->hdr.psTableDef->numRecords > 0 &&
814
0
             _AVCBinReadNextDBFTableRec(psFile->hDBFFile,
815
0
                                        &(psFile->nCurDBFRecord),
816
0
                                        psFile->hdr.psTableDef->numFields,
817
0
                                        psFile->hdr.psTableDef->pasFieldDef,
818
0
                                        psFile->cur.pasFields) == 0)
819
0
    {
820
0
        return psFile->cur.pasFields;
821
0
    }
822
823
2.99k
    return nullptr;
824
72.9k
}
825
826
/*=====================================================================
827
 *                              ARC
828
 *====================================================================*/
829
830
/**********************************************************************
831
 *                          _AVCBinReadNextArc()
832
 *
833
 * (This function is for internal library use... external calls should
834
 * go to AVCBinReadNextArc() instead)
835
 *
836
 * Read the next Arc structure from the file.
837
 *
838
 * The contents of the psArc structure is assumed to be valid, and the
839
 * psArc->pasVertices buffer may be reallocated or free()'d if it is not
840
 * nullptr.
841
 *
842
 * Returns 0 on success or -1 on error.
843
 **********************************************************************/
844
static int _AVCBinReadNextArc(AVCRawBinFile *psFile, AVCArc *psArc,
845
                              int nPrecision)
846
121k
{
847
121k
    int i, numVertices;
848
121k
    int nRecordSize, nStartPos, nBytesRead;
849
850
121k
    psArc->nArcId = AVCRawBinReadInt32(psFile);
851
121k
    if (AVCRawBinEOF(psFile))
852
208
        return -1;
853
854
120k
    nRecordSize = AVCRawBinReadInt32(psFile);
855
120k
    if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
856
1.39k
        return -1;
857
119k
    nRecordSize *= 2;
858
119k
    nStartPos = psFile->nCurPos + psFile->nOffset;
859
119k
    psArc->nUserId = AVCRawBinReadInt32(psFile);
860
119k
    psArc->nFNode = AVCRawBinReadInt32(psFile);
861
119k
    psArc->nTNode = AVCRawBinReadInt32(psFile);
862
119k
    psArc->nLPoly = AVCRawBinReadInt32(psFile);
863
119k
    psArc->nRPoly = AVCRawBinReadInt32(psFile);
864
119k
    numVertices = AVCRawBinReadInt32(psFile);
865
119k
    if (numVertices < 0 || numVertices > 100 * 1024 * 1024)
866
1.15k
        return -1;
867
118k
    if (numVertices > 10 * 1024 * 1024 &&
868
358
        !AVCRawBinIsFileGreaterThan(
869
358
            psFile,
870
358
            cpl::fits_on<int>(numVertices *
871
358
                              ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
872
358
    {
873
358
        return -1;
874
358
    }
875
876
    /* Realloc the vertices array only if it needs to grow...
877
     * do not realloc to a smaller size.
878
     * Note that for simplicity reasons, we always store the vertices as
879
     * double values in memory, even for single precision coverages.
880
     */
881
118k
    if (psArc->pasVertices == nullptr || numVertices > psArc->numVertices)
882
10.9k
    {
883
10.9k
        AVCVertex *pasNewVertices = (AVCVertex *)VSIRealloc(
884
10.9k
            psArc->pasVertices, numVertices * sizeof(AVCVertex));
885
10.9k
        if (pasNewVertices == nullptr)
886
0
            return -1;
887
10.9k
        psArc->pasVertices = pasNewVertices;
888
10.9k
    }
889
890
118k
    psArc->numVertices = numVertices;
891
892
118k
    if (nPrecision == AVC_SINGLE_PREC)
893
1.90k
    {
894
37.2k
        for (i = 0; i < numVertices; i++)
895
35.6k
        {
896
35.6k
            psArc->pasVertices[i].x = AVCRawBinReadFloat(psFile);
897
35.6k
            psArc->pasVertices[i].y = AVCRawBinReadFloat(psFile);
898
35.6k
            if (psFile->nCurSize == 0)
899
254
                return -1;
900
35.6k
        }
901
1.90k
    }
902
116k
    else
903
116k
    {
904
2.38M
        for (i = 0; i < numVertices; i++)
905
2.27M
        {
906
2.27M
            psArc->pasVertices[i].x = AVCRawBinReadDouble(psFile);
907
2.27M
            psArc->pasVertices[i].y = AVCRawBinReadDouble(psFile);
908
2.27M
            if (psFile->nCurSize == 0)
909
382
                return -1;
910
2.27M
        }
911
116k
    }
912
913
    /*-----------------------------------------------------------------
914
     * Record size may be larger than number of vertices.  Skip up to
915
     * start of next object.
916
     *----------------------------------------------------------------*/
917
117k
    nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
918
117k
    if (nBytesRead < nRecordSize)
919
12.6k
        AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
920
921
117k
    return 0;
922
118k
}
923
924
/**********************************************************************
925
 *                          AVCBinReadNextArc()
926
 *
927
 * Read the next Arc structure from the file.
928
 *
929
 * Returns a pointer to a static AVCArc structure whose contents will be
930
 * valid only until the next call or nullptr if an error happened or if EOF
931
 * was reached.
932
 **********************************************************************/
933
AVCArc *AVCBinReadNextArc(AVCBinFile *psFile)
934
121k
{
935
121k
    if (psFile->eFileType != AVCFileARC || AVCRawBinEOF(psFile->psRawBinFile) ||
936
121k
        _AVCBinReadNextArc(psFile->psRawBinFile, psFile->cur.psArc,
937
121k
                           psFile->nPrecision) != 0)
938
3.90k
    {
939
3.90k
        return nullptr;
940
3.90k
    }
941
942
117k
    return psFile->cur.psArc;
943
121k
}
944
945
/*=====================================================================
946
 *                              PAL
947
 *====================================================================*/
948
949
/**********************************************************************
950
 *                          _AVCBinReadNextPal()
951
 *
952
 * (This function is for internal library use... external calls should
953
 * go to AVCBinReadNextPal() instead)
954
 *
955
 * Read the next PAL (Polygon Arc List) structure from the file.
956
 *
957
 * The contents of the psPal structure is assumed to be valid, and the
958
 * psPal->paVertices buffer may be reallocated or free()'d if it is not
959
 * nullptr.
960
 *
961
 * Returns 0 on success or -1 on error.
962
 **********************************************************************/
963
static int _AVCBinReadNextPal(AVCRawBinFile *psFile, AVCPal *psPal,
964
                              int nPrecision)
965
24.8k
{
966
24.8k
    int i, numArcs;
967
24.8k
    int nRecordSize, nStartPos, nBytesRead;
968
969
24.8k
    psPal->nPolyId = AVCRawBinReadInt32(psFile);
970
24.8k
    nRecordSize = AVCRawBinReadInt32(psFile);
971
24.8k
    if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
972
1.98k
        return -1;
973
22.8k
    nRecordSize *= 2;
974
22.8k
    nStartPos = psFile->nCurPos + psFile->nOffset;
975
976
22.8k
    if (AVCRawBinEOF(psFile))
977
95
        return -1;
978
979
22.7k
    if (nPrecision == AVC_SINGLE_PREC)
980
3.67k
    {
981
3.67k
        psPal->sMin.x = AVCRawBinReadFloat(psFile);
982
3.67k
        psPal->sMin.y = AVCRawBinReadFloat(psFile);
983
3.67k
        psPal->sMax.x = AVCRawBinReadFloat(psFile);
984
3.67k
        psPal->sMax.y = AVCRawBinReadFloat(psFile);
985
3.67k
    }
986
19.0k
    else
987
19.0k
    {
988
19.0k
        psPal->sMin.x = AVCRawBinReadDouble(psFile);
989
19.0k
        psPal->sMin.y = AVCRawBinReadDouble(psFile);
990
19.0k
        psPal->sMax.x = AVCRawBinReadDouble(psFile);
991
19.0k
        psPal->sMax.y = AVCRawBinReadDouble(psFile);
992
19.0k
    }
993
994
22.7k
    numArcs = AVCRawBinReadInt32(psFile);
995
22.7k
    if (numArcs < 0 || numArcs > 100 * 1024 * 1024)
996
834
        return -1;
997
21.9k
    if (numArcs > 10 * 1024 * 1024 &&
998
68
        !AVCRawBinIsFileGreaterThan(psFile, numArcs * sizeof(int) * 3))
999
68
    {
1000
68
        return -1;
1001
68
    }
1002
1003
    /* Realloc the arc list array only if it needs to grow...
1004
     * do not realloc to a smaller size.
1005
     */
1006
21.8k
    if (psPal->pasArcs == nullptr || numArcs > psPal->numArcs)
1007
8.70k
    {
1008
8.70k
        AVCPalArc *pasNewArcs = (AVCPalArc *)VSIRealloc(
1009
8.70k
            psPal->pasArcs, numArcs * sizeof(AVCPalArc));
1010
8.70k
        if (pasNewArcs == nullptr)
1011
0
            return -1;
1012
8.70k
        psPal->pasArcs = pasNewArcs;
1013
8.70k
    }
1014
1015
21.8k
    psPal->numArcs = numArcs;
1016
1017
294k
    for (i = 0; i < numArcs; i++)
1018
273k
    {
1019
273k
        psPal->pasArcs[i].nArcId = AVCRawBinReadInt32(psFile);
1020
273k
        psPal->pasArcs[i].nFNode = AVCRawBinReadInt32(psFile);
1021
273k
        psPal->pasArcs[i].nAdjPoly = AVCRawBinReadInt32(psFile);
1022
273k
        if (psFile->nCurSize == 0)
1023
401
            return -1;
1024
273k
    }
1025
1026
    /*-----------------------------------------------------------------
1027
     * Record size may be larger than number of vertices.  Skip up to
1028
     * start of next object.
1029
     *----------------------------------------------------------------*/
1030
21.4k
    nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
1031
21.4k
    if (nBytesRead < nRecordSize)
1032
794
        AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
1033
1034
21.4k
    return 0;
1035
21.8k
}
1036
1037
/**********************************************************************
1038
 *                          AVCBinReadNextPal()
1039
 *
1040
 * Read the next PAL structure from the file.
1041
 *
1042
 * Returns a pointer to a static AVCPal structure whose contents will be
1043
 * valid only until the next call or nullptr if an error happened or if EOF
1044
 * was reached.
1045
 **********************************************************************/
1046
AVCPal *AVCBinReadNextPal(AVCBinFile *psFile)
1047
26.4k
{
1048
26.4k
    if ((psFile->eFileType != AVCFilePAL && psFile->eFileType != AVCFileRPL) ||
1049
26.4k
        AVCRawBinEOF(psFile->psRawBinFile) ||
1050
24.8k
        _AVCBinReadNextPal(psFile->psRawBinFile, psFile->cur.psPal,
1051
24.8k
                           psFile->nPrecision) != 0)
1052
4.99k
    {
1053
4.99k
        return nullptr;
1054
4.99k
    }
1055
1056
21.4k
    return psFile->cur.psPal;
1057
26.4k
}
1058
1059
/*=====================================================================
1060
 *                              CNT
1061
 *====================================================================*/
1062
1063
/**********************************************************************
1064
 *                          _AVCBinReadNextCnt()
1065
 *
1066
 * (This function is for internal library use... external calls should
1067
 * go to AVCBinReadNextCnt() instead)
1068
 *
1069
 * Read the next CNT (Polygon Centroid) structure from the file.
1070
 *
1071
 * Returns 0 on success or -1 on error.
1072
 **********************************************************************/
1073
static int _AVCBinReadNextCnt(AVCRawBinFile *psFile, AVCCnt *psCnt,
1074
                              int nPrecision)
1075
3.27k
{
1076
3.27k
    int i, numLabels;
1077
3.27k
    int nRecordSize, nStartPos, nBytesRead;
1078
1079
3.27k
    psCnt->nPolyId = AVCRawBinReadInt32(psFile);
1080
3.27k
    nRecordSize = AVCRawBinReadInt32(psFile);
1081
3.27k
    if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
1082
58
        return -1;
1083
3.21k
    nRecordSize *= 2;
1084
3.21k
    nStartPos = psFile->nCurPos + psFile->nOffset;
1085
1086
3.21k
    if (AVCRawBinEOF(psFile))
1087
4
        return -1;
1088
1089
3.21k
    if (nPrecision == AVC_SINGLE_PREC)
1090
2.12k
    {
1091
2.12k
        psCnt->sCoord.x = AVCRawBinReadFloat(psFile);
1092
2.12k
        psCnt->sCoord.y = AVCRawBinReadFloat(psFile);
1093
2.12k
    }
1094
1.08k
    else
1095
1.08k
    {
1096
1.08k
        psCnt->sCoord.x = AVCRawBinReadDouble(psFile);
1097
1.08k
        psCnt->sCoord.y = AVCRawBinReadDouble(psFile);
1098
1.08k
    }
1099
1100
3.21k
    numLabels = AVCRawBinReadInt32(psFile);
1101
3.21k
    if (numLabels < 0 || numLabels > 100 * 1024 * 1024)
1102
37
        return -1;
1103
3.17k
    if (numLabels > 10 * 1024 * 1024 &&
1104
7
        !AVCRawBinIsFileGreaterThan(psFile, numLabels * sizeof(int)))
1105
7
    {
1106
7
        return -1;
1107
7
    }
1108
1109
    /* Realloc the LabelIds array only if it needs to grow...
1110
     * do not realloc to a smaller size.
1111
     */
1112
3.16k
    if (psCnt->panLabelIds == nullptr || numLabels > psCnt->numLabels)
1113
286
    {
1114
286
        GInt32 *panIds = (GInt32 *)VSIRealloc(psCnt->panLabelIds,
1115
286
                                              numLabels * sizeof(GInt32));
1116
286
        if (panIds == nullptr)
1117
0
            return -1;
1118
286
        psCnt->panLabelIds = panIds;
1119
286
    }
1120
1121
3.16k
    psCnt->numLabels = numLabels;
1122
1123
149k
    for (i = 0; i < numLabels; i++)
1124
146k
    {
1125
146k
        psCnt->panLabelIds[i] = AVCRawBinReadInt32(psFile);
1126
146k
        if (psFile->nCurSize == 0)
1127
44
            return -1;
1128
146k
    }
1129
1130
    /*-----------------------------------------------------------------
1131
     * Record size may be larger than number of vertices.  Skip up to
1132
     * start of next object.
1133
     *----------------------------------------------------------------*/
1134
3.12k
    nBytesRead = (psFile->nCurPos + psFile->nOffset) - nStartPos;
1135
3.12k
    if (nBytesRead < nRecordSize)
1136
152
        AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
1137
1138
3.12k
    return 0;
1139
3.16k
}
1140
1141
/**********************************************************************
1142
 *                          AVCBinReadNextCnt()
1143
 *
1144
 * Read the next CNT structure from the file.
1145
 *
1146
 * Returns a pointer to a static AVCCnt structure whose contents will be
1147
 * valid only until the next call or nullptr if an error happened or if EOF
1148
 * was reached.
1149
 **********************************************************************/
1150
AVCCnt *AVCBinReadNextCnt(AVCBinFile *psFile)
1151
3.31k
{
1152
3.31k
    if (psFile->eFileType != AVCFileCNT || AVCRawBinEOF(psFile->psRawBinFile) ||
1153
3.27k
        _AVCBinReadNextCnt(psFile->psRawBinFile, psFile->cur.psCnt,
1154
3.27k
                           psFile->nPrecision) != 0)
1155
194
    {
1156
194
        return nullptr;
1157
194
    }
1158
1159
3.12k
    return psFile->cur.psCnt;
1160
3.31k
}
1161
1162
/*=====================================================================
1163
 *                              LAB
1164
 *====================================================================*/
1165
1166
/**********************************************************************
1167
 *                          _AVCBinReadNextLab()
1168
 *
1169
 * (This function is for internal library use... external calls should
1170
 * go to AVCBinReadNextLab() instead)
1171
 *
1172
 * Read the next LAB (Centroid Label) structure from the file.
1173
 *
1174
 * Returns 0 on success or -1 on error.
1175
 **********************************************************************/
1176
static int _AVCBinReadNextLab(AVCRawBinFile *psFile, AVCLab *psLab,
1177
                              int nPrecision)
1178
118k
{
1179
1180
118k
    psLab->nValue = AVCRawBinReadInt32(psFile);
1181
118k
    psLab->nPolyId = AVCRawBinReadInt32(psFile);
1182
1183
118k
    if (AVCRawBinEOF(psFile))
1184
311
        return -1;
1185
1186
117k
    if (nPrecision == AVC_SINGLE_PREC)
1187
107k
    {
1188
107k
        psLab->sCoord1.x = AVCRawBinReadFloat(psFile);
1189
107k
        psLab->sCoord1.y = AVCRawBinReadFloat(psFile);
1190
107k
        psLab->sCoord2.x = AVCRawBinReadFloat(psFile);
1191
107k
        psLab->sCoord2.y = AVCRawBinReadFloat(psFile);
1192
107k
        psLab->sCoord3.x = AVCRawBinReadFloat(psFile);
1193
107k
        psLab->sCoord3.y = AVCRawBinReadFloat(psFile);
1194
107k
    }
1195
10.8k
    else
1196
10.8k
    {
1197
10.8k
        psLab->sCoord1.x = AVCRawBinReadDouble(psFile);
1198
10.8k
        psLab->sCoord1.y = AVCRawBinReadDouble(psFile);
1199
10.8k
        psLab->sCoord2.x = AVCRawBinReadDouble(psFile);
1200
10.8k
        psLab->sCoord2.y = AVCRawBinReadDouble(psFile);
1201
10.8k
        psLab->sCoord3.x = AVCRawBinReadDouble(psFile);
1202
10.8k
        psLab->sCoord3.y = AVCRawBinReadDouble(psFile);
1203
10.8k
    }
1204
1205
117k
    return 0;
1206
118k
}
1207
1208
/**********************************************************************
1209
 *                          AVCBinReadNextLab()
1210
 *
1211
 * Read the next LAB structure from the file.
1212
 *
1213
 * Returns a pointer to a static AVCLab structure whose contents will be
1214
 * valid only until the next call or nullptr if an error happened or if EOF
1215
 * was reached.
1216
 **********************************************************************/
1217
AVCLab *AVCBinReadNextLab(AVCBinFile *psFile)
1218
119k
{
1219
119k
    if (psFile->eFileType != AVCFileLAB || AVCRawBinEOF(psFile->psRawBinFile) ||
1220
118k
        _AVCBinReadNextLab(psFile->psRawBinFile, psFile->cur.psLab,
1221
118k
                           psFile->nPrecision) != 0)
1222
1.37k
    {
1223
1.37k
        return nullptr;
1224
1.37k
    }
1225
1226
117k
    return psFile->cur.psLab;
1227
119k
}
1228
1229
/*=====================================================================
1230
 *                              TOL
1231
 *====================================================================*/
1232
1233
/**********************************************************************
1234
 *                          _AVCBinReadNextTol()
1235
 *
1236
 * (This function is for internal library use... external calls should
1237
 * go to AVCBinReadNextTol() instead)
1238
 *
1239
 * Read the next TOL (tolerance) structure from the file.
1240
 *
1241
 * Returns 0 on success or -1 on error.
1242
 **********************************************************************/
1243
static int _AVCBinReadNextTol(AVCRawBinFile *psFile, AVCTol *psTol,
1244
                              int nPrecision)
1245
0
{
1246
1247
0
    psTol->nIndex = AVCRawBinReadInt32(psFile);
1248
0
    psTol->nFlag = AVCRawBinReadInt32(psFile);
1249
1250
0
    if (AVCRawBinEOF(psFile))
1251
0
        return -1;
1252
1253
0
    if (nPrecision == AVC_SINGLE_PREC)
1254
0
    {
1255
0
        psTol->dValue = AVCRawBinReadFloat(psFile);
1256
0
    }
1257
0
    else
1258
0
    {
1259
0
        psTol->dValue = AVCRawBinReadDouble(psFile);
1260
0
    }
1261
1262
0
    return 0;
1263
0
}
1264
1265
/**********************************************************************
1266
 *                          AVCBinReadNextTol()
1267
 *
1268
 * Read the next TOL structure from the file.
1269
 *
1270
 * Returns a pointer to a static AVCTol structure whose contents will be
1271
 * valid only until the next call or nullptr if an error happened or if EOF
1272
 * was reached.
1273
 **********************************************************************/
1274
AVCTol *AVCBinReadNextTol(AVCBinFile *psFile)
1275
0
{
1276
0
    if (psFile->eFileType != AVCFileTOL || AVCRawBinEOF(psFile->psRawBinFile) ||
1277
0
        _AVCBinReadNextTol(psFile->psRawBinFile, psFile->cur.psTol,
1278
0
                           psFile->nPrecision) != 0)
1279
0
    {
1280
0
        return nullptr;
1281
0
    }
1282
1283
0
    return psFile->cur.psTol;
1284
0
}
1285
1286
/*=====================================================================
1287
 *                              PRJ
1288
 *====================================================================*/
1289
1290
/**********************************************************************
1291
 *                          _AVCBinReadOpenPrj()
1292
 *
1293
 * (This function is for internal library use... external calls should
1294
 * go to AVCBinReadOpen() with type AVCFilePRJ instead)
1295
 *
1296
 * Open a PRJ file.
1297
 *
1298
 * This call will actually read the whole PRJ file in memory since PRJ
1299
 * files are small text files.
1300
 **********************************************************************/
1301
AVCBinFile *_AVCBinReadOpenPrj(const char *pszPath, const char *pszName)
1302
14.4k
{
1303
14.4k
    AVCBinFile *psFile;
1304
14.4k
    char *pszFname, **papszPrj;
1305
1306
    /*-----------------------------------------------------------------
1307
     * Load the PRJ file contents into a stringlist.
1308
     *----------------------------------------------------------------*/
1309
14.4k
    pszFname = (char *)CPLMalloc(strlen(pszPath) + strlen(pszName) + 1);
1310
14.4k
    snprintf(pszFname, strlen(pszPath) + strlen(pszName) + 1, "%s%s", pszPath,
1311
14.4k
             pszName);
1312
1313
14.4k
    papszPrj = CSLLoad2(pszFname, 50, 160, nullptr);
1314
1315
14.4k
    CPLFree(pszFname);
1316
1317
14.4k
    if (papszPrj == nullptr)
1318
227
    {
1319
        /* Failed to open file... just return nullptr since an error message
1320
         * has already been issued by CSLLoad()
1321
         */
1322
227
        return nullptr;
1323
227
    }
1324
1325
    /*-----------------------------------------------------------------
1326
     * Alloc and init the AVCBinFile handle.
1327
     *----------------------------------------------------------------*/
1328
14.2k
    psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
1329
1330
14.2k
    psFile->eFileType = AVCFilePRJ;
1331
14.2k
    psFile->psRawBinFile = nullptr;
1332
14.2k
    psFile->cur.papszPrj = papszPrj;
1333
14.2k
    psFile->pszFilename = nullptr;
1334
1335
14.2k
    return psFile;
1336
14.4k
}
1337
1338
/**********************************************************************
1339
 *                          AVCBinReadPrj()
1340
 *
1341
 * Return the contents of the previously opened PRJ (projection) file.
1342
 *
1343
 * PRJ files are simple text files with variable length lines, so we
1344
 * don't use the AVCRawBin*() functions for this case.
1345
 *
1346
 * Returns a reference to a static stringlist with the whole file
1347
 * contents, or nullptr in case of error.
1348
 *
1349
 * The returned stringlist should NOT be freed by the caller.
1350
 **********************************************************************/
1351
char **AVCBinReadNextPrj(AVCBinFile *psFile)
1352
14.2k
{
1353
    /*-----------------------------------------------------------------
1354
     * The file should have already been loaded by AVCBinFileOpen(),
1355
     * so there is not much to do here!
1356
     *----------------------------------------------------------------*/
1357
14.2k
    return psFile->cur.papszPrj;
1358
14.2k
}
1359
1360
/*=====================================================================
1361
 *                              TXT/TX6/TX7
1362
 *====================================================================*/
1363
1364
/**********************************************************************
1365
 *                          _AVCBinReadNextTxt()
1366
 *
1367
 * (This function is for internal library use... external calls should
1368
 * go to AVCBinReadNextTxt() instead)
1369
 *
1370
 * Read the next TXT/TX6/TX7 (Annotation) structure from the file.
1371
 *
1372
 * Returns 0 on success or -1 on error.
1373
 **********************************************************************/
1374
static int _AVCBinReadNextTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
1375
                              int nPrecision)
1376
5.80k
{
1377
5.80k
    int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize;
1378
5.80k
    int numBytesRead;
1379
1380
5.80k
    numVerticesBefore =
1381
5.80k
        std::abs(psTxt->numVerticesLine) + std::abs(psTxt->numVerticesArrow);
1382
1383
5.80k
    psTxt->nTxtId = AVCRawBinReadInt32(psFile);
1384
5.80k
    if (AVCRawBinEOF(psFile))
1385
34
        return -1;
1386
1387
5.77k
    nRecordSize = AVCRawBinReadInt32(psFile);
1388
5.77k
    if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
1389
368
        return -1;
1390
5.40k
    nRecordSize = nRecordSize * 2 + 8;
1391
1392
5.40k
    psTxt->nUserId = AVCRawBinReadInt32(psFile);
1393
5.40k
    psTxt->nLevel = AVCRawBinReadInt32(psFile);
1394
1395
5.40k
    psTxt->f_1e2 = AVCRawBinReadFloat(psFile);
1396
5.40k
    psTxt->nSymbol = AVCRawBinReadInt32(psFile);
1397
5.40k
    psTxt->numVerticesLine = AVCRawBinReadInt32(psFile);
1398
5.40k
    psTxt->n28 = AVCRawBinReadInt32(psFile);
1399
5.40k
    psTxt->numChars = AVCRawBinReadInt32(psFile);
1400
5.40k
    if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024)
1401
111
        return -1;
1402
5.29k
    psTxt->numVerticesArrow = AVCRawBinReadInt32(psFile);
1403
1404
111k
    for (i = 0; i < 20; i++)
1405
105k
    {
1406
105k
        psTxt->anJust1[i] = AVCRawBinReadInt16(psFile);
1407
105k
    }
1408
111k
    for (i = 0; i < 20; i++)
1409
105k
    {
1410
105k
        psTxt->anJust2[i] = AVCRawBinReadInt16(psFile);
1411
105k
    }
1412
1413
5.29k
    if (nPrecision == AVC_SINGLE_PREC)
1414
3.92k
    {
1415
3.92k
        psTxt->dHeight = AVCRawBinReadFloat(psFile);
1416
3.92k
        psTxt->dV2 = AVCRawBinReadFloat(psFile);
1417
3.92k
        psTxt->dV3 = AVCRawBinReadFloat(psFile);
1418
3.92k
    }
1419
1.37k
    else
1420
1.37k
    {
1421
1.37k
        psTxt->dHeight = AVCRawBinReadDouble(psFile);
1422
1.37k
        psTxt->dV2 = AVCRawBinReadDouble(psFile);
1423
1.37k
        psTxt->dV3 = AVCRawBinReadDouble(psFile);
1424
1.37k
    }
1425
1426
5.29k
    numCharsToRead = ((int)(psTxt->numChars + 3) / 4) * 4;
1427
5.29k
    if (psTxt->pszText == nullptr ||
1428
4.70k
        ((int)(strlen((char *)psTxt->pszText) + 3) / 4) * 4 < numCharsToRead)
1429
862
    {
1430
862
        GByte *pszNewText = (GByte *)VSIRealloc(
1431
862
            psTxt->pszText, (numCharsToRead + 1) * sizeof(char));
1432
862
        if (pszNewText == nullptr)
1433
0
            return -1;
1434
862
        psTxt->pszText = pszNewText;
1435
862
    }
1436
1437
5.29k
    AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText);
1438
5.29k
    psTxt->pszText[psTxt->numChars] = '\0';
1439
1440
    /* Realloc the vertices array only if it needs to grow...
1441
     * do not realloc to a smaller size.
1442
     */
1443
5.29k
    if (psTxt->numVerticesLine == INT_MIN ||
1444
5.27k
        psTxt->numVerticesArrow == INT_MIN ||
1445
5.25k
        std::abs(psTxt->numVerticesLine) >
1446
5.25k
            100 * 1024 * 1024 - std::abs(psTxt->numVerticesArrow))
1447
106
        return -1;
1448
5.18k
    numVertices =
1449
5.18k
        std::abs(psTxt->numVerticesLine) + std::abs(psTxt->numVerticesArrow);
1450
5.18k
    if (numVertices > 10 * 1024 * 1024 &&
1451
34
        !AVCRawBinIsFileGreaterThan(
1452
34
            psFile,
1453
34
            cpl::fits_on<int>(numVertices *
1454
34
                              ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
1455
34
    {
1456
34
        return -1;
1457
34
    }
1458
1459
5.15k
    if (psTxt->pasVertices == nullptr || numVertices > numVerticesBefore)
1460
2.44k
        psTxt->pasVertices = (AVCVertex *)CPLRealloc(
1461
2.44k
            psTxt->pasVertices, numVertices * sizeof(AVCVertex));
1462
1463
5.15k
    if (nPrecision == AVC_SINGLE_PREC)
1464
3.85k
    {
1465
43.3k
        for (i = 0; i < numVertices; i++)
1466
39.6k
        {
1467
39.6k
            psTxt->pasVertices[i].x = AVCRawBinReadFloat(psFile);
1468
39.6k
            psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile);
1469
39.6k
            if (psFile->nCurSize == 0)
1470
98
                return -1;
1471
39.6k
        }
1472
3.85k
    }
1473
1.29k
    else
1474
1.29k
    {
1475
3.84k
        for (i = 0; i < numVertices; i++)
1476
2.58k
        {
1477
2.58k
            psTxt->pasVertices[i].x = AVCRawBinReadDouble(psFile);
1478
2.58k
            psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile);
1479
2.58k
            if (psFile->nCurSize == 0)
1480
43
                return -1;
1481
2.58k
        }
1482
1.29k
    }
1483
1484
    /* In V7 Coverages, we always have 8 bytes of junk at end of record.
1485
     * In Weird coverages, these 8 bytes are sometimes present, and
1486
     * sometimes not!!! (Probably another AI "random feature"! ;-)
1487
     * So we use the record size to establish if there is any junk to skip
1488
     */
1489
5.01k
    if (nPrecision == AVC_SINGLE_PREC)
1490
3.75k
        numBytesRead = 132 + numCharsToRead + numVertices * 2 * 4;
1491
1.25k
    else
1492
1.25k
        numBytesRead = 144 + numCharsToRead + numVertices * 2 * 8;
1493
1494
5.01k
    if (numBytesRead < nRecordSize)
1495
174
        AVCRawBinFSeek(psFile, nRecordSize - numBytesRead, SEEK_CUR);
1496
1497
5.01k
    return 0;
1498
5.15k
}
1499
1500
/**********************************************************************
1501
 *                          _AVCBinReadNextPCCoverageTxt()
1502
 *
1503
 * (This function is for internal library use... external calls should
1504
 * go to AVCBinReadNextTxt() instead)
1505
 *
1506
 * Read the next TXT (Annotation) structure from a PC Coverage file.
1507
 * Note that it is assumed that PC Coverage files are always single
1508
 * precision.
1509
 *
1510
 * Returns 0 on success or -1 on error.
1511
 **********************************************************************/
1512
static int _AVCBinReadNextPCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
1513
                                        int nPrecision)
1514
480
{
1515
480
    int i, numVerticesBefore, numVertices, numCharsToRead, nRecordSize;
1516
1517
480
    numVerticesBefore =
1518
480
        std::abs(psTxt->numVerticesLine) + std::abs(psTxt->numVerticesArrow);
1519
1520
480
    psTxt->nTxtId = AVCRawBinReadInt32(psFile);
1521
480
    if (AVCRawBinEOF(psFile))
1522
1
        return -1;
1523
1524
479
    nRecordSize = AVCRawBinReadInt32(psFile);
1525
479
    if (nRecordSize < 0 || nRecordSize > 100 * 1024 * 1024)
1526
25
        return -1;
1527
454
    nRecordSize = nRecordSize * 2 + 8;
1528
1529
454
    psTxt->nUserId = 0;
1530
454
    psTxt->nLevel = AVCRawBinReadInt32(psFile);
1531
1532
454
    psTxt->numVerticesLine = AVCRawBinReadInt32(psFile);
1533
    /* We are not expecting more than 4 vertices */
1534
454
    psTxt->numVerticesLine = std::min(psTxt->numVerticesLine, 4);
1535
1536
454
    psTxt->numVerticesArrow = 0;
1537
1538
    /* Realloc the vertices array only if it needs to grow...
1539
     * do not realloc to a smaller size.
1540
     *
1541
     * Note that because of the way V7 binary TXT files work, the rest of the
1542
     * lib expects to receive duplicate coords for the first vertex, so
1543
     * we have to include an additional vertex for that.
1544
     */
1545
454
    psTxt->numVerticesLine += 1;
1546
454
    if (psTxt->numVerticesLine == INT_MIN ||
1547
454
        std::abs(psTxt->numVerticesLine) > 100 * 1024 * 1024)
1548
4
        return -1;
1549
450
    numVertices = std::abs(psTxt->numVerticesLine);
1550
450
    if (numVertices < 2)
1551
8
        return -1;
1552
442
    if (numVertices > 10 * 1024 * 1024 &&
1553
7
        !AVCRawBinIsFileGreaterThan(
1554
7
            psFile,
1555
7
            cpl::fits_on<int>(numVertices *
1556
7
                              ((nPrecision == AVC_SINGLE_PREC) ? 8 : 16))))
1557
7
    {
1558
7
        return -1;
1559
7
    }
1560
1561
435
    if (psTxt->pasVertices == nullptr || numVertices > numVerticesBefore)
1562
175
        psTxt->pasVertices = (AVCVertex *)CPLRealloc(
1563
175
            psTxt->pasVertices, numVertices * sizeof(AVCVertex));
1564
1565
179k
    for (i = 1; i < numVertices; i++)
1566
179k
    {
1567
179k
        if (nPrecision == AVC_SINGLE_PREC)
1568
178k
        {
1569
178k
            psTxt->pasVertices[i].x = AVCRawBinReadFloat(psFile);
1570
178k
            psTxt->pasVertices[i].y = AVCRawBinReadFloat(psFile);
1571
178k
            if (psFile->nCurSize == 0)
1572
14
                return -1;
1573
178k
        }
1574
626
        else
1575
626
        {
1576
626
            psTxt->pasVertices[i].x = AVCRawBinReadDouble(psFile);
1577
626
            psTxt->pasVertices[i].y = AVCRawBinReadDouble(psFile);
1578
626
            if (psFile->nCurSize == 0)
1579
10
                return -1;
1580
626
        }
1581
179k
    }
1582
    /* Duplicate the first vertex because that's the way the other binary TXT
1583
     * files work and that's what the lib expects to generate the E00.
1584
     */
1585
411
    psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
1586
411
    psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
1587
1588
    /* Skip the other floats (vertices) that are unused */
1589
411
    if (nPrecision == AVC_SINGLE_PREC)
1590
387
        AVCRawBinFSeek(psFile, 4 * (15 - 2 * (numVertices - 1)), SEEK_CUR);
1591
24
    else
1592
24
        AVCRawBinFSeek(psFile, 8 * (15 - 2 * (numVertices - 1)), SEEK_CUR);
1593
1594
411
    if (nPrecision == AVC_SINGLE_PREC)
1595
387
    {
1596
387
        psTxt->dHeight = AVCRawBinReadFloat(psFile);
1597
387
    }
1598
24
    else
1599
24
    {
1600
24
        psTxt->dHeight = AVCRawBinReadDouble(psFile);
1601
24
    }
1602
411
    psTxt->f_1e2 = AVCRawBinReadFloat(psFile);
1603
411
    psTxt->nSymbol = AVCRawBinReadInt32(psFile);
1604
411
    psTxt->numChars = AVCRawBinReadInt32(psFile);
1605
411
    if (psTxt->numChars < 0)
1606
17
        return -1;
1607
1608
    /* In some cases, we may need to skip additional spaces after the
1609
     * text string... more than should be required to simply align with
1610
     * a 4 bytes boundary... include that in numCharsToRead
1611
     */
1612
394
    if (nPrecision == AVC_SINGLE_PREC)
1613
370
    {
1614
370
        numCharsToRead = nRecordSize - (28 + 16 * 4);
1615
370
    }
1616
24
    else
1617
24
    {
1618
24
        numCharsToRead = nRecordSize - (28 + 16 * 8);
1619
24
    }
1620
394
    if (numCharsToRead < 0)
1621
4
        return -1;
1622
1623
    /* Do a quick check in case file is corrupt! */
1624
390
    psTxt->numChars = std::min(psTxt->numChars, numCharsToRead);
1625
1626
390
    if (psTxt->pszText == nullptr ||
1627
271
        ((int)(strlen((char *)psTxt->pszText) + 3) / 4) * 4 < numCharsToRead)
1628
378
    {
1629
378
        psTxt->pszText = (GByte *)CPLRealloc(
1630
378
            psTxt->pszText, (numCharsToRead + 5) * sizeof(char));
1631
378
    }
1632
1633
390
    AVCRawBinReadString(psFile, numCharsToRead, psTxt->pszText);
1634
390
    psTxt->pszText[psTxt->numChars] = '\0';
1635
1636
    /* Set unused members to default values...
1637
     */
1638
390
    psTxt->dV2 = 0.0;
1639
390
    psTxt->dV3 = 0.0;
1640
390
    psTxt->n28 = 0;
1641
8.19k
    for (i = 0; i < 20; i++)
1642
7.80k
    {
1643
7.80k
        psTxt->anJust1[i] = 0;
1644
7.80k
        psTxt->anJust2[i] = 0;
1645
7.80k
    }
1646
1647
390
    return 0;
1648
394
}
1649
1650
/**********************************************************************
1651
 *                          AVCBinReadNextTxt()
1652
 *
1653
 * Read the next TXT/TX6/TX7 structure from the file.
1654
 *
1655
 * Returns a pointer to a static AVCTxt structure whose contents will be
1656
 * valid only until the next call or nullptr if an error happened or if EOF
1657
 * was reached.
1658
 **********************************************************************/
1659
AVCTxt *AVCBinReadNextTxt(AVCBinFile *psFile)
1660
7.07k
{
1661
7.07k
    int nStatus = 0;
1662
1663
7.07k
    if ((psFile->eFileType != AVCFileTXT && psFile->eFileType != AVCFileTX6) ||
1664
7.07k
        AVCRawBinEOF(psFile->psRawBinFile))
1665
788
    {
1666
788
        return nullptr;
1667
788
    }
1668
1669
    /* AVCCoverPC have a different TXT format than AVCCoverV7
1670
     *
1671
     * Note: Some Weird coverages use the PC TXT structure, and some use the
1672
     *       V7 structure.  We distinguish them using the header's precision
1673
     *       field in AVCBinReadRewind().
1674
     */
1675
6.28k
    if (psFile->eFileType == AVCFileTXT &&
1676
3.07k
        (psFile->eCoverType == AVCCoverPC ||
1677
2.63k
         psFile->eCoverType == AVCCoverWeird))
1678
480
    {
1679
        /* TXT file in PC Coverages (and some Weird Coverages)
1680
         */
1681
480
        nStatus = _AVCBinReadNextPCCoverageTxt(
1682
480
            psFile->psRawBinFile, psFile->cur.psTxt, psFile->nPrecision);
1683
480
    }
1684
5.80k
    else
1685
5.80k
    {
1686
        /* TXT in V7 Coverages (and some Weird Coverages), and TX6/TX7 in
1687
         * all coverage types
1688
         */
1689
5.80k
        nStatus = _AVCBinReadNextTxt(psFile->psRawBinFile, psFile->cur.psTxt,
1690
5.80k
                                     psFile->nPrecision);
1691
5.80k
    }
1692
1693
6.28k
    if (nStatus != 0)
1694
884
    {
1695
884
        return nullptr;
1696
884
    }
1697
1698
5.40k
    return psFile->cur.psTxt;
1699
6.28k
}
1700
1701
/*=====================================================================
1702
 *                              RXP
1703
 *====================================================================*/
1704
1705
/**********************************************************************
1706
 *                          _AVCBinReadNextRxp()
1707
 *
1708
 * (This function is for internal library use... external calls should
1709
 * go to AVCBinReadNextRxp() instead)
1710
 *
1711
 * Read the next RXP (Region something...) structure from the file.
1712
 *
1713
 * Returns 0 on success or -1 on error.
1714
 **********************************************************************/
1715
static int _AVCBinReadNextRxp(AVCRawBinFile *psFile, AVCRxp *psRxp,
1716
                              CPL_UNUSED int nPrecision)
1717
0
{
1718
1719
0
    psRxp->n1 = AVCRawBinReadInt32(psFile);
1720
0
    if (AVCRawBinEOF(psFile))
1721
0
        return -1;
1722
0
    psRxp->n2 = AVCRawBinReadInt32(psFile);
1723
1724
0
    return 0;
1725
0
}
1726
1727
/**********************************************************************
1728
 *                          AVCBinReadNextRxp()
1729
 *
1730
 * Read the next RXP structure from the file.
1731
 *
1732
 * Returns a pointer to a static AVCRxp structure whose contents will be
1733
 * valid only until the next call or nullptr if an error happened or if EOF
1734
 * was reached.
1735
 **********************************************************************/
1736
AVCRxp *AVCBinReadNextRxp(AVCBinFile *psFile)
1737
0
{
1738
0
    if (psFile->eFileType != AVCFileRXP || AVCRawBinEOF(psFile->psRawBinFile) ||
1739
0
        _AVCBinReadNextRxp(psFile->psRawBinFile, psFile->cur.psRxp,
1740
0
                           psFile->nPrecision) != 0)
1741
0
    {
1742
0
        return nullptr;
1743
0
    }
1744
1745
0
    return psFile->cur.psRxp;
1746
0
}
1747
1748
/*=====================================================================
1749
 *                         NATIVE (V7.x) TABLEs
1750
 *
1751
 * Note: Also applies to AVCCoverWeird
1752
 *====================================================================*/
1753
1754
/**********************************************************************
1755
 *                          _AVCBinReadNextArcDir()
1756
 *
1757
 * (This function is for internal library use... external calls should
1758
 * go to AVCBinReadOpen() with type AVCFileTABLE instead)
1759
 *
1760
 * Read the next record from an arc.dir (or "arcdr9") file.
1761
 *
1762
 * Note that arc.dir files have no header... they start with the
1763
 * first record immediately.
1764
 *
1765
 * Returns 0 on success or -1 on error.
1766
 **********************************************************************/
1767
1768
int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir)
1769
139k
{
1770
139k
    int i;
1771
1772
    /* Arc/Info Table name
1773
     */
1774
139k
    AVCRawBinReadString(psFile, 32, (GByte *)psArcDir->szTableName);
1775
139k
    psArcDir->szTableName[32] = '\0';
1776
1777
139k
    if (AVCRawBinEOF(psFile))
1778
524
        return -1;
1779
1780
    /* "ARC####" basename for .DAT and .NIT files
1781
     */
1782
138k
    AVCRawBinReadString(psFile, 8, (GByte *)psArcDir->szInfoFile);
1783
138k
    psArcDir->szInfoFile[7] = '\0';
1784
162k
    for (i = 6; i > 0 && psArcDir->szInfoFile[i] == ' '; i--)
1785
24.0k
        psArcDir->szInfoFile[i] = '\0';
1786
1787
138k
    psArcDir->numFields = AVCRawBinReadInt16(psFile);
1788
138k
    psArcDir->nRecSize = AVCRawBinReadInt16(psFile);
1789
1790
138k
    AVCRawBinFSeek(psFile, 18, SEEK_CUR); /* Skip 18 bytes */
1791
1792
138k
    psArcDir->bDeletedFlag = AVCRawBinReadInt16(psFile);
1793
138k
    psArcDir->numRecords = AVCRawBinReadInt32(psFile);
1794
1795
138k
    AVCRawBinFSeek(psFile, 10, SEEK_CUR); /* Skip 10 bytes */
1796
1797
138k
    AVCRawBinReadBytes(psFile, 2, (GByte *)psArcDir->szExternal);
1798
138k
    psArcDir->szExternal[2] = '\0';
1799
1800
138k
    AVCRawBinFSeek(psFile, 300, SEEK_CUR); /* Skip the remaining 300 bytes */
1801
1802
138k
    return 0;
1803
139k
}
1804
1805
/**********************************************************************
1806
 *                          _AVCBinReadNextNit()
1807
 *
1808
 * (This function is for internal library use... external calls should
1809
 * go to AVCBinReadOpen() with type AVCFileTABLE instead)
1810
 *
1811
 * Read the next record from an arc####.nit file.
1812
 *
1813
 * Note that arc####.nit files have no header... they start with the
1814
 * first record immediately.
1815
 *
1816
 * Returns 0 on success or -1 on error.
1817
 **********************************************************************/
1818
static int _AVCBinReadNextArcNit(AVCRawBinFile *psFile, AVCFieldInfo *psField)
1819
14.5k
{
1820
14.5k
    AVCRawBinReadString(psFile, 16, (GByte *)psField->szName);
1821
14.5k
    psField->szName[16] = '\0';
1822
1823
14.5k
    if (AVCRawBinEOF(psFile))
1824
54
        return -1;
1825
1826
14.4k
    psField->nSize = AVCRawBinReadInt16(psFile);
1827
14.4k
    if (psField->nSize < 0)
1828
48
        return -1;
1829
14.4k
    psField->v2 = AVCRawBinReadInt16(psFile); /* Always -1 ? */
1830
14.4k
    psField->nOffset = AVCRawBinReadInt16(psFile);
1831
14.4k
    psField->v4 = AVCRawBinReadInt16(psFile); /* Always 4 ?  */
1832
14.4k
    psField->v5 = AVCRawBinReadInt16(psFile); /* Always -1 ? */
1833
14.4k
    psField->nFmtWidth = AVCRawBinReadInt16(psFile);
1834
14.4k
    psField->nFmtPrec = AVCRawBinReadInt16(psFile);
1835
14.4k
    psField->nType1 = AVCRawBinReadInt16(psFile);
1836
14.4k
    psField->nType2 = AVCRawBinReadInt16(psFile); /* Always 0 ? */
1837
14.4k
    psField->v10 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
1838
14.4k
    psField->v11 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
1839
14.4k
    psField->v12 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
1840
14.4k
    psField->v13 = AVCRawBinReadInt16(psFile);    /* Always -1 ? */
1841
1842
14.4k
    AVCRawBinReadString(psFile, 16,
1843
14.4k
                        (GByte *)psField->szAltName); /* Always Blank ? */
1844
14.4k
    psField->szAltName[16] = '\0';
1845
1846
14.4k
    AVCRawBinFSeek(psFile, 56, SEEK_CUR); /* Skip 56 bytes */
1847
1848
14.4k
    psField->nIndex = AVCRawBinReadInt16(psFile);
1849
1850
14.4k
    AVCRawBinFSeek(psFile, 28, SEEK_CUR); /* Skip the remaining 28 bytes */
1851
1852
14.4k
    return 0;
1853
14.4k
}
1854
1855
/**********************************************************************
1856
 *                          _AVCBinReadGetInfoFilename()
1857
 *
1858
 * Look for the DAT or NIT files for a given table... returns TRUE if
1859
 * they exist, or FALSE otherwise.
1860
 *
1861
 * If pszRetFnmae/pszRetNitFile != nullptr then the filename with full path
1862
 * will be copied to the specified buffer.
1863
 **********************************************************************/
1864
static GBool _AVCBinReadGetInfoFilename(const char *pszInfoPath,
1865
                                        const char *pszBasename,
1866
                                        const char *pszDatOrNit,
1867
                                        AVCCoverType eCoverType,
1868
                                        char *pszRetFname, size_t nRetFnameLen)
1869
73.1k
{
1870
73.1k
    GBool bFilesExist = FALSE;
1871
73.1k
    char *pszBuf = nullptr;
1872
73.1k
    VSIStatBufL sStatBuf;
1873
73.1k
    size_t nBufLen;
1874
1875
73.1k
    if (pszRetFname)
1876
10.4k
    {
1877
10.4k
        pszBuf = pszRetFname;
1878
10.4k
        nBufLen = nRetFnameLen;
1879
10.4k
    }
1880
62.7k
    else
1881
62.7k
    {
1882
62.7k
        nBufLen = strlen(pszInfoPath) + strlen(pszBasename) + 10;
1883
62.7k
        pszBuf = (char *)CPLMalloc(nBufLen);
1884
62.7k
    }
1885
1886
73.1k
    if (eCoverType == AVCCoverWeird)
1887
495
    {
1888
495
        snprintf(pszBuf, nBufLen, "%s%s%s", pszInfoPath, pszBasename,
1889
495
                 pszDatOrNit);
1890
495
    }
1891
72.7k
    else
1892
72.7k
    {
1893
72.7k
        snprintf(pszBuf, nBufLen, "%s%s.%s", pszInfoPath, pszBasename,
1894
72.7k
                 pszDatOrNit);
1895
72.7k
    }
1896
1897
73.1k
    AVCAdjustCaseSensitiveFilename(pszBuf);
1898
1899
73.1k
    if (VSIStatL(pszBuf, &sStatBuf) == 0)
1900
50.3k
        bFilesExist = TRUE;
1901
1902
73.1k
    if (eCoverType == AVCCoverWeird && !bFilesExist)
1903
180
    {
1904
        /* In some cases, the filename can be truncated to 8 chars
1905
         * and we end up with "ARC000DA"... check that possibility.
1906
         */
1907
180
        pszBuf[strlen(pszBuf) - 1] = '\0';
1908
1909
180
        AVCAdjustCaseSensitiveFilename(pszBuf);
1910
1911
180
        if (VSIStatL(pszBuf, &sStatBuf) == 0)
1912
145
            bFilesExist = TRUE;
1913
180
    }
1914
1915
73.1k
    if (pszRetFname == nullptr)
1916
62.7k
        CPLFree(pszBuf);
1917
1918
73.1k
    return bFilesExist;
1919
73.1k
}
1920
1921
/**********************************************************************
1922
 *                          _AVCBinReadInfoFilesExist()
1923
 *
1924
 * Look for the DAT and NIT files for a given table... returns TRUE if
1925
 * they exist, or FALSE otherwise.
1926
 *
1927
 * If pszRetDatFile/pszRetNitFile != nullptr then the .DAT and .NIT filename
1928
 * without the info path will be copied to the specified buffers.
1929
 **********************************************************************/
1930
static GBool _AVCBinReadInfoFileExists(const char *pszInfoPath,
1931
                                       const char *pszBasename,
1932
                                       AVCCoverType eCoverType)
1933
42.2k
{
1934
1935
42.2k
    return (_AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "dat",
1936
42.2k
                                       eCoverType, nullptr, 0) == TRUE &&
1937
20.5k
            _AVCBinReadGetInfoFilename(pszInfoPath, pszBasename, "nit",
1938
20.5k
                                       eCoverType, nullptr, 0) == TRUE);
1939
42.2k
}
1940
1941
/**********************************************************************
1942
 *                          AVCBinReadListTables()
1943
 *
1944
 * Scan the arc.dir file and return stringlist with one entry for the
1945
 * Arc/Info name of each table that belongs to the specified coverage.
1946
 * Pass pszCoverName = nullptr to get the list of all tables.
1947
 *
1948
 * ppapszArcDatFiles if not nullptr will be set to point to a stringlist
1949
 * with the corresponding "ARC????" info file basenames corresponding
1950
 * to each table found.
1951
 *
1952
 * Note that arc.dir files have no header... they start with the
1953
 * first record immediately.
1954
 *
1955
 * In AVCCoverWeird, the file is called "arcdr9"
1956
 *
1957
 * Returns a stringlist that should be deallocated by the caller
1958
 * with CSLDestroy(), or nullptr on error.
1959
 **********************************************************************/
1960
char **AVCBinReadListTables(const char *pszInfoPath, const char *pszCoverName,
1961
                            char ***ppapszArcDatFiles, AVCCoverType eCoverType,
1962
                            AVCDBCSInfo *psDBCSInfo)
1963
11.0k
{
1964
11.0k
    char **papszList = nullptr;
1965
11.0k
    char *pszFname;
1966
11.0k
    char szNameToFind[33] = "";
1967
11.0k
    int nLen;
1968
11.0k
    AVCRawBinFile *hFile;
1969
11.0k
    AVCTableDef sEntry;
1970
1971
11.0k
    if (ppapszArcDatFiles)
1972
11.0k
        *ppapszArcDatFiles = nullptr;
1973
1974
    /*-----------------------------------------------------------------
1975
     * For AVCCoverV7Tables type we do not look for tables for a specific
1976
     * coverage, we return all tables from the info dir.
1977
     *----------------------------------------------------------------*/
1978
11.0k
    if (eCoverType == AVCCoverV7Tables)
1979
456
        pszCoverName = nullptr;
1980
1981
    /*-----------------------------------------------------------------
1982
     * All tables that belong to a given coverage have their name starting
1983
     * with the coverage name (in uppercase letters), followed by a 3
1984
     * letters extension.
1985
     *----------------------------------------------------------------*/
1986
11.0k
    if (pszCoverName != nullptr)
1987
        // cppcheck-suppress bufferAccessOutOfBounds
1988
10.6k
        snprintf(szNameToFind, sizeof(szNameToFind), "%-.28s.", pszCoverName);
1989
11.0k
    nLen = (int)strlen(szNameToFind);
1990
1991
    /*-----------------------------------------------------------------
1992
     * Open the arc.dir and add all entries that match the criteria
1993
     * to our list.
1994
     * In AVCCoverWeird, the file is called "arcdr9"
1995
     *----------------------------------------------------------------*/
1996
11.0k
    pszFname = (char *)CPLMalloc(strlen(pszInfoPath) + 9);
1997
11.0k
    if (eCoverType == AVCCoverWeird)
1998
54
        snprintf(pszFname, strlen(pszInfoPath) + 9, "%sarcdr9", pszInfoPath);
1999
11.0k
    else
2000
11.0k
        snprintf(pszFname, strlen(pszInfoPath) + 9, "%sarc.dir", pszInfoPath);
2001
2002
11.0k
    AVCAdjustCaseSensitiveFilename(pszFname);
2003
2004
11.0k
    hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
2005
11.0k
                          psDBCSInfo);
2006
2007
11.0k
    if (hFile)
2008
11.0k
    {
2009
132k
        while (!AVCRawBinEOF(hFile) &&
2010
121k
               _AVCBinReadNextArcDir(hFile, &sEntry) == 0)
2011
121k
        {
2012
121k
            if (/* sEntry.numRecords > 0 && (DO NOT skip empty tables) */
2013
121k
                !sEntry.bDeletedFlag &&
2014
54.2k
                (pszCoverName == nullptr ||
2015
19.3k
                 EQUALN(szNameToFind, sEntry.szTableName, nLen)) &&
2016
36.8k
                _AVCBinReadInfoFileExists(pszInfoPath, sEntry.szInfoFile,
2017
36.8k
                                          eCoverType))
2018
14.2k
            {
2019
14.2k
                papszList = CSLAddString(papszList, sEntry.szTableName);
2020
2021
14.2k
                if (ppapszArcDatFiles)
2022
14.2k
                    *ppapszArcDatFiles =
2023
14.2k
                        CSLAddString(*ppapszArcDatFiles, sEntry.szInfoFile);
2024
14.2k
            }
2025
121k
        }
2026
11.0k
        AVCRawBinClose(hFile);
2027
11.0k
    }
2028
2029
11.0k
    CPLFree(pszFname);
2030
2031
11.0k
    return papszList;
2032
11.0k
}
2033
2034
/**********************************************************************
2035
 *                         _AVCBinReadOpenTable()
2036
 *
2037
 * (This function is for internal library use... external calls should
2038
 * go to AVCBinReadOpen() with type AVCFileTABLE instead)
2039
 *
2040
 * Open a INFO table, read the header file (.NIT), and finally open
2041
 * the associated data file to be ready to read records from it.
2042
 *
2043
 * Returns a valid AVCBinFile handle, or nullptr if the file could
2044
 * not be opened.
2045
 *
2046
 * _AVCBinReadCloseTable() will eventually have to be called to release the
2047
 * resources used by the AVCBinFile structure.
2048
 **********************************************************************/
2049
AVCBinFile *_AVCBinReadOpenTable(const char *pszInfoPath,
2050
                                 const char *pszTableName,
2051
                                 AVCCoverType eCoverType,
2052
                                 AVCDBCSInfo *psDBCSInfo)
2053
5.29k
{
2054
5.29k
    AVCBinFile *psFile;
2055
5.29k
    AVCRawBinFile *hFile;
2056
5.29k
    AVCTableDef sTableDef;
2057
5.29k
    AVCFieldInfo *pasFieldDef;
2058
5.29k
    char *pszFname;
2059
5.29k
    GBool bFound;
2060
5.29k
    int i;
2061
5.29k
    size_t nFnameLen;
2062
2063
5.29k
    memset(&sTableDef, 0, sizeof(sTableDef));
2064
5.29k
    sTableDef.numFields = 0;
2065
5.29k
    sTableDef.pasFieldDef = nullptr;
2066
2067
    /* Alloc a buffer big enough for the longest possible filename...
2068
     */
2069
5.29k
    nFnameLen = strlen(pszInfoPath) + 81;
2070
5.29k
    pszFname = (char *)CPLMalloc(nFnameLen);
2071
2072
    /*-----------------------------------------------------------------
2073
     * Fetch info about this table from the "arc.dir"
2074
     *----------------------------------------------------------------*/
2075
5.29k
    if (eCoverType == AVCCoverWeird)
2076
38
        snprintf(pszFname, nFnameLen, "%sarcdr9", pszInfoPath);
2077
5.25k
    else
2078
5.25k
        snprintf(pszFname, nFnameLen, "%sarc.dir", pszInfoPath);
2079
2080
5.29k
    AVCAdjustCaseSensitiveFilename(pszFname);
2081
2082
5.29k
    hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
2083
5.29k
                          psDBCSInfo);
2084
5.29k
    bFound = FALSE;
2085
2086
5.29k
    if (hFile)
2087
5.29k
    {
2088
23.0k
        while (!bFound && _AVCBinReadNextArcDir(hFile, &sTableDef) == 0)
2089
17.7k
        {
2090
17.7k
            if (!sTableDef.bDeletedFlag &&
2091
9.84k
                EQUALN(sTableDef.szTableName, pszTableName,
2092
17.7k
                       strlen(pszTableName)) &&
2093
5.36k
                _AVCBinReadInfoFileExists(pszInfoPath, sTableDef.szInfoFile,
2094
5.36k
                                          eCoverType))
2095
5.28k
            {
2096
5.28k
                bFound = TRUE;
2097
5.28k
            }
2098
17.7k
        }
2099
5.29k
        AVCRawBinClose(hFile);
2100
5.29k
    }
2101
2102
    /* Hummm... quite likely that this table does not exist!
2103
     */
2104
5.29k
    if (!bFound)
2105
8
    {
2106
8
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open table %s",
2107
8
                 pszTableName);
2108
8
        CPLFree(pszFname);
2109
8
        return nullptr;
2110
8
    }
2111
    /* To please Coverity */
2112
5.28k
    if (sTableDef.numFields < 0 || sTableDef.numFields >= 32767)
2113
71
    {
2114
71
        CPLError(CE_Failure, CPLE_OpenFailed, "Invalid numFields in %s",
2115
71
                 pszTableName);
2116
71
        CPLFree(pszFname);
2117
71
        return nullptr;
2118
71
    }
2119
2120
    /*-----------------------------------------------------------------
2121
     * Establish the location of the data file... depends on the
2122
     * szExternal[] field.
2123
     *----------------------------------------------------------------*/
2124
5.21k
    if (EQUAL(sTableDef.szExternal, "XX"))
2125
2.56k
    {
2126
        /*-------------------------------------------------------------
2127
         * The data file is located outside of the INFO directory.
2128
         * Read the path to the data file from the arc####.dat file
2129
         *------------------------------------------------------------*/
2130
2.56k
        _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat",
2131
2.56k
                                   eCoverType, pszFname, nFnameLen);
2132
2.56k
        AVCAdjustCaseSensitiveFilename(pszFname);
2133
2134
2.56k
        hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
2135
2.56k
                              psDBCSInfo);
2136
2137
2.56k
        if (hFile)
2138
2.55k
        {
2139
            /* Read the relative file path, and remove trailing spaces.
2140
             */
2141
2.55k
            AVCRawBinReadBytes(hFile, 80, (GByte *)sTableDef.szDataFile);
2142
2.55k
            sTableDef.szDataFile[80] = '\0';
2143
2144
2.55k
            for (i = (int)strlen(sTableDef.szDataFile) - 1;
2145
9.47k
                 i >= 0 && isspace((unsigned char)sTableDef.szDataFile[i]); i--)
2146
6.92k
            {
2147
6.92k
                sTableDef.szDataFile[i] = '\0';
2148
6.92k
            }
2149
2150
2.55k
            AVCRawBinClose(hFile);
2151
2.55k
        }
2152
14
        else
2153
14
        {
2154
14
            CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
2155
14
                     pszFname);
2156
14
            CPLFree(pszFname);
2157
14
            return nullptr;
2158
14
        }
2159
2.56k
    }
2160
2.64k
    else
2161
2.64k
    {
2162
        /*-------------------------------------------------------------
2163
         * The data file IS the arc####.dat file
2164
         * Note: sTableDef.szDataFile must be relative to info directory
2165
         *------------------------------------------------------------*/
2166
2.64k
        _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "dat",
2167
2.64k
                                   eCoverType, pszFname, nFnameLen);
2168
2.64k
        snprintf(sTableDef.szDataFile, sizeof(sTableDef.szDataFile), "%s",
2169
2.64k
                 pszFname + strlen(pszInfoPath));
2170
2.64k
    }
2171
2172
    /*-----------------------------------------------------------------
2173
     * Read the table field definitions from the "arc####.nit" file.
2174
     *----------------------------------------------------------------*/
2175
5.19k
    _AVCBinReadGetInfoFilename(pszInfoPath, sTableDef.szInfoFile, "nit",
2176
5.19k
                               eCoverType, pszFname, nFnameLen);
2177
5.19k
    AVCAdjustCaseSensitiveFilename(pszFname);
2178
2179
5.19k
    hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
2180
5.19k
                          psDBCSInfo);
2181
2182
5.19k
    if (hFile)
2183
5.13k
    {
2184
5.13k
        int iField;
2185
2186
5.13k
        pasFieldDef = (AVCFieldInfo *)CPLCalloc(sTableDef.numFields,
2187
5.13k
                                                sizeof(AVCFieldInfo));
2188
2189
        /*-------------------------------------------------------------
2190
         * There must be at least sTableDef.numFields valid entries
2191
         * in the .NIT file...
2192
         *
2193
         * Note that we ignore any deleted field entries (entries with
2194
         * index=-1)... I don't see any use for these deleted fields...
2195
         * and I don't understand why Arc/Info includes them in their
2196
         * E00 table headers...
2197
         *------------------------------------------------------------*/
2198
19.5k
        for (i = 0, iField = 0; iField < sTableDef.numFields; i++)
2199
14.5k
        {
2200
14.5k
            if (_AVCBinReadNextArcNit(hFile, &(pasFieldDef[iField])) != 0)
2201
102
            {
2202
                /* Problems.... is the NIT file corrupt???
2203
                 */
2204
102
                AVCRawBinClose(hFile);
2205
102
                CPLFree(pszFname);
2206
102
                CPLFree(pasFieldDef);
2207
102
                CPLError(CE_Failure, CPLE_FileIO,
2208
102
                         "Failed reading table field info for table %s "
2209
102
                         "File may be corrupt?",
2210
102
                         pszTableName);
2211
102
                return nullptr;
2212
102
            }
2213
2214
            /*---------------------------------------------------------
2215
             * Check if the field has been deleted (nIndex == -1).
2216
             * We just ignore deleted fields
2217
             *--------------------------------------------------------*/
2218
14.4k
            if (pasFieldDef[iField].nIndex > 0)
2219
12.7k
                iField++;
2220
14.4k
        }
2221
2222
5.03k
        AVCRawBinClose(hFile);
2223
5.03k
    }
2224
64
    else
2225
64
    {
2226
64
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
2227
64
                 pszFname);
2228
64
        CPLFree(pszFname);
2229
64
        return nullptr;
2230
64
    }
2231
2232
    /*-----------------------------------------------------------------
2233
     * Open the data file... ready to read records from it.
2234
     * If the header says that table has 0 records, then we don't
2235
     * try to open the file... but we don't consider that as an error.
2236
     *----------------------------------------------------------------*/
2237
5.03k
    if (sTableDef.numRecords > 0 &&
2238
4.93k
        AVCFileExists(pszInfoPath, sTableDef.szDataFile))
2239
2.68k
    {
2240
2.68k
        VSIStatBufL sStatBuf;
2241
2242
2.68k
        snprintf(pszFname, nFnameLen, "%s%s", pszInfoPath,
2243
2.68k
                 sTableDef.szDataFile);
2244
2.68k
        AVCAdjustCaseSensitiveFilename(pszFname);
2245
2246
2.68k
        hFile = AVCRawBinOpen(pszFname, "r", AVC_COVER_BYTE_ORDER(eCoverType),
2247
2.68k
                              psDBCSInfo);
2248
2249
        /* OOPS... data file does not exist!
2250
         */
2251
2.68k
        if (hFile == nullptr)
2252
0
        {
2253
0
            CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
2254
0
                     pszFname);
2255
0
            CPLFree(pszFname);
2256
0
            return nullptr;
2257
0
        }
2258
2259
        /*-------------------------------------------------------------
2260
         * In some cases, the number of records field for a table in the
2261
         * arc.dir does not correspond to the real number of records
2262
         * in the data file.  In this kind of situation, the number of
2263
         * records returned by Arc/Info in an E00 file will be based
2264
         * on the real data file size, and not on the value from the arc.dir.
2265
         *
2266
         * Fetch the data file size, and correct the number of record
2267
         * field in the table header if necessary.
2268
         *------------------------------------------------------------*/
2269
2.68k
        if (VSIStatL(pszFname, &sStatBuf) != -1 && sTableDef.nRecSize > 0 &&
2270
655
            sStatBuf.st_size / sTableDef.nRecSize != sTableDef.numRecords)
2271
579
        {
2272
579
            sTableDef.numRecords = (int)(sStatBuf.st_size / sTableDef.nRecSize);
2273
579
        }
2274
2.68k
    }
2275
2.35k
    else
2276
2.35k
    {
2277
2.35k
        hFile = nullptr;
2278
2.35k
        sTableDef.numRecords = 0;
2279
2.35k
    }
2280
2281
    /*-----------------------------------------------------------------
2282
     * Alloc. and init. the AVCBinFile structure.
2283
     *----------------------------------------------------------------*/
2284
5.03k
    psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
2285
2286
5.03k
    psFile->psRawBinFile = hFile;
2287
5.03k
    psFile->eCoverType = AVCCoverV7;
2288
5.03k
    psFile->eFileType = AVCFileTABLE;
2289
5.03k
    psFile->pszFilename = pszFname;
2290
2291
5.03k
    psFile->hdr.psTableDef = (AVCTableDef *)CPLMalloc(sizeof(AVCTableDef));
2292
5.03k
    *(psFile->hdr.psTableDef) = sTableDef;
2293
2294
5.03k
    psFile->hdr.psTableDef->pasFieldDef = pasFieldDef;
2295
2296
    /* We can't really tell the precision from a Table header...
2297
     * just set an arbitrary value... it probably won't be used anyways!
2298
     */
2299
5.03k
    psFile->nPrecision = AVC_SINGLE_PREC;
2300
2301
    /*-----------------------------------------------------------------
2302
     * Allocate temp. structures to use to read records from the file
2303
     * And allocate buffers for those fields that are stored as strings.
2304
     *----------------------------------------------------------------*/
2305
5.03k
    psFile->cur.pasFields =
2306
5.03k
        (AVCField *)CPLCalloc(sTableDef.numFields, sizeof(AVCField));
2307
2308
17.3k
    for (i = 0; i < sTableDef.numFields; i++)
2309
12.3k
    {
2310
12.3k
        if (pasFieldDef[i].nType1 * 10 == AVC_FT_DATE ||
2311
12.0k
            pasFieldDef[i].nType1 * 10 == AVC_FT_CHAR ||
2312
10.4k
            pasFieldDef[i].nType1 * 10 == AVC_FT_FIXINT ||
2313
9.76k
            pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM)
2314
7.49k
        {
2315
7.49k
            psFile->cur.pasFields[i].pszStr =
2316
7.49k
                (GByte *)CPLCalloc(pasFieldDef[i].nSize + 1, sizeof(char));
2317
7.49k
        }
2318
12.3k
    }
2319
2320
5.03k
    return psFile;
2321
5.03k
}
2322
2323
/**********************************************************************
2324
 *                         _AVCBinReadNextTableRec()
2325
 *
2326
 * (This function is for internal library use... external calls should
2327
 * go to AVCBinReadNextTableRec() instead)
2328
 *
2329
 * Reads the next record from an attribute table and fills the
2330
 * pasFields[] array.
2331
 *
2332
 * Note that it is assumed that the pasFields[] array has been properly
2333
 * initialized, re the allocation of buffers for fields stored as
2334
 * strings.
2335
 *
2336
 * Returns 0 on success or -1 on error.
2337
 **********************************************************************/
2338
static int _AVCBinReadNextTableRec(AVCRawBinFile *psFile, int nFields,
2339
                                   AVCFieldInfo *pasDef, AVCField *pasFields,
2340
                                   int nRecordSize)
2341
72.3k
{
2342
72.3k
    int i, nType, nBytesRead = 0;
2343
2344
72.3k
    if (psFile == nullptr)
2345
0
        return -1;
2346
2347
328k
    for (i = 0; i < nFields; i++)
2348
258k
    {
2349
258k
        if (AVCRawBinEOF(psFile))
2350
621
            return -1;
2351
2352
257k
        nType = pasDef[i].nType1 * 10;
2353
2354
257k
        if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
2355
184k
            nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
2356
244k
        {
2357
            /*---------------------------------------------------------
2358
             * Values stored as strings
2359
             *--------------------------------------------------------*/
2360
244k
            AVCRawBinReadString(psFile, pasDef[i].nSize, pasFields[i].pszStr);
2361
244k
            pasFields[i].pszStr[pasDef[i].nSize] = '\0';
2362
244k
        }
2363
13.5k
        else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
2364
5.13k
        {
2365
            /*---------------------------------------------------------
2366
             * 32 bit binary integers
2367
             *--------------------------------------------------------*/
2368
5.13k
            pasFields[i].nInt32 = AVCRawBinReadInt32(psFile);
2369
5.13k
        }
2370
8.37k
        else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
2371
500
        {
2372
            /*---------------------------------------------------------
2373
             * 16 bit binary integers
2374
             *--------------------------------------------------------*/
2375
500
            pasFields[i].nInt16 = AVCRawBinReadInt16(psFile);
2376
500
        }
2377
7.87k
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
2378
4.97k
        {
2379
            /*---------------------------------------------------------
2380
             * Single precision floats
2381
             *--------------------------------------------------------*/
2382
4.97k
            pasFields[i].fFloat = AVCRawBinReadFloat(psFile);
2383
4.97k
        }
2384
2.89k
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
2385
1.18k
        {
2386
            /*---------------------------------------------------------
2387
             * Double precision floats
2388
             *--------------------------------------------------------*/
2389
1.18k
            pasFields[i].dDouble = AVCRawBinReadDouble(psFile);
2390
1.18k
        }
2391
1.71k
        else
2392
1.71k
        {
2393
            /*---------------------------------------------------------
2394
             * Hummm... unsupported field type...
2395
             *--------------------------------------------------------*/
2396
1.71k
            CPLError(CE_Failure, CPLE_NotSupported,
2397
1.71k
                     "Unsupported field type: (type=%d, size=%d)", nType,
2398
1.71k
                     pasDef[i].nSize);
2399
1.71k
            return -1;
2400
1.71k
        }
2401
2402
256k
        nBytesRead += pasDef[i].nSize;
2403
256k
    }
2404
2405
    /*-----------------------------------------------------------------
2406
     * Record size is rounded to a multiple of 2 bytes.
2407
     * Check the number of bytes read, and move the read pointer if
2408
     * necessary.
2409
     *----------------------------------------------------------------*/
2410
69.9k
    if (nBytesRead < nRecordSize)
2411
300
        AVCRawBinFSeek(psFile, nRecordSize - nBytesRead, SEEK_CUR);
2412
2413
69.9k
    return 0;
2414
72.3k
}
2415
2416
/*=====================================================================
2417
 *                         PC Arc/Info DBF TABLEs
2418
 *====================================================================*/
2419
2420
void _AVCBinReadRepairDBFFieldName(char *pszFieldName);
2421
2422
/**********************************************************************
2423
 *                         _AVCBinReadOpenDBFTable()
2424
 *
2425
 * (This function is for internal library use... external calls should
2426
 * go to AVCBinReadOpen() with type AVCCoverPC/AVCFileTABLE instead)
2427
 *
2428
 * Open the DBF table, reads the header information and inits the
2429
 * AVCBinFile handle to be ready to read records from it.
2430
 *
2431
 * Returns a valid AVCBinFile handle, or nullptr if the file could
2432
 * not be opened.
2433
 *
2434
 * _AVCBinReadCloseDBFTable() will eventually have to be called to release the
2435
 * resources used by the AVCBinFile structure.
2436
 **********************************************************************/
2437
AVCBinFile *_AVCBinReadOpenDBFTable(const char *pszDBFFilename,
2438
                                    const char *pszArcInfoTableName)
2439
334
{
2440
334
    AVCBinFile *psFile;
2441
334
    DBFHandle hDBFFile = nullptr;
2442
334
    int iField;
2443
334
    AVCTableDef *psTableDef;
2444
334
    AVCFieldInfo *pasFieldDef;
2445
2446
    /*-----------------------------------------------------------------
2447
     * Try to open the DBF file
2448
     *----------------------------------------------------------------*/
2449
334
    if ((hDBFFile = DBFOpen(pszDBFFilename, "rb")) == nullptr)
2450
112
    {
2451
112
        CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open table %s",
2452
112
                 pszDBFFilename);
2453
112
        return nullptr;
2454
112
    }
2455
2456
    /*-----------------------------------------------------------------
2457
     * Alloc. and init. the AVCBinFile structure.
2458
     *----------------------------------------------------------------*/
2459
222
    psFile = (AVCBinFile *)CPLCalloc(1, sizeof(AVCBinFile));
2460
2461
222
    psFile->hDBFFile = hDBFFile;
2462
2463
222
    psFile->eCoverType = AVCCoverPC;
2464
222
    psFile->eFileType = AVCFileTABLE;
2465
222
    psFile->pszFilename = CPLStrdup(pszDBFFilename);
2466
2467
222
    psFile->hdr.psTableDef = nullptr;
2468
2469
    /* nCurDBFRecord is used to keep track of the 0-based index of the
2470
     * last record we read from the DBF file... this is to emulate
2471
     * sequential access which is assumed by the rest of the lib.
2472
     * Since the first record (record 0) has not been read yet, then
2473
     * we init the index at -1.
2474
     */
2475
222
    psFile->nCurDBFRecord = -1;
2476
2477
    /* We can't really tell the precision from a Table header...
2478
     * just set an arbitrary value... it probably won't be used anyways!
2479
     */
2480
222
    psFile->nPrecision = AVC_SINGLE_PREC;
2481
2482
    /*-----------------------------------------------------------------
2483
     * Build TableDef from the info in the DBF header
2484
     *----------------------------------------------------------------*/
2485
    /* Use calloc() to init some unused struct members */
2486
222
    psTableDef = (AVCTableDef *)CPLCalloc(1, sizeof(AVCTableDef));
2487
222
    psFile->hdr.psTableDef = psTableDef;
2488
2489
222
    snprintf(psTableDef->szTableName, sizeof(psTableDef->szTableName),
2490
222
             "%-32.32s", pszArcInfoTableName);
2491
2492
222
    psTableDef->numFields = (GInt16)DBFGetFieldCount(hDBFFile);
2493
2494
    /* We'll compute nRecSize value when we read fields info later */
2495
222
    psTableDef->nRecSize = 0;
2496
2497
222
    psTableDef->numRecords = DBFGetRecordCount(hDBFFile);
2498
2499
    /* All DBF tables are considered External */
2500
222
    strcpy(psTableDef->szExternal, "XX");
2501
2502
    /*-----------------------------------------------------------------
2503
     * Build Field definitions
2504
     *----------------------------------------------------------------*/
2505
222
    pasFieldDef =
2506
222
        (AVCFieldInfo *)CPLCalloc(psTableDef->numFields, sizeof(AVCFieldInfo));
2507
2508
222
    psTableDef->pasFieldDef = pasFieldDef;
2509
2510
32.5k
    for (iField = 0; iField < psTableDef->numFields; iField++)
2511
32.3k
    {
2512
32.3k
        int nWidth = 0, nDecimals = 0;
2513
        /* DBFFieldType eDBFType; */
2514
2515
        /*-------------------------------------------------------------
2516
         * Fetch DBF Field info and convert to Arc/Info type...
2517
         * Note that since DBF fields names are limited to 10 chars,
2518
         * we do not have to worry about field name length in the process.
2519
         *------------------------------------------------------------*/
2520
        /* eDBFType = */
2521
32.3k
        DBFGetFieldInfo(hDBFFile, iField, pasFieldDef[iField].szName, &nWidth,
2522
32.3k
                        &nDecimals);
2523
32.3k
        const char cNativeType = DBFGetNativeFieldType(hDBFFile, iField);
2524
2525
32.3k
        pasFieldDef[iField].nFmtWidth = (GInt16)nWidth;
2526
32.3k
        pasFieldDef[iField].nFmtPrec = (GInt16)nDecimals;
2527
2528
        /* nIndex is the 1-based field index that we see in the E00 header */
2529
32.3k
        pasFieldDef[iField].nIndex = (GInt16)(iField + 1);
2530
2531
32.3k
        if (cNativeType == 'F' || (cNativeType == 'N' && nDecimals > 0))
2532
2.86k
        {
2533
            /*---------------------------------------------------------
2534
             * BINARY FLOAT
2535
             *--------------------------------------------------------*/
2536
2.86k
            pasFieldDef[iField].nType1 = AVC_FT_BINFLOAT / 10;
2537
2.86k
            pasFieldDef[iField].nSize = 4;
2538
2.86k
            pasFieldDef[iField].nFmtWidth = 12; /* PC Arc/Info ignores the */
2539
2.86k
            pasFieldDef[iField].nFmtPrec = 3;   /* DBF width/precision     */
2540
2.86k
        }
2541
29.4k
        else if (cNativeType == 'N')
2542
1.08k
        {
2543
            /*---------------------------------------------------------
2544
             * BINARY INTEGER
2545
             *--------------------------------------------------------*/
2546
1.08k
            pasFieldDef[iField].nType1 = AVC_FT_BININT / 10;
2547
1.08k
            pasFieldDef[iField].nSize = 4;
2548
1.08k
            pasFieldDef[iField].nFmtWidth = 5; /* PC Arc/Info ignores the */
2549
1.08k
            pasFieldDef[iField].nFmtPrec = -1; /* DBF width/precision     */
2550
2551
            /*---------------------------------------------------------
2552
             * Some special integer fields need to have their names
2553
             * repaired because DBF does not support special characters.
2554
             *--------------------------------------------------------*/
2555
1.08k
            _AVCBinReadRepairDBFFieldName(pasFieldDef[iField].szName);
2556
1.08k
        }
2557
28.3k
        else if (cNativeType == 'D')
2558
183
        {
2559
            /*---------------------------------------------------------
2560
             * DATE - Actually handled as a string internally
2561
             *--------------------------------------------------------*/
2562
183
            pasFieldDef[iField].nType1 = AVC_FT_DATE / 10;
2563
183
            pasFieldDef[iField].nSize = (GInt16)nWidth;
2564
183
            pasFieldDef[iField].nFmtPrec = -1;
2565
183
        }
2566
28.1k
        else /* (cNativeType == 'C' || cNativeType == 'L') */
2567
28.1k
        {
2568
            /*---------------------------------------------------------
2569
             * CHAR STRINGS ... and all unknown types also handled as strings
2570
             *--------------------------------------------------------*/
2571
28.1k
            pasFieldDef[iField].nType1 = AVC_FT_CHAR / 10;
2572
28.1k
            pasFieldDef[iField].nSize = (GInt16)nWidth;
2573
28.1k
            pasFieldDef[iField].nFmtPrec = -1;
2574
28.1k
        }
2575
2576
        /*---------------------------------------------------------
2577
         * Keep track of position of field in record... first one always
2578
         * starts at offset=1
2579
         *--------------------------------------------------------*/
2580
32.3k
        if (iField == 0)
2581
212
            pasFieldDef[iField].nOffset = 1;
2582
32.1k
        else
2583
32.1k
            pasFieldDef[iField].nOffset = (pasFieldDef[iField - 1].nOffset +
2584
32.1k
                                           pasFieldDef[iField - 1].nSize);
2585
2586
        /*---------------------------------------------------------
2587
         * Set default values for all other unused members in the struct
2588
         *--------------------------------------------------------*/
2589
32.3k
        pasFieldDef[iField].v2 = -1;    /* Always -1 ? */
2590
32.3k
        pasFieldDef[iField].v4 = 4;     /* Always 4 ?  */
2591
32.3k
        pasFieldDef[iField].v5 = -1;    /* Always -1 ? */
2592
32.3k
        pasFieldDef[iField].nType2 = 0; /* Always 0 ?  */
2593
32.3k
        pasFieldDef[iField].v10 = -1;   /* Always -1 ? */
2594
32.3k
        pasFieldDef[iField].v11 = -1;   /* Always -1 ? */
2595
32.3k
        pasFieldDef[iField].v12 = -1;   /* Always -1 ? */
2596
32.3k
        pasFieldDef[iField].v13 = -1;   /* Always -1 ? */
2597
32.3k
    }
2598
2599
    /*-----------------------------------------------------------------
2600
     * Compute record size...
2601
     * Record size has to be rounded to a multiple of 2 bytes.
2602
     *----------------------------------------------------------------*/
2603
222
    if (psTableDef->numFields > 0)
2604
212
    {
2605
212
        psTableDef->nRecSize =
2606
212
            (pasFieldDef[psTableDef->numFields - 1].nOffset - 1 +
2607
212
             pasFieldDef[psTableDef->numFields - 1].nSize);
2608
212
        psTableDef->nRecSize = ((psTableDef->nRecSize + 1) / 2) * 2;
2609
212
    }
2610
10
    else
2611
10
        psTableDef->nRecSize = 0;
2612
2613
    /*-----------------------------------------------------------------
2614
     * Allocate temp. structures to use to read records from the file
2615
     * And allocate buffers for those fields that are stored as strings.
2616
     *----------------------------------------------------------------*/
2617
222
    psFile->cur.pasFields =
2618
222
        (AVCField *)CPLCalloc(psTableDef->numFields, sizeof(AVCField));
2619
2620
32.5k
    for (iField = 0; iField < psTableDef->numFields; iField++)
2621
32.3k
    {
2622
32.3k
        if (pasFieldDef[iField].nType1 * 10 == AVC_FT_DATE ||
2623
32.1k
            pasFieldDef[iField].nType1 * 10 == AVC_FT_CHAR ||
2624
3.94k
            pasFieldDef[iField].nType1 * 10 == AVC_FT_FIXINT ||
2625
3.94k
            pasFieldDef[iField].nType1 * 10 == AVC_FT_FIXNUM)
2626
28.3k
        {
2627
28.3k
            psFile->cur.pasFields[iField].pszStr = (GByte *)CPLCalloc(
2628
28.3k
                pasFieldDef[iField].nSize + 1, sizeof(GByte));
2629
28.3k
        }
2630
32.3k
    }
2631
2632
222
    return psFile;
2633
334
}
2634
2635
/**********************************************************************
2636
 *                         _AVCBinReadNextDBFTableRec()
2637
 *
2638
 * (This function is for internal library use... external calls should
2639
 * go to AVCBinReadNextTableRec() instead)
2640
 *
2641
 * Reads the next record from a AVCCoverPC DBF attribute table and fills the
2642
 * pasFields[] array.
2643
 *
2644
 * Note that it is assumed that the pasFields[] array has been properly
2645
 * initialized, re the allocation of buffers for fields stored as
2646
 * strings.
2647
 *
2648
 * Returns 0 on success or -1 on error.
2649
 **********************************************************************/
2650
static int _AVCBinReadNextDBFTableRec(DBFHandle hDBFFile, int *piRecordIndex,
2651
                                      int nFields, AVCFieldInfo *pasDef,
2652
                                      AVCField *pasFields)
2653
0
{
2654
0
    int i, nType;
2655
2656
    /*-----------------------------------------------------------------
2657
     * Increment current record index.
2658
     * We use nCurDBFRecord to keep track of the 0-based index of the
2659
     * last record we read from the DBF file... this is to emulate
2660
     * sequential access which is assumed by the rest of the lib.
2661
     *----------------------------------------------------------------*/
2662
0
    if (hDBFFile == nullptr || piRecordIndex == nullptr || pasDef == nullptr ||
2663
0
        pasFields == nullptr)
2664
0
        return -1;
2665
2666
0
    (*piRecordIndex)++;
2667
2668
0
    if (*piRecordIndex >= DBFGetRecordCount(hDBFFile))
2669
0
        return -1; /* Reached EOF */
2670
2671
    /*-----------------------------------------------------------------
2672
     * Read/convert each field based on type
2673
     *----------------------------------------------------------------*/
2674
0
    for (i = 0; i < nFields; i++)
2675
0
    {
2676
0
        nType = pasDef[i].nType1 * 10;
2677
2678
0
        if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
2679
0
            nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
2680
0
        {
2681
            /*---------------------------------------------------------
2682
             * Values stored as strings
2683
             *--------------------------------------------------------*/
2684
0
            const char *pszValue;
2685
0
            pszValue = DBFReadStringAttribute(hDBFFile, *piRecordIndex, i);
2686
0
            strncpy((char *)pasFields[i].pszStr, pszValue, pasDef[i].nSize);
2687
0
            pasFields[i].pszStr[pasDef[i].nSize] = '\0';
2688
0
        }
2689
0
        else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
2690
0
        {
2691
            /*---------------------------------------------------------
2692
             * 32 bit binary integers
2693
             *--------------------------------------------------------*/
2694
0
            pasFields[i].nInt32 =
2695
0
                DBFReadIntegerAttribute(hDBFFile, *piRecordIndex, i);
2696
0
        }
2697
0
        else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
2698
0
        {
2699
            /*---------------------------------------------------------
2700
             * 16 bit binary integers
2701
             *--------------------------------------------------------*/
2702
0
            pasFields[i].nInt16 =
2703
0
                (GInt16)DBFReadIntegerAttribute(hDBFFile, *piRecordIndex, i);
2704
0
        }
2705
0
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
2706
0
        {
2707
            /*---------------------------------------------------------
2708
             * Single precision floats
2709
             *--------------------------------------------------------*/
2710
0
            pasFields[i].fFloat =
2711
0
                (float)DBFReadDoubleAttribute(hDBFFile, *piRecordIndex, i);
2712
0
        }
2713
0
        else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
2714
0
        {
2715
            /*---------------------------------------------------------
2716
             * Double precision floats
2717
             *--------------------------------------------------------*/
2718
0
            pasFields[i].dDouble =
2719
0
                DBFReadDoubleAttribute(hDBFFile, *piRecordIndex, i);
2720
0
        }
2721
0
        else
2722
0
        {
2723
            /*---------------------------------------------------------
2724
             * Hummm... unsupported field type...
2725
             *--------------------------------------------------------*/
2726
0
            CPLError(CE_Failure, CPLE_NotSupported,
2727
0
                     "Unsupported field type: (type=%d, size=%d)", nType,
2728
0
                     pasDef[i].nSize);
2729
0
            return -1;
2730
0
        }
2731
0
    }
2732
2733
0
    return 0;
2734
0
}
2735
2736
/**********************************************************************
2737
 *                         _AVCBinReadRepairDBFFieldName()
2738
 *
2739
 * Attempt to repair some special integer field names that usually
2740
 * carry special chars such as '#' or '-' but that are lost because of
2741
 * DBF limitations and are replaced by '_'.
2742
 *
2743
 **********************************************************************/
2744
void _AVCBinReadRepairDBFFieldName(char *pszFieldName)
2745
1.08k
{
2746
1.08k
    char *pszTmp;
2747
2748
1.08k
    if ((pszTmp = strrchr(pszFieldName, '_')) == nullptr)
2749
615
        return; /* No special char to process */
2750
2751
    /*-----------------------------------------------------------------
2752
     * Replace '_' at end of field name by a '#', as in:
2753
     *   COVER# , FNODE#, TNODE#, LPOLY#, RPOLY#
2754
     *
2755
     * and replace names that end with "_ID" with "-ID" as in COVER-ID
2756
     *----------------------------------------------------------------*/
2757
465
    if (EQUAL(pszTmp, "_"))
2758
94
        *pszTmp = '#';
2759
371
    else if (EQUAL(pszTmp, "_ID"))
2760
18
        *pszTmp = '-';
2761
465
}