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