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