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