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