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