1 : /**********************************************************************
2 : * $Id: avc_e00read.c,v 1.28 2008/07/30 19:22:18 dmorissette Exp $
3 : *
4 : * Name: avc_e00read.c
5 : * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library
6 : * Language: ANSI C
7 : * Purpose: Functions to open a binary coverage and read it as if it
8 : * was an ASCII E00 file. This file is the main entry point
9 : * for the library.
10 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
11 : *
12 : **********************************************************************
13 : * Copyright (c) 1999-2005, Daniel Morissette
14 : *
15 : * Permission is hereby granted, free of charge, to any person obtaining a
16 : * copy of this software and associated documentation files (the "Software"),
17 : * to deal in the Software without restriction, including without limitation
18 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 : * and/or sell copies of the Software, and to permit persons to whom the
20 : * Software is furnished to do so, subject to the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be included
23 : * in all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 : * DEALINGS IN THE SOFTWARE.
32 : **********************************************************************
33 : *
34 : * $Log: avc_e00read.c,v $
35 : * Revision 1.28 2008/07/30 19:22:18 dmorissette
36 : * Move detection of EXP header directly in AVCE00ReadOpenE00() and use
37 : * VSIFGets() instead of CPLReadLine() to avoid problem with huge one line
38 : * files (GDAL/OGR ticket #1989)
39 : *
40 : * Revision 1.27 2008/07/30 18:35:53 dmorissette
41 : * Avoid scanning the whole E00 input file in AVCE00ReadOpenE00() if the
42 : * file does not start with an EXP line (GDAL/OGR ticket 1989)
43 : *
44 : * Revision 1.26 2008/07/30 16:17:46 dmorissette
45 : * Detect compressed E00 input files and refuse to open them instead of
46 : * crashing (bug 1928, GDAL/OGR ticket 2513)
47 : *
48 : * Revision 1.25 2008/07/24 20:34:12 dmorissette
49 : * Fixed VC++ WIN32 build problems in GDAL/OGR environment
50 : * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2500)
51 : *
52 : * Revision 1.24 2008/07/24 13:49:20 dmorissette
53 : * Fixed GCC compiler warning (GDAL ticket #2495)
54 : *
55 : * Revision 1.23 2006/08/17 19:51:01 dmorissette
56 : * #include <unistd.h> to solve warning on 64 bit platforms (bug 1461)
57 : *
58 : * Revision 1.22 2006/08/17 18:56:42 dmorissette
59 : * Support for reading standalone info tables (just tables, no coverage
60 : * data) by pointing AVCE00ReadOpen() to the info directory (bug 1549).
61 : *
62 : * Revision 1.21 2006/06/27 18:38:43 dmorissette
63 : * Cleaned up E00 reading (bug 1497, patch from James F.)
64 : *
65 : * Revision 1.20 2006/06/27 18:06:34 dmorissette
66 : * Applied patch for EOP processing from James F. (bug 1497)
67 : *
68 : * Revision 1.19 2006/06/16 11:48:11 daniel
69 : * New functions to read E00 files directly as opposed to translating to
70 : * binary coverage. Used in the implementation of E00 read support in OGR.
71 : * Contributed by James E. Flemer. (bug 1497)
72 : *
73 : * Revision 1.18 2006/06/14 16:31:28 daniel
74 : * Added support for AVCCoverPC2 type (bug 1491)
75 : *
76 : * Revision 1.17 2005/06/03 03:49:58 daniel
77 : * Update email address, website url, and copyright dates
78 : *
79 : * Revision 1.16 2004/07/14 18:49:50 daniel
80 : * Fixed leak when trying to open something that's not a coverage (bug513)
81 : *
82 : * Revision 1.15 2002/08/27 15:46:15 daniel
83 : * Applied fix made in GDAL/OGR by 'aubin' (moved include ctype.h after avc.h)
84 : *
85 : * Revision 1.14 2000/09/22 19:45:21 daniel
86 : * Switch to MIT-style license
87 : *
88 : * Revision 1.13 2000/05/29 15:31:31 daniel
89 : * Added Japanese DBCS support
90 : *
91 : * Revision 1.12 2000/02/14 17:21:01 daniel
92 : * Made more robust for corrupted or invalid files in cover directory
93 : *
94 : * Revision 1.11 2000/02/02 04:26:04 daniel
95 : * Support reading TX6/TX7/RXP/RPL files in weird coverages
96 : *
97 : * Revision 1.10 2000/01/10 02:56:30 daniel
98 : * Added read support for "weird" coverages
99 : *
100 : * Revision 1.9 2000/01/07 07:12:49 daniel
101 : * Added support for reading PC Coverage TXT files
102 : *
103 : * Revision 1.8 1999/12/24 07:41:08 daniel
104 : * Check fname length before testing for extension in AVCE00ReadFindCoverType()
105 : *
106 : * Revision 1.7 1999/12/24 07:18:34 daniel
107 : * Added PC Arc/Info coverages support
108 : *
109 : * Revision 1.6 1999/08/26 17:22:18 daniel
110 : * Use VSIFopen() instead of fopen() directly
111 : *
112 : * Revision 1.5 1999/08/23 18:21:41 daniel
113 : * New syntax for AVCBinReadListTables()
114 : *
115 : * Revision 1.4 1999/05/11 02:10:01 daniel
116 : * Free psInfo struct inside AVCE00ReadClose()
117 : *
118 : * Revision 1.3 1999/04/06 19:43:26 daniel
119 : * Added E00 coverage path in EXP 0 header line
120 : *
121 : * Revision 1.2 1999/02/25 04:19:01 daniel
122 : * Added TXT, TX6/TX7, RXP and RPL support + other minor changes
123 : *
124 : * Revision 1.1 1999/01/29 16:28:52 daniel
125 : * Initial revision
126 : *
127 : **********************************************************************/
128 :
129 : #include "avc.h"
130 :
131 : #ifdef WIN32
132 : # include <direct.h> /* getcwd() */
133 : #else
134 : # include <unistd.h> /* getcwd() */
135 : #endif
136 :
137 : #include <ctype.h> /* toupper() */
138 :
139 : static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead);
140 : static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo,
141 : char **papszCoverDir);
142 : static AVCCoverType _AVCE00ReadFindCoverType(char **papszCoverDir);
143 :
144 :
145 : /**********************************************************************
146 : * AVCE00ReadOpen()
147 : *
148 : * Open a Arc/Info coverage to read it as if it was an E00 file.
149 : *
150 : * You can either pass the name of the coverage directory, or the path
151 : * to one of the files in the coverage directory. The name of the
152 : * coverage MUST be included in pszCoverPath... this means that
153 : * passing "." is invalid.
154 : * The following are all valid values for pszCoverPath:
155 : * /home/data/country
156 : * /home/data/country/
157 : * /home/data/country/arc.adf
158 : * (Of course you should replace the '/' with '\\' on DOS systems!)
159 : *
160 : * Returns a new AVCE00ReadPtr handle or NULL if the coverage could
161 : * not be opened or if it does not appear to be a valid Arc/Info coverage.
162 : *
163 : * The handle will eventually have to be released with AVCE00ReadClose().
164 : **********************************************************************/
165 27 : AVCE00ReadPtr AVCE00ReadOpen(const char *pszCoverPath)
166 : {
167 : AVCE00ReadPtr psInfo;
168 : int i, nLen, nCoverPrecision;
169 : VSIStatBuf sStatBuf;
170 27 : char **papszCoverDir = NULL;
171 :
172 27 : CPLErrorReset();
173 :
174 : /*-----------------------------------------------------------------
175 : * pszCoverPath must be either a valid directory name or a valid
176 : * file name.
177 : *----------------------------------------------------------------*/
178 53 : if (pszCoverPath == NULL || strlen(pszCoverPath) == 0 ||
179 26 : VSIStat(pszCoverPath, &sStatBuf) == -1)
180 : {
181 3 : CPLError(CE_Failure, CPLE_OpenFailed,
182 : "Invalid coverage path: %s.",
183 : pszCoverPath?pszCoverPath:"(NULL)");
184 3 : return NULL;
185 : }
186 :
187 : /*-----------------------------------------------------------------
188 : * Alloc the AVCE00ReadPtr handle
189 : *----------------------------------------------------------------*/
190 24 : psInfo = (AVCE00ReadPtr)CPLCalloc(1, sizeof(struct AVCE00ReadInfo_t));
191 :
192 : /*-----------------------------------------------------------------
193 : * 2 possibilities about the value passed in pszCoverPath:
194 : * - It can be the directory name of the coverage
195 : * - or it can be the path to one of the files in the coverage
196 : *
197 : * If the name passed in pszCoverPath is not a directory, then we
198 : * need to strip the last part of the filename to keep only the
199 : * path, terminated by a '/' (or a '\\').
200 : *----------------------------------------------------------------*/
201 24 : if (VSI_ISDIR(sStatBuf.st_mode))
202 : {
203 : /*-------------------------------------------------------------
204 : * OK, we have a valid directory name... make sure it is
205 : * terminated with a '/' (or '\\')
206 : *------------------------------------------------------------*/
207 1 : nLen = strlen(pszCoverPath);
208 :
209 1 : if (pszCoverPath[nLen-1] == '/' || pszCoverPath[nLen-1] == '\\')
210 0 : psInfo->pszCoverPath = CPLStrdup(pszCoverPath);
211 : else
212 : {
213 : #ifdef WIN32
214 : psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s\\",pszCoverPath));
215 : #else
216 1 : psInfo->pszCoverPath = CPLStrdup(CPLSPrintf("%s/",pszCoverPath));
217 : #endif
218 : }
219 : }
220 : else
221 : {
222 : /*-------------------------------------------------------------
223 : * We are dealing with a filename.
224 : * Extract the coverage path component and store it.
225 : * The coverage path will remain terminated by a '/' or '\\' char.
226 : *------------------------------------------------------------*/
227 23 : psInfo->pszCoverPath = CPLStrdup(pszCoverPath);
228 :
229 1020 : for( i = strlen(psInfo->pszCoverPath)-1;
230 340 : i > 0 && psInfo->pszCoverPath[i] != '/' &&
231 317 : psInfo->pszCoverPath[i] != '\\';
232 317 : i-- ) {}
233 :
234 23 : psInfo->pszCoverPath[i+1] = '\0';
235 : }
236 :
237 :
238 : /*-----------------------------------------------------------------
239 : * Extract the coverage name from the coverage path. Note that
240 : * for this the coverage path must be in the form:
241 : * "dir1/dir2/dir3/covername/" ... if it is not the case, then
242 : * we would have to use getcwd() to find the current directory name...
243 : * but for now we'll just produce an error if this happens.
244 : *----------------------------------------------------------------*/
245 24 : nLen = 0;
246 397 : for( i = strlen(psInfo->pszCoverPath)-1;
247 88 : i > 0 && psInfo->pszCoverPath[i-1] != '/' &&
248 87 : psInfo->pszCoverPath[i-1] != '\\'&&
249 87 : psInfo->pszCoverPath[i-1] != ':';
250 87 : i-- )
251 : {
252 87 : nLen++;
253 : }
254 :
255 24 : if (nLen > 0)
256 : {
257 24 : psInfo->pszCoverName = CPLStrdup(psInfo->pszCoverPath+i);
258 24 : psInfo->pszCoverName[nLen] = '\0';
259 : }
260 : else
261 : {
262 0 : CPLError(CE_Failure, CPLE_OpenFailed,
263 : "Invalid coverage path (%s): "
264 : "coverage name must be included in path.", pszCoverPath);
265 :
266 0 : CPLFree(psInfo->pszCoverPath);
267 0 : CPLFree(psInfo);
268 0 : return NULL;
269 : }
270 :
271 : /*-----------------------------------------------------------------
272 : * Read the coverage directory listing and try to establish the cover type
273 : *----------------------------------------------------------------*/
274 24 : papszCoverDir = CPLReadDir(psInfo->pszCoverPath);
275 :
276 24 : psInfo->eCoverType = _AVCE00ReadFindCoverType(papszCoverDir);
277 :
278 24 : if (psInfo->eCoverType == AVCCoverTypeUnknown )
279 : {
280 23 : CPLError(CE_Failure, CPLE_OpenFailed,
281 : "Invalid coverage (%s): directory does not appear to "
282 : "contain any supported vector coverage file.", pszCoverPath);
283 23 : CPLFree(psInfo->pszCoverName);
284 23 : CPLFree(psInfo->pszCoverPath);
285 23 : CPLFree(psInfo->pszInfoPath);
286 23 : CPLFree(psInfo);
287 23 : CSLDestroy(papszCoverDir);
288 23 : return NULL;
289 : }
290 :
291 :
292 : /*-----------------------------------------------------------------
293 : * INFO path: PC Coverages have all files in the same dir, and unix
294 : * covers have the INFO files in ../info
295 : *----------------------------------------------------------------*/
296 1 : if (psInfo->eCoverType == AVCCoverPC || psInfo->eCoverType == AVCCoverPC2)
297 : {
298 0 : psInfo->pszInfoPath = CPLStrdup(psInfo->pszCoverPath);
299 : }
300 : else
301 : {
302 : /*-------------------------------------------------------------
303 : * Lazy way to build the INFO path: simply add "../info/"...
304 : * this could probably be improved!
305 : *------------------------------------------------------------*/
306 1 : psInfo->pszInfoPath =(char*)CPLMalloc((strlen(psInfo->pszCoverPath)+9)*
307 : sizeof(char));
308 : #ifdef WIN32
309 : # define AVC_INFOPATH "..\\info\\"
310 : #else
311 : # define AVC_INFOPATH "../info/"
312 : #endif
313 1 : sprintf(psInfo->pszInfoPath, "%s%s", psInfo->pszCoverPath,
314 : AVC_INFOPATH);
315 :
316 1 : AVCAdjustCaseSensitiveFilename(psInfo->pszInfoPath);
317 : }
318 :
319 : /*-----------------------------------------------------------------
320 : * For Unix coverages, check that the info directory exists and
321 : * contains the "arc.dir". In AVCCoverWeird, the arc.dir is
322 : * called "../INFO/ARCDR9".
323 : * PC Coverages have their info tables in the same direcotry as
324 : * the coverage files.
325 : *----------------------------------------------------------------*/
326 3 : if (((psInfo->eCoverType == AVCCoverV7 ||
327 0 : psInfo->eCoverType == AVCCoverV7Tables) &&
328 1 : ! AVCFileExists(psInfo->pszInfoPath, "arc.dir") ) ||
329 1 : (psInfo->eCoverType == AVCCoverWeird &&
330 0 : ! AVCFileExists(psInfo->pszInfoPath, "arcdr9") ) )
331 : {
332 0 : CPLError(CE_Failure, CPLE_OpenFailed,
333 : "Invalid coverage (%s): 'info' directory not found or invalid.",
334 : pszCoverPath);
335 0 : CPLFree(psInfo->pszCoverName);
336 0 : CPLFree(psInfo->pszCoverPath);
337 0 : CPLFree(psInfo->pszInfoPath);
338 0 : CPLFree(psInfo);
339 0 : CSLDestroy(papszCoverDir);
340 0 : return NULL;
341 : }
342 :
343 : /*-----------------------------------------------------------------
344 : * Make sure there was no error until now before we build squeleton.
345 : *----------------------------------------------------------------*/
346 1 : if (CPLGetLastErrorNo() != 0)
347 : {
348 0 : CPLFree(psInfo->pszCoverName);
349 0 : CPLFree(psInfo->pszCoverPath);
350 0 : CPLFree(psInfo->pszInfoPath);
351 0 : CPLFree(psInfo);
352 0 : CSLDestroy(papszCoverDir);
353 0 : return NULL;
354 : }
355 :
356 : /*-----------------------------------------------------------------
357 : * Build the E00 file squeleton and be ready to return a E00 header...
358 : * We'll also read the coverage precision by the same way.
359 : *----------------------------------------------------------------*/
360 1 : nCoverPrecision = _AVCE00ReadBuildSqueleton(psInfo, papszCoverDir);
361 :
362 : /* Ignore warnings produced while building squeleton */
363 1 : CPLErrorReset();
364 :
365 1 : CSLDestroy(papszCoverDir);
366 1 : papszCoverDir = NULL;
367 :
368 1 : psInfo->iCurSection = 0;
369 1 : psInfo->iCurStep = AVC_GEN_NOTSTARTED;
370 1 : psInfo->bReadAllSections = TRUE;
371 :
372 : /*-----------------------------------------------------------------
373 : * Init the E00 generator.
374 : *----------------------------------------------------------------*/
375 1 : psInfo->hGenInfo = AVCE00GenInfoAlloc(nCoverPrecision);
376 :
377 : /*-----------------------------------------------------------------
378 : * Init multibyte encoding info
379 : *----------------------------------------------------------------*/
380 1 : psInfo->psDBCSInfo = AVCAllocDBCSInfo();
381 :
382 : /*-----------------------------------------------------------------
383 : * If an error happened during the open call, cleanup and return NULL.
384 : *----------------------------------------------------------------*/
385 1 : if (CPLGetLastErrorNo() != 0)
386 : {
387 0 : AVCE00ReadClose(psInfo);
388 0 : psInfo = NULL;
389 : }
390 :
391 1 : return psInfo;
392 : }
393 :
394 : /**********************************************************************
395 : * AVCE00ReadOpenE00()
396 : *
397 : * Open a E00 file for reading.
398 : *
399 : * Returns a new AVCE00ReadE00Ptr handle or NULL if the file could
400 : * not be opened or if it does not appear to be a valid E00 file.
401 : *
402 : * The handle will eventually have to be released with
403 : * AVCE00ReadCloseE00().
404 : **********************************************************************/
405 52 : AVCE00ReadE00Ptr AVCE00ReadOpenE00(const char *pszE00FileName)
406 : {
407 : AVCE00ReadE00Ptr psRead;
408 : VSIStatBuf sStatBuf;
409 : FILE *fp;
410 : char *p;
411 : char szHeader[10];
412 :
413 52 : CPLErrorReset();
414 :
415 : /*-----------------------------------------------------------------
416 : * pszE00FileName must be a valid file that can be opened for
417 : * reading
418 : *----------------------------------------------------------------*/
419 148 : if (pszE00FileName == NULL || strlen(pszE00FileName) == 0 ||
420 50 : VSIStat(pszE00FileName, &sStatBuf) == -1 ||
421 46 : VSI_ISDIR(sStatBuf.st_mode))
422 : {
423 6 : CPLError(CE_Failure, CPLE_OpenFailed,
424 : "Invalid E00 file path: %s.",
425 : pszE00FileName?pszE00FileName:"(NULL)");
426 6 : return NULL;
427 : }
428 :
429 46 : if (NULL == (fp = VSIFOpen(pszE00FileName, "r")))
430 0 : return NULL;
431 :
432 : /*-----------------------------------------------------------------
433 : * Make sure the file starts with a "EXP 0" or "EXP 1" header
434 : *----------------------------------------------------------------*/
435 46 : if (VSIFGets(szHeader, 5, fp) == NULL || !EQUALN("EXP ", szHeader, 4) )
436 : {
437 44 : CPLError(CE_Failure, CPLE_OpenFailed,
438 : "This does not look like a E00 file: does not start with "
439 : "a EXP header." );
440 44 : VSIFClose(fp);
441 44 : return NULL;
442 : }
443 2 : VSIRewind(fp);
444 :
445 : /*-----------------------------------------------------------------
446 : * Alloc the AVCE00ReadE00Ptr handle
447 : *----------------------------------------------------------------*/
448 2 : psRead = (AVCE00ReadE00Ptr)CPLCalloc(1,
449 : sizeof(struct AVCE00ReadInfoE00_t));
450 :
451 2 : psRead->hFile = fp;
452 2 : psRead->pszCoverPath = CPLStrdup(pszE00FileName);
453 2 : psRead->eCurFileType = AVCFileUnknown;
454 :
455 : /*-----------------------------------------------------------------
456 : * Extract the coverage name from the coverage path.
457 : *----------------------------------------------------------------*/
458 4 : if (NULL != (p = strrchr(psRead->pszCoverPath, '/')) ||
459 0 : NULL != (p = strrchr(psRead->pszCoverPath, '\\')) ||
460 0 : NULL != (p = strrchr(psRead->pszCoverPath, ':')))
461 : {
462 2 : psRead->pszCoverName = CPLStrdup(p + 1);
463 : }
464 : else
465 : {
466 0 : psRead->pszCoverName = CPLStrdup(psRead->pszCoverPath);
467 : }
468 2 : if (NULL != (p = strrchr(psRead->pszCoverName, '.')))
469 : {
470 2 : *p = '\0';
471 : }
472 :
473 : /*-----------------------------------------------------------------
474 : * Make sure there was no error until now before we scan file.
475 : *----------------------------------------------------------------*/
476 2 : if (CPLGetLastErrorNo() != 0)
477 : {
478 0 : AVCE00ReadCloseE00(psRead);
479 0 : return NULL;
480 : }
481 :
482 2 : psRead->hParseInfo = AVCE00ParseInfoAlloc();
483 :
484 : /*-----------------------------------------------------------------
485 : * Scan the E00 file for sections
486 : *----------------------------------------------------------------*/
487 2 : _AVCE00ReadScanE00(psRead);
488 2 : AVCE00ReadRewindE00(psRead);
489 2 : CPLErrorReset();
490 :
491 2 : if (psRead->numSections < 1)
492 : {
493 0 : AVCE00ReadCloseE00(psRead);
494 0 : return NULL;
495 : }
496 :
497 2 : psRead->bReadAllSections = TRUE;
498 :
499 : /*-----------------------------------------------------------------
500 : * If an error happened during the open call, cleanup and return NULL.
501 : *----------------------------------------------------------------*/
502 2 : if (CPLGetLastErrorNo() != 0)
503 : {
504 0 : AVCE00ReadCloseE00(psRead);
505 0 : psRead = NULL;
506 : }
507 :
508 2 : return psRead;
509 : }
510 :
511 : /**********************************************************************
512 : * AVCE00ReadClose()
513 : *
514 : * Close a coverage and release all memory used by the AVCE00ReadPtr
515 : * handle.
516 : **********************************************************************/
517 1 : void AVCE00ReadClose(AVCE00ReadPtr psInfo)
518 : {
519 1 : CPLErrorReset();
520 :
521 1 : if (psInfo == NULL)
522 0 : return;
523 :
524 1 : CPLFree(psInfo->pszCoverPath);
525 1 : CPLFree(psInfo->pszInfoPath);
526 1 : CPLFree(psInfo->pszCoverName);
527 :
528 1 : if (psInfo->hFile)
529 0 : AVCBinReadClose(psInfo->hFile);
530 :
531 1 : if (psInfo->hGenInfo)
532 1 : AVCE00GenInfoFree(psInfo->hGenInfo);
533 :
534 1 : if (psInfo->pasSections)
535 : {
536 : int i;
537 13 : for(i=0; i<psInfo->numSections; i++)
538 : {
539 12 : CPLFree(psInfo->pasSections[i].pszName);
540 12 : CPLFree(psInfo->pasSections[i].pszFilename);
541 : }
542 1 : CPLFree(psInfo->pasSections);
543 : }
544 :
545 1 : AVCFreeDBCSInfo(psInfo->psDBCSInfo);
546 :
547 1 : CPLFree(psInfo);
548 : }
549 :
550 : /**********************************************************************
551 : * AVCE00ReadCloseE00()
552 : *
553 : * Close a coverage and release all memory used by the AVCE00ReadE00Ptr
554 : * handle.
555 : **********************************************************************/
556 2 : void AVCE00ReadCloseE00(AVCE00ReadE00Ptr psRead)
557 : {
558 2 : CPLErrorReset();
559 :
560 2 : if (psRead == NULL)
561 0 : return;
562 :
563 2 : CPLFree(psRead->pszCoverPath);
564 2 : CPLFree(psRead->pszCoverName);
565 :
566 2 : if (psRead->hFile)
567 : {
568 2 : VSIFClose(psRead->hFile);
569 2 : psRead->hFile = 0;
570 : }
571 :
572 2 : if (psRead->pasSections)
573 : {
574 : int i;
575 16 : for(i=0; i<psRead->numSections; i++)
576 : {
577 14 : CPLFree(psRead->pasSections[i].pszName);
578 14 : CPLFree(psRead->pasSections[i].pszFilename);
579 : }
580 2 : CPLFree(psRead->pasSections);
581 : }
582 :
583 : /* These Free calls handle NULL's */
584 2 : AVCE00ParseInfoFree(psRead->hParseInfo);
585 2 : psRead->hParseInfo = NULL;
586 :
587 2 : CPLFree(psRead);
588 : }
589 :
590 :
591 : /**********************************************************************
592 : * _AVCIncreaseSectionsArray()
593 : *
594 : * Add a number of structures to the Sections array and return the
595 : * index of the first one that was added. Note that the address of the
596 : * original array (*pasArray) is quite likely to change!
597 : *
598 : * The value of *pnumItems will be updated to reflect the new array size.
599 : **********************************************************************/
600 22 : static int _AVCIncreaseSectionsArray(AVCE00Section **pasArray, int *pnumItems,
601 : int numToAdd)
602 : {
603 : int i;
604 :
605 22 : *pasArray = (AVCE00Section*)CPLRealloc(*pasArray,
606 22 : (*pnumItems+numToAdd)*
607 : sizeof(AVCE00Section));
608 :
609 48 : for(i=0; i<numToAdd; i++)
610 : {
611 26 : (*pasArray)[*pnumItems+i].eType = AVCFileUnknown;
612 26 : (*pasArray)[*pnumItems+i].pszName = NULL;
613 26 : (*pasArray)[*pnumItems+i].pszFilename = NULL;
614 26 : (*pasArray)[*pnumItems+i].nLineNum = 0;
615 26 : (*pasArray)[*pnumItems+i].nFeatureCount = -1;
616 : }
617 :
618 22 : i = *pnumItems;
619 22 : (*pnumItems) += numToAdd;
620 :
621 22 : return i;
622 : }
623 :
624 : /**********************************************************************
625 : * _AVCE00ReadFindCoverType()
626 : *
627 : * This functions tries to establish the coverage type by looking
628 : * at the coverage directory listing passed as argument.
629 : *
630 : * Returns one of AVCCoverV7 for Arc/Info V7 (Unix) coverages, or
631 : * AVCCoverPC for PC Arc/Info coverages.
632 : * AVCCoverWeird for an hybrid between V7 and PC
633 : *
634 : * If coverage type cannot be established then AVCCoverTypeUnknown is
635 : * returned.
636 : **********************************************************************/
637 24 : static AVCCoverType _AVCE00ReadFindCoverType(char **papszCoverDir)
638 : {
639 : int i, nLen;
640 24 : GBool bFoundAdfFile=FALSE, bFoundArcFile=FALSE,
641 24 : bFoundTableFile=FALSE, bFoundDbfFile=FALSE,
642 24 : bFoundArcDirFile=FALSE;
643 :
644 : /*-----------------------------------------------------------------
645 : * Scan the list of files, looking for well known filenames.
646 : * Start with the funky types first...
647 : *----------------------------------------------------------------*/
648 1589 : for(i=0; papszCoverDir && papszCoverDir[i]; i++)
649 : {
650 1565 : nLen = strlen(papszCoverDir[i]);
651 1572 : if (nLen > 4 && EQUAL(papszCoverDir[i]+nLen-4, ".adf") )
652 : {
653 7 : bFoundAdfFile = TRUE;
654 : }
655 1767 : else if (nLen > 4 && EQUAL(papszCoverDir[i]+nLen-4, ".dbf") )
656 : {
657 209 : bFoundDbfFile = TRUE;
658 : }
659 8094 : else if (EQUAL(papszCoverDir[i], "arc") ||
660 1349 : EQUAL(papszCoverDir[i], "cnt") ||
661 1349 : EQUAL(papszCoverDir[i], "pal") ||
662 1349 : EQUAL(papszCoverDir[i], "lab") ||
663 1349 : EQUAL(papszCoverDir[i], "prj") ||
664 1349 : EQUAL(papszCoverDir[i], "tol") )
665 : {
666 0 : bFoundArcFile = TRUE;
667 : }
668 5396 : else if (EQUAL(papszCoverDir[i], "aat") ||
669 1349 : EQUAL(papszCoverDir[i], "pat") ||
670 1349 : EQUAL(papszCoverDir[i], "bnd") ||
671 1349 : EQUAL(papszCoverDir[i], "tic") )
672 : {
673 0 : bFoundTableFile = TRUE;
674 : }
675 1349 : else if (EQUAL(papszCoverDir[i], "arc.dir") )
676 : {
677 0 : bFoundArcDirFile = TRUE;
678 : }
679 :
680 : }
681 :
682 : /*-----------------------------------------------------------------
683 : * Check for PC Arc/Info coverage - variant 1.
684 : * These PC coverages have files with no extension (e.g. "ARC","PAL",...)
685 : * and their tables filenames are in the form "???.dbf"
686 : *----------------------------------------------------------------*/
687 24 : if (bFoundArcFile && bFoundDbfFile)
688 0 : return AVCCoverPC;
689 :
690 : /*-----------------------------------------------------------------
691 : * Check for PC Arc/Info coverage - variant 2.
692 : * looks like a hybrid between AVCCoverPC and AVCCoverV7
693 : * These PC coverages have files with .adf extension (e.g."ARC.ADF"),
694 : * and their tables filenames are in the form "???.dbf"
695 : *----------------------------------------------------------------*/
696 24 : if (bFoundAdfFile && bFoundDbfFile)
697 0 : return AVCCoverPC2;
698 :
699 : /*-----------------------------------------------------------------
700 : * Check for the weird coverages.
701 : * Their coverage files have no extension just like PC Coverages,
702 : * and their tables have 3 letters filenames with no extension
703 : * either (e.g. "AAT", "PAT", etc.)
704 : * They also have a ../info directory, but we don't really need
705 : * to check that (not yet!).
706 : *----------------------------------------------------------------*/
707 24 : if (bFoundArcFile && bFoundTableFile)
708 0 : return AVCCoverWeird;
709 :
710 : /*-----------------------------------------------------------------
711 : * V7 Coverages... they are the easiest to recognize
712 : * because of the ".adf" file extension
713 : *----------------------------------------------------------------*/
714 24 : if (bFoundAdfFile)
715 1 : return AVCCoverV7;
716 :
717 : /*-----------------------------------------------------------------
718 : * Standalone info tables.
719 : * We were pointed at the "info" directory. We'll treat this as
720 : * a coverage with just info tables.
721 : *----------------------------------------------------------------*/
722 23 : if (bFoundArcDirFile)
723 0 : return AVCCoverV7Tables;
724 :
725 23 : return AVCCoverTypeUnknown;
726 : }
727 :
728 :
729 : /**********************************************************************
730 : * _AVCE00ReadAddJabberwockySection()
731 : *
732 : * Add to the squeleton a section that contains subsections
733 : * for all the files with a given extension.
734 : *
735 : * Returns Updated Coverage precision
736 : **********************************************************************/
737 3 : static int _AVCE00ReadAddJabberwockySection(AVCE00ReadPtr psInfo,
738 : AVCFileType eFileType,
739 : const char *pszSectionName,
740 : int nCoverPrecision,
741 : const char *pszFileExtension,
742 : char **papszCoverDir )
743 : {
744 : int iSect, iDirEntry, nLen, nExtLen;
745 3 : GBool bFoundFiles = FALSE;
746 3 : AVCBinFile *psFile=NULL;
747 :
748 3 : nExtLen = strlen(pszFileExtension);
749 :
750 : /*-----------------------------------------------------------------
751 : * Scan the directory for files with a ".txt" extension.
752 : *----------------------------------------------------------------*/
753 :
754 33 : for (iDirEntry=0; papszCoverDir && papszCoverDir[iDirEntry]; iDirEntry++)
755 : {
756 30 : nLen = strlen(papszCoverDir[iDirEntry]);
757 :
758 30 : if (nLen > nExtLen && EQUAL(papszCoverDir[iDirEntry] + nLen-nExtLen,
759 : pszFileExtension) &&
760 0 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath,
761 0 : papszCoverDir[iDirEntry],
762 : psInfo->eCoverType, eFileType,
763 : psInfo->psDBCSInfo)) != NULL)
764 : {
765 0 : if (nCoverPrecision == AVC_DEFAULT_PREC)
766 0 : nCoverPrecision = psFile->nPrecision;
767 0 : AVCBinReadClose(psFile);
768 :
769 0 : if (bFoundFiles == FALSE)
770 : {
771 : /* Insert a "TX6 #" header before the first TX6 file
772 : */
773 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
774 : &(psInfo->numSections), 1);
775 0 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
776 :
777 0 : psInfo->pasSections[iSect].pszName =
778 0 : CPLStrdup(CPLSPrintf("%s %c", pszSectionName,
779 : (nCoverPrecision==AVC_DOUBLE_PREC)?'3':'2'));
780 :
781 0 : bFoundFiles = TRUE;
782 : }
783 :
784 : /* Add this file to the squeleton
785 : */
786 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
787 : &(psInfo->numSections), 1);
788 :
789 0 : psInfo->pasSections[iSect].eType = eFileType;
790 0 : psInfo->pasSections[iSect].pszFilename=
791 0 : CPLStrdup(papszCoverDir[iDirEntry]);
792 :
793 : /* pszName will contain only the classname without the file
794 : * extension */
795 0 : psInfo->pasSections[iSect].pszName =
796 0 : CPLStrdup(papszCoverDir[iDirEntry]);
797 0 : psInfo->pasSections[iSect].pszName[nLen-nExtLen] = '\0';
798 : }
799 : }
800 :
801 3 : if (bFoundFiles)
802 : {
803 : /* Add a line to close the TX6 section.
804 : */
805 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
806 : &(psInfo->numSections), 1);
807 0 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
808 0 : psInfo->pasSections[iSect].pszName = CPLStrdup("JABBERWOCKY");
809 : }
810 :
811 3 : return nCoverPrecision;
812 : }
813 :
814 : /**********************************************************************
815 : * _AVCE00ReadNextLineE00()
816 : *
817 : * Processes the next line of input from the E00 file.
818 : * (See AVCE00WriteNextLine() for similar processing.)
819 : *
820 : * Returns the next object from the E00 file, or NULL.
821 : **********************************************************************/
822 250 : static void *_AVCE00ReadNextLineE00(AVCE00ReadE00Ptr psRead,
823 : const char *pszLine)
824 : {
825 250 : int nStatus = 0;
826 250 : void *psObj = 0;
827 :
828 250 : AVCE00ParseInfo *psInfo = psRead->hParseInfo;
829 :
830 250 : CPLErrorReset();
831 :
832 250 : ++psInfo->nCurLineNum;
833 :
834 250 : if (psInfo->bForceEndOfSection)
835 : {
836 : /*-------------------------------------------------------------
837 : * The last call encountered an implicit end of section, so
838 : * we close the section now without waiting for an end-of-section
839 : * line (there won't be any!)... and get ready to proceed with
840 : * the next section.
841 : * This is used for TABLEs.
842 : *------------------------------------------------------------*/
843 10 : AVCE00ParseSectionEnd(psInfo, pszLine, TRUE);
844 10 : psRead->eCurFileType = AVCFileUnknown;
845 : }
846 :
847 : /*-----------------------------------------------------------------
848 : * If we're at the top level inside a supersection... check if this
849 : * supersection ends here.
850 : *----------------------------------------------------------------*/
851 250 : if (AVCE00ParseSuperSectionEnd(psInfo, pszLine) == TRUE)
852 : {
853 : /* Nothing to do... it's all been done by the call to
854 : * AVCE00ParseSuperSectionEnd()
855 : */
856 : }
857 248 : else if (psRead->eCurFileType == AVCFileUnknown)
858 : {
859 : /*-------------------------------------------------------------
860 : * We're at the top level or inside a supersection... waiting
861 : * to encounter a valid section or supersection header
862 : * (i.e. "ARC 2", etc...)
863 : *------------------------------------------------------------*/
864 :
865 : /*-------------------------------------------------------------
866 : * First check for a supersection header (TX6, RXP, IFO, ...)
867 : *------------------------------------------------------------*/
868 29 : if ( AVCE00ParseSuperSectionHeader(psInfo,
869 : pszLine) == AVCFileUnknown )
870 : {
871 : /*---------------------------------------------------------
872 : * This was not a supersection header... check if it's a simple
873 : * section header
874 : *--------------------------------------------------------*/
875 27 : psRead->eCurFileType = AVCE00ParseSectionHeader(psInfo,
876 : pszLine);
877 : }
878 : else
879 : {
880 : /* got supersection */
881 : }
882 :
883 29 : if (psRead->eCurFileType == AVCFileTABLE)
884 : {
885 : /*---------------------------------------------------------
886 : * send the first header line to the parser and wait until
887 : * the whole header has been read.
888 : *--------------------------------------------------------*/
889 8 : AVCE00ParseNextLine(psInfo, pszLine);
890 : }
891 21 : else if (psRead->eCurFileType != AVCFileUnknown)
892 : {
893 : /*---------------------------------------------------------
894 : * found a valid section header
895 : *--------------------------------------------------------*/
896 : }
897 : }
898 357 : else if (psRead->eCurFileType == AVCFileTABLE &&
899 92 : ! psInfo->bTableHdrComplete )
900 : {
901 : /*-------------------------------------------------------------
902 : * We're reading a TABLE header... continue reading lines
903 : * from the header
904 : *
905 : * Note: When parsing a TABLE, the first object returned will
906 : * be the AVCTableDef, then data records will follow.
907 : *------------------------------------------------------------*/
908 46 : psObj = AVCE00ParseNextLine(psInfo, pszLine);
909 46 : if (psObj)
910 : {
911 : /* got table header */
912 : /* TODO: Enable return of table definition? */
913 8 : psObj = NULL;
914 : }
915 : }
916 : else
917 : {
918 : /*-------------------------------------------------------------
919 : * We're are in the middle of a section... first check if we
920 : * have reached the end.
921 : *
922 : * note: The first call to AVCE00ParseSectionEnd() with FALSE will
923 : * not reset the parser until we close the file... and then
924 : * we call the function again to reset the parser.
925 : *------------------------------------------------------------*/
926 173 : if (AVCE00ParseSectionEnd(psInfo, pszLine, FALSE))
927 : {
928 7 : psRead->eCurFileType = AVCFileUnknown;
929 7 : AVCE00ParseSectionEnd(psInfo, pszLine, TRUE);
930 : }
931 : else
932 : /*-------------------------------------------------------------
933 : * ... not at the end yet, so continue reading objects.
934 : *------------------------------------------------------------*/
935 : {
936 166 : psObj = AVCE00ParseNextLine(psInfo, pszLine);
937 :
938 : if (psObj)
939 : {
940 : /* got object */
941 : }
942 : }
943 : }
944 :
945 250 : if (CPLGetLastErrorNo() != 0)
946 0 : nStatus = -1;
947 :
948 250 : return psObj;
949 : }
950 :
951 : /**********************************************************************
952 : * _AVCE00ReadBuildSqueleton()
953 : *
954 : * Build the squeleton of the E00 file corresponding to the specified
955 : * coverage and set the appropriate fields in the AVCE00ReadPtr struct.
956 : *
957 : * Note that the order of the sections in the squeleton is important
958 : * since some software may rely on this ordering when they read E00 files.
959 : *
960 : * The function returns the coverage precision that it will read from one
961 : * of the file headers.
962 : **********************************************************************/
963 1 : static int _AVCE00ReadBuildSqueleton(AVCE00ReadPtr psInfo,
964 : char **papszCoverDir)
965 : {
966 : int iSect, iTable, numTables, iFile, nLen;
967 1 : char **papszTables, **papszFiles, szCWD[75]="", *pcTmp;
968 1 : char *pszEXPPath=NULL;
969 1 : int nCoverPrecision = AVC_DEFAULT_PREC;
970 1 : char cPrecisionCode = '2';
971 1 : const char *szFname = NULL;
972 1 : AVCBinFile *psFile=NULL;
973 :
974 1 : psInfo->numSections = 0;
975 1 : psInfo->pasSections = NULL;
976 :
977 : /*-----------------------------------------------------------------
978 : * Build the absolute coverage path to include in the EXP 0 line
979 : * This line usually contains the full path of the E00 file that
980 : * is being created, but since the lib does not write the output
981 : * file directly, there is no simple way to get that value. Instead,
982 : * we will use the absolute coverage path to which we add a .E00
983 : * extension.
984 : * We need also make sure cover path is all in uppercase.
985 : *----------------------------------------------------------------*/
986 : #ifdef WIN32
987 : if (psInfo->pszCoverPath[0] != '\\' &&
988 : !(isalpha(psInfo->pszCoverPath[0]) && psInfo->pszCoverPath[1] == ':'))
989 : #else
990 1 : if (psInfo->pszCoverPath[0] != '/')
991 : #endif
992 : {
993 1 : if (getcwd(szCWD, 74) == NULL)
994 0 : szCWD[0] = '\0'; /* Failed: buffer may be too small */
995 :
996 1 : nLen = strlen(szCWD);
997 :
998 : #ifdef WIN32
999 : if (nLen > 0 && szCWD[nLen -1] != '\\')
1000 : strcat(szCWD, "\\");
1001 : #else
1002 1 : if (nLen > 0 && szCWD[nLen -1] != '/')
1003 1 : strcat(szCWD, "/");
1004 : #endif
1005 : }
1006 :
1007 2 : pszEXPPath = CPLStrdup(CPLSPrintf("EXP 0 %s%-.*s.E00", szCWD,
1008 1 : (int)strlen(psInfo->pszCoverPath)-1,
1009 : psInfo->pszCoverPath));
1010 1 : pcTmp = pszEXPPath;
1011 54 : for( ; *pcTmp != '\0'; pcTmp++)
1012 53 : *pcTmp = toupper(*pcTmp);
1013 :
1014 : /*-----------------------------------------------------------------
1015 : * EXP Header
1016 : *----------------------------------------------------------------*/
1017 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1018 : &(psInfo->numSections), 1);
1019 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1020 1 : psInfo->pasSections[iSect].pszName = pszEXPPath;
1021 :
1022 : /*-----------------------------------------------------------------
1023 : * We have to try to open each file as we go for 2 reasons:
1024 : * - To validate the file's signature in order to detect cases like a user
1025 : * that places files such as "mystuff.txt" in the cover directory...
1026 : * this has already happened and obviously lead to problems!)
1027 : * - We also need to find the coverage's precision from the headers
1028 : *----------------------------------------------------------------*/
1029 :
1030 : /*-----------------------------------------------------------------
1031 : * ARC section (arc.adf)
1032 : *----------------------------------------------------------------*/
1033 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1034 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "arc.adf": "arc";
1035 2 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1036 1 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1037 : psInfo->eCoverType, AVCFileARC,
1038 : psInfo->psDBCSInfo)) != NULL)
1039 : {
1040 1 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1041 1 : nCoverPrecision = psFile->nPrecision;
1042 1 : AVCBinReadClose(psFile);
1043 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1044 : &(psInfo->numSections), 1);
1045 :
1046 1 : psInfo->pasSections[iSect].eType = AVCFileARC;
1047 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("ARC");
1048 1 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1049 : }
1050 :
1051 : /*-----------------------------------------------------------------
1052 : * CNT section (cnt.adf)
1053 : *----------------------------------------------------------------*/
1054 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1055 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "cnt.adf": "cnt";
1056 1 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1057 0 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1058 : psInfo->eCoverType, AVCFileCNT,
1059 : psInfo->psDBCSInfo)) != NULL)
1060 : {
1061 0 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1062 0 : nCoverPrecision = psFile->nPrecision;
1063 0 : AVCBinReadClose(psFile);
1064 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1065 : &(psInfo->numSections), 1);
1066 :
1067 0 : psInfo->pasSections[iSect].eType = AVCFileCNT;
1068 0 : psInfo->pasSections[iSect].pszName = CPLStrdup("CNT");
1069 0 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1070 : }
1071 :
1072 : /*-----------------------------------------------------------------
1073 : * LAB section (lab.adf)
1074 : *----------------------------------------------------------------*/
1075 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1076 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "lab.adf": "lab";
1077 2 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1078 1 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1079 : psInfo->eCoverType, AVCFileLAB,
1080 : psInfo->psDBCSInfo)) != NULL)
1081 : {
1082 1 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1083 0 : nCoverPrecision = psFile->nPrecision;
1084 1 : AVCBinReadClose(psFile);
1085 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1086 : &(psInfo->numSections), 1);
1087 :
1088 1 : psInfo->pasSections[iSect].eType = AVCFileLAB;
1089 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("LAB");
1090 1 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1091 : }
1092 :
1093 : /*-----------------------------------------------------------------
1094 : * PAL section (pal.adf)
1095 : *----------------------------------------------------------------*/
1096 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1097 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "pal.adf": "pal";
1098 1 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1099 0 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1100 : psInfo->eCoverType, AVCFilePAL,
1101 : psInfo->psDBCSInfo)) != NULL)
1102 : {
1103 0 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1104 0 : nCoverPrecision = psFile->nPrecision;
1105 0 : AVCBinReadClose(psFile);
1106 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1107 : &(psInfo->numSections), 1);
1108 :
1109 0 : psInfo->pasSections[iSect].eType = AVCFilePAL;
1110 0 : psInfo->pasSections[iSect].pszName = CPLStrdup("PAL");
1111 0 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1112 : }
1113 :
1114 : /*-----------------------------------------------------------------
1115 : * TOL section (tol.adf for single precision, par.adf for double)
1116 : *----------------------------------------------------------------*/
1117 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1118 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "tol.adf": "tol";
1119 2 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1120 1 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1121 : psInfo->eCoverType, AVCFileTOL,
1122 : psInfo->psDBCSInfo)) != NULL)
1123 : {
1124 1 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1125 0 : nCoverPrecision = psFile->nPrecision;
1126 1 : AVCBinReadClose(psFile);
1127 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1128 : &(psInfo->numSections), 1);
1129 :
1130 1 : psInfo->pasSections[iSect].eType = AVCFileTOL;
1131 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("TOL");
1132 1 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1133 : }
1134 :
1135 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1136 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "par.adf": "par";
1137 1 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1138 0 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1139 : psInfo->eCoverType, AVCFileTOL,
1140 : psInfo->psDBCSInfo)) != NULL)
1141 : {
1142 0 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1143 0 : nCoverPrecision = psFile->nPrecision;
1144 0 : AVCBinReadClose(psFile);
1145 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1146 : &(psInfo->numSections), 1);
1147 :
1148 0 : psInfo->pasSections[iSect].eType = AVCFileTOL;
1149 0 : psInfo->pasSections[iSect].pszName = CPLStrdup("TOL");
1150 0 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1151 : }
1152 :
1153 : /*-----------------------------------------------------------------
1154 : * TXT section (txt.adf)
1155 : *----------------------------------------------------------------*/
1156 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1157 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "txt.adf": "txt";
1158 1 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 &&
1159 0 : (psFile = AVCBinReadOpen(psInfo->pszCoverPath, szFname,
1160 : psInfo->eCoverType, AVCFileTXT,
1161 : psInfo->psDBCSInfo)) != NULL)
1162 : {
1163 0 : if (nCoverPrecision == AVC_DEFAULT_PREC)
1164 0 : nCoverPrecision = psFile->nPrecision;
1165 0 : AVCBinReadClose(psFile);
1166 0 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1167 : &(psInfo->numSections), 1);
1168 :
1169 0 : psInfo->pasSections[iSect].eType = AVCFileTXT;
1170 0 : psInfo->pasSections[iSect].pszName = CPLStrdup("TXT");
1171 0 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1172 : }
1173 :
1174 : /*-----------------------------------------------------------------
1175 : * TX6 section (*.txt)
1176 : * Scan the directory for files with a ".txt" extension.
1177 : * Note: Never seen those in a PC Arc/Info coverage!
1178 : * In weird coverages, the filename ends with "txt" but there is no "."
1179 : *----------------------------------------------------------------*/
1180 1 : if (psInfo->eCoverType == AVCCoverV7)
1181 1 : nCoverPrecision = _AVCE00ReadAddJabberwockySection(psInfo, AVCFileTX6,
1182 : "TX6",
1183 : nCoverPrecision,
1184 : ".txt",
1185 : papszCoverDir);
1186 0 : else if (psInfo->eCoverType == AVCCoverWeird)
1187 0 : nCoverPrecision = _AVCE00ReadAddJabberwockySection(psInfo, AVCFileTX6,
1188 : "TX6",
1189 : nCoverPrecision,
1190 : "txt",
1191 : papszCoverDir);
1192 :
1193 : /*-----------------------------------------------------------------
1194 : * At this point, we should have read the coverage precsion... and if
1195 : * we haven't yet then we'll just use single by default.
1196 : * We'll need cPrecisionCode for some of the sections that follow.
1197 : *----------------------------------------------------------------*/
1198 1 : if (nCoverPrecision == AVC_DOUBLE_PREC)
1199 0 : cPrecisionCode = '3';
1200 : else
1201 1 : cPrecisionCode = '2';
1202 :
1203 : /*-----------------------------------------------------------------
1204 : * SIN 2/3 and EOX lines ... ???
1205 : *----------------------------------------------------------------*/
1206 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1207 : &(psInfo->numSections), 2);
1208 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1209 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("SIN X");
1210 1 : psInfo->pasSections[iSect].pszName[5] = cPrecisionCode;
1211 1 : iSect++;
1212 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1213 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("EOX");
1214 1 : iSect++;
1215 :
1216 : /*-----------------------------------------------------------------
1217 : * LOG section (log.adf) (ends with EOL)
1218 : *----------------------------------------------------------------*/
1219 :
1220 : /*-----------------------------------------------------------------
1221 : * PRJ section (prj.adf) (ends with EOP)
1222 : *----------------------------------------------------------------*/
1223 1 : szFname = (psInfo->eCoverType==AVCCoverV7 ||
1224 0 : psInfo->eCoverType==AVCCoverPC2 ) ? "prj.adf": "prj";
1225 1 : if ( (iFile=CSLFindString(papszCoverDir, szFname)) != -1 )
1226 : {
1227 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1228 : &(psInfo->numSections), 1);
1229 :
1230 1 : psInfo->pasSections[iSect].eType = AVCFilePRJ;
1231 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("PRJ");
1232 1 : psInfo->pasSections[iSect].pszFilename=CPLStrdup(papszCoverDir[iFile]);
1233 : }
1234 :
1235 : /*-----------------------------------------------------------------
1236 : * RXP section (*.rxp)
1237 : * Scan the directory for files with a ".rxp" extension.
1238 : *----------------------------------------------------------------*/
1239 1 : if (psInfo->eCoverType == AVCCoverV7)
1240 1 : _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRXP, "RXP",
1241 : nCoverPrecision,".rxp",papszCoverDir);
1242 0 : else if (psInfo->eCoverType == AVCCoverWeird)
1243 0 : _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRXP, "RXP",
1244 : nCoverPrecision,"rxp",papszCoverDir);
1245 :
1246 :
1247 : /*-----------------------------------------------------------------
1248 : * RPL section (*.pal)
1249 : * Scan the directory for files with a ".rpl" extension.
1250 : *----------------------------------------------------------------*/
1251 1 : if (psInfo->eCoverType == AVCCoverV7)
1252 1 : _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRPL, "RPL",
1253 : nCoverPrecision,".pal",papszCoverDir);
1254 0 : else if (psInfo->eCoverType == AVCCoverWeird)
1255 0 : _AVCE00ReadAddJabberwockySection(psInfo, AVCFileRPL, "RPL",
1256 : nCoverPrecision,"rpl",papszCoverDir);
1257 :
1258 : /*-----------------------------------------------------------------
1259 : * IFO section (tables)
1260 : *----------------------------------------------------------------*/
1261 1 : papszTables = papszFiles = NULL;
1262 2 : if (psInfo->eCoverType == AVCCoverV7 ||
1263 0 : psInfo->eCoverType == AVCCoverV7Tables ||
1264 0 : psInfo->eCoverType == AVCCoverWeird)
1265 : {
1266 : /*-------------------------------------------------------------
1267 : * Unix coverages: get tables from the ../info/arc.dir
1268 : * Weird coverages: the arc.dir is similar but called "arcdr9"
1269 : *------------------------------------------------------------*/
1270 2 : papszTables = AVCBinReadListTables(psInfo->pszInfoPath,
1271 1 : psInfo->pszCoverName,
1272 : &papszFiles, psInfo->eCoverType,
1273 : psInfo->psDBCSInfo);
1274 : }
1275 0 : else if (psInfo->eCoverType == AVCCoverPC ||
1276 0 : psInfo->eCoverType == AVCCoverPC2)
1277 : {
1278 : /*-------------------------------------------------------------
1279 : * PC coverages: look for "???.dbf" in the coverage directory
1280 : * and build the table name using the coverage name
1281 : * as the table basename, and the dbf file basename
1282 : * as the table extension.
1283 : *------------------------------------------------------------*/
1284 0 : for(iFile=0; papszCoverDir && papszCoverDir[iFile]; iFile++)
1285 : {
1286 0 : if ((nLen = strlen(papszCoverDir[iFile])) == 7 &&
1287 0 : EQUAL(papszCoverDir[iFile] + nLen -4, ".dbf"))
1288 : {
1289 0 : papszCoverDir[iFile][nLen - 4] = '\0';
1290 0 : szFname = CPLSPrintf("%s.%s", psInfo->pszCoverName,
1291 0 : papszCoverDir[iFile]);
1292 0 : pcTmp = (char*)szFname;
1293 0 : for( ; *pcTmp != '\0'; pcTmp++)
1294 0 : *pcTmp = toupper(*pcTmp);
1295 0 : papszCoverDir[iFile][nLen - 4] = '.';
1296 :
1297 0 : papszTables = CSLAddString(papszTables, szFname);
1298 0 : papszFiles = CSLAddString(papszFiles, papszCoverDir[iFile]);
1299 : }
1300 : }
1301 : }
1302 :
1303 1 : if ((numTables = CSLCount(papszTables)) > 0)
1304 : {
1305 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1306 : &(psInfo->numSections), numTables+2);
1307 :
1308 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1309 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("IFO X");
1310 1 : psInfo->pasSections[iSect].pszName[5] = cPrecisionCode;
1311 1 : iSect++;
1312 :
1313 3 : for(iTable=0; iTable<numTables; iTable++)
1314 : {
1315 2 : psInfo->pasSections[iSect].eType = AVCFileTABLE;
1316 2 : psInfo->pasSections[iSect].pszName=CPLStrdup(papszTables[iTable]);
1317 2 : if (papszFiles)
1318 : {
1319 4 : psInfo->pasSections[iSect].pszFilename=
1320 2 : CPLStrdup(papszFiles[iTable]);
1321 : }
1322 2 : iSect++;
1323 : }
1324 :
1325 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1326 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("EOI");
1327 1 : iSect++;
1328 :
1329 : }
1330 1 : CSLDestroy(papszTables);
1331 1 : CSLDestroy(papszFiles);
1332 :
1333 : /*-----------------------------------------------------------------
1334 : * File ends with EOS
1335 : *----------------------------------------------------------------*/
1336 1 : iSect = _AVCIncreaseSectionsArray(&(psInfo->pasSections),
1337 : &(psInfo->numSections), 1);
1338 1 : psInfo->pasSections[iSect].eType = AVCFileUnknown;
1339 1 : psInfo->pasSections[iSect].pszName = CPLStrdup("EOS");
1340 :
1341 :
1342 1 : return nCoverPrecision;
1343 : }
1344 :
1345 :
1346 : /**********************************************************************
1347 : * _AVCE00ReadScanE00()
1348 : *
1349 : * Processes an entire E00 file to find all the interesting sections.
1350 : **********************************************************************/
1351 2 : static void _AVCE00ReadScanE00(AVCE00ReadE00Ptr psRead)
1352 : {
1353 2 : AVCE00ParseInfo *psInfo = psRead->hParseInfo;
1354 :
1355 : const char *pszLine;
1356 2 : const char *pszName = 0;
1357 : void *obj;
1358 2 : int iSect = 0;
1359 2 : GBool bFirstLine = TRUE;
1360 :
1361 458 : while (CPLGetLastErrorNo() == 0 &&
1362 228 : (pszLine = CPLReadLine(psRead->hFile) ) != NULL )
1363 : {
1364 226 : if (bFirstLine)
1365 : {
1366 : /* Look for the first non-empty line, after the EXP header,
1367 : * trying to detect compressed E00 files. If the file is
1368 : * compressed, the first line of data should be 79 or 80 chars
1369 : * long and contain several '~' characters.
1370 : */
1371 4 : int nLen = strlen(pszLine);
1372 4 : if (nLen == 0 || EQUALN("EXP ", pszLine, 4))
1373 2 : continue; /* Skip empty and EXP header lines */
1374 2 : else if ( (nLen == 79 || nLen == 80) &&
1375 0 : strchr(pszLine, '~') != NULL )
1376 : {
1377 : /* Looks like a compressed file. Just log an error and return.
1378 : * The caller should reject the file because it contains 0
1379 : * sections
1380 : */
1381 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1382 : "This looks like a compressed E00 file and cannot be "
1383 : "processed directly. You may need to uncompress it "
1384 : "first using the E00compr library or the e00conv "
1385 : "program." );
1386 0 : return;
1387 : }
1388 :
1389 : /* All seems fine. Continue with normal processing */
1390 2 : bFirstLine = FALSE;
1391 : }
1392 :
1393 224 : obj = _AVCE00ReadNextLineE00(psRead, pszLine);
1394 :
1395 224 : if (obj)
1396 : {
1397 68 : pszName = 0;
1398 68 : switch (psInfo->eFileType)
1399 : {
1400 : case AVCFileARC:
1401 14 : pszName = "ARC";
1402 14 : break;
1403 :
1404 : case AVCFilePAL:
1405 0 : pszName = "PAL";
1406 0 : break;
1407 :
1408 : case AVCFileCNT:
1409 0 : pszName = "CNT";
1410 0 : break;
1411 :
1412 : case AVCFileLAB:
1413 4 : pszName = "LAB";
1414 4 : break;
1415 :
1416 : case AVCFileRPL:
1417 0 : pszName = "RPL";
1418 0 : break;
1419 :
1420 : case AVCFileTXT:
1421 0 : pszName = "TXT";
1422 0 : break;
1423 :
1424 : case AVCFileTX6:
1425 0 : pszName = "TX6";
1426 0 : break;
1427 :
1428 : case AVCFilePRJ:
1429 2 : pszName = "PRJ";
1430 2 : break;
1431 :
1432 : case AVCFileTABLE:
1433 28 : pszName = psInfo->hdr.psTableDef->szTableName;
1434 : break;
1435 :
1436 : default:
1437 : break;
1438 : }
1439 :
1440 154 : if (pszName && (psRead->numSections == 0 ||
1441 46 : psRead->pasSections[iSect].eType != psInfo->eFileType ||
1442 40 : !EQUAL(pszName, psRead->pasSections[iSect].pszName)))
1443 : {
1444 14 : iSect = _AVCIncreaseSectionsArray(&(psRead->pasSections),
1445 : &(psRead->numSections), 1);
1446 :
1447 14 : psRead->pasSections[iSect].eType = psInfo->eFileType;
1448 : /* psRead->pasSections[iSect].pszName = CPLStrdup(psRead->pszCoverName); */
1449 14 : psRead->pasSections[iSect].pszName = CPLStrdup(pszName);
1450 14 : psRead->pasSections[iSect].pszFilename = CPLStrdup(psRead->pszCoverPath);
1451 14 : psRead->pasSections[iSect].nLineNum = psInfo->nStartLineNum;
1452 14 : psRead->pasSections[iSect].nFeatureCount = 0;
1453 : }
1454 :
1455 68 : if (pszName && psRead->numSections)
1456 : {
1457 : /* increase feature count for current layer */
1458 48 : ++psRead->pasSections[iSect].nFeatureCount;
1459 : }
1460 : }
1461 : }
1462 : }
1463 :
1464 : /**********************************************************************
1465 : * _AVCE00ReadNextTableLine()
1466 : *
1467 : * Return the next line of the E00 representation of a info table.
1468 : *
1469 : * This function is used by AVCE00ReadNextLine() to generate table
1470 : * output... it should never be called directly.
1471 : **********************************************************************/
1472 0 : static const char *_AVCE00ReadNextTableLine(AVCE00ReadPtr psInfo)
1473 : {
1474 0 : const char *pszLine = NULL;
1475 : AVCE00Section *psSect;
1476 :
1477 0 : psSect = &(psInfo->pasSections[psInfo->iCurSection]);
1478 :
1479 : CPLAssert(psSect->eType == AVCFileTABLE);
1480 :
1481 0 : if (psInfo->iCurStep == AVC_GEN_NOTSTARTED)
1482 : {
1483 : /*---------------------------------------------------------
1484 : * Open table and start returning header
1485 : *--------------------------------------------------------*/
1486 0 : if (psInfo->eCoverType == AVCCoverPC ||
1487 0 : psInfo->eCoverType == AVCCoverPC2)
1488 : {
1489 : /*---------------------------------------------------------
1490 : * PC Arc/Info: We pass the DBF table's full filename + the
1491 : * Arc/Info table name (for E00 header)
1492 : *--------------------------------------------------------*/
1493 : char *pszFname;
1494 0 : pszFname = CPLStrdup(CPLSPrintf("%s%s", psInfo->pszInfoPath,
1495 : psSect->pszFilename ));
1496 0 : psInfo->hFile = AVCBinReadOpen(pszFname, psSect->pszName,
1497 : psInfo->eCoverType, psSect->eType,
1498 : psInfo->psDBCSInfo);
1499 0 : CPLFree(pszFname);
1500 : }
1501 : else
1502 : {
1503 : /*---------------------------------------------------------
1504 : * AVCCoverV7 and AVCCoverWeird:
1505 : * We pass the INFO dir's path, and the Arc/Info table name
1506 : * will be searched in the arc.dir
1507 : *--------------------------------------------------------*/
1508 0 : psInfo->hFile = AVCBinReadOpen(psInfo->pszInfoPath,
1509 0 : psSect->pszName,
1510 : psInfo->eCoverType, psSect->eType,
1511 : psInfo->psDBCSInfo);
1512 : }
1513 :
1514 :
1515 : /* For some reason the file could not be opened... abort now.
1516 : * An error message should have already been produced by
1517 : * AVCBinReadOpen()
1518 : */
1519 0 : if (psInfo->hFile == NULL)
1520 0 : return NULL;
1521 :
1522 0 : psInfo->iCurStep = AVC_GEN_TABLEHEADER;
1523 :
1524 0 : pszLine = AVCE00GenTableHdr(psInfo->hGenInfo,
1525 0 : psInfo->hFile->hdr.psTableDef,
1526 : FALSE);
1527 : }
1528 :
1529 0 : if (pszLine == NULL &&
1530 0 : psInfo->iCurStep == AVC_GEN_TABLEHEADER)
1531 : {
1532 : /*---------------------------------------------------------
1533 : * Continue table header
1534 : *--------------------------------------------------------*/
1535 0 : pszLine = AVCE00GenTableHdr(psInfo->hGenInfo,
1536 0 : psInfo->hFile->hdr.psTableDef,
1537 : TRUE);
1538 :
1539 0 : if (pszLine == NULL)
1540 : {
1541 : /* Finished with table header... time to proceed with the
1542 : * table data.
1543 : * Reset the AVCE00GenInfo struct. so that it returns NULL,
1544 : * which will force reading of the first record from the
1545 : * file on the next call to AVCE00ReadNextLine()
1546 : */
1547 0 : AVCE00GenReset(psInfo->hGenInfo);
1548 0 : psInfo->iCurStep = AVC_GEN_TABLEDATA;
1549 : }
1550 :
1551 : }
1552 :
1553 0 : if (pszLine == NULL &&
1554 0 : psInfo->iCurStep == AVC_GEN_TABLEDATA)
1555 : {
1556 : /*---------------------------------------------------------
1557 : * Continue with records of data
1558 : *--------------------------------------------------------*/
1559 :
1560 0 : pszLine = AVCE00GenTableRec(psInfo->hGenInfo,
1561 0 : psInfo->hFile->hdr.psTableDef->numFields,
1562 0 : psInfo->hFile->hdr.psTableDef->pasFieldDef,
1563 0 : psInfo->hFile->cur.pasFields,
1564 : TRUE);
1565 :
1566 0 : if (pszLine == NULL)
1567 : {
1568 : /* Current record is finished generating... we need to read
1569 : * a new one from the file.
1570 : */
1571 0 : if (AVCBinReadNextObject(psInfo->hFile) != NULL)
1572 : {
1573 0 : pszLine = AVCE00GenTableRec(psInfo->hGenInfo,
1574 0 : psInfo->hFile->hdr.psTableDef->numFields,
1575 0 : psInfo->hFile->hdr.psTableDef->pasFieldDef,
1576 0 : psInfo->hFile->cur.pasFields,
1577 : FALSE);
1578 : }
1579 :
1580 : }
1581 : }
1582 :
1583 0 : if (pszLine == NULL)
1584 : {
1585 : /*---------------------------------------------------------
1586 : * No more lines to output for this table ... Close it.
1587 : *--------------------------------------------------------*/
1588 0 : AVCBinReadClose(psInfo->hFile);
1589 0 : psInfo->hFile = NULL;
1590 :
1591 : /*---------------------------------------------------------
1592 : * And now proceed to the next section...
1593 : * OK, I don't really like recursivity either... but it was
1594 : * the simplest way to do this, and anyways we should never
1595 : * have more than one level of recursivity.
1596 : *--------------------------------------------------------*/
1597 0 : if (psInfo->bReadAllSections)
1598 0 : psInfo->iCurSection++;
1599 : else
1600 0 : psInfo->iCurSection = psInfo->numSections;
1601 0 : psInfo->iCurStep = AVC_GEN_NOTSTARTED;
1602 :
1603 0 : pszLine = AVCE00ReadNextLine(psInfo);
1604 : }
1605 :
1606 : /*-----------------------------------------------------------------
1607 : * Check for errors... if any error happened, tehn return NULL
1608 : *----------------------------------------------------------------*/
1609 0 : if (CPLGetLastErrorNo() != 0)
1610 : {
1611 0 : pszLine = NULL;
1612 : }
1613 :
1614 0 : return pszLine;
1615 : }
1616 :
1617 :
1618 : /**********************************************************************
1619 : * AVCE00ReadNextLine()
1620 : *
1621 : * Returns the next line of the E00 representation of the coverage
1622 : * or NULL when there are no more lines to generate, or if an error happened.
1623 : * The returned line is a null-terminated string, and it does not
1624 : * include a newline character.
1625 : *
1626 : * Call CPLGetLastErrorNo() after calling AVCE00ReadNextLine() to
1627 : * make sure that the line was generated succesfully.
1628 : *
1629 : * Note that AVCE00ReadNextLine() returns a reference to an
1630 : * internal buffer whose contents will
1631 : * be valid only until the next call to this function. The caller should
1632 : * not attempt to free() the returned pointer.
1633 : **********************************************************************/
1634 0 : const char *AVCE00ReadNextLine(AVCE00ReadPtr psInfo)
1635 : {
1636 0 : const char *pszLine = NULL;
1637 : AVCE00Section *psSect;
1638 :
1639 0 : CPLErrorReset();
1640 :
1641 : /*-----------------------------------------------------------------
1642 : * Check if we have finished generating E00 output
1643 : *----------------------------------------------------------------*/
1644 0 : if (psInfo->iCurSection >= psInfo->numSections)
1645 0 : return NULL;
1646 :
1647 0 : psSect = &(psInfo->pasSections[psInfo->iCurSection]);
1648 :
1649 : /*-----------------------------------------------------------------
1650 : * For simplicity, the generation of table output is in a separate
1651 : * function.
1652 : *----------------------------------------------------------------*/
1653 0 : if (psSect->eType == AVCFileTABLE)
1654 : {
1655 0 : return _AVCE00ReadNextTableLine(psInfo);
1656 : }
1657 :
1658 0 : if (psSect->eType == AVCFileUnknown)
1659 : {
1660 : /*-----------------------------------------------------------------
1661 : * Section not attached to any file, used to hold header lines
1662 : * or section separators, etc... just return the line directly and
1663 : * move pointer to the next section.
1664 : *----------------------------------------------------------------*/
1665 0 : pszLine = psSect->pszName;
1666 0 : if (psInfo->bReadAllSections)
1667 0 : psInfo->iCurSection++;
1668 : else
1669 0 : psInfo->iCurSection = psInfo->numSections;
1670 0 : psInfo->iCurStep = AVC_GEN_NOTSTARTED;
1671 : }
1672 : /*=================================================================
1673 : * ARC, PAL, CNT, LAB, TOL and TXT
1674 : *================================================================*/
1675 0 : else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED &&
1676 0 : (psSect->eType == AVCFileARC ||
1677 0 : psSect->eType == AVCFilePAL ||
1678 0 : psSect->eType == AVCFileRPL ||
1679 0 : psSect->eType == AVCFileCNT ||
1680 0 : psSect->eType == AVCFileLAB ||
1681 0 : psSect->eType == AVCFileTOL ||
1682 0 : psSect->eType == AVCFileTXT ||
1683 0 : psSect->eType == AVCFileTX6 ||
1684 0 : psSect->eType == AVCFileRXP ) )
1685 : {
1686 : /*-----------------------------------------------------------------
1687 : * Start processing of an ARC, PAL, CNT, LAB or TOL section:
1688 : * Open the file, get ready to read the first object from the
1689 : * file, and return the header line.
1690 : * If the file fails to open then we will return NULL.
1691 : *----------------------------------------------------------------*/
1692 0 : psInfo->hFile = AVCBinReadOpen(psInfo->pszCoverPath,
1693 0 : psSect->pszFilename,
1694 : psInfo->eCoverType, psSect->eType,
1695 : psInfo->psDBCSInfo);
1696 :
1697 : /*-------------------------------------------------------------
1698 : * For some reason the file could not be opened... abort now.
1699 : * An error message should have already been produced by
1700 : * AVCBinReadOpen()
1701 : *------------------------------------------------------------*/
1702 0 : if (psInfo->hFile == NULL)
1703 0 : return NULL;
1704 :
1705 0 : pszLine = AVCE00GenStartSection(psInfo->hGenInfo,
1706 0 : psSect->eType, psSect->pszName);
1707 :
1708 : /*-------------------------------------------------------------
1709 : * Reset the AVCE00GenInfo struct. so that it returns NULL,
1710 : * which will force reading of the first object from the
1711 : * file on the next call to AVCE00ReadNextLine()
1712 : *------------------------------------------------------------*/
1713 0 : AVCE00GenReset(psInfo->hGenInfo);
1714 0 : psInfo->iCurStep = AVC_GEN_DATA;
1715 : }
1716 0 : else if (psInfo->iCurStep == AVC_GEN_DATA &&
1717 0 : (psSect->eType == AVCFileARC ||
1718 0 : psSect->eType == AVCFilePAL ||
1719 0 : psSect->eType == AVCFileRPL ||
1720 0 : psSect->eType == AVCFileCNT ||
1721 0 : psSect->eType == AVCFileLAB ||
1722 0 : psSect->eType == AVCFileTOL ||
1723 0 : psSect->eType == AVCFileTXT ||
1724 0 : psSect->eType == AVCFileTX6 ||
1725 0 : psSect->eType == AVCFileRXP ) )
1726 : {
1727 : /*-----------------------------------------------------------------
1728 : * Return the next line of an ARC/PAL/CNT/TOL/TXT object...
1729 : * if necessary, read the next object from the binary file.
1730 : *----------------------------------------------------------------*/
1731 0 : pszLine = AVCE00GenObject(psInfo->hGenInfo,
1732 : psSect->eType,
1733 0 : (psSect->eType==AVCFileARC?(void*)(psInfo->hFile->cur.psArc):
1734 0 : psSect->eType==AVCFilePAL?(void*)(psInfo->hFile->cur.psPal):
1735 0 : psSect->eType==AVCFileRPL?(void*)(psInfo->hFile->cur.psPal):
1736 0 : psSect->eType==AVCFileCNT?(void*)(psInfo->hFile->cur.psCnt):
1737 0 : psSect->eType==AVCFileLAB?(void*)(psInfo->hFile->cur.psLab):
1738 0 : psSect->eType==AVCFileTOL?(void*)(psInfo->hFile->cur.psTol):
1739 0 : psSect->eType==AVCFileTXT?(void*)(psInfo->hFile->cur.psTxt):
1740 0 : psSect->eType==AVCFileTX6?(void*)(psInfo->hFile->cur.psTxt):
1741 0 : psSect->eType==AVCFileRXP?(void*)(psInfo->hFile->cur.psRxp):
1742 : NULL),
1743 : TRUE);
1744 0 : if (pszLine == NULL)
1745 : {
1746 : /*---------------------------------------------------------
1747 : * Current object is finished generating... we need to read
1748 : * a new one from the file.
1749 : *--------------------------------------------------------*/
1750 0 : if (AVCBinReadNextObject(psInfo->hFile) != NULL)
1751 : {
1752 0 : pszLine = AVCE00GenObject(psInfo->hGenInfo,
1753 : psSect->eType,
1754 0 : (psSect->eType==AVCFileARC?(void*)(psInfo->hFile->cur.psArc):
1755 0 : psSect->eType==AVCFilePAL?(void*)(psInfo->hFile->cur.psPal):
1756 0 : psSect->eType==AVCFileRPL?(void*)(psInfo->hFile->cur.psPal):
1757 0 : psSect->eType==AVCFileCNT?(void*)(psInfo->hFile->cur.psCnt):
1758 0 : psSect->eType==AVCFileLAB?(void*)(psInfo->hFile->cur.psLab):
1759 0 : psSect->eType==AVCFileTOL?(void*)(psInfo->hFile->cur.psTol):
1760 0 : psSect->eType==AVCFileTXT?(void*)(psInfo->hFile->cur.psTxt):
1761 0 : psSect->eType==AVCFileTX6?(void*)(psInfo->hFile->cur.psTxt):
1762 0 : psSect->eType==AVCFileRXP?(void*)(psInfo->hFile->cur.psRxp):
1763 : NULL),
1764 : FALSE);
1765 : }
1766 : }
1767 0 : if (pszLine == NULL)
1768 : {
1769 : /*---------------------------------------------------------
1770 : * Still NULL ??? This means we finished reading this file...
1771 : * Start returning the "end of section" line(s)...
1772 : *--------------------------------------------------------*/
1773 0 : AVCBinReadClose(psInfo->hFile);
1774 0 : psInfo->hFile = NULL;
1775 0 : psInfo->iCurStep = AVC_GEN_ENDSECTION;
1776 0 : pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType,
1777 : FALSE);
1778 : }
1779 : }
1780 : /*=================================================================
1781 : * PRJ
1782 : *================================================================*/
1783 0 : else if (psInfo->iCurStep == AVC_GEN_NOTSTARTED &&
1784 0 : psSect->eType == AVCFilePRJ )
1785 : {
1786 : /*-------------------------------------------------------------
1787 : * Start processing of PRJ section... return first header line.
1788 : *------------------------------------------------------------*/
1789 0 : pszLine = AVCE00GenStartSection(psInfo->hGenInfo,
1790 : psSect->eType, NULL);
1791 :
1792 0 : psInfo->hFile = NULL;
1793 0 : psInfo->iCurStep = AVC_GEN_DATA;
1794 : }
1795 0 : else if (psInfo->iCurStep == AVC_GEN_DATA &&
1796 0 : psSect->eType == AVCFilePRJ )
1797 : {
1798 : /*-------------------------------------------------------------
1799 : * Return the next line of a PRJ section
1800 : *------------------------------------------------------------*/
1801 0 : if (psInfo->hFile == NULL)
1802 : {
1803 : /*---------------------------------------------------------
1804 : * File has not been read yet...
1805 : * Read the PRJ file, and return the first PRJ line.
1806 : *--------------------------------------------------------*/
1807 0 : psInfo->hFile = AVCBinReadOpen(psInfo->pszCoverPath,
1808 0 : psSect->pszFilename,
1809 : psInfo->eCoverType, psSect->eType,
1810 : psInfo->psDBCSInfo);
1811 :
1812 : /* For some reason the file could not be opened... abort now.
1813 : * An error message should have already been produced by
1814 : * AVCBinReadOpen()
1815 : */
1816 0 : if (psInfo->hFile == NULL)
1817 0 : return NULL;
1818 :
1819 0 : pszLine = AVCE00GenPrj(psInfo->hGenInfo,
1820 0 : psInfo->hFile->cur.papszPrj, FALSE);
1821 : }
1822 : else
1823 : {
1824 : /*---------------------------------------------------------
1825 : * Generate the next line of output.
1826 : *--------------------------------------------------------*/
1827 0 : pszLine = AVCE00GenPrj(psInfo->hGenInfo,
1828 0 : psInfo->hFile->cur.papszPrj, TRUE);
1829 : }
1830 :
1831 0 : if (pszLine == NULL)
1832 : {
1833 : /*---------------------------------------------------------
1834 : * Still NULL ??? This means we finished generating this PRJ
1835 : * section...
1836 : * Start returning the "end of section" line(s)...
1837 : *--------------------------------------------------------*/
1838 0 : AVCBinReadClose(psInfo->hFile);
1839 0 : psInfo->hFile = NULL;
1840 0 : psInfo->iCurStep = AVC_GEN_ENDSECTION;
1841 0 : pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType,
1842 : FALSE);
1843 : }
1844 : }
1845 0 : else if (psInfo->iCurStep != AVC_GEN_ENDSECTION)
1846 : {
1847 : /* We should never get here! */
1848 : CPLAssert(FALSE);
1849 : }
1850 :
1851 :
1852 : /*=================================================================
1853 : * End of section, for all files
1854 : *================================================================*/
1855 :
1856 : /*-----------------------------------------------------------------
1857 : * Finished processing of an ARC, PAL, CNT, LAB, TOL, PRJ file ...
1858 : * continue returning the "end of section" line(s), and move the pointer
1859 : * to the next section once we're done.
1860 : *----------------------------------------------------------------*/
1861 0 : if (psInfo->iCurStep == AVC_GEN_ENDSECTION && pszLine == NULL)
1862 : {
1863 0 : pszLine = AVCE00GenEndSection(psInfo->hGenInfo, psSect->eType, TRUE);
1864 :
1865 0 : if (pszLine == NULL)
1866 : {
1867 : /*---------------------------------------------------------
1868 : * Finished returning the last lines of the section...
1869 : * proceed to the next section...
1870 : * OK, I don't really like recursivity either... but it was
1871 : * the simplest way to do this, and anyways we should never
1872 : * have more than one level of recursivity.
1873 : *--------------------------------------------------------*/
1874 0 : if (psInfo->bReadAllSections)
1875 0 : psInfo->iCurSection++;
1876 : else
1877 0 : psInfo->iCurSection = psInfo->numSections;
1878 0 : psInfo->iCurStep = AVC_GEN_NOTSTARTED;
1879 :
1880 0 : pszLine = AVCE00ReadNextLine(psInfo);
1881 : }
1882 : }
1883 :
1884 0 : return pszLine;
1885 : }
1886 :
1887 :
1888 :
1889 : /**********************************************************************
1890 : * AVCE00ReadSectionsList()
1891 : *
1892 : * Returns an array of AVCE00Section structures that describe the
1893 : * squeleton of the whole coverage. The value of *numSect will be
1894 : * set to the number of sections in the array.
1895 : *
1896 : * You can scan the returned array, and use AVCE00ReadGotoSection() to move
1897 : * the read pointer directly to the beginning of a given section
1898 : * of the file.
1899 : *
1900 : * Sections of type AVCFileUnknown correspond to lines in the
1901 : * E00 output that are not directly linked to any coverage file, like
1902 : * the "EXP 0" line, the "IFO X", "SIN X", etc.
1903 : *
1904 : * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE
1905 : * MODIFIED OR FREED BY THE CALLER... its contents will be valid
1906 : * for as long as the coverage will remain open.
1907 : **********************************************************************/
1908 0 : AVCE00Section *AVCE00ReadSectionsList(AVCE00ReadPtr psInfo, int *numSect)
1909 : {
1910 0 : CPLErrorReset();
1911 :
1912 0 : *numSect = psInfo->numSections;
1913 0 : return psInfo->pasSections;
1914 : }
1915 :
1916 : /**********************************************************************
1917 : * AVCE00ReadGotoSection()
1918 : *
1919 : * Move the read pointer to the E00 section (coverage file) described in
1920 : * the psSect structure. Call AVCE00ReadSectionsList() to get the list of
1921 : * sections for the current coverage.
1922 : *
1923 : * if bContinue=TRUE, then reading will automatically continue with the
1924 : * next sections of the file once the requested section is finished.
1925 : * Otherwise, if bContinue=FALSE then reading will stop at the end
1926 : * of this section (i.e. AVCE00ReadNextLine() will return NULL when
1927 : * it reaches the end of this section)
1928 : *
1929 : * Sections of type AVCFileUnknown returned by AVCE00ReadSectionsList()
1930 : * correspond to lines in the E00 output that are not directly linked
1931 : * to any coverage file, like the "EXP 0" line, the "IFO X", "SIN X", etc.
1932 : * You can jump to these sections or any other one without problems.
1933 : *
1934 : * This function returns 0 on success or -1 on error.
1935 : **********************************************************************/
1936 0 : int AVCE00ReadGotoSection(AVCE00ReadPtr psInfo, AVCE00Section *psSect,
1937 : GBool bContinue)
1938 : {
1939 : int iSect;
1940 0 : GBool bFound = FALSE;
1941 :
1942 0 : CPLErrorReset();
1943 :
1944 : /*-----------------------------------------------------------------
1945 : * Locate the requested section in the array.
1946 : *----------------------------------------------------------------*/
1947 0 : for(iSect=0; iSect<psInfo->numSections; iSect++)
1948 : {
1949 0 : if (psInfo->pasSections[iSect].eType == psSect->eType &&
1950 0 : EQUAL(psInfo->pasSections[iSect].pszName, psSect->pszName))
1951 : {
1952 0 : bFound = TRUE;
1953 0 : break;
1954 : }
1955 : }
1956 :
1957 : /*-----------------------------------------------------------------
1958 : * Not found ... generate an error...
1959 : *----------------------------------------------------------------*/
1960 0 : if (!bFound)
1961 : {
1962 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1963 : "Requested E00 section does not exist!");
1964 0 : return -1;
1965 : }
1966 :
1967 : /*-----------------------------------------------------------------
1968 : * Found it ... close current section and get ready to read
1969 : * the new one.
1970 : *----------------------------------------------------------------*/
1971 0 : if (psInfo->hFile)
1972 : {
1973 0 : AVCBinReadClose(psInfo->hFile);
1974 0 : psInfo->hFile = NULL;
1975 : }
1976 :
1977 0 : psInfo->bReadAllSections = bContinue;
1978 0 : psInfo->iCurSection = iSect;
1979 0 : psInfo->iCurStep = AVC_GEN_NOTSTARTED;
1980 :
1981 0 : return 0;
1982 : }
1983 :
1984 : /**********************************************************************
1985 : * AVCE00ReadRewind()
1986 : *
1987 : * Rewinds the AVCE00ReadPtr just like the stdio rewind()
1988 : * function would do if you were reading an ASCII E00 file.
1989 : *
1990 : * Returns 0 on success or -1 on error.
1991 : **********************************************************************/
1992 0 : int AVCE00ReadRewind(AVCE00ReadPtr psInfo)
1993 : {
1994 0 : CPLErrorReset();
1995 :
1996 0 : return AVCE00ReadGotoSection(psInfo, &(psInfo->pasSections[0]), TRUE);
1997 : }
1998 :
1999 : /**********************************************************************
2000 : * AVCE00ReadRewindE00()
2001 : *
2002 : * Rewinds the AVCE00ReadE00Ptr just like the stdio rewind()
2003 : * function would do if you were reading an ASCII E00 file.
2004 : *
2005 : * Returns 0 on success or -1 on error.
2006 : **********************************************************************/
2007 5 : int AVCE00ReadRewindE00(AVCE00ReadE00Ptr psRead)
2008 : {
2009 5 : CPLErrorReset();
2010 :
2011 5 : psRead->bReadAllSections = TRUE;
2012 5 : psRead->eCurFileType = AVCFileUnknown;
2013 :
2014 5 : psRead->hParseInfo->nCurLineNum = 0;
2015 5 : psRead->hParseInfo->nStartLineNum = 0;
2016 5 : psRead->hParseInfo->bForceEndOfSection = TRUE;
2017 5 : psRead->hParseInfo->eSuperSectionType = AVCFileUnknown;
2018 5 : AVCE00ParseSectionEnd(psRead->hParseInfo, NULL, 1);
2019 :
2020 5 : return fseek(psRead->hFile, 0, SEEK_SET);
2021 : }
2022 :
2023 : /**********************************************************************
2024 : * _AVCE00ReadSeekE00()
2025 : *
2026 : * Seeks to a new location in the E00 file, keeping parse state
2027 : * appropriately.
2028 : *
2029 : * NOTE: This is a pretty slow implementation.
2030 : * NOTE: The SEEK_END is not implemented.
2031 : *
2032 : * Returns 0 on success or -1 on error.
2033 : **********************************************************************/
2034 3 : static int _AVCE00ReadSeekE00(AVCE00ReadE00Ptr psRead, int nOffset,
2035 : int nWhence)
2036 : {
2037 : const char *pszLine;
2038 : void *obj;
2039 :
2040 3 : switch (nWhence)
2041 : {
2042 : case SEEK_CUR:
2043 0 : break;
2044 :
2045 : case SEEK_SET:
2046 3 : AVCE00ReadRewindE00(psRead);
2047 : break;
2048 :
2049 : default:
2050 : CPLAssert(nWhence == SEEK_CUR || nWhence == SEEK_SET);
2051 : break;
2052 : }
2053 :
2054 15 : while (nOffset-- &&
2055 3 : CPLGetLastErrorNo() == 0 &&
2056 3 : (pszLine = CPLReadLine(psRead->hFile) ) != NULL )
2057 : {
2058 3 : obj = _AVCE00ReadNextLineE00(psRead, pszLine);
2059 : }
2060 :
2061 3 : return nOffset ? -1 : 0;
2062 : }
2063 :
2064 : /**********************************************************************
2065 : * AVCE00ReadNextObjectE00()
2066 : *
2067 : * Returns the next object in an E00 file or NULL when there are no
2068 : * more objects, or if an error happened. The object type can be
2069 : * determined via the eCurFileType attribute of the
2070 : * AVCE00ReadE00Ptr object.
2071 : *
2072 : * Note that AVCE00ReadNextLine() returns a reference to an internal
2073 : * buffer whose contents will be valid only until the next call to
2074 : * this function. The caller should not attempt to free() the
2075 : * returned pointer.
2076 : **********************************************************************/
2077 9 : void *AVCE00ReadNextObjectE00(AVCE00ReadE00Ptr psRead)
2078 : {
2079 : const char *pszLine;
2080 9 : void *obj = NULL;
2081 :
2082 : do
2083 : {
2084 23 : pszLine = CPLReadLine(psRead->hFile);
2085 23 : if (pszLine == 0)
2086 0 : break;
2087 23 : obj = _AVCE00ReadNextLineE00(psRead, pszLine);
2088 : }
2089 : while (obj == NULL &&
2090 15 : (psRead->bReadAllSections ||
2091 15 : psRead->eCurFileType != AVCFileUnknown) &&
2092 53 : CPLGetLastErrorNo() == 0);
2093 9 : return obj;
2094 : }
2095 :
2096 : /**********************************************************************
2097 : * AVCE00ReadSectionsListE00()
2098 : *
2099 : * Returns an array of AVCE00Section structures that describe the
2100 : * sections in the E00 file. The value of *numSect will be set to the
2101 : * number of sections in the array.
2102 : *
2103 : * You can scan the returned array, and use AVCE00ReadGotoSectionE00()
2104 : * to move the read pointer directly to the beginning of a given
2105 : * section of the file.
2106 : *
2107 : * THE RETURNED ARRAY IS AN INTERNAL STRUCTURE AND SHOULD NOT BE
2108 : * MODIFIED OR FREED BY THE CALLER... its contents will be valid
2109 : * for as long as the coverage will remain open.
2110 : **********************************************************************/
2111 0 : AVCE00Section *AVCE00ReadSectionsListE00(AVCE00ReadE00Ptr psRead,
2112 : int *numSect)
2113 : {
2114 0 : CPLErrorReset();
2115 :
2116 0 : *numSect = psRead->numSections;
2117 0 : return psRead->pasSections;
2118 : }
2119 :
2120 : /**********************************************************************
2121 : * AVCE00ReadGotoSectionE00()
2122 : *
2123 : * Move the read pointer to the E00 section described in the psSect
2124 : * structure. Call AVCE00ReadSectionsListE00() to get the list of
2125 : * sections for the current coverage.
2126 : *
2127 : * If bContinue is TRUE, then reading will automatically continue with
2128 : * the next section of the file once the requested section is finished.
2129 : * Otherwise, if bContinue is FALSE then reading will stop at the end
2130 : * of this section (i.e. AVCE00ReadNextObjectE00() will return NULL
2131 : * when the end of this section is reached)
2132 : *
2133 : * This function returns 0 on success or -1 on error.
2134 : **********************************************************************/
2135 3 : int AVCE00ReadGotoSectionE00(AVCE00ReadE00Ptr psRead,
2136 : AVCE00Section *psSect, GBool bContinue)
2137 : {
2138 : int iSect;
2139 3 : GBool bFound = FALSE;
2140 :
2141 3 : CPLErrorReset();
2142 :
2143 : /*-----------------------------------------------------------------
2144 : * Locate the requested section in the array.
2145 : *----------------------------------------------------------------*/
2146 3 : for(iSect=0; iSect<psRead->numSections; iSect++)
2147 : {
2148 6 : if (psRead->pasSections[iSect].eType == psSect->eType &&
2149 3 : EQUAL(psRead->pasSections[iSect].pszName, psSect->pszName))
2150 : {
2151 3 : bFound = TRUE;
2152 3 : break;
2153 : }
2154 : }
2155 :
2156 : /*-----------------------------------------------------------------
2157 : * Not found ... generate an error...
2158 : *----------------------------------------------------------------*/
2159 3 : if (!bFound)
2160 : {
2161 0 : CPLError(CE_Failure, CPLE_IllegalArg,
2162 : "Requested E00 section does not exist!");
2163 0 : return -1;
2164 : }
2165 :
2166 : /*-----------------------------------------------------------------
2167 : * Found it ... advance parser to line number of start of section
2168 : *----------------------------------------------------------------*/
2169 3 : _AVCE00ReadSeekE00(psRead, psRead->pasSections[iSect].nLineNum, SEEK_SET);
2170 :
2171 3 : psRead->bReadAllSections = bContinue;
2172 :
2173 3 : return 0;
2174 : }
|