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