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