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