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