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