/src/gdal/ogr/ogrsf_frmts/avc/avc_e00parse.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | static int AVCE00Str2Int(const char *pszStr, int numChars) |
93 | 60.3M | { |
94 | 60.3M | int nValue = 0; |
95 | | |
96 | 60.3M | if (pszStr && numChars >= (int)strlen(pszStr)) |
97 | 2.46M | return atoi(pszStr); |
98 | 57.9M | else if (pszStr) |
99 | 57.9M | { |
100 | 57.9M | char cNextDigit; |
101 | 57.9M | char *pszTmp; |
102 | | |
103 | | /* Get rid of const */ |
104 | 57.9M | pszTmp = (char *)pszStr; |
105 | | |
106 | 57.9M | cNextDigit = pszTmp[numChars]; |
107 | 57.9M | pszTmp[numChars] = '\0'; |
108 | 57.9M | nValue = atoi(pszTmp); |
109 | 57.9M | pszTmp[numChars] = cNextDigit; |
110 | 57.9M | } |
111 | | |
112 | 57.9M | return nValue; |
113 | 60.3M | } |
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 | | AVCE00ParseInfo *AVCE00ParseInfoAlloc(void) |
126 | 77.1k | { |
127 | 77.1k | AVCE00ParseInfo *psInfo; |
128 | | |
129 | 77.1k | 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 | 77.1k | psInfo->nBufSize = 2048; |
136 | 77.1k | 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 | 77.1k | psInfo->nPrecision = AVC_SINGLE_PREC; |
142 | | |
143 | 77.1k | return psInfo; |
144 | 77.1k | } |
145 | | |
146 | | /********************************************************************** |
147 | | * _AVCE00ParseDestroyCurObject() |
148 | | * |
149 | | * Release mem. associated with the psInfo->cur.* object we are |
150 | | * currently using. |
151 | | **********************************************************************/ |
152 | | static void _AVCE00ParseDestroyCurObject(AVCE00ParseInfo *psInfo) |
153 | 19.2M | { |
154 | 19.2M | if (psInfo->eFileType == AVCFileUnknown) |
155 | 9.68M | return; |
156 | | |
157 | 9.55M | if (psInfo->eFileType == AVCFileARC) |
158 | 1.12M | { |
159 | 1.12M | CPLFree(psInfo->cur.psArc->pasVertices); |
160 | 1.12M | CPLFree(psInfo->cur.psArc); |
161 | 1.12M | psInfo->cur.psArc = nullptr; |
162 | 1.12M | } |
163 | 8.42M | else if (psInfo->eFileType == AVCFilePAL || psInfo->eFileType == AVCFileRPL) |
164 | 2.68M | { |
165 | 2.68M | CPLFree(psInfo->cur.psPal->pasArcs); |
166 | 2.68M | CPLFree(psInfo->cur.psPal); |
167 | 2.68M | psInfo->cur.psPal = nullptr; |
168 | 2.68M | } |
169 | 5.74M | else if (psInfo->eFileType == AVCFileCNT) |
170 | 109k | { |
171 | 109k | CPLFree(psInfo->cur.psCnt->panLabelIds); |
172 | 109k | CPLFree(psInfo->cur.psCnt); |
173 | 109k | psInfo->cur.psCnt = nullptr; |
174 | 109k | } |
175 | 5.63M | else if (psInfo->eFileType == AVCFileLAB) |
176 | 1.98M | { |
177 | 1.98M | CPLFree(psInfo->cur.psLab); |
178 | 1.98M | psInfo->cur.psLab = nullptr; |
179 | 1.98M | } |
180 | 3.65M | else if (psInfo->eFileType == AVCFileTOL) |
181 | 710 | { |
182 | 710 | CPLFree(psInfo->cur.psTol); |
183 | 710 | psInfo->cur.psTol = nullptr; |
184 | 710 | } |
185 | 3.65M | else if (psInfo->eFileType == AVCFilePRJ) |
186 | 1.74M | { |
187 | 1.74M | psInfo->aosPrj.Clear(); |
188 | 1.74M | } |
189 | 1.91M | else if (psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6) |
190 | 18.6k | { |
191 | 18.6k | CPLFree(psInfo->cur.psTxt->pasVertices); |
192 | 18.6k | CPLFree(psInfo->cur.psTxt->pszText); |
193 | 18.6k | CPLFree(psInfo->cur.psTxt); |
194 | 18.6k | psInfo->cur.psTxt = nullptr; |
195 | 18.6k | } |
196 | 1.89M | else if (psInfo->eFileType == AVCFileRXP) |
197 | 2.33k | { |
198 | 2.33k | CPLFree(psInfo->cur.psRxp); |
199 | 2.33k | psInfo->cur.psRxp = nullptr; |
200 | 2.33k | } |
201 | 1.88M | else if (psInfo->eFileType == AVCFileTABLE) |
202 | 1.88M | { |
203 | 1.88M | _AVCDestroyTableFields(psInfo->hdr.psTableDef, psInfo->cur.pasFields); |
204 | 1.88M | _AVCDestroyTableDef(psInfo->hdr.psTableDef); |
205 | 1.88M | psInfo->hdr.psTableDef = nullptr; |
206 | 1.88M | psInfo->cur.pasFields = nullptr; |
207 | 1.88M | psInfo->bTableHdrComplete = FALSE; |
208 | 1.88M | } |
209 | 0 | else |
210 | 0 | { |
211 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
212 | 0 | "_AVCE00ParseDestroyCurObject(): Unsupported file type!"); |
213 | 0 | } |
214 | | |
215 | 9.55M | psInfo->eFileType = AVCFileUnknown; |
216 | 9.55M | } |
217 | | |
218 | | /********************************************************************** |
219 | | * AVCE00ParseInfoFree() |
220 | | * |
221 | | * Free any memory associated with a AVCE00ParseInfo structure. |
222 | | **********************************************************************/ |
223 | | void AVCE00ParseInfoFree(AVCE00ParseInfo *psInfo) |
224 | 77.1k | { |
225 | 77.1k | if (psInfo) |
226 | 77.1k | { |
227 | 77.1k | CPLFree(psInfo->pszSectionHdrLine); |
228 | 77.1k | psInfo->pszSectionHdrLine = nullptr; |
229 | 77.1k | CPLFree(psInfo->pszBuf); |
230 | 77.1k | _AVCE00ParseDestroyCurObject(psInfo); |
231 | 77.1k | } |
232 | | |
233 | 77.1k | delete psInfo; |
234 | 77.1k | } |
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 | | void AVCE00ParseReset(AVCE00ParseInfo *psInfo) |
243 | 9.60M | { |
244 | 9.60M | psInfo->iCurItem = psInfo->numItems = 0; |
245 | 9.60M | psInfo->bForceEndOfSection = FALSE; |
246 | 9.60M | } |
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 | | AVCFileType AVCE00ParseSuperSectionHeader(AVCE00ParseInfo *psInfo, |
265 | | const char *pszLine) |
266 | 36.5M | { |
267 | | /*----------------------------------------------------------------- |
268 | | * If we're already inside a supersection or a section, then |
269 | | * return AVCFileUnknown right away. |
270 | | *----------------------------------------------------------------*/ |
271 | 36.5M | if (psInfo == nullptr || psInfo->eSuperSectionType != AVCFileUnknown || |
272 | 36.5M | psInfo->eFileType != AVCFileUnknown) |
273 | 1.98M | { |
274 | 1.98M | return AVCFileUnknown; |
275 | 1.98M | } |
276 | | |
277 | | /*----------------------------------------------------------------- |
278 | | * Check if pszLine is a valid supersection header line. |
279 | | *----------------------------------------------------------------*/ |
280 | 34.5M | if (STARTS_WITH_CI(pszLine, "RPL ")) |
281 | 9.37k | psInfo->eSuperSectionType = AVCFileRPL; |
282 | 34.5M | else if (STARTS_WITH_CI(pszLine, "TX6 ") || |
283 | 34.5M | STARTS_WITH_CI(pszLine, "TX7 ")) |
284 | 3.88k | psInfo->eSuperSectionType = AVCFileTX6; |
285 | 34.5M | else if (STARTS_WITH_CI(pszLine, "RXP ")) |
286 | 571 | psInfo->eSuperSectionType = AVCFileRXP; |
287 | 34.5M | else if (STARTS_WITH_CI(pszLine, "IFO ")) |
288 | 1.86M | psInfo->eSuperSectionType = AVCFileTABLE; |
289 | 32.6M | else |
290 | 32.6M | return AVCFileUnknown; |
291 | | |
292 | | /*----------------------------------------------------------------- |
293 | | * Record the start of the supersection (for faster seeking) |
294 | | *----------------------------------------------------------------*/ |
295 | 1.87M | 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 | 1.87M | if (atoi(pszLine + 4) == 2) |
302 | 347k | psInfo->nPrecision = AVC_SINGLE_PREC; |
303 | 1.53M | else if (atoi(pszLine + 4) == 3) |
304 | 1.53M | psInfo->nPrecision = AVC_DOUBLE_PREC; |
305 | 64 | else |
306 | 64 | { |
307 | 64 | CPLError(CE_Failure, CPLE_AppDefined, |
308 | 64 | "Parse Error: Invalid section header line (\"%s\")!", pszLine); |
309 | 64 | psInfo->eSuperSectionType = AVCFileUnknown; |
310 | | /* psInfo->nStartLineNum = -1; */ |
311 | 64 | } |
312 | | |
313 | 1.87M | return psInfo->eSuperSectionType; |
314 | 34.5M | } |
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 | | GBool AVCE00ParseSuperSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine) |
326 | 87.9M | { |
327 | 87.9M | if (psInfo->eFileType == AVCFileUnknown && |
328 | 87.9M | psInfo->eSuperSectionType != AVCFileUnknown && |
329 | 87.9M | (STARTS_WITH_CI(pszLine, "JABBERWOCKY") || |
330 | 3.83M | (psInfo->eSuperSectionType == AVCFileTABLE && |
331 | 1.98M | STARTS_WITH_CI(pszLine, "EOI")))) |
332 | 1.84M | { |
333 | 1.84M | psInfo->eSuperSectionType = AVCFileUnknown; |
334 | | /* psInfo->nStartLineNum = -1; */ |
335 | 1.84M | return TRUE; |
336 | 1.84M | } |
337 | | |
338 | 86.0M | return FALSE; |
339 | 87.9M | } |
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 | | AVCFileType AVCE00ParseSectionHeader(AVCE00ParseInfo *psInfo, |
353 | | const char *pszLine) |
354 | 34.6M | { |
355 | 34.6M | AVCFileType eNewType = AVCFileUnknown; |
356 | | |
357 | 34.6M | if (psInfo == nullptr || psInfo->eFileType != AVCFileUnknown) |
358 | 0 | { |
359 | 0 | return AVCFileUnknown; |
360 | 0 | } |
361 | | |
362 | | /*----------------------------------------------------------------- |
363 | | * Check if pszLine is a valid section header line. |
364 | | *----------------------------------------------------------------*/ |
365 | 34.6M | if (psInfo->eSuperSectionType == AVCFileUnknown) |
366 | 32.6M | { |
367 | | /*------------------------------------------------------------- |
368 | | * We're looking for a top-level section... |
369 | | *------------------------------------------------------------*/ |
370 | 32.6M | if (STARTS_WITH_CI(pszLine, "ARC ")) |
371 | 1.12M | eNewType = AVCFileARC; |
372 | 31.5M | else if (STARTS_WITH_CI(pszLine, "PAL ")) |
373 | 2.67M | eNewType = AVCFilePAL; |
374 | 28.8M | else if (STARTS_WITH_CI(pszLine, "CNT ")) |
375 | 109k | eNewType = AVCFileCNT; |
376 | 28.7M | else if (STARTS_WITH_CI(pszLine, "LAB ")) |
377 | 1.98M | eNewType = AVCFileLAB; |
378 | 26.7M | else if (STARTS_WITH_CI(pszLine, "TOL ")) |
379 | 713 | eNewType = AVCFileTOL; |
380 | 26.7M | else if (STARTS_WITH_CI(pszLine, "PRJ ")) |
381 | 1.74M | eNewType = AVCFilePRJ; |
382 | 25.0M | else if (STARTS_WITH_CI(pszLine, "TXT ")) |
383 | 10.0k | eNewType = AVCFileTXT; |
384 | 24.9M | else |
385 | 24.9M | { |
386 | 24.9M | return AVCFileUnknown; |
387 | 24.9M | } |
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 | 7.64M | if (atoi(pszLine + 4) == 2) |
394 | 5.45M | psInfo->nPrecision = AVC_SINGLE_PREC; |
395 | 2.18M | else if (atoi(pszLine + 4) == 3) |
396 | 2.18M | psInfo->nPrecision = AVC_DOUBLE_PREC; |
397 | 69 | else |
398 | 69 | { |
399 | 69 | CPLError(CE_Failure, CPLE_AppDefined, |
400 | 69 | "Parse Error: Invalid section header line (\"%s\")!", |
401 | 69 | pszLine); |
402 | 69 | return AVCFileUnknown; |
403 | 69 | } |
404 | 7.64M | } |
405 | 1.98M | else |
406 | 1.98M | { |
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 | 1.98M | if (psInfo->eSuperSectionType == AVCFileTX6 && strlen(pszLine) == 0) |
421 | 4.15k | { |
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 | 4.15k | eNewType = psInfo->eSuperSectionType; |
427 | 4.15k | } |
428 | 1.98M | else if (strlen(pszLine) > 0 && !isspace((unsigned char)pszLine[0]) && |
429 | 1.98M | !STARTS_WITH_CI(pszLine, "JABBERWOCKY") && |
430 | 1.98M | !STARTS_WITH_CI(pszLine, "EOI") && |
431 | 1.98M | !(psInfo->eSuperSectionType == AVCFileRPL && |
432 | 1.90M | STARTS_WITH_CI(pszLine, " 0.00000"))) |
433 | 1.90M | { |
434 | 1.90M | eNewType = psInfo->eSuperSectionType; |
435 | 1.90M | } |
436 | 77.0k | else |
437 | 77.0k | { |
438 | 77.0k | return AVCFileUnknown; |
439 | 77.0k | } |
440 | 1.98M | } |
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 | 9.55M | 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 | 9.55M | _AVCE00ParseDestroyCurObject(psInfo); |
454 | | |
455 | 9.55M | if (eNewType == AVCFileARC) |
456 | 1.12M | { |
457 | 1.12M | psInfo->cur.psArc = (AVCArc *)CPLCalloc(1, sizeof(AVCArc)); |
458 | 1.12M | } |
459 | 8.42M | else if (eNewType == AVCFilePAL || eNewType == AVCFileRPL) |
460 | 2.68M | { |
461 | 2.68M | psInfo->cur.psPal = (AVCPal *)CPLCalloc(1, sizeof(AVCPal)); |
462 | 2.68M | } |
463 | 5.74M | else if (eNewType == AVCFileCNT) |
464 | 109k | { |
465 | 109k | psInfo->cur.psCnt = (AVCCnt *)CPLCalloc(1, sizeof(AVCCnt)); |
466 | 109k | } |
467 | 5.63M | else if (eNewType == AVCFileLAB) |
468 | 1.98M | { |
469 | 1.98M | psInfo->cur.psLab = (AVCLab *)CPLCalloc(1, sizeof(AVCLab)); |
470 | 1.98M | } |
471 | 3.65M | else if (eNewType == AVCFileTOL) |
472 | 710 | { |
473 | 710 | psInfo->cur.psTol = (AVCTol *)CPLCalloc(1, sizeof(AVCTol)); |
474 | 710 | } |
475 | 3.65M | else if (eNewType == AVCFilePRJ) |
476 | 1.74M | { |
477 | 1.74M | psInfo->aosPrj.Clear(); |
478 | 1.74M | } |
479 | 1.91M | else if (eNewType == AVCFileTXT || eNewType == AVCFileTX6) |
480 | 18.6k | { |
481 | 18.6k | psInfo->cur.psTxt = (AVCTxt *)CPLCalloc(1, sizeof(AVCTxt)); |
482 | 18.6k | } |
483 | 1.89M | else if (eNewType == AVCFileRXP) |
484 | 2.33k | { |
485 | 2.33k | psInfo->cur.psRxp = (AVCRxp *)CPLCalloc(1, sizeof(AVCRxp)); |
486 | 2.33k | } |
487 | 1.88M | else if (eNewType == AVCFileTABLE) |
488 | 1.88M | { |
489 | 1.88M | psInfo->cur.pasFields = nullptr; |
490 | 1.88M | psInfo->hdr.psTableDef = nullptr; |
491 | 1.88M | psInfo->bTableHdrComplete = FALSE; |
492 | 1.88M | } |
493 | 0 | else |
494 | 0 | { |
495 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
496 | 0 | "AVCE00ParseSectionHeader(): Unsupported file type!"); |
497 | 0 | eNewType = AVCFileUnknown; |
498 | 0 | } |
499 | | |
500 | 9.55M | if (eNewType != AVCFileUnknown) |
501 | 9.55M | { |
502 | | /*----------------------------------------------------------------- |
503 | | * Record the start of the section (for faster seeking) |
504 | | *----------------------------------------------------------------*/ |
505 | 9.55M | 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 | 9.55M | CPLFree(psInfo->pszSectionHdrLine); |
512 | 9.55M | psInfo->pszSectionHdrLine = CPLStrdup(pszLine); |
513 | 9.55M | } |
514 | | |
515 | 9.55M | psInfo->eFileType = eNewType; |
516 | | |
517 | 9.55M | return psInfo->eFileType; |
518 | 34.6M | } |
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 | | GBool AVCE00ParseSectionEnd(AVCE00ParseInfo *psInfo, const char *pszLine, |
533 | | GBool bResetParseInfo) |
534 | 57.2M | { |
535 | 57.2M | if (psInfo->bForceEndOfSection || |
536 | 57.2M | ((psInfo->eFileType == AVCFileARC || psInfo->eFileType == AVCFilePAL || |
537 | 53.5M | psInfo->eFileType == AVCFileLAB || psInfo->eFileType == AVCFileRPL || |
538 | 53.5M | psInfo->eFileType == AVCFileCNT || psInfo->eFileType == AVCFileTOL || |
539 | 53.5M | psInfo->eFileType == AVCFileTXT || psInfo->eFileType == AVCFileTX6 || |
540 | 53.5M | psInfo->eFileType == AVCFileRXP) && |
541 | 53.5M | STARTS_WITH_CI(pszLine, " -1 0"))) |
542 | 15.4M | { |
543 | | /* Reset ParseInfo only if explicitly requested. |
544 | | */ |
545 | 15.4M | if (bResetParseInfo) |
546 | 9.60M | { |
547 | 9.60M | _AVCE00ParseDestroyCurObject(psInfo); |
548 | 9.60M | AVCE00ParseReset(psInfo); |
549 | 9.60M | psInfo->eFileType = AVCFileUnknown; |
550 | | |
551 | 9.60M | CPLFree(psInfo->pszSectionHdrLine); |
552 | 9.60M | psInfo->pszSectionHdrLine = nullptr; |
553 | | |
554 | 9.60M | psInfo->bForceEndOfSection = FALSE; |
555 | 9.60M | } |
556 | | |
557 | 15.4M | return TRUE; /* YES, we reached the end */ |
558 | 15.4M | } |
559 | | |
560 | 41.8M | return FALSE; /* NO, it is not the end of section line */ |
561 | 57.2M | } |
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 | | void *AVCE00ParseNextLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
587 | 45.5M | { |
588 | 45.5M | void *psObj = nullptr; |
589 | | |
590 | 45.5M | CPLAssert(psInfo); |
591 | 45.5M | switch (psInfo->eFileType) |
592 | 45.5M | { |
593 | 1.45M | case AVCFileARC: |
594 | 1.45M | psObj = (void *)AVCE00ParseNextArcLine(psInfo, pszLine); |
595 | 1.45M | break; |
596 | 5.31M | case AVCFilePAL: |
597 | 5.34M | case AVCFileRPL: |
598 | 5.34M | psObj = (void *)AVCE00ParseNextPalLine(psInfo, pszLine); |
599 | 5.34M | break; |
600 | 597k | case AVCFileCNT: |
601 | 597k | psObj = (void *)AVCE00ParseNextCntLine(psInfo, pszLine); |
602 | 597k | break; |
603 | 4.22M | case AVCFileLAB: |
604 | 4.22M | psObj = (void *)AVCE00ParseNextLabLine(psInfo, pszLine); |
605 | 4.22M | break; |
606 | 1.74k | case AVCFileTOL: |
607 | 1.74k | psObj = (void *)AVCE00ParseNextTolLine(psInfo, pszLine); |
608 | 1.74k | break; |
609 | 28.1M | case AVCFilePRJ: |
610 | 28.1M | psObj = (void *)AVCE00ParseNextPrjLine(psInfo, pszLine); |
611 | 28.1M | break; |
612 | 83.4k | case AVCFileTXT: |
613 | 83.4k | psObj = (void *)AVCE00ParseNextTxtLine(psInfo, pszLine); |
614 | 83.4k | break; |
615 | 96.9k | case AVCFileTX6: |
616 | 96.9k | psObj = (void *)AVCE00ParseNextTx6Line(psInfo, pszLine); |
617 | 96.9k | break; |
618 | 4.71k | case AVCFileRXP: |
619 | 4.71k | psObj = (void *)AVCE00ParseNextRxpLine(psInfo, pszLine); |
620 | 4.71k | break; |
621 | 5.63M | case AVCFileTABLE: |
622 | 5.63M | if (!psInfo->bTableHdrComplete) |
623 | 3.75M | psObj = (void *)AVCE00ParseNextTableDefLine(psInfo, pszLine); |
624 | 1.87M | else |
625 | 1.87M | psObj = (void *)AVCE00ParseNextTableRecLine(psInfo, pszLine); |
626 | 5.63M | break; |
627 | 0 | default: |
628 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
629 | 0 | "AVCE00ParseNextLine(): Unsupported file type!"); |
630 | 45.5M | } |
631 | | |
632 | 45.5M | return psObj; |
633 | 45.5M | } |
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 | | AVCArc *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
652 | 1.45M | { |
653 | 1.45M | AVCArc *psArc; |
654 | 1.45M | size_t nLen; |
655 | | |
656 | 1.45M | CPLAssert(psInfo->eFileType == AVCFileARC); |
657 | | |
658 | 1.45M | psArc = psInfo->cur.psArc; |
659 | | |
660 | 1.45M | nLen = strlen(pszLine); |
661 | | |
662 | 1.45M | if (psInfo->numItems == 0) |
663 | 1.41M | { |
664 | | /*------------------------------------------------------------- |
665 | | * Begin processing a new object, read header line: |
666 | | * ArcId, UserId, FNode, TNode, LPoly, RPoly, numVertices |
667 | | *------------------------------------------------------------*/ |
668 | 1.41M | if (nLen < 70) |
669 | 20 | { |
670 | 20 | CPLError(CE_Failure, CPLE_AppDefined, |
671 | 20 | "Error parsing E00 ARC line: \"%s\"", pszLine); |
672 | 20 | return nullptr; |
673 | 20 | } |
674 | 1.41M | else |
675 | 1.41M | { |
676 | 1.41M | psArc->nArcId = AVCE00Str2Int(pszLine, 10); |
677 | 1.41M | psArc->nUserId = AVCE00Str2Int(pszLine + 10, 10); |
678 | 1.41M | psArc->nFNode = AVCE00Str2Int(pszLine + 20, 10); |
679 | 1.41M | psArc->nTNode = AVCE00Str2Int(pszLine + 30, 10); |
680 | 1.41M | psArc->nLPoly = AVCE00Str2Int(pszLine + 40, 10); |
681 | 1.41M | psArc->nRPoly = AVCE00Str2Int(pszLine + 50, 10); |
682 | 1.41M | psArc->numVertices = AVCE00Str2Int(pszLine + 60, 10); |
683 | 1.41M | if (psArc->numVertices < 0 || psArc->numVertices > 10 * 1024 * 1024) |
684 | 21 | { |
685 | 21 | CPLError(CE_Failure, CPLE_AppDefined, |
686 | 21 | "Error parsing E00 ARC line: \"%s\"", pszLine); |
687 | 21 | psInfo->numItems = psInfo->iCurItem = 0; |
688 | 21 | return nullptr; |
689 | 21 | } |
690 | | |
691 | | /* Realloc the array of vertices |
692 | | */ |
693 | 1.41M | psArc->pasVertices = (AVCVertex *)CPLRealloc( |
694 | 1.41M | 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 | 1.41M | psInfo->iCurItem = 0; |
700 | 1.41M | psInfo->numItems = psArc->numVertices; |
701 | 1.41M | } |
702 | 1.41M | } |
703 | 34.8k | else if (psInfo->iCurItem < psInfo->numItems && |
704 | 34.8k | psInfo->nPrecision == AVC_SINGLE_PREC && |
705 | 34.8k | ((psInfo->iCurItem == psInfo->numItems - 1 && nLen >= 28) || |
706 | 32.5k | nLen >= 56)) |
707 | 32.5k | { |
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 | 32.5k | psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine); |
713 | 32.5k | psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 14); |
714 | 32.5k | if (psInfo->iCurItem < psInfo->numItems && nLen >= 56) |
715 | 22.4k | { |
716 | 22.4k | psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine + 28); |
717 | 22.4k | psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 42); |
718 | 22.4k | } |
719 | 32.5k | } |
720 | 2.26k | else if (psInfo->iCurItem < psInfo->numItems && |
721 | 2.26k | psInfo->nPrecision == AVC_DOUBLE_PREC && nLen >= 42) |
722 | 2.23k | { |
723 | | /*------------------------------------------------------------- |
724 | | * Double precision ARCs: 1 pair of X,Y values per line |
725 | | *------------------------------------------------------------*/ |
726 | 2.23k | psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine); |
727 | 2.23k | psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine + 21); |
728 | 2.23k | } |
729 | 26 | else |
730 | 26 | { |
731 | 26 | CPLError(CE_Failure, CPLE_AppDefined, |
732 | 26 | "Error parsing E00 ARC line: \"%s\"", pszLine); |
733 | 26 | psInfo->numItems = psInfo->iCurItem = 0; |
734 | 26 | return nullptr; |
735 | 26 | } |
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 | 1.45M | if (psInfo->iCurItem >= psInfo->numItems) |
744 | 1.39M | { |
745 | 1.39M | psInfo->numItems = psInfo->iCurItem = 0; |
746 | 1.39M | return psArc; |
747 | 1.39M | } |
748 | | |
749 | 53.8k | return nullptr; |
750 | 1.45M | } |
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 | | AVCPal *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
769 | 5.34M | { |
770 | 5.34M | AVCPal *psPal; |
771 | 5.34M | size_t nLen; |
772 | | |
773 | 5.34M | CPLAssert(psInfo->eFileType == AVCFilePAL || |
774 | 5.34M | psInfo->eFileType == AVCFileRPL); |
775 | | |
776 | 5.34M | psPal = psInfo->cur.psPal; |
777 | | |
778 | 5.34M | nLen = strlen(pszLine); |
779 | | |
780 | 5.34M | if (psInfo->numItems == 0) |
781 | 2.66M | { |
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 | 2.66M | if (nLen < 52) |
788 | 56 | { |
789 | 56 | CPLError(CE_Failure, CPLE_AppDefined, |
790 | 56 | "Error parsing E00 PAL line: \"%s\"", pszLine); |
791 | 56 | return nullptr; |
792 | 56 | } |
793 | 2.66M | else |
794 | 2.66M | { |
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 | 2.66M | psPal->nPolyId = ++psInfo->nCurObjectId; |
800 | | |
801 | 2.66M | psPal->numArcs = AVCE00Str2Int(pszLine, 10); |
802 | 2.66M | if (psPal->numArcs < 0 || psPal->numArcs > 10 * 1024 * 1024) |
803 | 6 | { |
804 | 6 | CPLError(CE_Failure, CPLE_AppDefined, |
805 | 6 | "Error parsing E00 PAL line: \"%s\"", pszLine); |
806 | 6 | psInfo->numItems = psInfo->iCurItem = 0; |
807 | 6 | return nullptr; |
808 | 6 | } |
809 | | |
810 | | /* If a PAL record has 0 arcs, it really has a single "0 0 0" |
811 | | * triplet as its data. |
812 | | */ |
813 | 2.66M | if (psPal->numArcs == 0) |
814 | 2.39M | { |
815 | 2.39M | psPal->numArcs = 1; |
816 | 2.39M | } |
817 | | |
818 | | /* Realloc the array of Arcs |
819 | | */ |
820 | 2.66M | psPal->pasArcs = (AVCPalArc *)CPLRealloc( |
821 | 2.66M | 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 | 2.66M | psInfo->iCurItem = 0; |
827 | 2.66M | psInfo->numItems = psPal->numArcs; |
828 | | |
829 | 2.66M | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
830 | 2.66M | { |
831 | 2.66M | psPal->sMin.x = CPLAtof(pszLine + 10); |
832 | 2.66M | psPal->sMin.y = CPLAtof(pszLine + 24); |
833 | 2.66M | psPal->sMax.x = CPLAtof(pszLine + 38); |
834 | 2.66M | psPal->sMax.y = CPLAtof(pszLine + 52); |
835 | 2.66M | } |
836 | 3.89k | else |
837 | 3.89k | { |
838 | 3.89k | psPal->sMin.x = CPLAtof(pszLine + 10); |
839 | 3.89k | 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 | 3.89k | psInfo->iCurItem = -1; |
844 | 3.89k | } |
845 | 2.66M | } |
846 | 2.66M | } |
847 | 2.67M | else if (psInfo->iCurItem == -1 && nLen >= 42) |
848 | 3.67k | { |
849 | 3.67k | psPal->sMax.x = CPLAtof(pszLine); |
850 | 3.67k | psPal->sMax.y = CPLAtof(pszLine + 21); |
851 | 3.67k | psInfo->iCurItem++; |
852 | 3.67k | } |
853 | 2.67M | else if (psInfo->iCurItem < psPal->numArcs && |
854 | 2.67M | (nLen >= 60 || |
855 | 2.67M | (psInfo->iCurItem == psPal->numArcs - 1 && nLen >= 30))) |
856 | 2.67M | { |
857 | | /*------------------------------------------------------------- |
858 | | * 2 PAL entries (ArcId, FNode, AdjPoly) per line, |
859 | | * (Except on the last line with an odd number of vertices) |
860 | | *------------------------------------------------------------*/ |
861 | 2.67M | psPal->pasArcs[psInfo->iCurItem].nArcId = AVCE00Str2Int(pszLine, 10); |
862 | 2.67M | psPal->pasArcs[psInfo->iCurItem].nFNode = |
863 | 2.67M | AVCE00Str2Int(pszLine + 10, 10); |
864 | 2.67M | psPal->pasArcs[psInfo->iCurItem++].nAdjPoly = |
865 | 2.67M | AVCE00Str2Int(pszLine + 20, 10); |
866 | | |
867 | 2.67M | if (psInfo->iCurItem < psInfo->numItems) |
868 | 48.1k | { |
869 | 48.1k | psPal->pasArcs[psInfo->iCurItem].nArcId = |
870 | 48.1k | AVCE00Str2Int(pszLine + 30, 10); |
871 | 48.1k | psPal->pasArcs[psInfo->iCurItem].nFNode = |
872 | 48.1k | AVCE00Str2Int(pszLine + 40, 10); |
873 | 48.1k | psPal->pasArcs[psInfo->iCurItem++].nAdjPoly = |
874 | 48.1k | AVCE00Str2Int(pszLine + 50, 10); |
875 | 48.1k | } |
876 | 2.67M | } |
877 | 50 | else |
878 | 50 | { |
879 | 50 | CPLError(CE_Failure, CPLE_AppDefined, |
880 | 50 | "Error parsing E00 PAL line: \"%s\"", pszLine); |
881 | 50 | psInfo->numItems = psInfo->iCurItem = 0; |
882 | 50 | return nullptr; |
883 | 50 | } |
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 | 5.34M | if (psInfo->iCurItem >= psInfo->numItems) |
892 | 2.64M | { |
893 | 2.64M | psInfo->numItems = psInfo->iCurItem = 0; |
894 | 2.64M | return psPal; |
895 | 2.64M | } |
896 | | |
897 | 2.70M | return nullptr; |
898 | 5.34M | } |
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 | | AVCCnt *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
917 | 597k | { |
918 | 597k | AVCCnt *psCnt; |
919 | 597k | size_t nLen; |
920 | | |
921 | 597k | CPLAssert(psInfo->eFileType == AVCFileCNT); |
922 | | |
923 | 597k | psCnt = psInfo->cur.psCnt; |
924 | | |
925 | 597k | nLen = strlen(pszLine); |
926 | | |
927 | 597k | if (psInfo->numItems == 0) |
928 | 162k | { |
929 | | /*------------------------------------------------------------- |
930 | | * Begin processing a new object, read header line: |
931 | | * numLabels, X, Y |
932 | | *------------------------------------------------------------*/ |
933 | 162k | if (nLen < 38) |
934 | 146 | { |
935 | 146 | CPLError(CE_Failure, CPLE_AppDefined, |
936 | 146 | "Error parsing E00 CNT line: \"%s\"", pszLine); |
937 | 146 | return nullptr; |
938 | 146 | } |
939 | 162k | else |
940 | 162k | { |
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 | 162k | psCnt->nPolyId = ++psInfo->nCurObjectId; |
946 | | |
947 | 162k | psCnt->numLabels = AVCE00Str2Int(pszLine, 10); |
948 | 162k | if (psCnt->numLabels < 0 || psCnt->numLabels > 10 * 1024 * 1024) |
949 | 32 | { |
950 | 32 | CPLError(CE_Failure, CPLE_AppDefined, |
951 | 32 | "Error parsing E00 CNT line: \"%s\"", pszLine); |
952 | 32 | psInfo->numItems = psInfo->iCurItem = 0; |
953 | 32 | return nullptr; |
954 | 32 | } |
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 | 162k | if (psCnt->numLabels > 0) |
961 | 22.2k | psCnt->panLabelIds = (GInt32 *)CPLRealloc( |
962 | 22.2k | psCnt->panLabelIds, psCnt->numLabels * sizeof(GInt32)); |
963 | | |
964 | 162k | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
965 | 52.4k | { |
966 | 52.4k | psCnt->sCoord.x = CPLAtof(pszLine + 10); |
967 | 52.4k | psCnt->sCoord.y = CPLAtof(pszLine + 24); |
968 | 52.4k | } |
969 | 110k | else |
970 | 110k | { |
971 | 110k | psCnt->sCoord.x = CPLAtof(pszLine + 10); |
972 | 110k | psCnt->sCoord.y = CPLAtof(pszLine + 31); |
973 | 110k | } |
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 | 162k | psInfo->iCurItem = 0; |
979 | 162k | psInfo->numItems = psCnt->numLabels; |
980 | 162k | } |
981 | 162k | } |
982 | 434k | else if (psInfo->iCurItem < psInfo->numItems) |
983 | 434k | { |
984 | | /*------------------------------------------------------------- |
985 | | * Each line can contain up to 8 label ids (10 chars each) |
986 | | *------------------------------------------------------------*/ |
987 | 434k | size_t i = 0; |
988 | 1.59M | while (psInfo->iCurItem < psInfo->numItems && nLen >= (i + 1) * 10) |
989 | 1.15M | { |
990 | 1.15M | psCnt->panLabelIds[psInfo->iCurItem++] = |
991 | 1.15M | AVCE00Str2Int(pszLine + i * 10, 10); |
992 | 1.15M | i++; |
993 | 1.15M | } |
994 | 434k | } |
995 | 0 | else |
996 | 0 | { |
997 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
998 | 0 | "Error parsing E00 CNT line: \"%s\"", pszLine); |
999 | 0 | psInfo->numItems = psInfo->iCurItem = 0; |
1000 | 0 | return nullptr; |
1001 | 0 | } |
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 | 597k | if (psInfo->iCurItem >= psInfo->numItems) |
1010 | 142k | { |
1011 | 142k | psInfo->numItems = psInfo->iCurItem = 0; |
1012 | 142k | return psCnt; |
1013 | 142k | } |
1014 | | |
1015 | 455k | return nullptr; |
1016 | 597k | } |
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 | | AVCLab *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
1035 | 4.22M | { |
1036 | 4.22M | AVCLab *psLab; |
1037 | 4.22M | size_t nLen; |
1038 | | |
1039 | 4.22M | CPLAssert(psInfo->eFileType == AVCFileLAB); |
1040 | | |
1041 | 4.22M | psLab = psInfo->cur.psLab; |
1042 | | |
1043 | 4.22M | nLen = strlen(pszLine); |
1044 | | |
1045 | 4.22M | if (psInfo->numItems == 0) |
1046 | 2.19M | { |
1047 | | /*------------------------------------------------------------- |
1048 | | * Begin processing a new object, read header line: |
1049 | | * LabelValue, PolyId, X1, Y1 |
1050 | | *------------------------------------------------------------*/ |
1051 | 2.19M | if (nLen < 48) |
1052 | 15 | { |
1053 | 15 | CPLError(CE_Failure, CPLE_AppDefined, |
1054 | 15 | "Error parsing E00 LAB line: \"%s\"", pszLine); |
1055 | 15 | return nullptr; |
1056 | 15 | } |
1057 | 2.19M | else |
1058 | 2.19M | { |
1059 | 2.19M | psLab->nValue = AVCE00Str2Int(pszLine, 10); |
1060 | 2.19M | psLab->nPolyId = AVCE00Str2Int(pszLine + 10, 10); |
1061 | | |
1062 | 2.19M | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
1063 | 2.18M | { |
1064 | 2.18M | psLab->sCoord1.x = CPLAtof(pszLine + 20); |
1065 | 2.18M | psLab->sCoord1.y = CPLAtof(pszLine + 34); |
1066 | 2.18M | } |
1067 | 2.02k | else |
1068 | 2.02k | { |
1069 | 2.02k | psLab->sCoord1.x = CPLAtof(pszLine + 20); |
1070 | 2.02k | psLab->sCoord1.y = CPLAtof(pszLine + 41); |
1071 | 2.02k | } |
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 | 2.19M | psInfo->iCurItem = 1; |
1077 | 2.19M | psInfo->numItems = 3; |
1078 | 2.19M | } |
1079 | 2.19M | } |
1080 | 2.03M | else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC && |
1081 | 2.03M | nLen >= 56) |
1082 | 2.03M | { |
1083 | 2.03M | psLab->sCoord2.x = CPLAtof(pszLine); |
1084 | 2.03M | psLab->sCoord2.y = CPLAtof(pszLine + 14); |
1085 | 2.03M | psLab->sCoord3.x = CPLAtof(pszLine + 28); |
1086 | 2.03M | psLab->sCoord3.y = CPLAtof(pszLine + 42); |
1087 | 2.03M | psInfo->iCurItem += 2; |
1088 | 2.03M | } |
1089 | 3.32k | else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC && |
1090 | 3.32k | nLen >= 42) |
1091 | 1.74k | { |
1092 | 1.74k | psLab->sCoord2.x = CPLAtof(pszLine); |
1093 | 1.74k | psLab->sCoord2.y = CPLAtof(pszLine + 21); |
1094 | 1.74k | psInfo->iCurItem++; |
1095 | 1.74k | } |
1096 | 1.57k | else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC && |
1097 | 1.57k | nLen >= 42) |
1098 | 1.56k | { |
1099 | 1.56k | psLab->sCoord3.x = CPLAtof(pszLine); |
1100 | 1.56k | psLab->sCoord3.y = CPLAtof(pszLine + 21); |
1101 | 1.56k | psInfo->iCurItem++; |
1102 | 1.56k | } |
1103 | 9 | else |
1104 | 9 | { |
1105 | 9 | CPLError(CE_Failure, CPLE_AppDefined, |
1106 | 9 | "Error parsing E00 LAB line: \"%s\"", pszLine); |
1107 | 9 | psInfo->numItems = psInfo->iCurItem = 0; |
1108 | 9 | return nullptr; |
1109 | 9 | } |
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 | 4.22M | if (psInfo->iCurItem >= psInfo->numItems) |
1118 | 2.03M | { |
1119 | 2.03M | psInfo->numItems = psInfo->iCurItem = 0; |
1120 | 2.03M | return psLab; |
1121 | 2.03M | } |
1122 | | |
1123 | 2.19M | return nullptr; |
1124 | 4.22M | } |
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 | | AVCTol *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
1143 | 1.74k | { |
1144 | 1.74k | AVCTol *psTol; |
1145 | 1.74k | size_t nLen; |
1146 | | |
1147 | 1.74k | CPLAssert(psInfo->eFileType == AVCFileTOL); |
1148 | | |
1149 | 1.74k | psTol = psInfo->cur.psTol; |
1150 | | |
1151 | 1.74k | nLen = strlen(pszLine); |
1152 | | |
1153 | 1.74k | if (nLen >= 34) |
1154 | 1.72k | { |
1155 | | /*------------------------------------------------------------- |
1156 | | * TOL Entries are only one line each: |
1157 | | * TolIndex, TolFlag, TolValue |
1158 | | *------------------------------------------------------------*/ |
1159 | 1.72k | psTol->nIndex = AVCE00Str2Int(pszLine, 10); |
1160 | 1.72k | psTol->nFlag = AVCE00Str2Int(pszLine + 10, 10); |
1161 | | |
1162 | 1.72k | psTol->dValue = CPLAtof(pszLine + 20); |
1163 | 1.72k | } |
1164 | 11 | else |
1165 | 11 | { |
1166 | 11 | CPLError(CE_Failure, CPLE_AppDefined, |
1167 | 11 | "Error parsing E00 TOL line: \"%s\"", pszLine); |
1168 | 11 | psInfo->numItems = psInfo->iCurItem = 0; |
1169 | 11 | return nullptr; |
1170 | 11 | } |
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 | 1.72k | if (psInfo->iCurItem >= psInfo->numItems) |
1179 | 1.72k | { |
1180 | 1.72k | psInfo->numItems = psInfo->iCurItem = 0; |
1181 | 1.72k | return psTol; |
1182 | 1.72k | } |
1183 | | |
1184 | 0 | return nullptr; |
1185 | 1.72k | } |
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 | | char **AVCE00ParseNextPrjLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
1210 | 28.1M | { |
1211 | 28.1M | 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 | 28.1M | if (STARTS_WITH_CI(pszLine, "EOP")) |
1222 | 1.74M | { |
1223 | | /*------------------------------------------------------------- |
1224 | | * We reached end of section... return the PRJ. |
1225 | | *------------------------------------------------------------*/ |
1226 | 1.74M | psInfo->bForceEndOfSection = TRUE; |
1227 | 1.74M | return psInfo->aosPrj.List(); |
1228 | 1.74M | } |
1229 | | |
1230 | 26.4M | if (pszLine[0] != '~') |
1231 | 24.4M | { |
1232 | | /*------------------------------------------------------------- |
1233 | | * This is a new line... add it to the papszPrj stringlist. |
1234 | | *------------------------------------------------------------*/ |
1235 | 24.4M | psInfo->aosPrj.AddString(pszLine); |
1236 | 24.4M | } |
1237 | 1.96M | else if (strlen(pszLine) > 1) |
1238 | 707k | { |
1239 | | /*------------------------------------------------------------- |
1240 | | * '~' is a line continuation char. Append what follows the '~' |
1241 | | * to the end of the previous line. |
1242 | | *------------------------------------------------------------*/ |
1243 | 707k | if (!psInfo->aosPrj.empty()) |
1244 | 705k | { |
1245 | 705k | size_t nOldLen = |
1246 | 705k | strlen(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1]); |
1247 | 705k | size_t nAddLen = strlen(pszLine + 1); |
1248 | 705k | psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] = |
1249 | 705k | static_cast<char *>( |
1250 | 705k | CPLRealloc(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1], |
1251 | 705k | nOldLen + nAddLen + 1)); |
1252 | 705k | memcpy(psInfo->aosPrj.List()[psInfo->aosPrj.size() - 1] + nOldLen, |
1253 | 705k | pszLine + 1, nAddLen + 1); |
1254 | 705k | } |
1255 | 707k | } |
1256 | | |
1257 | 26.4M | return nullptr; |
1258 | 28.1M | } |
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 | | AVCTxt *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
1277 | 83.4k | { |
1278 | 83.4k | AVCTxt *psTxt; |
1279 | 83.4k | int i, numFixedLines; |
1280 | 83.4k | size_t nLen; |
1281 | | |
1282 | 83.4k | CPLAssert(psInfo->eFileType == AVCFileTXT); |
1283 | | |
1284 | 83.4k | psTxt = psInfo->cur.psTxt; |
1285 | | |
1286 | 83.4k | nLen = strlen(pszLine); |
1287 | | |
1288 | | /* numFixedLines is the number of lines to expect before the line(s) |
1289 | | * with the text string |
1290 | | */ |
1291 | 83.4k | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
1292 | 20.4k | numFixedLines = 4; |
1293 | 62.9k | else |
1294 | 62.9k | numFixedLines = 6; |
1295 | | |
1296 | 83.4k | if (psInfo->numItems == 0) |
1297 | 13.0k | { |
1298 | | /*------------------------------------------------------------- |
1299 | | * Begin processing a new object, read header line: |
1300 | | *------------------------------------------------------------*/ |
1301 | 13.0k | if (nLen < 50) |
1302 | 22 | { |
1303 | 22 | CPLError(CE_Failure, CPLE_AppDefined, |
1304 | 22 | "Error parsing E00 TXT line: \"%s\"", pszLine); |
1305 | 22 | return nullptr; |
1306 | 22 | } |
1307 | 13.0k | else |
1308 | 13.0k | { |
1309 | 13.0k | int numVertices; |
1310 | | /*--------------------------------------------------------- |
1311 | | * With TXT, there are several unused fields that have to be |
1312 | | * set to default values... usually 0. |
1313 | | *--------------------------------------------------------*/ |
1314 | 13.0k | psTxt->nUserId = 0; |
1315 | 13.0k | psTxt->n28 = 0; |
1316 | 273k | for (i = 0; i < 20; i++) |
1317 | 260k | psTxt->anJust1[i] = psTxt->anJust2[i] = 0; |
1318 | 13.0k | 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 | 13.0k | psTxt->nTxtId = ++psInfo->nCurObjectId; |
1326 | | |
1327 | 13.0k | 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 | 13.0k | psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 10, 10); |
1333 | 13.0k | if (psTxt->numVerticesLine < 0 || |
1334 | 13.0k | psTxt->numVerticesLine > 10 * 1024 * 1024) |
1335 | 27 | { |
1336 | 27 | CPLError(CE_Failure, CPLE_AppDefined, |
1337 | 27 | "Error parsing E00 TXT line: \"%s\"", pszLine); |
1338 | 27 | psInfo->numItems = psInfo->iCurItem = 0; |
1339 | 27 | return nullptr; |
1340 | 27 | } |
1341 | 13.0k | psTxt->numVerticesLine++; |
1342 | | |
1343 | 13.0k | psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 20, 10); |
1344 | 13.0k | if (psTxt->numVerticesArrow < -10 * 1024 * 1024 || |
1345 | 13.0k | psTxt->numVerticesArrow > 10 * 1024 * 1024) |
1346 | 9 | { |
1347 | 9 | CPLError(CE_Failure, CPLE_AppDefined, |
1348 | 9 | "Error parsing E00 TXT line: \"%s\"", pszLine); |
1349 | 9 | psInfo->numItems = psInfo->iCurItem = 0; |
1350 | 9 | return nullptr; |
1351 | 9 | } |
1352 | 12.9k | psTxt->nSymbol = AVCE00Str2Int(pszLine + 30, 10); |
1353 | 12.9k | psTxt->numChars = AVCE00Str2Int(pszLine + 40, 10); |
1354 | 12.9k | if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024) |
1355 | 31 | { |
1356 | 31 | CPLError(CE_Failure, CPLE_AppDefined, |
1357 | 31 | "Error parsing E00 TXT line: \"%s\"", pszLine); |
1358 | 31 | psInfo->numItems = psInfo->iCurItem = 0; |
1359 | 31 | return nullptr; |
1360 | 31 | } |
1361 | | |
1362 | | /*--------------------------------------------------------- |
1363 | | * Realloc the string buffer and array of vertices |
1364 | | *--------------------------------------------------------*/ |
1365 | 12.9k | psTxt->pszText = (GByte *)CPLRealloc( |
1366 | 12.9k | psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte)); |
1367 | 12.9k | numVertices = |
1368 | 12.9k | ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); |
1369 | 12.9k | if (numVertices > 0) |
1370 | 12.9k | psTxt->pasVertices = (AVCVertex *)CPLRealloc( |
1371 | 12.9k | 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 | 12.9k | memset(psTxt->pszText, ' ', psTxt->numChars); |
1378 | 12.9k | 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 | 12.9k | psInfo->iCurItem = 0; |
1385 | 12.9k | psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1); |
1386 | 12.9k | } |
1387 | 13.0k | } |
1388 | 70.4k | else if (psInfo->iCurItem < psInfo->numItems && |
1389 | 70.4k | psInfo->iCurItem < numFixedLines - 1 && nLen >= 63) |
1390 | 38.1k | { |
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 | 38.1k | int iCurCoord = 0, numCoordPerLine, nItemSize, iVertex; |
1405 | 38.1k | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
1406 | 8.95k | { |
1407 | 8.95k | numCoordPerLine = 5; |
1408 | 8.95k | nItemSize = 14; /* Num of chars for single precision float*/ |
1409 | 8.95k | } |
1410 | 29.1k | else |
1411 | 29.1k | { |
1412 | 29.1k | numCoordPerLine = 3; |
1413 | 29.1k | nItemSize = 21; /* Num of chars for double precision float*/ |
1414 | 29.1k | } |
1415 | 38.1k | iCurCoord = psInfo->iCurItem * numCoordPerLine; |
1416 | | |
1417 | 38.1k | for (i = 0; |
1418 | 170k | i < numCoordPerLine && nLen > static_cast<size_t>(i) * nItemSize; |
1419 | 132k | i++, iCurCoord++) |
1420 | 132k | { |
1421 | 132k | if (iCurCoord < 4 && |
1422 | 132k | (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1) |
1423 | 8.69k | { |
1424 | 8.69k | psTxt->pasVertices[iVertex + 1].x = |
1425 | 8.69k | CPLAtof(pszLine + i * nItemSize); |
1426 | | /* The first vertex is always duplicated */ |
1427 | 8.69k | if (iVertex == 0) |
1428 | 2.22k | psTxt->pasVertices[0].x = psTxt->pasVertices[1].x; |
1429 | 8.69k | } |
1430 | 123k | else if (iCurCoord >= 4 && iCurCoord < 8 && |
1431 | 123k | (iVertex = iCurCoord % 4) < psTxt->numVerticesLine - 1) |
1432 | 7.58k | { |
1433 | 7.58k | psTxt->pasVertices[iVertex + 1].y = |
1434 | 7.58k | CPLAtof(pszLine + i * nItemSize); |
1435 | | /* The first vertex is always duplicated */ |
1436 | 7.58k | if (iVertex == 0) |
1437 | 2.21k | psTxt->pasVertices[0].y = psTxt->pasVertices[1].y; |
1438 | 7.58k | } |
1439 | 116k | else if (iCurCoord >= 8 && iCurCoord < 11 && |
1440 | 116k | (iVertex = (iCurCoord - 8) % 3) < |
1441 | 24.5k | ABS(psTxt->numVerticesArrow)) |
1442 | 4.04k | { |
1443 | 4.04k | psTxt->pasVertices[iVertex + psTxt->numVerticesLine].x = |
1444 | 4.04k | CPLAtof(pszLine + i * nItemSize); |
1445 | 4.04k | } |
1446 | 112k | else if (iCurCoord >= 11 && iCurCoord < 14 && |
1447 | 112k | (iVertex = (iCurCoord - 8) % 3) < |
1448 | 23.9k | ABS(psTxt->numVerticesArrow)) |
1449 | 4.00k | { |
1450 | 4.00k | psTxt->pasVertices[iVertex + psTxt->numVerticesLine].y = |
1451 | 4.00k | CPLAtof(pszLine + i * nItemSize); |
1452 | 4.00k | } |
1453 | 108k | else if (iCurCoord == 14) |
1454 | 7.92k | { |
1455 | 7.92k | psTxt->dHeight = CPLAtof(pszLine + i * nItemSize); |
1456 | 7.92k | } |
1457 | 132k | } |
1458 | | |
1459 | 38.1k | psInfo->iCurItem++; |
1460 | 38.1k | } |
1461 | 32.2k | else if (psInfo->iCurItem < psInfo->numItems && |
1462 | 32.2k | psInfo->iCurItem == numFixedLines - 1 && nLen >= 14) |
1463 | 5.77k | { |
1464 | | /*------------------------------------------------------------- |
1465 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
1466 | | *------------------------------------------------------------*/ |
1467 | 5.77k | psTxt->f_1e2 = (float)CPLAtof(pszLine); |
1468 | | |
1469 | 5.77k | psInfo->iCurItem++; |
1470 | 5.77k | } |
1471 | 26.4k | else if (psInfo->iCurItem < psInfo->numItems && |
1472 | 26.4k | psInfo->iCurItem >= numFixedLines) |
1473 | 26.4k | { |
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 | 26.4k | int numLines, iLine; |
1480 | 26.4k | numLines = (psTxt->numChars - 1) / 80 + 1; |
1481 | 26.4k | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
1482 | | |
1483 | 26.4k | if (iLine == numLines - 1) |
1484 | 4.49k | { |
1485 | 4.49k | memcpy((char *)psTxt->pszText + (iLine * 80), pszLine, |
1486 | 4.49k | MIN((int)nLen, (psTxt->numChars - (iLine * 80)))); |
1487 | 4.49k | } |
1488 | 21.9k | else |
1489 | 21.9k | { |
1490 | 21.9k | memcpy((char *)psTxt->pszText + (iLine * 80), pszLine, |
1491 | 21.9k | MIN(nLen, 80)); |
1492 | 21.9k | } |
1493 | | |
1494 | 26.4k | psInfo->iCurItem++; |
1495 | 26.4k | } |
1496 | 48 | else |
1497 | 48 | { |
1498 | 48 | CPLError(CE_Failure, CPLE_AppDefined, |
1499 | 48 | "Error parsing E00 TXT line: \"%s\"", pszLine); |
1500 | 48 | psInfo->numItems = psInfo->iCurItem = 0; |
1501 | 48 | return nullptr; |
1502 | 48 | } |
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 | 83.3k | if (psInfo->iCurItem >= psInfo->numItems) |
1511 | 4.49k | { |
1512 | 4.49k | psInfo->numItems = psInfo->iCurItem = 0; |
1513 | 4.49k | return psTxt; |
1514 | 4.49k | } |
1515 | | |
1516 | 78.8k | return nullptr; |
1517 | 83.3k | } |
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 | | AVCTxt *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine) |
1536 | 96.9k | { |
1537 | 96.9k | AVCTxt *psTxt; |
1538 | 96.9k | int i; |
1539 | 96.9k | size_t nLen; |
1540 | | |
1541 | 96.9k | CPLAssert(psInfo->eFileType == AVCFileTX6); |
1542 | | |
1543 | 96.9k | psTxt = psInfo->cur.psTxt; |
1544 | | |
1545 | 96.9k | nLen = strlen(pszLine); |
1546 | | |
1547 | 96.9k | if (psInfo->numItems == 0) |
1548 | 7.69k | { |
1549 | | /*------------------------------------------------------------- |
1550 | | * Begin processing a new object, read header line: |
1551 | | *------------------------------------------------------------*/ |
1552 | 7.69k | if (nLen < 70) |
1553 | 39 | { |
1554 | 39 | CPLError(CE_Failure, CPLE_AppDefined, |
1555 | 39 | "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); |
1556 | 39 | return nullptr; |
1557 | 39 | } |
1558 | 7.65k | else |
1559 | 7.65k | { |
1560 | 7.65k | 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 | 7.65k | psTxt->nTxtId = ++psInfo->nCurObjectId; |
1567 | | |
1568 | 7.65k | psTxt->nUserId = AVCE00Str2Int(pszLine, 10); |
1569 | 7.65k | psTxt->nLevel = AVCE00Str2Int(pszLine + 10, 10); |
1570 | 7.65k | psTxt->numVerticesLine = AVCE00Str2Int(pszLine + 20, 10); |
1571 | 7.65k | if (psTxt->numVerticesLine < 0 || |
1572 | 7.65k | psTxt->numVerticesLine > 10 * 1024 * 1024) |
1573 | 9 | { |
1574 | 9 | CPLError(CE_Failure, CPLE_AppDefined, |
1575 | 9 | "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); |
1576 | 9 | psInfo->numItems = psInfo->iCurItem = 0; |
1577 | 9 | return nullptr; |
1578 | 9 | } |
1579 | 7.64k | psTxt->numVerticesArrow = AVCE00Str2Int(pszLine + 30, 10); |
1580 | 7.64k | if (psTxt->numVerticesArrow < -10 * 1024 * 1024 || |
1581 | 7.64k | psTxt->numVerticesArrow > 10 * 1024 * 1024) |
1582 | 13 | { |
1583 | 13 | CPLError(CE_Failure, CPLE_AppDefined, |
1584 | 13 | "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); |
1585 | 13 | psInfo->numItems = psInfo->iCurItem = 0; |
1586 | 13 | return nullptr; |
1587 | 13 | } |
1588 | 7.63k | psTxt->nSymbol = AVCE00Str2Int(pszLine + 40, 10); |
1589 | 7.63k | psTxt->n28 = AVCE00Str2Int(pszLine + 50, 10); |
1590 | 7.63k | psTxt->numChars = AVCE00Str2Int(pszLine + 60, 10); |
1591 | 7.63k | if (psTxt->numChars < 0 || psTxt->numChars > 10 * 1024 * 1024) |
1592 | 21 | { |
1593 | 21 | CPLError(CE_Failure, CPLE_AppDefined, |
1594 | 21 | "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); |
1595 | 21 | psInfo->numItems = psInfo->iCurItem = 0; |
1596 | 21 | return nullptr; |
1597 | 21 | } |
1598 | | |
1599 | | /*--------------------------------------------------------- |
1600 | | * Realloc the string buffer and array of vertices |
1601 | | *--------------------------------------------------------*/ |
1602 | 7.60k | psTxt->pszText = (GByte *)CPLRealloc( |
1603 | 7.60k | psTxt->pszText, (psTxt->numChars + 1) * sizeof(GByte)); |
1604 | | |
1605 | 7.60k | numVertices = |
1606 | 7.60k | ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow); |
1607 | 7.60k | if (numVertices > 0) |
1608 | 1.67k | psTxt->pasVertices = (AVCVertex *)CPLRealloc( |
1609 | 1.67k | 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 | 7.60k | memset(psTxt->pszText, ' ', psTxt->numChars); |
1616 | 7.60k | 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 | 7.60k | psInfo->iCurItem = 0; |
1623 | 7.60k | psInfo->numItems = |
1624 | 7.60k | 8 + numVertices + ((psTxt->numChars - 1) / 80 + 1); |
1625 | 7.60k | } |
1626 | 7.69k | } |
1627 | 89.2k | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6 && |
1628 | 89.2k | nLen >= 60) |
1629 | 22.5k | { |
1630 | | /*------------------------------------------------------------- |
1631 | | * Text Justification stuff... 2 sets of 20 int16 values. |
1632 | | *------------------------------------------------------------*/ |
1633 | 22.5k | GInt16 *pValue; |
1634 | 22.5k | int numValPerLine = 7; |
1635 | | |
1636 | 22.5k | if (psInfo->iCurItem < 3) |
1637 | 14.6k | pValue = psTxt->anJust2 + psInfo->iCurItem * 7; |
1638 | 7.90k | else |
1639 | 7.90k | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1640 | | |
1641 | | /* Last line of each set contains only 6 values instead of 7 */ |
1642 | 22.5k | if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5) |
1643 | 5.68k | numValPerLine = 6; |
1644 | | |
1645 | 22.5k | for (i = 0; |
1646 | 173k | i < numValPerLine && nLen >= static_cast<size_t>(i) * 10 + 10; i++) |
1647 | 150k | pValue[i] = (GInt16)AVCE00Str2Int(pszLine + i * 10, 10); |
1648 | | |
1649 | 22.5k | psInfo->iCurItem++; |
1650 | 22.5k | } |
1651 | 66.6k | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6 && |
1652 | 66.6k | nLen >= 14) |
1653 | 2.37k | { |
1654 | | /*------------------------------------------------------------- |
1655 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
1656 | | *------------------------------------------------------------*/ |
1657 | 2.37k | psTxt->f_1e2 = (float)CPLAtof(pszLine); |
1658 | 2.37k | psInfo->iCurItem++; |
1659 | 2.37k | } |
1660 | 64.2k | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7 && |
1661 | 64.2k | nLen >= 42) |
1662 | 2.33k | { |
1663 | | /*------------------------------------------------------------- |
1664 | | * Line with 3 values, 1st value is text height. |
1665 | | *------------------------------------------------------------*/ |
1666 | 2.33k | psTxt->dHeight = CPLAtof(pszLine); |
1667 | 2.33k | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
1668 | 1.93k | { |
1669 | 1.93k | psTxt->dV2 = CPLAtof(pszLine + 14); |
1670 | 1.93k | psTxt->dV3 = CPLAtof(pszLine + 28); |
1671 | 1.93k | } |
1672 | 398 | else |
1673 | 398 | { |
1674 | 398 | psTxt->dV2 = CPLAtof(pszLine + 21); |
1675 | 398 | psTxt->dV3 = CPLAtof(pszLine + 42); |
1676 | 398 | } |
1677 | | |
1678 | 2.33k | psInfo->iCurItem++; |
1679 | 2.33k | } |
1680 | 61.9k | else if (psInfo->iCurItem >= 8 && |
1681 | 61.9k | psInfo->iCurItem < (8 + ABS(psTxt->numVerticesLine) + |
1682 | 61.8k | ABS(psTxt->numVerticesArrow)) && |
1683 | 61.9k | nLen >= 28) |
1684 | 2.99k | { |
1685 | | /*------------------------------------------------------------- |
1686 | | * One line for each pair of X,Y coordinates |
1687 | | * (Lines 8 to 8+numVertices-1) |
1688 | | *------------------------------------------------------------*/ |
1689 | 2.99k | psTxt->pasVertices[psInfo->iCurItem - 8].x = CPLAtof(pszLine); |
1690 | 2.99k | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
1691 | 2.03k | psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 14); |
1692 | 962 | else |
1693 | 962 | psTxt->pasVertices[psInfo->iCurItem - 8].y = CPLAtof(pszLine + 21); |
1694 | | |
1695 | 2.99k | psInfo->iCurItem++; |
1696 | 2.99k | } |
1697 | 58.9k | else if (psInfo->iCurItem >= (8 + ABS(psTxt->numVerticesLine) + |
1698 | 58.9k | ABS(psTxt->numVerticesArrow)) && |
1699 | 58.9k | psInfo->iCurItem < psInfo->numItems && |
1700 | 58.9k | (psTxt->numChars - 1) / 80 + 1 - |
1701 | 58.8k | (psInfo->numItems - psInfo->iCurItem) >= |
1702 | 58.8k | 0) |
1703 | 58.8k | { |
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 | 58.8k | int numLines, iLine; |
1710 | 58.8k | numLines = (psTxt->numChars - 1) / 80 + 1; |
1711 | 58.8k | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
1712 | | |
1713 | 58.8k | if (iLine == numLines - 1) |
1714 | 1.83k | { |
1715 | 1.83k | memcpy((char *)psTxt->pszText + (iLine * 80), pszLine, |
1716 | 1.83k | MIN((int)nLen, (psTxt->numChars - (iLine * 80)))); |
1717 | 1.83k | } |
1718 | 57.0k | else |
1719 | 57.0k | { |
1720 | 57.0k | memcpy((char *)psTxt->pszText + (iLine * 80), pszLine, |
1721 | 57.0k | MIN(nLen, 80)); |
1722 | 57.0k | } |
1723 | | |
1724 | 58.8k | psInfo->iCurItem++; |
1725 | 58.8k | } |
1726 | 95 | else |
1727 | 95 | { |
1728 | 95 | CPLError(CE_Failure, CPLE_AppDefined, |
1729 | 95 | "Error parsing E00 TX6/TX7 line: \"%s\"", pszLine); |
1730 | 95 | psInfo->numItems = psInfo->iCurItem = 0; |
1731 | 95 | return nullptr; |
1732 | 95 | } |
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 | 96.7k | if (psInfo->iCurItem >= psInfo->numItems) |
1741 | 1.83k | { |
1742 | 1.83k | psInfo->numItems = psInfo->iCurItem = 0; |
1743 | 1.83k | return psTxt; |
1744 | 1.83k | } |
1745 | | |
1746 | 94.9k | return nullptr; |
1747 | 96.7k | } |
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 | | AVCRxp *AVCE00ParseNextRxpLine(AVCE00ParseInfo *psInfo, const char *pszLine) |
1766 | 4.71k | { |
1767 | 4.71k | AVCRxp *psRxp; |
1768 | 4.71k | size_t nLen; |
1769 | | |
1770 | 4.71k | CPLAssert(psInfo->eFileType == AVCFileRXP); |
1771 | | |
1772 | 4.71k | psRxp = psInfo->cur.psRxp; |
1773 | | |
1774 | 4.71k | nLen = strlen(pszLine); |
1775 | | |
1776 | 4.71k | if (nLen >= 20) |
1777 | 4.69k | { |
1778 | | /*------------------------------------------------------------- |
1779 | | * RXP Entries are only one line each: |
1780 | | * Value1, Value2 (meaning of the value??? Don't know!!!) |
1781 | | *------------------------------------------------------------*/ |
1782 | 4.69k | psRxp->n1 = AVCE00Str2Int(pszLine, 10); |
1783 | 4.69k | psRxp->n2 = AVCE00Str2Int(pszLine + 10, 10); |
1784 | 4.69k | } |
1785 | 18 | else |
1786 | 18 | { |
1787 | 18 | CPLError(CE_Failure, CPLE_AppDefined, |
1788 | 18 | "Error parsing E00 RXP line: \"%s\"", pszLine); |
1789 | 18 | psInfo->numItems = psInfo->iCurItem = 0; |
1790 | 18 | return nullptr; |
1791 | 18 | } |
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 | 4.69k | if (psInfo->iCurItem >= psInfo->numItems) |
1800 | 4.69k | { |
1801 | 4.69k | psInfo->numItems = psInfo->iCurItem = 0; |
1802 | 4.69k | return psRxp; |
1803 | 4.69k | } |
1804 | | |
1805 | 0 | return nullptr; |
1806 | 4.69k | } |
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 | | AVCTableDef *AVCE00ParseNextTableDefLine(AVCE00ParseInfo *psInfo, |
1829 | | const char *pszLine) |
1830 | 3.75M | { |
1831 | 3.75M | AVCTableDef *psTableDef; |
1832 | 3.75M | size_t nLen; |
1833 | | |
1834 | 3.75M | CPLAssert(psInfo->eFileType == AVCFileTABLE); |
1835 | | |
1836 | 3.75M | psTableDef = psInfo->hdr.psTableDef; /* May be nullptr on first call */ |
1837 | | |
1838 | 3.75M | nLen = strlen(pszLine); |
1839 | | |
1840 | 3.75M | if (psInfo->numItems == 0) |
1841 | 1.88M | { |
1842 | | /*------------------------------------------------------------- |
1843 | | * Begin processing a new TableDef. Read header line: |
1844 | | * TableName, extFlag, numFields, RecSize, numRecords |
1845 | | *------------------------------------------------------------*/ |
1846 | 1.88M | if (nLen < 56) |
1847 | 81 | { |
1848 | 81 | CPLError(CE_Failure, CPLE_AppDefined, |
1849 | 81 | "Error parsing E00 Table Definition line: \"%s\"", |
1850 | 81 | pszLine); |
1851 | 81 | return nullptr; |
1852 | 81 | } |
1853 | 1.88M | else |
1854 | 1.88M | { |
1855 | | /*--------------------------------------------------------- |
1856 | | * Parse header line and alloc and init. a new psTableDef struct |
1857 | | *--------------------------------------------------------*/ |
1858 | 1.88M | psTableDef = psInfo->hdr.psTableDef = |
1859 | 1.88M | (AVCTableDef *)CPLCalloc(1, sizeof(AVCTableDef)); |
1860 | 1.88M | psInfo->bTableHdrComplete = FALSE; |
1861 | | |
1862 | 1.88M | strncpy(psTableDef->szTableName, pszLine, 32); |
1863 | 1.88M | psTableDef->szTableName[32] = '\0'; |
1864 | 1.88M | strncpy(psTableDef->szExternal, pszLine + 32, 2); |
1865 | 1.88M | psTableDef->szExternal[2] = '\0'; |
1866 | | |
1867 | 1.88M | psTableDef->numFields = (GInt16)AVCE00Str2Int(pszLine + 34, 4); |
1868 | 1.88M | psTableDef->nRecSize = (GInt16)AVCE00Str2Int(pszLine + 42, 4); |
1869 | 1.88M | psTableDef->numRecords = AVCE00Str2Int(pszLine + 46, 10); |
1870 | 1.88M | if (psTableDef->numFields < 0 || psTableDef->numFields > 10 * 1024) |
1871 | 6 | { |
1872 | 6 | CPLError(CE_Failure, CPLE_AppDefined, |
1873 | 6 | "Error parsing E00 Table Definition line: \"%s\"", |
1874 | 6 | pszLine); |
1875 | 6 | psInfo->numItems = psInfo->iCurItem = 0; |
1876 | 6 | psTableDef->numFields = 0; |
1877 | 6 | return nullptr; |
1878 | 6 | } |
1879 | | |
1880 | | /*--------------------------------------------------------- |
1881 | | * Alloc array of fields defs, will be filled in further calls |
1882 | | *--------------------------------------------------------*/ |
1883 | 1.88M | psTableDef->pasFieldDef = (AVCFieldInfo *)CPLCalloc( |
1884 | 1.88M | 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 | 1.88M | psInfo->numItems = AVCE00Str2Int(pszLine + 38, 4); |
1892 | 1.88M | psInfo->iCurItem = 0; |
1893 | 1.88M | psInfo->nCurObjectId = 0; /* We'll use it as a field index */ |
1894 | 1.88M | } |
1895 | 1.88M | } |
1896 | 1.86M | else if (psInfo->iCurItem < psInfo->numItems && nLen >= 69) |
1897 | 1.86M | { |
1898 | | /*------------------------------------------------------------- |
1899 | | * Read an attribute field definition |
1900 | | * If field index is -1, then we ignore this line... |
1901 | | *------------------------------------------------------------*/ |
1902 | 1.86M | int nIndex; |
1903 | | |
1904 | 1.86M | nIndex = AVCE00Str2Int(pszLine + 65, 4); |
1905 | | |
1906 | 1.86M | if (nIndex > 0 && psInfo->nCurObjectId >= psTableDef->numFields) |
1907 | 1 | { |
1908 | 1 | CPLError(CE_Failure, CPLE_AppDefined, |
1909 | 1 | "Error parsing E00 INFO Table Header: " |
1910 | 1 | "number of fields is invalid " |
1911 | 1 | "(expected %d, got at least %d)", |
1912 | 1 | psTableDef->numFields, psInfo->nCurObjectId + 1); |
1913 | 1 | psInfo->numItems = psInfo->iCurItem = psInfo->nCurObjectId; |
1914 | 1 | return nullptr; |
1915 | 1 | } |
1916 | | |
1917 | 1.86M | if (nIndex > 0) |
1918 | 1.85M | { |
1919 | 1.85M | AVCFieldInfo *psDef; |
1920 | 1.85M | psDef = &(psTableDef->pasFieldDef[psInfo->nCurObjectId]); |
1921 | | |
1922 | 1.85M | psDef->nIndex = (GInt16)nIndex; |
1923 | | |
1924 | 1.85M | strncpy(psDef->szName, pszLine, 16); |
1925 | 1.85M | psDef->szName[16] = '\0'; |
1926 | | |
1927 | 1.85M | psDef->nSize = (GInt16)AVCE00Str2Int(pszLine + 16, 3); |
1928 | 1.85M | psDef->v2 = (GInt16)AVCE00Str2Int(pszLine + 19, 2); |
1929 | | |
1930 | 1.85M | psDef->nOffset = (GInt16)AVCE00Str2Int(pszLine + 21, 4); |
1931 | | |
1932 | 1.85M | psDef->v4 = (GInt16)AVCE00Str2Int(pszLine + 25, 1); |
1933 | 1.85M | psDef->v5 = (GInt16)AVCE00Str2Int(pszLine + 26, 2); |
1934 | 1.85M | psDef->nFmtWidth = (GInt16)AVCE00Str2Int(pszLine + 28, 4); |
1935 | 1.85M | psDef->nFmtPrec = (GInt16)AVCE00Str2Int(pszLine + 32, 2); |
1936 | 1.85M | psDef->nType1 = (GInt16)AVCE00Str2Int(pszLine + 34, 3) / 10; |
1937 | 1.85M | psDef->nType2 = AVCE00Str2Int(pszLine + 34, 3) % 10; |
1938 | 1.85M | psDef->v10 = (GInt16)AVCE00Str2Int(pszLine + 37, 2); |
1939 | 1.85M | psDef->v11 = (GInt16)AVCE00Str2Int(pszLine + 39, 4); |
1940 | 1.85M | psDef->v12 = (GInt16)AVCE00Str2Int(pszLine + 43, 4); |
1941 | 1.85M | psDef->v13 = (GInt16)AVCE00Str2Int(pszLine + 47, 2); |
1942 | 1.85M | strncpy(psDef->szAltName, pszLine + 49, 16); |
1943 | 1.85M | psDef->szAltName[16] = '\0'; |
1944 | | |
1945 | 1.85M | if (psDef->nSize < 0) |
1946 | 4 | { |
1947 | 4 | CPLError(CE_Failure, CPLE_AppDefined, |
1948 | 4 | "Error parsing E00 Table Definition line: \"%s\"", |
1949 | 4 | pszLine); |
1950 | 4 | psInfo->numItems = psInfo->iCurItem = 0; |
1951 | 4 | return nullptr; |
1952 | 4 | } |
1953 | | |
1954 | 1.85M | psInfo->nCurObjectId++; |
1955 | 1.85M | } |
1956 | 1.86M | psInfo->iCurItem++; |
1957 | 1.86M | } |
1958 | 30 | else |
1959 | 30 | { |
1960 | 30 | CPLError(CE_Failure, CPLE_AppDefined, |
1961 | 30 | "Error parsing E00 Table Definition line: \"%s\"", pszLine); |
1962 | 30 | psInfo->numItems = psInfo->iCurItem = 0; |
1963 | 30 | return nullptr; |
1964 | 30 | } |
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 | 3.75M | if (psInfo->iCurItem >= psInfo->numItems) |
1975 | 1.88M | { |
1976 | 1.88M | psInfo->numItems = psInfo->iCurItem = 0; |
1977 | 1.88M | psInfo->nCurObjectId = 0; |
1978 | | |
1979 | 1.88M | 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 | 1.88M | if (psTableDef->numRecords == 0) |
1986 | 74.3k | psInfo->bForceEndOfSection = TRUE; |
1987 | | |
1988 | 1.88M | return psTableDef; |
1989 | 1.88M | } |
1990 | | |
1991 | 1.86M | return nullptr; |
1992 | 3.75M | } |
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 | | static AVCField *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo) |
2004 | 1.86M | { |
2005 | 1.86M | AVCField *pasFields; |
2006 | 1.86M | AVCFieldInfo *pasDef; |
2007 | 1.86M | AVCTableDef *psTableDef; |
2008 | 1.86M | int i, nType, nSize; |
2009 | 1.86M | char szFormat[20]; |
2010 | 1.86M | char *pszBuf, szTmp[30]; |
2011 | | |
2012 | 1.86M | pasFields = psInfo->cur.pasFields; |
2013 | 1.86M | psTableDef = psInfo->hdr.psTableDef; |
2014 | 1.86M | pasDef = psTableDef->pasFieldDef; |
2015 | | |
2016 | 1.86M | pszBuf = psInfo->pszBuf; |
2017 | 1.86M | CPLAssert(pszBuf); |
2018 | | |
2019 | 3.93M | for (i = 0; i < psTableDef->numFields; i++) |
2020 | 2.07M | { |
2021 | 2.07M | nType = pasDef[i].nType1 * 10; |
2022 | 2.07M | nSize = pasDef[i].nSize; |
2023 | | |
2024 | 2.07M | if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR || |
2025 | 2.07M | nType == AVC_FT_FIXINT) |
2026 | 1.60M | { |
2027 | 1.60M | strncpy((char *)pasFields[i].pszStr, pszBuf, nSize); |
2028 | 1.60M | pasFields[i].pszStr[nSize] = '\0'; |
2029 | 1.60M | pszBuf += nSize; |
2030 | 1.60M | } |
2031 | 470k | else if (nType == AVC_FT_FIXNUM) |
2032 | 341k | { |
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 | 341k | const char *pszTmpStr; |
2038 | 341k | strncpy(szTmp, pszBuf, 14); |
2039 | 341k | szTmp[14] = '\0'; |
2040 | 341k | 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 | 341k | if (!strchr(szTmp, 'E') && !strchr(szTmp, 'e')) |
2051 | 339k | { |
2052 | 339k | char *pszTmp; |
2053 | 339k | if ((pszTmp = strchr(szTmp, '.')) != nullptr && pszTmp != szTmp) |
2054 | 320k | { |
2055 | 320k | *pszTmp = *(pszTmp - 1); |
2056 | 320k | *(pszTmp - 1) = '.'; |
2057 | 320k | } |
2058 | 339k | } |
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 | 341k | snprintf(szFormat, sizeof(szFormat), "%%%d.%df", nSize, |
2065 | 341k | pasDef[i].nFmtPrec); |
2066 | 341k | 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 | 341k | if ((int)strlen(pszTmpStr) > nSize) |
2072 | 336k | pszTmpStr = pszTmpStr + strlen(pszTmpStr) - nSize; |
2073 | 341k | strncpy((char *)pasFields[i].pszStr, pszTmpStr, nSize); |
2074 | 341k | pasFields[i].pszStr[nSize] = '\0'; |
2075 | 341k | } |
2076 | 129k | else if (nType == AVC_FT_BININT && nSize == 4) |
2077 | 41.1k | { |
2078 | 41.1k | pasFields[i].nInt32 = AVCE00Str2Int(pszBuf, 11); |
2079 | 41.1k | pszBuf += 11; |
2080 | 41.1k | } |
2081 | 88.6k | else if (nType == AVC_FT_BININT && nSize == 2) |
2082 | 24.3k | { |
2083 | 24.3k | pasFields[i].nInt16 = (GInt16)AVCE00Str2Int(pszBuf, 6); |
2084 | 24.3k | pszBuf += 6; |
2085 | 24.3k | } |
2086 | 64.2k | else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4) |
2087 | 31.7k | { |
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 | 31.7k | strncpy(szTmp, pszBuf, 14); |
2093 | 31.7k | szTmp[14] = '\0'; |
2094 | 31.7k | pasFields[i].fFloat = (float)CPLAtof(szTmp); |
2095 | 31.7k | pszBuf += 14; |
2096 | 31.7k | } |
2097 | 32.5k | else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8) |
2098 | 32.5k | { |
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 | 32.5k | strncpy(szTmp, pszBuf, 24); |
2104 | 32.5k | szTmp[24] = '\0'; |
2105 | 32.5k | pasFields[i].dDouble = CPLAtof(szTmp); |
2106 | 32.5k | pszBuf += 24; |
2107 | 32.5k | } |
2108 | 0 | else |
2109 | 0 | { |
2110 | | /*----------------------------------------------------- |
2111 | | * Hummm... unsupported field type... |
2112 | | *----------------------------------------------------*/ |
2113 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
2114 | 0 | "_AVCE00ParseTableRecord(): Unsupported field type " |
2115 | 0 | "(type=%d, size=%d)", |
2116 | 0 | nType, pasDef[i].nSize); |
2117 | 0 | return nullptr; |
2118 | 0 | } |
2119 | 2.07M | } |
2120 | | |
2121 | 1.86M | CPLAssert(pszBuf == psInfo->pszBuf + psInfo->nTableE00RecLength); |
2122 | | |
2123 | 1.86M | return pasFields; |
2124 | 1.86M | } |
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 | | AVCField *AVCE00ParseNextTableRecLine(AVCE00ParseInfo *psInfo, |
2143 | | const char *pszLine) |
2144 | 1.87M | { |
2145 | 1.87M | AVCField *pasFields = nullptr; |
2146 | 1.87M | AVCTableDef *psTableDef; |
2147 | 1.87M | int i; |
2148 | | |
2149 | 1.87M | CPLAssert(psInfo->eFileType == AVCFileTABLE); |
2150 | | |
2151 | 1.87M | psTableDef = psInfo->hdr.psTableDef; |
2152 | | |
2153 | 1.87M | if (psInfo->bForceEndOfSection || psTableDef->numFields == 0 || |
2154 | 1.87M | psTableDef->numRecords == 0) |
2155 | 1.53k | { |
2156 | 1.53k | psInfo->bForceEndOfSection = TRUE; |
2157 | 1.53k | return nullptr; |
2158 | 1.53k | } |
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 | 1.87M | if (psInfo->numItems == 0 && psInfo->nCurObjectId == 0) |
2169 | 1.81M | { |
2170 | | /*------------------------------------------------------------- |
2171 | | * Realloc E00 buffer |
2172 | | *------------------------------------------------------------*/ |
2173 | 1.81M | psInfo->nTableE00RecLength = _AVCE00ComputeRecSize( |
2174 | 1.81M | psTableDef->numFields, psTableDef->pasFieldDef, FALSE); |
2175 | 1.81M | if (psInfo->nTableE00RecLength < 0) |
2176 | 41 | { |
2177 | 41 | return nullptr; |
2178 | 41 | } |
2179 | | |
2180 | 1.81M | if (psInfo->nBufSize < psInfo->nTableE00RecLength + 1) |
2181 | 0 | { |
2182 | 0 | psInfo->nBufSize = psInfo->nTableE00RecLength + 1; |
2183 | 0 | psInfo->pszBuf = |
2184 | 0 | (char *)CPLRealloc(psInfo->pszBuf, psInfo->nBufSize); |
2185 | 0 | } |
2186 | | |
2187 | | /*--------------------------------------------------------- |
2188 | | * Alloc psInfo->cur.pasFields[] |
2189 | | * Also alloc buffers for string attributes. |
2190 | | *--------------------------------------------------------*/ |
2191 | 1.81M | psInfo->cur.pasFields = |
2192 | 1.81M | (AVCField *)CPLCalloc(psTableDef->numFields, sizeof(AVCField)); |
2193 | 3.66M | for (i = 0; i < psTableDef->numFields; i++) |
2194 | 1.85M | { |
2195 | 1.85M | if (psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_DATE || |
2196 | 1.85M | psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_CHAR || |
2197 | 1.85M | psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXINT || |
2198 | 1.85M | psTableDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM) |
2199 | 1.82M | { |
2200 | 1.82M | psInfo->cur.pasFields[i].pszStr = (GByte *)CPLCalloc( |
2201 | 1.82M | psTableDef->pasFieldDef[i].nSize + 1, sizeof(GByte)); |
2202 | 1.82M | } |
2203 | 1.85M | } |
2204 | 1.81M | } |
2205 | | |
2206 | 1.87M | if (psInfo->numItems == 0) |
2207 | 1.86M | { |
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 | 1.86M | memset(psInfo->pszBuf, ' ', psInfo->nTableE00RecLength); |
2221 | 1.86M | 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 | 1.86M | psInfo->numItems = psInfo->nTableE00RecLength; |
2228 | 1.86M | psInfo->iCurItem = 0; |
2229 | 1.86M | } |
2230 | | |
2231 | 1.87M | if (psInfo->iCurItem < psInfo->numItems) |
2232 | 386k | { |
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 | 386k | int nSrcLen, nLenToCopy; |
2240 | | |
2241 | 386k | nSrcLen = (int)strlen(pszLine); |
2242 | 386k | nLenToCopy = |
2243 | 386k | MIN(80, MIN(nSrcLen, (psInfo->numItems - psInfo->iCurItem))); |
2244 | 386k | strncpy(psInfo->pszBuf + psInfo->iCurItem, pszLine, nLenToCopy); |
2245 | | |
2246 | 386k | psInfo->iCurItem += 80; |
2247 | 386k | } |
2248 | | |
2249 | 1.87M | if (psInfo->iCurItem >= psInfo->numItems) |
2250 | 1.86M | { |
2251 | | /*------------------------------------------------------------- |
2252 | | * OK, we've got one full record in the buffer... parse it and |
2253 | | * return the pasFields[] |
2254 | | *------------------------------------------------------------*/ |
2255 | 1.86M | pasFields = _AVCE00ParseTableRecord(psInfo); |
2256 | | |
2257 | 1.86M | if (pasFields == nullptr) |
2258 | 0 | { |
2259 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2260 | 0 | "Error parsing E00 Table Record: \"%s\"", psInfo->pszBuf); |
2261 | 0 | return nullptr; |
2262 | 0 | } |
2263 | | |
2264 | 1.86M | psInfo->numItems = psInfo->iCurItem = 0; |
2265 | 1.86M | psInfo->nCurObjectId++; |
2266 | 1.86M | } |
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 | 1.87M | if (psInfo->nCurObjectId >= psTableDef->numRecords) |
2273 | 1.80M | { |
2274 | 1.80M | psInfo->bForceEndOfSection = TRUE; |
2275 | 1.80M | } |
2276 | | |
2277 | 1.87M | return pasFields; |
2278 | 1.87M | } |