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