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