1 : /**********************************************************************
2 : * $Id: avc_e00parse.c,v 1.19 2008/07/23 20:51:38 dmorissette Exp $
3 : *
4 : * Name: avc_e00parse.c
5 : * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library
6 : * Language: ANSI C
7 : * Purpose: Functions to parse ASCII E00 lines and fill binary structures.
8 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999-2005, Daniel Morissette
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : **********************************************************************
31 : *
32 : * $Log: avc_e00parse.c,v $
33 : * Revision 1.19 2008/07/23 20:51:38 dmorissette
34 : * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
35 : * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
36 : *
37 : * Revision 1.18 2006/06/27 18:06:34 dmorissette
38 : * Applied patch for EOP processing from James F. (bug 1497)
39 : *
40 : * Revision 1.17 2006/06/19 14:35:47 dmorissette
41 : * New patch from James F. for E00 read support in OGR (bug 1497)
42 : *
43 : * Revision 1.16 2006/06/16 11:48:11 daniel
44 : * New functions to read E00 files directly as opposed to translating to
45 : * binary coverage. Used in the implementation of E00 read support in OGR.
46 : * Contributed by James E. Flemer. (bug 1497)
47 : *
48 : * Revision 1.15 2006/03/02 22:46:26 daniel
49 : * Accept empty subclass names for TX6/TX7 sections (bug 1261)
50 : *
51 : * Revision 1.14 2005/06/03 03:49:58 daniel
52 : * Update email address, website url, and copyright dates
53 : *
54 : * Revision 1.13 2002/08/27 15:43:02 daniel
55 : * Small typo in type 40 fix (forgot to commit to CVS on 2002-08-05)
56 : *
57 : * Revision 1.12 2002/08/05 20:20:17 daniel
58 : * Fixed parsing type 40 fields to properly detect negative exp. (bug 1272)
59 : *
60 : * Revision 1.11 2001/11/25 21:15:23 daniel
61 : * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
62 : * digits to double precision as we generate E00 output (bug599)
63 : *
64 : * Revision 1.10 2001/11/25 19:45:32 daniel
65 : * Fixed reading of type 40 when not in exponent format (bug599)
66 : *
67 : * Revision 1.9 2001/07/12 20:59:34 daniel
68 : * Properly handle PAL entries with 0 arcs
69 : *
70 : * Revision 1.8 2000/09/22 19:45:20 daniel
71 : * Switch to MIT-style license
72 : *
73 : * Revision 1.7 2000/03/16 03:48:00 daniel
74 : * Accept 0-length text strings in TX6/TX7 objects
75 : *
76 : * Revision 1.6 2000/02/03 07:21:40 daniel
77 : * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks
78 : *
79 : * Revision 1.5 1999/12/05 03:40:13 daniel
80 : * Fixed signed/unsigned mismatch compile warning
81 : *
82 : * Revision 1.4 1999/11/23 05:27:58 daniel
83 : * Added AVCE00Str2Int() to extract integer values in E00 lines
84 : *
85 : * Revision 1.3 1999/08/23 18:20:49 daniel
86 : * Fixed support for attribute fields type 40
87 : *
88 : * Revision 1.2 1999/05/17 16:20:48 daniel
89 : * Added RXP + TXT/TX6/TX7 write support + some simple problems fixed
90 : *
91 : * Revision 1.1 1999/05/11 02:34:46 daniel
92 : * Initial revision
93 : *
94 : **********************************************************************/
95 :
96 : #include "avc.h"
97 :
98 : #include <ctype.h> /* toupper() */
99 :
100 :
101 : /**********************************************************************
102 : * AVCE00Str2Int()
103 : *
104 : * Convert a portion of a string to an integer value.
105 : * The difference between this function and atoi() is that this version
106 : * takes only the specified number of characters... so it can handle the
107 : * case of 2 numbers that are part of the same string but are not separated
108 : * by a space.
109 : **********************************************************************/
110 940 : int AVCE00Str2Int(const char *pszStr, int numChars)
111 : {
112 940 : int nValue = 0;
113 :
114 940 : if (pszStr && numChars >= (int)strlen(pszStr))
115 30 : return atoi(pszStr);
116 910 : else if (pszStr)
117 : {
118 : char cNextDigit;
119 : char *pszTmp;
120 :
121 : /* Get rid of const */
122 910 : pszTmp = (char*)pszStr;
123 :
124 910 : cNextDigit = pszTmp[numChars];
125 910 : pszTmp[numChars] = '\0';
126 910 : nValue = atoi(pszTmp);
127 910 : pszTmp[numChars] = cNextDigit;
128 : }
129 :
130 910 : return nValue;
131 : }
132 :
133 : /**********************************************************************
134 : * AVCE00ParseInfoAlloc()
135 : *
136 : * Allocate and initialize a new AVCE00ParseInfo structure.
137 : *
138 : * AVCE00ParseStartSection() will have to be called at least once
139 : * to specify the type of objects to parse.
140 : *
141 : * The structure will eventually have to be freed with AVCE00ParseInfoFree().
142 : **********************************************************************/
143 2 : AVCE00ParseInfo *AVCE00ParseInfoAlloc()
144 : {
145 : AVCE00ParseInfo *psInfo;
146 :
147 2 : psInfo = (AVCE00ParseInfo*)CPLCalloc(1,sizeof(AVCE00ParseInfo));
148 :
149 2 : psInfo->eFileType = AVCFileUnknown;
150 2 : psInfo->eSuperSectionType = AVCFileUnknown;
151 :
152 : /* Allocate output buffer.
153 : * 2k should be enough... the biggest thing we'll need to store
154 : * in it will be 1 complete INFO table record.
155 : */
156 2 : psInfo->nBufSize = 2048;
157 2 : psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize*sizeof(char));
158 :
159 : /* Set a default precision, but this value will be set on a section
160 : * by section basis inside AVCE00ParseStartSection()
161 : */
162 2 : psInfo->nPrecision = AVC_SINGLE_PREC;
163 :
164 2 : return psInfo;
165 : }
166 :
167 : /**********************************************************************
168 : * _AVCE00ParseDestroyCurObject()
169 : *
170 : * Release mem. associated with the psInfo->cur.* object we are
171 : * currently using.
172 : **********************************************************************/
173 42 : void _AVCE00ParseDestroyCurObject(AVCE00ParseInfo *psInfo)
174 : {
175 42 : if (psInfo->eFileType == AVCFileUnknown)
176 24 : return;
177 :
178 18 : if (psInfo->eFileType == AVCFileARC)
179 : {
180 4 : CPLFree(psInfo->cur.psArc->pasVertices);
181 4 : CPLFree(psInfo->cur.psArc);
182 : }
183 28 : else if (psInfo->eFileType == AVCFilePAL ||
184 14 : psInfo->eFileType == AVCFileRPL )
185 : {
186 0 : CPLFree(psInfo->cur.psPal->pasArcs);
187 0 : CPLFree(psInfo->cur.psPal);
188 : }
189 14 : else if (psInfo->eFileType == AVCFileCNT)
190 : {
191 0 : CPLFree(psInfo->cur.psCnt->panLabelIds);
192 0 : CPLFree(psInfo->cur.psCnt);
193 : }
194 14 : else if (psInfo->eFileType == AVCFileLAB)
195 : {
196 2 : CPLFree(psInfo->cur.psLab);
197 : }
198 12 : else if (psInfo->eFileType == AVCFileTOL)
199 : {
200 2 : CPLFree(psInfo->cur.psTol);
201 : }
202 10 : else if (psInfo->eFileType == AVCFilePRJ)
203 : {
204 2 : CSLDestroy(psInfo->cur.papszPrj);
205 : }
206 16 : else if (psInfo->eFileType == AVCFileTXT ||
207 8 : psInfo->eFileType == AVCFileTX6)
208 : {
209 0 : CPLFree(psInfo->cur.psTxt->pasVertices);
210 0 : CPLFree(psInfo->cur.psTxt->pszText);
211 0 : CPLFree(psInfo->cur.psTxt);
212 : }
213 8 : else if (psInfo->eFileType == AVCFileRXP)
214 : {
215 0 : CPLFree(psInfo->cur.psRxp);
216 : }
217 8 : else if (psInfo->eFileType == AVCFileTABLE)
218 : {
219 8 : _AVCDestroyTableFields(psInfo->hdr.psTableDef, psInfo->cur.pasFields);
220 8 : _AVCDestroyTableDef(psInfo->hdr.psTableDef);
221 8 : psInfo->bTableHdrComplete = FALSE;
222 : }
223 : else
224 : {
225 0 : CPLError(CE_Failure, CPLE_NotSupported,
226 : "_AVCE00ParseDestroyCurObject(): Unsupported file type!");
227 : }
228 :
229 18 : psInfo->eFileType = AVCFileUnknown;
230 18 : psInfo->cur.psArc = NULL;
231 : }
232 :
233 : /**********************************************************************
234 : * AVCE00ParseInfoFree()
235 : *
236 : * Free any memory associated with a AVCE00ParseInfo structure.
237 : **********************************************************************/
238 2 : void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo)
239 : {
240 2 : if (psInfo)
241 : {
242 2 : CPLFree(psInfo->pszSectionHdrLine);
243 2 : psInfo->pszSectionHdrLine = NULL;
244 2 : CPLFree(psInfo->pszBuf);
245 2 : _AVCE00ParseDestroyCurObject(psInfo);
246 : }
247 :
248 2 : CPLFree(psInfo);
249 2 : }
250 :
251 : /**********************************************************************
252 : * AVCE00ParseReset()
253 : *
254 : * Reset the fields in a AVCE00ParseInfo structure so that further calls
255 : * to the API will be ready to process a new object.
256 : **********************************************************************/
257 22 : void AVCE00ParseReset(AVCE00ParseInfo *psInfo)
258 : {
259 22 : psInfo->iCurItem = psInfo->numItems = 0;
260 22 : psInfo->bForceEndOfSection = FALSE;
261 22 : }
262 :
263 :
264 : /**********************************************************************
265 : * AVCE00ParseSuperSectionHeader()
266 : *
267 : * Check if pszLine is a valid "supersection" header line, if it is one
268 : * then store the supersection type in the ParseInfo structure.
269 : *
270 : * What I call a "supersection" is a section that contains several
271 : * files, such as the TX6/TX7, RPL, RXP, ... and also the IFO (TABLEs).
272 : *
273 : * The ParseInfo structure won't be ready to read objects until
274 : * a call to AVCE00ParseSectionHeader() (see below) succesfully
275 : * recognizes the beginning of a subsection of this type.
276 : *
277 : * Returns the new supersection type, or AVCFileUnknown if the line is
278 : * not recognized.
279 : **********************************************************************/
280 29 : AVCFileType AVCE00ParseSuperSectionHeader(AVCE00ParseInfo *psInfo,
281 : const char *pszLine)
282 : {
283 : /*-----------------------------------------------------------------
284 : * If we're already inside a supersection or a section, then
285 : * return AVCFileUnknown right away.
286 : *----------------------------------------------------------------*/
287 79 : if (psInfo == NULL ||
288 29 : psInfo->eSuperSectionType != AVCFileUnknown ||
289 21 : psInfo->eFileType != AVCFileUnknown )
290 : {
291 8 : return AVCFileUnknown;
292 : }
293 :
294 : /*-----------------------------------------------------------------
295 : * Check if pszLine is a valid supersection header line.
296 : *----------------------------------------------------------------*/
297 21 : if (EQUALN(pszLine, "RPL ", 5))
298 0 : psInfo->eSuperSectionType = AVCFileRPL;
299 21 : else if (EQUALN(pszLine, "TX6 ", 5) || EQUALN(pszLine, "TX7 ", 5))
300 0 : psInfo->eSuperSectionType = AVCFileTX6;
301 21 : else if (EQUALN(pszLine, "RXP ", 5))
302 0 : psInfo->eSuperSectionType = AVCFileRXP;
303 21 : else if (EQUALN(pszLine, "IFO ", 5))
304 2 : psInfo->eSuperSectionType = AVCFileTABLE;
305 : else
306 19 : return AVCFileUnknown;
307 :
308 : /*-----------------------------------------------------------------
309 : * Record the start of the supersection (for faster seeking)
310 : *----------------------------------------------------------------*/
311 2 : psInfo->nStartLineNum = psInfo->nCurLineNum;
312 :
313 : /*-----------------------------------------------------------------
314 : * OK, we have a valid new section header. Set the precision and
315 : * get ready to read objects from it.
316 : *----------------------------------------------------------------*/
317 2 : if (atoi(pszLine+4) == 2)
318 2 : psInfo->nPrecision = AVC_SINGLE_PREC;
319 0 : else if (atoi(pszLine+4) == 3)
320 0 : psInfo->nPrecision = AVC_DOUBLE_PREC;
321 : else
322 : {
323 0 : CPLError(CE_Failure, CPLE_AppDefined,
324 : "Parse Error: Invalid section header line (\"%s\")!",
325 : pszLine);
326 0 : psInfo->eSuperSectionType = AVCFileUnknown;
327 : /* psInfo->nStartLineNum = -1; */
328 : }
329 :
330 2 : return psInfo->eSuperSectionType;
331 : }
332 :
333 : /**********************************************************************
334 : * AVCE00ParseSuperSectionEnd()
335 : *
336 : * Check if pszLine marks the end of a supersection, and if it is the
337 : * case, then reset the supersection flag in the ParseInfo.
338 : *
339 : * Supersections always end with the line "JABBERWOCKY", except for
340 : * the IFO section.
341 : **********************************************************************/
342 250 : GBool AVCE00ParseSuperSectionEnd(AVCE00ParseInfo *psInfo,
343 : const char *pszLine )
344 : {
345 311 : if (psInfo->eFileType == AVCFileUnknown &&
346 31 : psInfo->eSuperSectionType != AVCFileUnknown &&
347 10 : (EQUALN(pszLine, "JABBERWOCKY", 11) ||
348 10 : (psInfo->eSuperSectionType == AVCFileTABLE &&
349 10 : EQUALN(pszLine, "EOI", 3) ) ) )
350 : {
351 2 : psInfo->eSuperSectionType = AVCFileUnknown;
352 : /* psInfo->nStartLineNum = -1; */
353 2 : return TRUE;
354 : }
355 :
356 248 : return FALSE;
357 : }
358 :
359 :
360 : /**********************************************************************
361 : * AVCE00ParseSectionHeader()
362 : *
363 : * Check if pszLine is a valid section header line, then initialize the
364 : * ParseInfo structure to be ready to parse of object from that section.
365 : *
366 : * Returns the new section type, or AVCFileUnknown if the line is
367 : * not recognized as a valid section header.
368 : *
369 : * Note: by section header lines, we mean the "ARC 2", "PAL 2", etc.
370 : **********************************************************************/
371 27 : AVCFileType AVCE00ParseSectionHeader(AVCE00ParseInfo *psInfo,
372 : const char *pszLine)
373 : {
374 27 : AVCFileType eNewType = AVCFileUnknown;
375 :
376 54 : if (psInfo == NULL ||
377 27 : psInfo->eFileType != AVCFileUnknown)
378 : {
379 0 : return AVCFileUnknown;
380 : }
381 :
382 : /*-----------------------------------------------------------------
383 : * Check if pszLine is a valid section header line.
384 : *----------------------------------------------------------------*/
385 27 : if (psInfo->eSuperSectionType == AVCFileUnknown)
386 : {
387 : /*-------------------------------------------------------------
388 : * We're looking for a top-level section...
389 : *------------------------------------------------------------*/
390 19 : if (EQUALN(pszLine, "ARC ", 5))
391 4 : eNewType = AVCFileARC;
392 15 : else if (EQUALN(pszLine, "PAL ", 5))
393 0 : eNewType = AVCFilePAL;
394 15 : else if (EQUALN(pszLine, "CNT ", 5))
395 0 : eNewType = AVCFileCNT;
396 15 : else if (EQUALN(pszLine, "LAB ", 5))
397 2 : eNewType = AVCFileLAB;
398 13 : else if (EQUALN(pszLine, "TOL ", 5))
399 2 : eNewType = AVCFileTOL;
400 11 : else if (EQUALN(pszLine, "PRJ ", 5))
401 2 : eNewType = AVCFilePRJ;
402 9 : else if (EQUALN(pszLine, "TXT ", 5))
403 0 : eNewType = AVCFileTXT;
404 : else
405 : {
406 9 : eNewType = AVCFileUnknown;
407 9 : return AVCFileUnknown;
408 : }
409 :
410 : /*-------------------------------------------------------------
411 : * OK, we have a valid new section header. Set the precision and
412 : * get ready to read objects from it.
413 : *------------------------------------------------------------*/
414 10 : if (atoi(pszLine+4) == 2)
415 10 : psInfo->nPrecision = AVC_SINGLE_PREC;
416 0 : else if (atoi(pszLine+4) == 3)
417 0 : psInfo->nPrecision = AVC_DOUBLE_PREC;
418 : else
419 : {
420 0 : CPLError(CE_Failure, CPLE_AppDefined,
421 : "Parse Error: Invalid section header line (\"%s\")!",
422 : pszLine);
423 0 : eNewType = AVCFileUnknown;
424 0 : return AVCFileUnknown;
425 : }
426 :
427 : }
428 : else
429 : {
430 : /*-------------------------------------------------------------
431 : * We're looking for a section inside a super-section...
432 : * in this case, the header line contains the subclass name,
433 : * so any non-empty line is acceptable!
434 : * Note: the precision is already set from the previous call to
435 : * AVCE00ParseSuperSectionHeader()
436 : * Note2: Inside a double precision RPL supersection, the end of
437 : * each sub-section is marked by 2 lines, just like what
438 : * happens with double precision PALs... we have to make
439 : * sure we don't catch that second line as the beginning
440 : * of a new RPL sub-section.
441 : *------------------------------------------------------------*/
442 :
443 8 : if (psInfo->eSuperSectionType == AVCFileTX6 && strlen(pszLine)==0)
444 : {
445 : /* See bug 1261: It seems that empty subclass names are valid
446 : * for TX7. We don't know if that's valid for other supersection
447 : * types, so we'll handle this as a specific case just for TX7
448 : */
449 0 : eNewType = psInfo->eSuperSectionType;
450 : }
451 32 : else if (strlen(pszLine) > 0 && !isspace((unsigned char)pszLine[0]) &&
452 8 : !EQUALN(pszLine, "JABBERWOCKY", 11) &&
453 8 : !EQUALN(pszLine, "EOI", 3) &&
454 : ! ( psInfo->eSuperSectionType == AVCFileRPL &&
455 0 : EQUALN(pszLine, " 0.00000", 6) ) )
456 : {
457 8 : eNewType = psInfo->eSuperSectionType;
458 : }
459 0 : else if (strlen(pszLine) == 0 &&
460 0 : psInfo->eSuperSectionType == AVCFileTX6)
461 : {
462 0 : eNewType = psInfo->eSuperSectionType;
463 : }
464 : else
465 : {
466 0 : eNewType = AVCFileUnknown;
467 0 : return AVCFileUnknown;
468 : }
469 : }
470 :
471 : /*-----------------------------------------------------------------
472 : * nCurObjectId is used to keep track of sequential ids that are
473 : * not explicitly stored in E00. e.g. polygon Id in a PAL section.
474 : *----------------------------------------------------------------*/
475 18 : psInfo->nCurObjectId = 0;
476 :
477 : /*-----------------------------------------------------------------
478 : * Allocate a temp. structure to use to store the objects we read
479 : * (Using Calloc() will automatically initialize the struct contents
480 : * to NULL... this is very important for ARCs and PALs)
481 : *----------------------------------------------------------------*/
482 18 : _AVCE00ParseDestroyCurObject(psInfo);
483 :
484 18 : if (eNewType == AVCFileARC)
485 : {
486 4 : psInfo->cur.psArc = (AVCArc*)CPLCalloc(1, sizeof(AVCArc));
487 : }
488 14 : else if (eNewType == AVCFilePAL ||
489 : eNewType == AVCFileRPL )
490 : {
491 0 : psInfo->cur.psPal = (AVCPal*)CPLCalloc(1, sizeof(AVCPal));
492 : }
493 14 : else if (eNewType == AVCFileCNT)
494 : {
495 0 : psInfo->cur.psCnt = (AVCCnt*)CPLCalloc(1, sizeof(AVCCnt));
496 : }
497 14 : else if (eNewType == AVCFileLAB)
498 : {
499 2 : psInfo->cur.psLab = (AVCLab*)CPLCalloc(1, sizeof(AVCLab));
500 : }
501 12 : else if (eNewType == AVCFileTOL)
502 : {
503 2 : psInfo->cur.psTol = (AVCTol*)CPLCalloc(1, sizeof(AVCTol));
504 : }
505 10 : else if (eNewType == AVCFilePRJ)
506 : {
507 2 : psInfo->cur.papszPrj = NULL;
508 : }
509 8 : else if (eNewType == AVCFileTXT ||
510 : eNewType == AVCFileTX6)
511 : {
512 0 : psInfo->cur.psTxt = (AVCTxt*)CPLCalloc(1, sizeof(AVCTxt));
513 : }
514 8 : else if (eNewType == AVCFileRXP)
515 : {
516 0 : psInfo->cur.psRxp = (AVCRxp*)CPLCalloc(1, sizeof(AVCRxp));
517 : }
518 8 : else if (eNewType == AVCFileTABLE)
519 : {
520 8 : psInfo->cur.pasFields = NULL;
521 8 : psInfo->hdr.psTableDef = NULL;
522 8 : psInfo->bTableHdrComplete = FALSE;
523 : }
524 : else
525 : {
526 0 : CPLError(CE_Failure, CPLE_NotSupported,
527 : "AVCE00ParseSectionHeader(): Unsupported file type!");
528 0 : eNewType = AVCFileUnknown;
529 : }
530 :
531 18 : if (eNewType != AVCFileUnknown)
532 : {
533 : /*-----------------------------------------------------------------
534 : * Record the start of the section (for faster seeking)
535 : *----------------------------------------------------------------*/
536 18 : psInfo->nStartLineNum = psInfo->nCurLineNum;
537 :
538 : /*-----------------------------------------------------------------
539 : * Keep track of section header line... this is used for some file
540 : * types, specially the ones enclosed inside supersections.
541 : *----------------------------------------------------------------*/
542 18 : CPLFree(psInfo->pszSectionHdrLine);
543 18 : psInfo->pszSectionHdrLine = CPLStrdup(pszLine);
544 : }
545 :
546 18 : psInfo->eFileType = eNewType;
547 :
548 18 : return psInfo->eFileType;
549 : }
550 :
551 :
552 : /**********************************************************************
553 : * AVCE00ParseSectionEnd()
554 : *
555 : * Check if pszLine marks the end of the current section.
556 : *
557 : * Passing bResetParseInfo=TRUE will reset the parser struct if an end of
558 : * section is found. Passing FALSE simply tests for the end of section
559 : * without affecting the parse info struct.
560 : *
561 : * Return TRUE if this is the end of the section (and reset the
562 : * ParseInfo structure) , or FALSE otherwise.
563 : **********************************************************************/
564 195 : GBool AVCE00ParseSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine,
565 : GBool bResetParseInfo)
566 : {
567 1287 : if ( psInfo->bForceEndOfSection ||
568 180 : ((psInfo->eFileType == AVCFileARC ||
569 120 : psInfo->eFileType == AVCFilePAL ||
570 120 : psInfo->eFileType == AVCFileLAB ||
571 108 : psInfo->eFileType == AVCFileRPL ||
572 108 : psInfo->eFileType == AVCFileCNT ||
573 108 : psInfo->eFileType == AVCFileTOL ||
574 84 : psInfo->eFileType == AVCFileTXT ||
575 84 : psInfo->eFileType == AVCFileTX6 ||
576 84 : psInfo->eFileType == AVCFileRXP ) &&
577 96 : EQUALN(pszLine, " -1 0", 20) ) )
578 : {
579 : /* Reset ParseInfo only if explicitly requested.
580 : */
581 29 : if (bResetParseInfo)
582 : {
583 22 : _AVCE00ParseDestroyCurObject(psInfo);
584 22 : AVCE00ParseReset(psInfo);
585 22 : psInfo->eFileType = AVCFileUnknown;
586 :
587 22 : CPLFree(psInfo->pszSectionHdrLine);
588 22 : psInfo->pszSectionHdrLine = NULL;
589 :
590 22 : psInfo->bForceEndOfSection = FALSE;
591 : }
592 :
593 29 : return TRUE; /* YES, we reached the end */
594 : }
595 :
596 166 : return FALSE; /* NO, it's not the end of section line */
597 : }
598 :
599 : /**********************************************************************
600 : * AVCE00ParseNextLine()
601 : *
602 : * Take the next line of E00 input and parse it.
603 : *
604 : * Returns NULL if the current object is not complete yet (expecting
605 : * more lines of input) or a reference to a complete object if it
606 : * is complete.
607 : *
608 : * The returned object is a reference to an internal data structure.
609 : * It should not be modified or freed by the caller.
610 : *
611 : * If the input is invalid or other problems happen, then a CPLError()
612 : * will be generated. CPLGetLastErrorNo() should be called to check
613 : * that the line was parsed succesfully.
614 : *
615 : * Note for TABLES:
616 : * When parsing input from info tables, the first valid object that
617 : * will be returned will be the AVCTableDef, and then the data records
618 : * will follow. When all the records have been read, then the
619 : * psInfo->bForceEndOfSection flag will be set to TRUE since there is
620 : * no explicit "end of table" line in E00.
621 : **********************************************************************/
622 220 : void *AVCE00ParseNextLine(AVCE00ParseInfo *psInfo, const char *pszLine)
623 : {
624 220 : void *psObj = NULL;
625 :
626 220 : CPLAssert(psInfo);
627 220 : switch(psInfo->eFileType)
628 : {
629 : case AVCFileARC:
630 54 : psObj = (void*)AVCE00ParseNextArcLine(psInfo, pszLine);
631 54 : break;
632 : case AVCFilePAL:
633 : case AVCFileRPL:
634 0 : psObj = (void*)AVCE00ParseNextPalLine(psInfo, pszLine);
635 0 : break;
636 : case AVCFileCNT:
637 0 : psObj = (void*)AVCE00ParseNextCntLine(psInfo, pszLine);
638 0 : break;
639 : case AVCFileLAB:
640 8 : psObj = (void*)AVCE00ParseNextLabLine(psInfo, pszLine);
641 8 : break;
642 : case AVCFileTOL:
643 20 : psObj = (void*)AVCE00ParseNextTolLine(psInfo, pszLine);
644 20 : break;
645 : case AVCFilePRJ:
646 38 : psObj = (void*)AVCE00ParseNextPrjLine(psInfo, pszLine);
647 38 : break;
648 : case AVCFileTXT:
649 0 : psObj = (void*)AVCE00ParseNextTxtLine(psInfo, pszLine);
650 0 : break;
651 : case AVCFileTX6:
652 0 : psObj = (void*)AVCE00ParseNextTx6Line(psInfo, pszLine);
653 0 : break;
654 : case AVCFileRXP:
655 0 : psObj = (void*)AVCE00ParseNextRxpLine(psInfo, pszLine);
656 0 : break;
657 : case AVCFileTABLE:
658 100 : if ( ! psInfo->bTableHdrComplete )
659 54 : psObj = (void*)AVCE00ParseNextTableDefLine(psInfo, pszLine);
660 : else
661 46 : psObj = (void*)AVCE00ParseNextTableRecLine(psInfo, pszLine);
662 100 : break;
663 : default:
664 0 : CPLError(CE_Failure, CPLE_NotSupported,
665 : "AVCE00ParseNextLine(): Unsupported file type!");
666 : }
667 :
668 220 : return psObj;
669 : }
670 :
671 :
672 : /**********************************************************************
673 : * AVCE00ParseNextArcLine()
674 : *
675 : * Take the next line of E00 input for an ARC object and parse it.
676 : *
677 : * Returns NULL if the current object is not complete yet (expecting
678 : * more lines of input) or a reference to a complete object if it
679 : * is complete.
680 : *
681 : * The returned object is a reference to an internal data structure.
682 : * It should not be modified or freed by the caller.
683 : *
684 : * If the input is invalid or other problems happen, then a CPLError()
685 : * will be generated. CPLGetLastErrorNo() should be called to check
686 : * that the line was parsed succesfully.
687 : **********************************************************************/
688 54 : AVCArc *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine)
689 : {
690 : AVCArc *psArc;
691 : int nLen;
692 :
693 54 : CPLAssert(psInfo->eFileType == AVCFileARC);
694 :
695 54 : psArc = psInfo->cur.psArc;
696 :
697 54 : nLen = strlen(pszLine);
698 :
699 54 : if (psInfo->numItems == 0)
700 : {
701 : /*-------------------------------------------------------------
702 : * Begin processing a new object, read header line:
703 : * ArcId, UserId, FNode, TNode, LPoly, RPoly, numVertices
704 : *------------------------------------------------------------*/
705 22 : if (nLen < 70)
706 : {
707 0 : CPLError(CE_Failure, CPLE_AppDefined,
708 : "Error parsing E00 ARC line: \"%s\"", pszLine);
709 0 : return NULL;
710 : }
711 : else
712 : {
713 22 : psArc->nArcId = AVCE00Str2Int(pszLine, 10);
714 22 : psArc->nUserId = AVCE00Str2Int(pszLine+10, 10);
715 22 : psArc->nFNode = AVCE00Str2Int(pszLine+20, 10);
716 22 : psArc->nTNode = AVCE00Str2Int(pszLine+30, 10);
717 22 : psArc->nLPoly = AVCE00Str2Int(pszLine+40, 10);
718 22 : psArc->nRPoly = AVCE00Str2Int(pszLine+50, 10);
719 22 : psArc->numVertices = AVCE00Str2Int(pszLine+60, 10);
720 :
721 : /* Realloc the array of vertices
722 : */
723 22 : psArc->pasVertices = (AVCVertex*)CPLRealloc(psArc->pasVertices,
724 : psArc->numVertices*
725 : sizeof(AVCVertex));
726 :
727 : /* psInfo->iCurItem is the last vertex that was read.
728 : * psInfo->numItems is the number of vertices to read.
729 : */
730 22 : psInfo->iCurItem = 0;
731 22 : psInfo->numItems = psArc->numVertices;
732 : }
733 : }
734 128 : else if (psInfo->iCurItem < psInfo->numItems &&
735 32 : psInfo->nPrecision == AVC_SINGLE_PREC &&
736 32 : ( (psInfo->iCurItem==psInfo->numItems-1 && nLen >= 28) ||
737 : nLen >= 56 ) )
738 : {
739 : /*-------------------------------------------------------------
740 : * Single precision ARCs: 2 pairs of X,Y values per line
741 : * Except on the last line with an odd number of vertices)
742 : *------------------------------------------------------------*/
743 32 : psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine);
744 32 : psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+14);
745 32 : if (psInfo->iCurItem < psInfo->numItems && nLen >= 56)
746 : {
747 26 : psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine+28);
748 26 : psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+42);
749 : }
750 : }
751 0 : else if (psInfo->iCurItem < psInfo->numItems &&
752 0 : psInfo->nPrecision == AVC_DOUBLE_PREC &&
753 : nLen >= 42)
754 : {
755 : /*-------------------------------------------------------------
756 : * Double precision ARCs: 1 pair of X,Y values per line
757 : *------------------------------------------------------------*/
758 0 : psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine);
759 0 : psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+21);
760 : }
761 : else
762 : {
763 0 : CPLError(CE_Failure, CPLE_AppDefined,
764 : "Error parsing E00 ARC line: \"%s\"", pszLine);
765 0 : psInfo->numItems = psInfo->iCurItem = 0;
766 0 : return NULL;
767 : }
768 :
769 : /*-----------------------------------------------------------------
770 : * If we're done parsing this ARC, then reset the ParseInfo,
771 : * and return a reference to the ARC structure
772 : * Otherwise return NULL, which means that we are expecting more
773 : * more lines of input.
774 : *----------------------------------------------------------------*/
775 54 : if (psInfo->iCurItem >= psInfo->numItems)
776 : {
777 22 : psInfo->numItems = psInfo->iCurItem = 0;
778 22 : return psArc;
779 : }
780 :
781 32 : return NULL;
782 : }
783 :
784 : /**********************************************************************
785 : * AVCE00ParseNextPalLine()
786 : *
787 : * Take the next line of E00 input for an PAL object and parse it.
788 : *
789 : * Returns NULL if the current object is not complete yet (expecting
790 : * more lines of input) or a reference to a complete object if it
791 : * is complete.
792 : *
793 : * The returned object is a reference to an internal data structure.
794 : * It should not be modified or freed by the caller.
795 : *
796 : * If the input is invalid or other problems happen, then a CPLError()
797 : * will be generated. CPLGetLastErrorNo() should be called to check
798 : * that the line was parsed succesfully.
799 : **********************************************************************/
800 0 : AVCPal *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine)
801 : {
802 : AVCPal *psPal;
803 : int nLen;
804 :
805 0 : CPLAssert(psInfo->eFileType == AVCFilePAL ||
806 : psInfo->eFileType == AVCFileRPL );
807 :
808 0 : psPal = psInfo->cur.psPal;
809 :
810 0 : nLen = strlen(pszLine);
811 :
812 0 : if (psInfo->numItems == 0)
813 : {
814 : /*-------------------------------------------------------------
815 : * Begin processing a new object, read header line:
816 : * numArcs, MinX, MinY, MaxX, MaxY
817 : * For Double precision, MaxX, MaxY are on a separate line.
818 : *------------------------------------------------------------*/
819 0 : if (nLen < 52)
820 : {
821 0 : CPLError(CE_Failure, CPLE_AppDefined,
822 : "Error parsing E00 PAL line: \"%s\"", pszLine);
823 0 : return NULL;
824 : }
825 : else
826 : {
827 : /* Polygon Id is not stored in the E00 file. Polygons are
828 : * stored in increasing order, starting at 1... so we just
829 : * increment the previous value.
830 : */
831 0 : psPal->nPolyId = ++psInfo->nCurObjectId;
832 :
833 0 : psPal->numArcs = AVCE00Str2Int(pszLine, 10);
834 :
835 : /* If a PAL record has 0 arcs, it really has a single "0 0 0"
836 : * triplet as its data.
837 : */
838 0 : if ( psPal->numArcs == 0 )
839 : {
840 0 : psPal->numArcs = 1;
841 : }
842 :
843 : /* Realloc the array of Arcs
844 : */
845 0 : psPal->pasArcs = (AVCPalArc*)CPLRealloc(psPal->pasArcs,
846 : psPal->numArcs*
847 : sizeof(AVCPalArc));
848 :
849 : /* psInfo->iCurItem is the index of the last arc that was read.
850 : * psInfo->numItems is the number of arcs to read.
851 : */
852 0 : psInfo->iCurItem = 0;
853 0 : psInfo->numItems = psPal->numArcs;
854 :
855 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
856 : {
857 0 : psPal->sMin.x = atof(pszLine + 10);
858 0 : psPal->sMin.y = atof(pszLine + 24);
859 0 : psPal->sMax.x = atof(pszLine + 38);
860 0 : psPal->sMax.y = atof(pszLine + 52);
861 : }
862 : else
863 : {
864 0 : psPal->sMin.x = atof(pszLine + 10);
865 0 : psPal->sMin.y = atof(pszLine + 31);
866 : /* Set psInfo->iCurItem = -1 since we still have 2 values
867 : * from the header to read on the next line.
868 : */
869 0 : psInfo->iCurItem = -1;
870 : }
871 :
872 : }
873 : }
874 0 : else if (psInfo->iCurItem == -1 && nLen >= 42)
875 : {
876 0 : psPal->sMax.x = atof(pszLine);
877 0 : psPal->sMax.y = atof(pszLine + 21);
878 0 : psInfo->iCurItem++;
879 : }
880 0 : else if (psInfo->iCurItem < psPal->numArcs &&
881 : (nLen >= 60 ||
882 0 : (psInfo->iCurItem == psPal->numArcs-1 && nLen >= 30)) )
883 : {
884 : /*-------------------------------------------------------------
885 : * 2 PAL entries (ArcId, FNode, AdjPoly) per line,
886 : * (Except on the last line with an odd number of vertices)
887 : *------------------------------------------------------------*/
888 0 : psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine, 10);
889 0 : psPal->pasArcs[psInfo->iCurItem].nFNode = AVCE00Str2Int(pszLine+10,10);
890 0 : psPal->pasArcs[psInfo->iCurItem++].nAdjPoly = AVCE00Str2Int(pszLine+20,
891 : 10);
892 :
893 0 : if (psInfo->iCurItem < psInfo->numItems)
894 : {
895 0 : psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine+30,
896 : 10);
897 0 : psPal->pasArcs[psInfo->iCurItem].nFNode = AVCE00Str2Int(pszLine+40,
898 : 10);
899 0 : psPal->pasArcs[psInfo->iCurItem++].nAdjPoly =
900 0 : AVCE00Str2Int(pszLine+50, 10);
901 : }
902 :
903 : }
904 : else
905 : {
906 0 : CPLError(CE_Failure, CPLE_AppDefined,
907 : "Error parsing E00 PAL line: \"%s\"", pszLine);
908 0 : psInfo->numItems = psInfo->iCurItem = 0;
909 0 : return NULL;
910 : }
911 :
912 : /*-----------------------------------------------------------------
913 : * If we're done parsing this PAL, then reset the ParseInfo,
914 : * and return a reference to the PAL structure
915 : * Otherwise return NULL, which means that we are expecting more
916 : * more lines of input.
917 : *----------------------------------------------------------------*/
918 0 : if (psInfo->iCurItem >= psInfo->numItems)
919 : {
920 0 : psInfo->numItems = psInfo->iCurItem = 0;
921 0 : return psPal;
922 : }
923 :
924 0 : return NULL;
925 : }
926 :
927 :
928 : /**********************************************************************
929 : * AVCE00ParseNextCntLine()
930 : *
931 : * Take the next line of E00 input for an CNT object and parse it.
932 : *
933 : * Returns NULL if the current object is not complete yet (expecting
934 : * more lines of input) or a reference to a complete object if it
935 : * is complete.
936 : *
937 : * The returned object is a reference to an internal data structure.
938 : * It should not be modified or freed by the caller.
939 : *
940 : * If the input is invalid or other problems happen, then a CPLError()
941 : * will be generated. CPLGetLastErrorNo() should be called to check
942 : * that the line was parsed succesfully.
943 : **********************************************************************/
944 0 : AVCCnt *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine)
945 : {
946 : AVCCnt *psCnt;
947 : int nLen;
948 :
949 0 : CPLAssert(psInfo->eFileType == AVCFileCNT);
950 :
951 0 : psCnt = psInfo->cur.psCnt;
952 :
953 0 : nLen = strlen(pszLine);
954 :
955 0 : if (psInfo->numItems == 0)
956 : {
957 : /*-------------------------------------------------------------
958 : * Begin processing a new object, read header line:
959 : * numLabels, X, Y
960 : *------------------------------------------------------------*/
961 0 : if (nLen < 38)
962 : {
963 0 : CPLError(CE_Failure, CPLE_AppDefined,
964 : "Error parsing E00 CNT line: \"%s\"", pszLine);
965 0 : return NULL;
966 : }
967 : else
968 : {
969 : /* Polygon Id is not stored in the E00 file. Centroids are
970 : * stored in increasing order of Polygon Id, starting at 1...
971 : * so we just increment the previous value.
972 : */
973 0 : psCnt->nPolyId = ++psInfo->nCurObjectId;
974 :
975 0 : psCnt->numLabels = AVCE00Str2Int(pszLine, 10);
976 :
977 : /* Realloc the array of Labels Ids
978 : * Avoid allocating a 0-length segment since centroids can have
979 : * 0 labels attached to them.
980 : */
981 0 : if (psCnt->numLabels > 0)
982 0 : psCnt->panLabelIds = (GInt32 *)CPLRealloc(psCnt->panLabelIds,
983 : psCnt->numLabels*
984 : sizeof(GInt32));
985 :
986 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
987 : {
988 0 : psCnt->sCoord.x = atof(pszLine + 10);
989 0 : psCnt->sCoord.y = atof(pszLine + 24);
990 : }
991 : else
992 : {
993 0 : psCnt->sCoord.x = atof(pszLine + 10);
994 0 : psCnt->sCoord.y = atof(pszLine + 31);
995 : }
996 :
997 : /* psInfo->iCurItem is the index of the last label that was read.
998 : * psInfo->numItems is the number of label ids to read.
999 : */
1000 0 : psInfo->iCurItem = 0;
1001 0 : psInfo->numItems = psCnt->numLabels;
1002 :
1003 : }
1004 : }
1005 0 : else if (psInfo->iCurItem < psInfo->numItems )
1006 : {
1007 : /*-------------------------------------------------------------
1008 : * Each line can contain up to 8 label ids (10 chars each)
1009 : *------------------------------------------------------------*/
1010 0 : int i=0;
1011 0 : while(psInfo->iCurItem < psInfo->numItems && nLen >= (i+1)*10)
1012 : {
1013 0 : psCnt->panLabelIds[psInfo->iCurItem++] =
1014 0 : AVCE00Str2Int(pszLine + i*10, 10);
1015 0 : i++;
1016 : }
1017 :
1018 : }
1019 : else
1020 : {
1021 0 : CPLError(CE_Failure, CPLE_AppDefined,
1022 : "Error parsing E00 CNT line: \"%s\"", pszLine);
1023 0 : psInfo->numItems = psInfo->iCurItem = 0;
1024 0 : return NULL;
1025 : }
1026 :
1027 : /*-----------------------------------------------------------------
1028 : * If we're done parsing this CNT, then reset the ParseInfo,
1029 : * and return a reference to the CNT structure
1030 : * Otherwise return NULL, which means that we are expecting more
1031 : * more lines of input.
1032 : *----------------------------------------------------------------*/
1033 0 : if (psInfo->iCurItem >= psInfo->numItems)
1034 : {
1035 0 : psInfo->numItems = psInfo->iCurItem = 0;
1036 0 : return psCnt;
1037 : }
1038 :
1039 0 : return NULL;
1040 : }
1041 :
1042 : /**********************************************************************
1043 : * AVCE00ParseNextLabLine()
1044 : *
1045 : * Take the next line of E00 input for an LAB object and parse it.
1046 : *
1047 : * Returns NULL if the current object is not complete yet (expecting
1048 : * more lines of input) or a reference to a complete object if it
1049 : * is complete.
1050 : *
1051 : * The returned object is a reference to an internal data structure.
1052 : * It should not be modified or freed by the caller.
1053 : *
1054 : * If the input is invalid or other problems happen, then a CPLError()
1055 : * will be generated. CPLGetLastErrorNo() should be called to check
1056 : * that the line was parsed succesfully.
1057 : **********************************************************************/
1058 8 : AVCLab *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1059 : {
1060 : AVCLab *psLab;
1061 : int nLen;
1062 :
1063 8 : CPLAssert(psInfo->eFileType == AVCFileLAB);
1064 :
1065 8 : psLab = psInfo->cur.psLab;
1066 :
1067 8 : nLen = strlen(pszLine);
1068 :
1069 8 : if (psInfo->numItems == 0)
1070 : {
1071 : /*-------------------------------------------------------------
1072 : * Begin processing a new object, read header line:
1073 : * LabelValue, PolyId, X1, Y1
1074 : *------------------------------------------------------------*/
1075 4 : if (nLen < 48)
1076 : {
1077 0 : CPLError(CE_Failure, CPLE_AppDefined,
1078 : "Error parsing E00 LAB line: \"%s\"", pszLine);
1079 0 : return NULL;
1080 : }
1081 : else
1082 : {
1083 4 : psLab->nValue = AVCE00Str2Int(pszLine, 10);
1084 4 : psLab->nPolyId = AVCE00Str2Int(pszLine+10, 10);
1085 :
1086 4 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
1087 : {
1088 4 : psLab->sCoord1.x = atof(pszLine + 20);
1089 4 : psLab->sCoord1.y = atof(pszLine + 34);
1090 : }
1091 : else
1092 : {
1093 0 : psLab->sCoord1.x = atof(pszLine + 20);
1094 0 : psLab->sCoord1.y = atof(pszLine + 41);
1095 : }
1096 :
1097 : /* psInfo->iCurItem is the index of the last X,Y pair we read.
1098 : * psInfo->numItems is the number of X,Y pairs to read.
1099 : */
1100 4 : psInfo->iCurItem = 1;
1101 4 : psInfo->numItems = 3;
1102 :
1103 :
1104 : }
1105 : }
1106 8 : else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC &&
1107 : nLen >= 56 )
1108 : {
1109 4 : psLab->sCoord2.x = atof(pszLine);
1110 4 : psLab->sCoord2.y = atof(pszLine + 14);
1111 4 : psLab->sCoord3.x = atof(pszLine + 28);
1112 4 : psLab->sCoord3.y = atof(pszLine + 42);
1113 4 : psInfo->iCurItem += 2;
1114 : }
1115 0 : else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
1116 : nLen >= 42 )
1117 : {
1118 0 : psLab->sCoord2.x = atof(pszLine);
1119 0 : psLab->sCoord2.y = atof(pszLine + 21);
1120 0 : psInfo->iCurItem++;
1121 : }
1122 0 : else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
1123 : nLen >= 42 )
1124 : {
1125 0 : psLab->sCoord3.x = atof(pszLine);
1126 0 : psLab->sCoord3.y = atof(pszLine + 21);
1127 0 : psInfo->iCurItem++;
1128 : }
1129 : else
1130 : {
1131 0 : CPLError(CE_Failure, CPLE_AppDefined,
1132 : "Error parsing E00 LAB line: \"%s\"", pszLine);
1133 0 : psInfo->numItems = psInfo->iCurItem = 0;
1134 0 : return NULL;
1135 : }
1136 :
1137 : /*-----------------------------------------------------------------
1138 : * If we're done parsing this LAB, then reset the ParseInfo,
1139 : * and return a reference to the LAB structure
1140 : * Otherwise return NULL, which means that we are expecting more
1141 : * more lines of input.
1142 : *----------------------------------------------------------------*/
1143 8 : if (psInfo->iCurItem >= psInfo->numItems)
1144 : {
1145 4 : psInfo->numItems = psInfo->iCurItem = 0;
1146 4 : return psLab;
1147 : }
1148 :
1149 4 : return NULL;
1150 : }
1151 :
1152 :
1153 :
1154 : /**********************************************************************
1155 : * AVCE00ParseNextTolLine()
1156 : *
1157 : * Take the next line of E00 input for an TOL object and parse it.
1158 : *
1159 : * Returns NULL if the current object is not complete yet (expecting
1160 : * more lines of input) or a reference to a complete object if it
1161 : * is complete.
1162 : *
1163 : * The returned object is a reference to an internal data structure.
1164 : * It should not be modified or freed by the caller.
1165 : *
1166 : * If the input is invalid or other problems happen, then a CPLError()
1167 : * will be generated. CPLGetLastErrorNo() should be called to check
1168 : * that the line was parsed succesfully.
1169 : **********************************************************************/
1170 20 : AVCTol *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1171 : {
1172 : AVCTol *psTol;
1173 : int nLen;
1174 :
1175 20 : CPLAssert(psInfo->eFileType == AVCFileTOL);
1176 :
1177 20 : psTol = psInfo->cur.psTol;
1178 :
1179 20 : nLen = strlen(pszLine);
1180 :
1181 20 : if (nLen >= 34)
1182 : {
1183 : /*-------------------------------------------------------------
1184 : * TOL Entries are only one line each:
1185 : * TolIndex, TolFlag, TolValue
1186 : *------------------------------------------------------------*/
1187 20 : psTol->nIndex = AVCE00Str2Int(pszLine, 10);
1188 20 : psTol->nFlag = AVCE00Str2Int(pszLine + 10, 10);
1189 :
1190 20 : psTol->dValue = atof(pszLine + 20);
1191 : }
1192 : else
1193 : {
1194 0 : CPLError(CE_Failure, CPLE_AppDefined,
1195 : "Error parsing E00 TOL line: \"%s\"", pszLine);
1196 0 : psInfo->numItems = psInfo->iCurItem = 0;
1197 0 : return NULL;
1198 : }
1199 :
1200 : /*-----------------------------------------------------------------
1201 : * If we're done parsing this TOL, then reset the ParseInfo,
1202 : * and return a reference to the TOL structure
1203 : * Otherwise return NULL, which means that we are expecting more
1204 : * more lines of input.
1205 : *----------------------------------------------------------------*/
1206 20 : if (psInfo->iCurItem >= psInfo->numItems)
1207 : {
1208 20 : psInfo->numItems = psInfo->iCurItem = 0;
1209 20 : return psTol;
1210 : }
1211 :
1212 0 : return NULL;
1213 : }
1214 :
1215 : /**********************************************************************
1216 : * AVCE00ParseNextPrjLine()
1217 : *
1218 : * Take the next line of E00 input for a PRJ object and parse it.
1219 : *
1220 : * Returns NULL if the current object is not complete yet (expecting
1221 : * more lines of input) or a reference to a complete object if it
1222 : * is complete.
1223 : *
1224 : * Since a PRJ section contains only ONE projection, the function will
1225 : * always return NULL, until it reaches the end-of-section (EOP) line.
1226 : * This is behavior is a bit different from the other section types that
1227 : * will usually return a valid object immediately before the last line
1228 : * of the section (the end-of-section line).
1229 : *
1230 : * The returned object is a reference to an internal data structure.
1231 : * It should not be modified or freed by the caller.
1232 : *
1233 : * If the input is invalid or other problems happen, then a CPLError()
1234 : * will be generated. CPLGetLastErrorNo() should be called to check
1235 : * that the line was parsed succesfully.
1236 : **********************************************************************/
1237 38 : char **AVCE00ParseNextPrjLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1238 : {
1239 38 : CPLAssert(psInfo->eFileType == AVCFilePRJ);
1240 :
1241 : /*-------------------------------------------------------------
1242 : * Since a PRJ section contains only ONE projection, this function will
1243 : * always return NULL until it reaches the end-of-section (EOP) line.
1244 : * This is behavior is a bit different from the other section types that
1245 : * will usually return a valid object immediately before the last line
1246 : * of the section (the end-of-section line).
1247 : *------------------------------------------------------------*/
1248 :
1249 38 : if (EQUALN(pszLine, "EOP", 3))
1250 : {
1251 : /*-------------------------------------------------------------
1252 : * We reached end of section... return the PRJ.
1253 : *------------------------------------------------------------*/
1254 2 : psInfo->bForceEndOfSection = TRUE;
1255 2 : return psInfo->cur.papszPrj;
1256 : }
1257 :
1258 36 : if ( pszLine[0] != '~' )
1259 : {
1260 : /*-------------------------------------------------------------
1261 : * This is a new line... add it to the papszPrj stringlist.
1262 : *------------------------------------------------------------*/
1263 18 : psInfo->cur.papszPrj = CSLAddString(psInfo->cur.papszPrj, pszLine);
1264 : }
1265 18 : else if ( strlen(pszLine) > 1 )
1266 : {
1267 : /*-------------------------------------------------------------
1268 : * '~' is a line continuation char. Append what follows the '~'
1269 : * to the end of the previous line.
1270 : *------------------------------------------------------------*/
1271 : int iLastLine, nNewLen;
1272 :
1273 0 : iLastLine = CSLCount(psInfo->cur.papszPrj) - 1;
1274 0 : nNewLen = strlen(psInfo->cur.papszPrj[iLastLine])+strlen(pszLine)-1+1;
1275 0 : if (iLastLine >= 0)
1276 : {
1277 0 : psInfo->cur.papszPrj[iLastLine] =
1278 0 : (char*)CPLRealloc(psInfo->cur.papszPrj[iLastLine],
1279 : nNewLen * sizeof(char));
1280 :
1281 0 : strcat(psInfo->cur.papszPrj[iLastLine], pszLine+1);
1282 : }
1283 : }
1284 :
1285 36 : return NULL;
1286 : }
1287 :
1288 :
1289 : /**********************************************************************
1290 : * AVCE00ParseNextTxtLine()
1291 : *
1292 : * Take the next line of E00 input for an TXT object and parse it.
1293 : *
1294 : * Returns NULL if the current object is not complete yet (expecting
1295 : * more lines of input) or a reference to a complete object if it
1296 : * is complete.
1297 : *
1298 : * The returned object is a reference to an internal data structure.
1299 : * It should not be modified or freed by the caller.
1300 : *
1301 : * If the input is invalid or other problems happen, then a CPLError()
1302 : * will be generated. CPLGetLastErrorNo() should be called to check
1303 : * that the line was parsed succesfully.
1304 : **********************************************************************/
1305 0 : AVCTxt *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1306 : {
1307 : AVCTxt *psTxt;
1308 : int i, nLen, numFixedLines;
1309 :
1310 0 : CPLAssert(psInfo->eFileType == AVCFileTXT);
1311 :
1312 0 : psTxt = psInfo->cur.psTxt;
1313 :
1314 0 : nLen = strlen(pszLine);
1315 :
1316 : /* numFixedLines is the number of lines to expect before the line(s)
1317 : * with the text string
1318 : */
1319 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
1320 0 : numFixedLines = 4;
1321 : else
1322 0 : numFixedLines = 6;
1323 :
1324 0 : if (psInfo->numItems == 0)
1325 : {
1326 : /*-------------------------------------------------------------
1327 : * Begin processing a new object, read header line:
1328 : *------------------------------------------------------------*/
1329 0 : if (nLen < 50)
1330 : {
1331 0 : CPLError(CE_Failure, CPLE_AppDefined,
1332 : "Error parsing E00 TXT line: \"%s\"", pszLine);
1333 0 : return NULL;
1334 : }
1335 : else
1336 : {
1337 : int numVertices;
1338 : /*---------------------------------------------------------
1339 : * With TXT, there are several unused fields that have to be
1340 : * set to default values... usually 0.
1341 : *--------------------------------------------------------*/
1342 0 : psTxt->nUserId = 0;
1343 0 : psTxt->n28 = 0;
1344 0 : for(i=0; i<20; i++)
1345 0 : psTxt->anJust1[i] = psTxt->anJust2[i] = 0;
1346 0 : psTxt->dV2 = psTxt->dV3 = 0.0;
1347 :
1348 : /*---------------------------------------------------------
1349 : * System Id is not stored in the E00 file. Annotations are
1350 : * stored in increasing order of System Id, starting at 1...
1351 : * so we just increment the previous value.
1352 : *--------------------------------------------------------*/
1353 0 : psTxt->nTxtId = ++psInfo->nCurObjectId;
1354 :
1355 0 : psTxt->nLevel = AVCE00Str2Int(pszLine, 10);
1356 :
1357 : /* Add 1 to numVerticesLine because the first vertex is
1358 : * always duplicated in the TXT binary structure...
1359 : */
1360 0 : psTxt->numVerticesLine = AVCE00Str2Int(pszLine+10, 10) + 1;
1361 :
1362 0 : psTxt->numVerticesArrow= AVCE00Str2Int(pszLine+20, 10);
1363 0 : psTxt->nSymbol = AVCE00Str2Int(pszLine+30, 10);
1364 0 : psTxt->numChars = AVCE00Str2Int(pszLine+40, 10);
1365 :
1366 :
1367 : /*---------------------------------------------------------
1368 : * Realloc the string buffer and array of vertices
1369 : *--------------------------------------------------------*/
1370 0 : psTxt->pszText = (GByte *)CPLRealloc(psTxt->pszText,
1371 0 : (psTxt->numChars+1)*
1372 : sizeof(GByte));
1373 0 : numVertices = ABS(psTxt->numVerticesLine) +
1374 0 : ABS(psTxt->numVerticesArrow);
1375 0 : if (numVertices > 0)
1376 0 : psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices,
1377 : numVertices*sizeof(AVCVertex));
1378 :
1379 : /*---------------------------------------------------------
1380 : * Fill the whole string buffer with spaces we'll just
1381 : * paste lines in it using strncpy()
1382 : *--------------------------------------------------------*/
1383 0 : memset(psTxt->pszText, ' ', psTxt->numChars);
1384 0 : psTxt->pszText[psTxt->numChars] = '\0';
1385 :
1386 : /*---------------------------------------------------------
1387 : * psInfo->iCurItem is the index of the last line that was read.
1388 : * psInfo->numItems is the number of lines to read.
1389 : *--------------------------------------------------------*/
1390 0 : psInfo->iCurItem = 0;
1391 0 : psInfo->numItems = numFixedLines + ((psTxt->numChars-1)/80 + 1);
1392 :
1393 : }
1394 : }
1395 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1396 0 : psInfo->iCurItem < numFixedLines-1 && nLen >=63)
1397 : {
1398 : /*-------------------------------------------------------------
1399 : * Then we have a set of 15 coordinate values... unused ones
1400 : * are present but are set to 0.00E+00
1401 : *
1402 : * Vals 1 to 4 are X coords of line along which text is drawn
1403 : * Vals 5 to 8 are the corresponding Y coords
1404 : * Vals 9 to 11 are the X coords of the text arrow
1405 : * Vals 12 to 14 are the corresponding Y coords
1406 : * The 15th value is the height
1407 : *
1408 : * Note that the first vertex (values 1 and 5) is duplicated
1409 : * in the TXT structure... go wonder why???
1410 : *------------------------------------------------------------*/
1411 0 : int iCurCoord=0, numCoordPerLine, nItemSize, iVertex;
1412 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
1413 : {
1414 0 : numCoordPerLine = 5;
1415 0 : nItemSize = 14; /* Num of chars for single precision float*/
1416 : }
1417 : else
1418 : {
1419 0 : numCoordPerLine = 3;
1420 0 : nItemSize = 21; /* Num of chars for double precision float*/
1421 : }
1422 0 : iCurCoord = psInfo->iCurItem * numCoordPerLine;
1423 :
1424 0 : for(i=0; i<numCoordPerLine; i++, iCurCoord++)
1425 : {
1426 0 : if (iCurCoord < 4 &&
1427 0 : (iVertex = iCurCoord % 4) < psTxt->numVerticesLine-1)
1428 : {
1429 0 : psTxt->pasVertices[iVertex+1].x = atof(pszLine+i*nItemSize);
1430 : /* The first vertex is always duplicated */
1431 0 : if (iVertex == 0)
1432 0 : psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
1433 : }
1434 0 : else if (iCurCoord >= 4 && iCurCoord < 8 &&
1435 0 : (iVertex = iCurCoord % 4) < psTxt->numVerticesLine-1)
1436 : {
1437 0 : psTxt->pasVertices[iVertex+1].y = atof(pszLine+i*nItemSize);
1438 : /* The first vertex is always duplicated */
1439 0 : if (iVertex == 0)
1440 0 : psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
1441 : }
1442 0 : else if (iCurCoord >= 8 && iCurCoord < 11 &&
1443 0 : (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow)
1444 : {
1445 0 : psTxt->pasVertices[iVertex+psTxt->numVerticesLine].x =
1446 0 : atof(pszLine+i*nItemSize);
1447 : }
1448 0 : else if (iCurCoord >= 11 && iCurCoord < 14 &&
1449 0 : (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow)
1450 : {
1451 0 : psTxt->pasVertices[iVertex+psTxt->numVerticesLine].y =
1452 0 : atof(pszLine+i*nItemSize);
1453 : }
1454 0 : else if (iCurCoord == 14)
1455 : {
1456 0 : psTxt->dHeight = atof(pszLine+i*nItemSize);
1457 : }
1458 :
1459 : }
1460 :
1461 0 : psInfo->iCurItem++;
1462 : }
1463 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1464 0 : psInfo->iCurItem == numFixedLines-1 && nLen >=14)
1465 : {
1466 : /*-------------------------------------------------------------
1467 : * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
1468 : *------------------------------------------------------------*/
1469 0 : psTxt->f_1e2 = (float)atof(pszLine);
1470 :
1471 0 : psInfo->iCurItem++;
1472 : }
1473 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1474 0 : psInfo->iCurItem >= numFixedLines)
1475 : {
1476 : /*-------------------------------------------------------------
1477 : * Last line, contains the text string
1478 : * Note that text can be split in 80 chars chunk and that buffer
1479 : * has been previously initialized with spaces and '\0'-terminated
1480 : *------------------------------------------------------------*/
1481 : int numLines, iLine;
1482 0 : numLines = (psTxt->numChars-1)/80 + 1;
1483 0 : iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1484 :
1485 0 : if (iLine == numLines-1)
1486 : {
1487 0 : strncpy((char*)psTxt->pszText+(iLine*80), pszLine,
1488 0 : MIN( nLen, (psTxt->numChars - (iLine*80)) ) );
1489 : }
1490 : else
1491 : {
1492 0 : strncpy((char*)psTxt->pszText+(iLine*80), pszLine, MIN(nLen, 80));
1493 : }
1494 :
1495 0 : psInfo->iCurItem++;
1496 : }
1497 : else
1498 : {
1499 0 : CPLError(CE_Failure, CPLE_AppDefined,
1500 : "Error parsing E00 TXT line: \"%s\"", pszLine);
1501 0 : psInfo->numItems = psInfo->iCurItem = 0;
1502 0 : return NULL;
1503 : }
1504 :
1505 : /*-----------------------------------------------------------------
1506 : * If we're done parsing this TXT, then reset the ParseInfo,
1507 : * and return a reference to the TXT structure
1508 : * Otherwise return NULL, which means that we are expecting more
1509 : * more lines of input.
1510 : *----------------------------------------------------------------*/
1511 0 : if (psInfo->iCurItem >= psInfo->numItems)
1512 : {
1513 0 : psInfo->numItems = psInfo->iCurItem = 0;
1514 0 : return psTxt;
1515 : }
1516 :
1517 0 : return NULL;
1518 : }
1519 :
1520 :
1521 : /**********************************************************************
1522 : * AVCE00ParseNextTx6Line()
1523 : *
1524 : * Take the next line of E00 input for an TX6/TX7 object and parse it.
1525 : *
1526 : * Returns NULL if the current object is not complete yet (expecting
1527 : * more lines of input) or a reference to a complete object if it
1528 : * is complete.
1529 : *
1530 : * The returned object is a reference to an internal data structure.
1531 : * It should not be modified or freed by the caller.
1532 : *
1533 : * If the input is invalid or other problems happen, then a CPLError()
1534 : * will be generated. CPLGetLastErrorNo() should be called to check
1535 : * that the line was parsed succesfully.
1536 : **********************************************************************/
1537 0 : AVCTxt *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine)
1538 : {
1539 : AVCTxt *psTxt;
1540 : int i, nLen;
1541 :
1542 0 : CPLAssert(psInfo->eFileType == AVCFileTX6);
1543 :
1544 0 : psTxt = psInfo->cur.psTxt;
1545 :
1546 0 : nLen = strlen(pszLine);
1547 :
1548 0 : if (psInfo->numItems == 0)
1549 : {
1550 : /*-------------------------------------------------------------
1551 : * Begin processing a new object, read header line:
1552 : *------------------------------------------------------------*/
1553 0 : if (nLen < 70)
1554 : {
1555 0 : CPLError(CE_Failure, CPLE_AppDefined,
1556 : "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1557 0 : return NULL;
1558 : }
1559 : else
1560 : {
1561 : int numVertices;
1562 : /*---------------------------------------------------------
1563 : * System Id is not stored in the E00 file. Annotations are
1564 : * stored in increasing order of System Id, starting at 1...
1565 : * so we just increment the previous value.
1566 : *--------------------------------------------------------*/
1567 0 : psTxt->nTxtId = ++psInfo->nCurObjectId;
1568 :
1569 0 : psTxt->nUserId = AVCE00Str2Int(pszLine, 10);
1570 0 : psTxt->nLevel = AVCE00Str2Int(pszLine+10, 10);
1571 0 : psTxt->numVerticesLine = AVCE00Str2Int(pszLine+20, 10);
1572 0 : psTxt->numVerticesArrow= AVCE00Str2Int(pszLine+30, 10);
1573 0 : psTxt->nSymbol = AVCE00Str2Int(pszLine+40, 10);
1574 0 : psTxt->n28 = AVCE00Str2Int(pszLine+50, 10);
1575 0 : psTxt->numChars = AVCE00Str2Int(pszLine+60, 10);
1576 :
1577 : /*---------------------------------------------------------
1578 : * Realloc the string buffer and array of vertices
1579 : *--------------------------------------------------------*/
1580 0 : psTxt->pszText = (GByte *)CPLRealloc(psTxt->pszText,
1581 0 : (psTxt->numChars+1)*
1582 : sizeof(GByte));
1583 :
1584 0 : numVertices = ABS(psTxt->numVerticesLine) +
1585 0 : ABS(psTxt->numVerticesArrow);
1586 0 : if (numVertices > 0)
1587 0 : psTxt->pasVertices = (AVCVertex*)CPLRealloc(psTxt->pasVertices,
1588 : numVertices*sizeof(AVCVertex));
1589 :
1590 : /*---------------------------------------------------------
1591 : * Fill the whole string buffer with spaces we'll just
1592 : * paste lines in it using strncpy()
1593 : *--------------------------------------------------------*/
1594 0 : memset(psTxt->pszText, ' ', psTxt->numChars);
1595 0 : psTxt->pszText[psTxt->numChars] = '\0';
1596 :
1597 : /*---------------------------------------------------------
1598 : * psInfo->iCurItem is the index of the last line that was read.
1599 : * psInfo->numItems is the number of lines to read.
1600 : *--------------------------------------------------------*/
1601 0 : psInfo->iCurItem = 0;
1602 0 : psInfo->numItems = 8 + numVertices + ((psTxt->numChars-1)/80 + 1);
1603 : }
1604 : }
1605 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1606 0 : psInfo->iCurItem < 6 && nLen >=60)
1607 : {
1608 : /*-------------------------------------------------------------
1609 : * Text Justification stuff... 2 sets of 20 int16 values.
1610 : *------------------------------------------------------------*/
1611 : GInt16 *pValue;
1612 0 : int numValPerLine=7;
1613 :
1614 0 : if (psInfo->iCurItem < 3)
1615 0 : pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
1616 : else
1617 0 : pValue = psTxt->anJust1 + (psInfo->iCurItem-3) * 7;
1618 :
1619 : /* Last line of each set contains only 6 values instead of 7 */
1620 0 : if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5)
1621 0 : numValPerLine = 6;
1622 :
1623 0 : for(i=0; i<numValPerLine; i++)
1624 0 : pValue[i] = AVCE00Str2Int(pszLine + i*10, 10);
1625 :
1626 0 : psInfo->iCurItem++;
1627 : }
1628 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1629 0 : psInfo->iCurItem == 6 && nLen >=14)
1630 : {
1631 : /*-------------------------------------------------------------
1632 : * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
1633 : *------------------------------------------------------------*/
1634 0 : psTxt->f_1e2 = (float)atof(pszLine);
1635 0 : psInfo->iCurItem++;
1636 : }
1637 0 : else if (psInfo->iCurItem < psInfo->numItems &&
1638 0 : psInfo->iCurItem == 7 && nLen >=42)
1639 : {
1640 : /*-------------------------------------------------------------
1641 : * Line with 3 values, 1st value is text height.
1642 : *------------------------------------------------------------*/
1643 0 : psTxt->dHeight = atof(pszLine);
1644 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
1645 : {
1646 0 : psTxt->dV2 = atof(pszLine+14);
1647 0 : psTxt->dV3 = atof(pszLine+28);
1648 : }
1649 : else
1650 : {
1651 0 : psTxt->dV2 = atof(pszLine+21);
1652 0 : psTxt->dV3 = atof(pszLine+42);
1653 : }
1654 :
1655 0 : psInfo->iCurItem++;
1656 : }
1657 0 : else if (psInfo->iCurItem < (8 + ABS(psTxt->numVerticesLine) +
1658 0 : ABS(psTxt->numVerticesArrow)) && nLen >= 28)
1659 : {
1660 : /*-------------------------------------------------------------
1661 : * One line for each pair of X,Y coordinates
1662 : * (Lines 8 to 8+numVertices-1)
1663 : *------------------------------------------------------------*/
1664 0 : psTxt->pasVertices[ psInfo->iCurItem-8 ].x = atof(pszLine);
1665 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
1666 0 : psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+14);
1667 : else
1668 0 : psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+21);
1669 :
1670 0 : psInfo->iCurItem++;
1671 : }
1672 0 : else if (psInfo->iCurItem < psInfo->numItems)
1673 : {
1674 : /*-------------------------------------------------------------
1675 : * Last line, contains the text string
1676 : * Note that text can be split in 80 chars chunk and that buffer
1677 : * has been previously initialized with spaces and '\0'-terminated
1678 : *------------------------------------------------------------*/
1679 : int numLines, iLine;
1680 0 : numLines = (psTxt->numChars-1)/80 + 1;
1681 0 : iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1682 :
1683 0 : if (iLine == numLines-1)
1684 : {
1685 0 : strncpy((char*)psTxt->pszText+(iLine*80), pszLine,
1686 0 : MIN( nLen, (psTxt->numChars - (iLine*80)) ) );
1687 : }
1688 : else
1689 : {
1690 0 : strncpy((char*)psTxt->pszText+(iLine*80), pszLine, MIN(nLen, 80));
1691 : }
1692 :
1693 0 : psInfo->iCurItem++;
1694 : }
1695 : else
1696 : {
1697 0 : CPLError(CE_Failure, CPLE_AppDefined,
1698 : "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine);
1699 0 : psInfo->numItems = psInfo->iCurItem = 0;
1700 0 : return NULL;
1701 : }
1702 :
1703 : /*-----------------------------------------------------------------
1704 : * If we're done parsing this TX6/TX7, then reset the ParseInfo,
1705 : * and return a reference to the TXT structure
1706 : * Otherwise return NULL, which means that we are expecting more
1707 : * more lines of input.
1708 : *----------------------------------------------------------------*/
1709 0 : if (psInfo->iCurItem >= psInfo->numItems)
1710 : {
1711 0 : psInfo->numItems = psInfo->iCurItem = 0;
1712 0 : return psTxt;
1713 : }
1714 :
1715 0 : return NULL;
1716 : }
1717 :
1718 :
1719 :
1720 : /**********************************************************************
1721 : * AVCE00ParseNextRxpLine()
1722 : *
1723 : * Take the next line of E00 input for an RXP object and parse it.
1724 : *
1725 : * Returns NULL if the current object is not complete yet (expecting
1726 : * more lines of input) or a reference to a complete object if it
1727 : * is complete.
1728 : *
1729 : * The returned object is a reference to an internal data structure.
1730 : * It should not be modified or freed by the caller.
1731 : *
1732 : * If the input is invalid or other problems happen, then a CPLError()
1733 : * will be generated. CPLGetLastErrorNo() should be called to check
1734 : * that the line was parsed succesfully.
1735 : **********************************************************************/
1736 0 : AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine)
1737 : {
1738 : AVCRxp *psRxp;
1739 : int nLen;
1740 :
1741 0 : CPLAssert(psInfo->eFileType == AVCFileRXP);
1742 :
1743 0 : psRxp = psInfo->cur.psRxp;
1744 :
1745 0 : nLen = strlen(pszLine);
1746 :
1747 0 : if (nLen >= 20)
1748 : {
1749 : /*-------------------------------------------------------------
1750 : * RXP Entries are only one line each:
1751 : * Value1, Value2 (meaning of the value??? Don't know!!!)
1752 : *------------------------------------------------------------*/
1753 0 : psRxp->n1 = AVCE00Str2Int(pszLine, 10);
1754 0 : psRxp->n2 = AVCE00Str2Int(pszLine + 10, 10);
1755 : }
1756 : else
1757 : {
1758 0 : CPLError(CE_Failure, CPLE_AppDefined,
1759 : "Error parsing E00 RXP line: \"%s\"", pszLine);
1760 0 : psInfo->numItems = psInfo->iCurItem = 0;
1761 0 : return NULL;
1762 : }
1763 :
1764 : /*-----------------------------------------------------------------
1765 : * If we're done parsing this RXP, then reset the ParseInfo,
1766 : * and return a reference to the RXP structure
1767 : * Otherwise return NULL, which means that we are expecting more
1768 : * more lines of input.
1769 : *----------------------------------------------------------------*/
1770 0 : if (psInfo->iCurItem >= psInfo->numItems)
1771 : {
1772 0 : psInfo->numItems = psInfo->iCurItem = 0;
1773 0 : return psRxp;
1774 : }
1775 :
1776 0 : return NULL;
1777 : }
1778 :
1779 :
1780 : /*=====================================================================
1781 : TABLE stuff
1782 : =====================================================================*/
1783 :
1784 : /**********************************************************************
1785 : * AVCE00ParseNextTableDefLine()
1786 : *
1787 : * Take the next line of E00 input for an TableDef object and parse it.
1788 : *
1789 : * Returns NULL if the current object is not complete yet (expecting
1790 : * more lines of input) or a reference to a complete object if it
1791 : * is complete.
1792 : *
1793 : * The returned object is a reference to an internal data structure.
1794 : * It should not be modified or freed by the caller.
1795 : *
1796 : * If the input is invalid or other problems happen, then a CPLError()
1797 : * will be generated. CPLGetLastErrorNo() should be called to check
1798 : * that the line was parsed succesfully.
1799 : **********************************************************************/
1800 54 : AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo,
1801 : const char *pszLine)
1802 : {
1803 : AVCTableDef *psTableDef;
1804 : int nLen;
1805 :
1806 54 : CPLAssert(psInfo->eFileType == AVCFileTABLE);
1807 :
1808 54 : psTableDef = psInfo->hdr.psTableDef; /* May be NULL on first call */
1809 :
1810 54 : nLen = strlen(pszLine);
1811 :
1812 54 : if (psInfo->numItems == 0)
1813 : {
1814 : /*-------------------------------------------------------------
1815 : * Begin processing a new TableDef. Read header line:
1816 : * TableName, extFlag, numFields, RecSize, numRecords
1817 : *------------------------------------------------------------*/
1818 8 : if (nLen < 56)
1819 : {
1820 0 : CPLError(CE_Failure, CPLE_AppDefined,
1821 : "Error parsing E00 Table Definition line: \"%s\"",
1822 : pszLine);
1823 0 : return NULL;
1824 : }
1825 : else
1826 : {
1827 : /*---------------------------------------------------------
1828 : * Parse header line and alloc and init. a new psTableDef struct
1829 : *--------------------------------------------------------*/
1830 8 : psTableDef = psInfo->hdr.psTableDef =
1831 8 : (AVCTableDef*)CPLCalloc(1, sizeof(AVCTableDef));
1832 8 : psInfo->bTableHdrComplete = FALSE;
1833 :
1834 8 : strncpy(psTableDef->szTableName, pszLine, 32);
1835 8 : psTableDef->szTableName[32] = '\0';
1836 8 : strncpy(psTableDef->szExternal, pszLine+32, 2);
1837 8 : psTableDef->szExternal[2] = '\0';
1838 :
1839 8 : psTableDef->numFields = AVCE00Str2Int(pszLine+34, 4);
1840 8 : psTableDef->nRecSize = AVCE00Str2Int(pszLine+42, 4);
1841 8 : psTableDef->numRecords = AVCE00Str2Int(pszLine+46, 10);
1842 :
1843 : /*---------------------------------------------------------
1844 : * Alloc array of fields defs, will be filled in further calls
1845 : *--------------------------------------------------------*/
1846 8 : psTableDef->pasFieldDef =
1847 8 : (AVCFieldInfo*)CPLCalloc(psTableDef->numFields,
1848 : sizeof(AVCFieldInfo));
1849 :
1850 : /*---------------------------------------------------------
1851 : * psInfo->iCurItem is the index of the last field def we read.
1852 : * psInfo->numItems is the number of field defs to read,
1853 : * including deleted ones.
1854 : *--------------------------------------------------------*/
1855 8 : psInfo->numItems = AVCE00Str2Int(pszLine+38, 4);
1856 8 : psInfo->iCurItem = 0;
1857 8 : psInfo->nCurObjectId = 0; /* We'll use it as a field index */
1858 : }
1859 : }
1860 92 : else if (psInfo->iCurItem < psInfo->numItems && nLen >= 69 )
1861 : {
1862 : /*-------------------------------------------------------------
1863 : * Read an attribute field definition
1864 : * If field index is -1, then we ignore this line... we do not
1865 : * even count it in psInfo->iCurItem.
1866 : *------------------------------------------------------------*/
1867 : int nIndex;
1868 :
1869 46 : nIndex = AVCE00Str2Int(pszLine + 65, 4);
1870 :
1871 46 : if (nIndex > 0 && psInfo->nCurObjectId >= psTableDef->numFields)
1872 : {
1873 0 : CPLError(CE_Failure, CPLE_AppDefined,
1874 : "Error parsing E00 INFO Table Header: "
1875 : "number of fields is invalid "
1876 : "(expected %d, got at least %d)",
1877 0 : psTableDef->numFields, psInfo->nCurObjectId+1);
1878 0 : psInfo->numItems = psInfo->iCurItem = psInfo->nCurObjectId;
1879 0 : return NULL;
1880 : }
1881 :
1882 46 : if (nIndex > 0)
1883 : {
1884 : AVCFieldInfo *psDef;
1885 46 : psDef = &(psTableDef->pasFieldDef[psInfo->iCurItem]);
1886 :
1887 46 : psDef->nIndex = nIndex;
1888 :
1889 46 : strncpy(psDef->szName, pszLine, 16);
1890 46 : psDef->szName[16] = '\0';
1891 :
1892 46 : psDef->nSize = AVCE00Str2Int(pszLine + 16, 3);
1893 46 : psDef->v2 = AVCE00Str2Int(pszLine + 19, 2);
1894 :
1895 46 : psDef->nOffset = AVCE00Str2Int(pszLine + 21, 4);
1896 :
1897 46 : psDef->v4 = AVCE00Str2Int(pszLine + 25, 1);
1898 46 : psDef->v5 = AVCE00Str2Int(pszLine + 26, 2);
1899 46 : psDef->nFmtWidth= AVCE00Str2Int(pszLine + 28, 4);
1900 46 : psDef->nFmtPrec = AVCE00Str2Int(pszLine + 32, 2);
1901 46 : psDef->nType1 = AVCE00Str2Int(pszLine + 34, 3)/10;
1902 46 : psDef->nType2 = AVCE00Str2Int(pszLine + 34, 3)%10;
1903 46 : psDef->v10 = AVCE00Str2Int(pszLine + 37, 2);
1904 46 : psDef->v11 = AVCE00Str2Int(pszLine + 39, 4);
1905 46 : psDef->v12 = AVCE00Str2Int(pszLine + 43, 4);
1906 46 : psDef->v13 = AVCE00Str2Int(pszLine + 47, 2);
1907 :
1908 46 : strncpy(psDef->szAltName, pszLine+49, 16);
1909 46 : psDef->szAltName[16] = '\0';
1910 :
1911 46 : psInfo->nCurObjectId++;
1912 : }
1913 46 : psInfo->iCurItem++;
1914 : }
1915 : else
1916 : {
1917 0 : CPLError(CE_Failure, CPLE_AppDefined,
1918 : "Error parsing E00 Table Definition line: \"%s\"", pszLine);
1919 0 : psInfo->numItems = psInfo->iCurItem = 0;
1920 0 : return NULL;
1921 : }
1922 :
1923 : /*-----------------------------------------------------------------
1924 : * If we're done parsing this TableDef, then reset the ParseInfo,
1925 : * and return a reference to the TableDef structure.
1926 : * Next calls should go to AVCE00ParseNextTableRecLine() to
1927 : * read data records.
1928 : * Otherwise return NULL, which means that we are expecting more
1929 : * more lines of input.
1930 : *----------------------------------------------------------------*/
1931 54 : if (psInfo->iCurItem >= psInfo->numItems)
1932 : {
1933 8 : psInfo->numItems = psInfo->iCurItem = 0;
1934 8 : psInfo->nCurObjectId = 0;
1935 :
1936 8 : psInfo->bTableHdrComplete = TRUE;
1937 :
1938 : /*---------------------------------------------------------
1939 : * It is possible to have a table with 0 records... in this
1940 : * case we are already at the end of the section for that table.
1941 : *--------------------------------------------------------*/
1942 8 : if (psTableDef->numRecords == 0)
1943 0 : psInfo->bForceEndOfSection = TRUE;
1944 :
1945 8 : return psTableDef;
1946 : }
1947 :
1948 46 : return NULL;
1949 : }
1950 :
1951 : /**********************************************************************
1952 : * _AVCE00ParseTableRecord()
1953 : *
1954 : * Parse the record data present inside psInfo->pszBuf and fill and
1955 : * return the psInfo->cur.pasFields[].
1956 : *
1957 : * This function should not be called directly... it is used by
1958 : * AVCE00ParseNextTableRecLine().
1959 : **********************************************************************/
1960 28 : static AVCField *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
1961 : {
1962 : AVCField *pasFields;
1963 : AVCFieldInfo *pasDef;
1964 : AVCTableDef *psTableDef;
1965 : int i, nType, nSize;
1966 : char *pszBuf, szTmp[30];
1967 :
1968 28 : pasFields = psInfo->cur.pasFields;
1969 28 : psTableDef = psInfo->hdr.psTableDef;
1970 28 : pasDef = psTableDef->pasFieldDef;
1971 :
1972 28 : pszBuf = psInfo->pszBuf;
1973 :
1974 204 : for(i=0; i<psTableDef->numFields; i++)
1975 : {
1976 176 : nType = pasDef[i].nType1*10;
1977 176 : nSize = pasDef[i].nSize;
1978 :
1979 194 : if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
1980 : nType == AVC_FT_FIXINT )
1981 : {
1982 18 : strncpy((char*)pasFields[i].pszStr, pszBuf, nSize);
1983 18 : pasFields[i].pszStr[nSize] = '\0';
1984 18 : pszBuf += nSize;
1985 : }
1986 158 : else if (nType == AVC_FT_FIXNUM)
1987 : {
1988 : /* TYPE 40 attributes are stored with 1 byte per digit
1989 : * in binary format, and as single precision floats in
1990 : * E00 tables, even in double precision coverages.
1991 : */
1992 : const char *pszTmpStr;
1993 0 : strncpy(szTmp, pszBuf, 14);
1994 0 : szTmp[14] = '\0';
1995 0 : pszBuf += 14;
1996 :
1997 : /* Compensate for a very odd behavior observed in some E00 files.
1998 : * A type 40 field can be written in decimal format instead of
1999 : * exponent format, but in this case the decimal point is shifted
2000 : * one position to the right, resulting in a value 10 times bigger
2001 : * than expected. So if the value is not in exponent format then
2002 : * we should shift the decimal point to the left before we
2003 : * interpret it. (bug 599)
2004 : */
2005 0 : if (!strchr(szTmp, 'E') && !strchr(szTmp, 'e'))
2006 : {
2007 : char *pszTmp;
2008 0 : if ( (pszTmp=strchr(szTmp, '.')) != NULL && pszTmp != szTmp )
2009 : {
2010 0 : *pszTmp = *(pszTmp-1);
2011 0 : *(pszTmp-1) = '.';
2012 : }
2013 : }
2014 :
2015 : /* We use nSize and nFmtPrec for the format because nFmtWidth can
2016 : * be different from nSize, but nSize has priority since it
2017 : * is the actual size of the field in memory.
2018 : */
2019 0 : pszTmpStr = CPLSPrintf("%*.*f",
2020 0 : nSize, pasDef[i].nFmtPrec, atof(szTmp));
2021 :
2022 : /* If value is bigger than size, then it's too bad... we
2023 : * truncate it... but this should never happen in clean datasets.
2024 : */
2025 0 : if ((int)strlen(pszTmpStr) > nSize)
2026 0 : pszTmpStr = pszTmpStr + strlen(pszTmpStr) - nSize;
2027 0 : strncpy((char*)pasFields[i].pszStr, pszTmpStr, nSize);
2028 0 : pasFields[i].pszStr[nSize] = '\0';
2029 : }
2030 220 : else if (nType == AVC_FT_BININT && nSize == 4)
2031 : {
2032 62 : pasFields[i].nInt32 = AVCE00Str2Int(pszBuf, 11);
2033 62 : pszBuf += 11;
2034 : }
2035 96 : else if (nType == AVC_FT_BININT && nSize == 2)
2036 : {
2037 0 : pasFields[i].nInt16 = AVCE00Str2Int(pszBuf, 6);
2038 0 : pszBuf += 6;
2039 : }
2040 192 : else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
2041 : {
2042 : /* NOTE: The E00 representation for a binary float is
2043 : * defined by its binary size, not by the coverage's
2044 : * precision.
2045 : */
2046 96 : strncpy(szTmp, pszBuf, 14);
2047 96 : szTmp[14] = '\0';
2048 96 : pasFields[i].fFloat = (float)atof(szTmp);
2049 96 : pszBuf += 14;
2050 : }
2051 0 : else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
2052 : {
2053 : /* NOTE: The E00 representation for a binary float is
2054 : * defined by its binary size, not by the coverage's
2055 : * precision.
2056 : */
2057 0 : strncpy(szTmp, pszBuf, 24);
2058 0 : szTmp[24] = '\0';
2059 0 : pasFields[i].dDouble = atof(szTmp);
2060 0 : pszBuf += 24;
2061 : }
2062 : else
2063 : {
2064 : /*-----------------------------------------------------
2065 : * Hummm... unsupported field type...
2066 : *----------------------------------------------------*/
2067 0 : CPLError(CE_Failure, CPLE_NotSupported,
2068 : "_AVCE00ParseTableRecord(): Unsupported field type "
2069 : "(type=%d, size=%d)",
2070 0 : nType, pasDef[i].nSize);
2071 0 : return NULL;
2072 : }
2073 : }
2074 :
2075 28 : CPLAssert(pszBuf == psInfo->pszBuf + psInfo->nTableE00RecLength);
2076 :
2077 28 : return pasFields;
2078 : }
2079 :
2080 : /**********************************************************************
2081 : * AVCE00ParseNextTableRecLine()
2082 : *
2083 : * Take the next line of E00 input for an Table data record and parse it.
2084 : *
2085 : * Returns NULL if the current record is not complete yet (expecting
2086 : * more lines of input) or a reference to a complete record if it
2087 : * is complete.
2088 : *
2089 : * The returned record is a reference to an internal data structure.
2090 : * It should not be modified or freed by the caller.
2091 : *
2092 : * If the input is invalid or other problems happen, then a CPLError()
2093 : * will be generated. CPLGetLastErrorNo() should be called to check
2094 : * that the line was parsed succesfully.
2095 : **********************************************************************/
2096 46 : AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo,
2097 : const char *pszLine)
2098 : {
2099 46 : AVCField *pasFields = NULL;
2100 : AVCTableDef *psTableDef;
2101 : int i;
2102 :
2103 46 : CPLAssert(psInfo->eFileType == AVCFileTABLE);
2104 :
2105 46 : psTableDef = psInfo->hdr.psTableDef;
2106 :
2107 92 : if (psInfo->bForceEndOfSection || psTableDef->numFields == 0 ||
2108 46 : psTableDef->numRecords == 0)
2109 : {
2110 0 : psInfo->bForceEndOfSection = TRUE;
2111 0 : return NULL;
2112 : }
2113 :
2114 : /*-----------------------------------------------------------------
2115 : * On the first call for a new table, we have some allocations to
2116 : * do:
2117 : * - make sure the psInfo->szBuf is big enough to hold one complete
2118 : * E00 data record.
2119 : * - Alloc the array of Field values (psInfo->cur.pasFields[])
2120 : * for the number of fields in this table.
2121 : *----------------------------------------------------------------*/
2122 46 : if (psInfo->numItems == 0 && psInfo->nCurObjectId == 0)
2123 : {
2124 : /*-------------------------------------------------------------
2125 : * Realloc E00 buffer
2126 : *------------------------------------------------------------*/
2127 8 : psInfo->nTableE00RecLength =
2128 8 : _AVCE00ComputeRecSize(psTableDef->numFields,
2129 : psTableDef->pasFieldDef, FALSE);
2130 :
2131 8 : if (psInfo->nBufSize < psInfo->nTableE00RecLength + 1)
2132 : {
2133 0 : psInfo->nBufSize = psInfo->nTableE00RecLength + 1;
2134 0 : psInfo->pszBuf = (char*)CPLRealloc(psInfo->pszBuf,
2135 0 : psInfo->nBufSize);
2136 : }
2137 :
2138 : /*---------------------------------------------------------
2139 : * Alloc psInfo->cur.pasFields[]
2140 : * Also alloc buffers for string attributes.
2141 : *--------------------------------------------------------*/
2142 8 : psInfo->cur.pasFields = (AVCField*)CPLCalloc(psTableDef->numFields,
2143 : sizeof(AVCField));
2144 54 : for(i=0; i<psTableDef->numFields; i++)
2145 : {
2146 176 : if (psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_DATE ||
2147 46 : psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_CHAR ||
2148 42 : psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXINT ||
2149 42 : psTableDef->pasFieldDef[i].nType1*10 == AVC_FT_FIXNUM )
2150 : {
2151 8 : psInfo->cur.pasFields[i].pszStr =
2152 4 : (GByte*)CPLCalloc(psTableDef->pasFieldDef[i].nSize+1,
2153 : sizeof(GByte));
2154 : }
2155 : }
2156 :
2157 : }
2158 :
2159 46 : if (psInfo->numItems == 0)
2160 : {
2161 : /*-----------------------------------------------------------------
2162 : * Begin processing a new record... we'll accumulate the 80
2163 : * chars lines until we have the whole record in our buffer
2164 : * and parse it only at the end.
2165 : * Lines shorter than 80 chars are legal, and in this case
2166 : * they will be padded with spaces up to 80 chars.
2167 : *----------------------------------------------------------------*/
2168 :
2169 : /*---------------------------------------------------------
2170 : * First fill the whole record buffer with spaces we'll just
2171 : * paste lines in it using strncpy()
2172 : *--------------------------------------------------------*/
2173 28 : memset(psInfo->pszBuf, ' ', psInfo->nTableE00RecLength);
2174 28 : psInfo->pszBuf[psInfo->nTableE00RecLength] = '\0';
2175 :
2176 :
2177 : /*---------------------------------------------------------
2178 : * psInfo->iCurItem is the number of chars buffered so far.
2179 : * psInfo->numItems is the number of chars to expect in one record.
2180 : *--------------------------------------------------------*/
2181 28 : psInfo->numItems = psInfo->nTableE00RecLength;
2182 28 : psInfo->iCurItem = 0;
2183 : }
2184 :
2185 :
2186 46 : if (psInfo->iCurItem < psInfo->numItems)
2187 : {
2188 : /*-------------------------------------------------------------
2189 : * Continue to accumulate the 80 chars lines until we have
2190 : * the whole record in our buffer. We'll parse it only at the end.
2191 : * Lines shorter than 80 chars are legal, and in this case
2192 : * they padded with spaces up to 80 chars.
2193 : *------------------------------------------------------------*/
2194 : int nSrcLen, nLenToCopy;
2195 :
2196 46 : nSrcLen = strlen(pszLine);
2197 46 : nLenToCopy = MIN(80, MIN(nSrcLen,(psInfo->numItems-psInfo->iCurItem)));
2198 46 : strncpy(psInfo->pszBuf+psInfo->iCurItem, pszLine, nLenToCopy);
2199 :
2200 46 : psInfo->iCurItem+=80;
2201 : }
2202 :
2203 :
2204 46 : if (psInfo->iCurItem >= psInfo->numItems)
2205 : {
2206 : /*-------------------------------------------------------------
2207 : * OK, we've got one full record in the buffer... parse it and
2208 : * return the pasFields[]
2209 : *------------------------------------------------------------*/
2210 28 : pasFields = _AVCE00ParseTableRecord(psInfo);
2211 :
2212 28 : if (pasFields == NULL)
2213 : {
2214 0 : CPLError(CE_Failure, CPLE_AppDefined,
2215 : "Error parsing E00 Table Record: \"%s\"",
2216 : psInfo->pszBuf);
2217 0 : return NULL;
2218 : }
2219 :
2220 28 : psInfo->numItems = psInfo->iCurItem = 0;
2221 28 : psInfo->nCurObjectId++;
2222 : }
2223 :
2224 : /*-----------------------------------------------------------------
2225 : * Since there is no explicit "end of table" line, we set the
2226 : * bForceEndOfSection flag when the last record is read.
2227 : *----------------------------------------------------------------*/
2228 46 : if (psInfo->nCurObjectId >= psTableDef->numRecords)
2229 : {
2230 8 : psInfo->bForceEndOfSection = TRUE;
2231 : }
2232 :
2233 46 : return pasFields;
2234 : }
2235 :
2236 :
|