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