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