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