/src/gdal/ogr/ogrsf_frmts/avc/avc_e00gen.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /********************************************************************** |
2 | | * |
3 | | * Name: avc_e00gen.c |
4 | | * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library |
5 | | * Language: ANSI C |
6 | | * Purpose: Functions to generate ASCII E00 lines form 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_e00gen.c,v $ |
16 | | * Revision 1.18 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.17 2006/06/14 15:01:33 daniel |
21 | | * Remove any embedded '\0' from data line in AVCE00GenTableRec() |
22 | | * |
23 | | * Revision 1.16 2005/06/03 03:49:58 daniel |
24 | | * Update email address, website url, and copyright dates |
25 | | * |
26 | | * Revision 1.15 2004/08/19 17:48:20 warmerda |
27 | | * Avoid uninitialized variable warnings. |
28 | | * |
29 | | * Revision 1.14 2001/11/25 21:15:23 daniel |
30 | | * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8 |
31 | | * digits to double precision as we generate E00 output (bug599) |
32 | | * |
33 | | * Revision 1.13 2001/11/19 20:39:48 daniel |
34 | | * Change to correctly format 0-arc PAL records, so that they have a |
35 | | * single "filler" arc record |
36 | | * |
37 | | * Revision 1.12 2000/09/26 20:21:04 daniel |
38 | | * Added AVCCoverPC write |
39 | | * |
40 | | * Revision 1.11 2000/09/22 19:45:20 daniel |
41 | | * Switch to MIT-style license |
42 | | * |
43 | | * Revision 1.10 2000/02/04 04:54:03 daniel |
44 | | * Fixed warnings |
45 | | * |
46 | | * Revision 1.9 2000/02/03 07:21:02 daniel |
47 | | * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks |
48 | | * |
49 | | * Revision 1.8 2000/02/02 04:28:00 daniel |
50 | | * Fixed support of TX6/RXP/RPL coming from "weird" coverages |
51 | | * |
52 | | * Revision 1.7 1999/08/23 18:20:49 daniel |
53 | | * Fixed support for attribute fields type 40 |
54 | | * |
55 | | * Revision 1.6 1999/05/17 16:19:39 daniel |
56 | | * Made sure ACVE00GenTableRec() removes all spaces at the end of a |
57 | | * table record line (it used to leave one space) |
58 | | * |
59 | | * Revision 1.5 1999/05/11 02:08:17 daniel |
60 | | * Simple changes related to the addition of coverage write support. |
61 | | * |
62 | | * Revision 1.4 1999/03/03 02:06:38 daniel |
63 | | * Properly handle 8 bytes floats inside single precision tables. |
64 | | * |
65 | | * Revision 1.3 1999/02/25 17:01:58 daniel |
66 | | * Added support for 16 bit integers in INFO tables (type=50, size=2) |
67 | | * |
68 | | * Revision 1.2 1999/02/25 04:17:51 daniel |
69 | | * Added TXT, TX6/TX7, RXP and RPL support + some minor changes |
70 | | * |
71 | | * Revision 1.1 1999/01/29 16:28:52 daniel |
72 | | * Initial revision |
73 | | * |
74 | | **********************************************************************/ |
75 | | |
76 | | #include "avc.h" |
77 | | |
78 | | #include <cassert> |
79 | | #include <ctype.h> /* toupper() */ |
80 | | |
81 | | /********************************************************************** |
82 | | * AVCE00GenInfoAlloc() |
83 | | * |
84 | | * Allocate and initialize a new AVCE00GenInfo structure. |
85 | | * |
86 | | * The structure will eventually have to be freed with AVCE00GenInfoFree(). |
87 | | **********************************************************************/ |
88 | | AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision) |
89 | 13.6k | { |
90 | 13.6k | AVCE00GenInfo *psInfo; |
91 | | |
92 | 13.6k | psInfo = (AVCE00GenInfo *)CPLCalloc(1, sizeof(AVCE00GenInfo)); |
93 | | |
94 | | /* Allocate output buffer. |
95 | | * 2k should be enough... the biggest thing we'll need to store |
96 | | * in it will be 1 complete INFO table record. |
97 | | */ |
98 | 13.6k | psInfo->nBufSize = 2048; |
99 | 13.6k | psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize * sizeof(char)); |
100 | | |
101 | 13.6k | psInfo->nPrecision = nCoverPrecision; |
102 | | |
103 | 13.6k | return psInfo; |
104 | 13.6k | } |
105 | | |
106 | | /********************************************************************** |
107 | | * AVCE00GenInfoFree() |
108 | | * |
109 | | * Free any memory associated with a AVCE00GenInfo structure. |
110 | | **********************************************************************/ |
111 | | void AVCE00GenInfoFree(AVCE00GenInfo *psInfo) |
112 | 13.6k | { |
113 | 13.6k | if (psInfo) |
114 | 13.6k | CPLFree(psInfo->pszBuf); |
115 | 13.6k | CPLFree(psInfo); |
116 | 13.6k | } |
117 | | |
118 | | /********************************************************************** |
119 | | * AVCE00GenReset() |
120 | | * |
121 | | * Reset the fields in the AVCE00GenInfo structure so that further calls |
122 | | * with bCont = TRUE (ex: AVCE00GenArc(psInfo, TRUE)) would return nullptr. |
123 | | **********************************************************************/ |
124 | | void AVCE00GenReset(AVCE00GenInfo *psInfo) |
125 | 0 | { |
126 | | /* Reinitialize counters so that further calls with bCont = TRUE, |
127 | | * like AVCE00GenArc(psInfo, TRUE) would return nullptr. |
128 | | */ |
129 | 0 | psInfo->iCurItem = psInfo->numItems = 0; |
130 | 0 | } |
131 | | |
132 | | /********************************************************************** |
133 | | * AVCE00GenStartSection() |
134 | | * |
135 | | * Generate the first line of an E00 section. |
136 | | * |
137 | | * pszClassName applies only to JABBERWOCKY type of sections. |
138 | | **********************************************************************/ |
139 | | const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType, |
140 | | const char *pszClassName) |
141 | 0 | { |
142 | 0 | const char *pszName = "UNK"; |
143 | |
|
144 | 0 | AVCE00GenReset(psInfo); |
145 | |
|
146 | 0 | if (eType == AVCFileTX6 || eType == AVCFileRXP || eType == AVCFileRPL) |
147 | 0 | { |
148 | | /* TX6/RXP/RPL sections start with the class name (the basename |
149 | | * of the file) in uppercase. |
150 | | * ex: The section for "cities.txt" would start with "CITIES" |
151 | | */ |
152 | 0 | int i; |
153 | 0 | for (i = 0; pszClassName[i] != '\0'; i++) |
154 | 0 | { |
155 | 0 | psInfo->pszBuf[i] = |
156 | 0 | (char)CPLToupper(static_cast<unsigned char>(pszClassName[i])); |
157 | 0 | } |
158 | 0 | psInfo->pszBuf[i] = '\0'; |
159 | 0 | } |
160 | 0 | else |
161 | 0 | { |
162 | | /* In most cases, the section starts with a 3 letters code followed |
163 | | * by the precision code (2 or 3) |
164 | | */ |
165 | 0 | switch (eType) |
166 | 0 | { |
167 | 0 | case AVCFileARC: |
168 | 0 | pszName = "ARC"; |
169 | 0 | break; |
170 | 0 | case AVCFilePAL: |
171 | 0 | pszName = "PAL"; |
172 | 0 | break; |
173 | 0 | case AVCFileCNT: |
174 | 0 | pszName = "CNT"; |
175 | 0 | break; |
176 | 0 | case AVCFileLAB: |
177 | 0 | pszName = "LAB"; |
178 | 0 | break; |
179 | 0 | case AVCFileTOL: |
180 | 0 | pszName = "TOL"; |
181 | 0 | break; |
182 | 0 | case AVCFilePRJ: |
183 | 0 | pszName = "PRJ"; |
184 | 0 | break; |
185 | 0 | case AVCFileTXT: |
186 | 0 | pszName = "TXT"; |
187 | 0 | break; |
188 | 0 | default: |
189 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
190 | 0 | "Unsupported E00 section type!"); |
191 | 0 | } |
192 | | |
193 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
194 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 3", pszName); |
195 | 0 | else |
196 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 2", pszName); |
197 | 0 | } |
198 | | |
199 | 0 | return psInfo->pszBuf; |
200 | 0 | } |
201 | | |
202 | | /********************************************************************** |
203 | | * AVCE00GenEndSection() |
204 | | * |
205 | | * Generate the last line(s) of an E00 section. |
206 | | * |
207 | | * This function should be called once with bCont=FALSE to get the |
208 | | * first "end of section" line for the current section, and then call |
209 | | * with bCont=TRUE to get all the other lines. |
210 | | * |
211 | | * The function returns nullptr when there are no more lines to generate |
212 | | * for this "end of section". |
213 | | **********************************************************************/ |
214 | | const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType, |
215 | | GBool bCont) |
216 | 0 | { |
217 | 0 | if (bCont == FALSE) |
218 | 0 | { |
219 | | /*------------------------------------------------------------- |
220 | | * Most section types end with only 1 line. |
221 | | *------------------------------------------------------------*/ |
222 | 0 | AVCE00GenReset(psInfo); |
223 | 0 | psInfo->iCurItem = 0; |
224 | |
|
225 | 0 | if (eType == AVCFileARC || eType == AVCFilePAL || eType == AVCFileRPL || |
226 | 0 | eType == AVCFileCNT || eType == AVCFileTOL || eType == AVCFileTXT || |
227 | 0 | eType == AVCFileTX6) |
228 | 0 | { |
229 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
230 | 0 | " -1 0 0 0 0 " |
231 | 0 | " 0 0"); |
232 | 0 | } |
233 | 0 | else if (eType == AVCFileLAB) |
234 | 0 | { |
235 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
236 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
237 | 0 | " -1 0 0.00000000000000E+00 " |
238 | 0 | "0.00000000000000E+00"); |
239 | 0 | else |
240 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
241 | 0 | " -1 0 0.0000000E+00 0.0000000E+00"); |
242 | 0 | } |
243 | 0 | else if (eType == AVCFilePRJ) |
244 | 0 | { |
245 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "EOP"); |
246 | 0 | } |
247 | 0 | else if (eType == AVCFileRXP) |
248 | 0 | { |
249 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, " -1 0"); |
250 | 0 | } |
251 | 0 | else |
252 | 0 | { |
253 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
254 | 0 | "Unsupported E00 section type!"); |
255 | 0 | return nullptr; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | else if (psInfo->iCurItem == 0 && psInfo->nPrecision == AVC_DOUBLE_PREC && |
259 | 0 | (eType == AVCFilePAL || eType == AVCFileRPL)) |
260 | 0 | { |
261 | | /*--------------------------------------------------------- |
262 | | * Return the 2nd line for the end of a PAL or RPL section. |
263 | | *--------------------------------------------------------*/ |
264 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
265 | 0 | " 0.00000000000000E+00 0.00000000000000E+00"); |
266 | |
|
267 | 0 | psInfo->iCurItem++; |
268 | 0 | } |
269 | 0 | else |
270 | 0 | { |
271 | | /*----------------------------------------------------- |
272 | | * All other section types end with only one line, and thus |
273 | | * we return nullptr when bCont==TRUE |
274 | | *----------------------------------------------------*/ |
275 | 0 | return nullptr; |
276 | 0 | } |
277 | | |
278 | 0 | return psInfo->pszBuf; |
279 | 0 | } |
280 | | |
281 | | /********************************************************************** |
282 | | * AVCE00GenObject() |
283 | | * |
284 | | * Cover function on top of AVCE00GenArc/Pal/Cnt/Lab() that will |
285 | | * call the right function according to argument eType. |
286 | | * |
287 | | * Since there is no compiler type checking on psObj, you have to |
288 | | * be very careful to make sure you pass an object of the right type |
289 | | * when you use this function! |
290 | | * |
291 | | * The function returns nullptr when there are no more lines to generate |
292 | | * for this ARC. |
293 | | **********************************************************************/ |
294 | | const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType, |
295 | | void *psObj, GBool bCont) |
296 | 0 | { |
297 | 0 | const char *pszLine = nullptr; |
298 | |
|
299 | 0 | switch (eType) |
300 | 0 | { |
301 | 0 | case AVCFileARC: |
302 | 0 | pszLine = AVCE00GenArc(psInfo, (AVCArc *)psObj, bCont); |
303 | 0 | break; |
304 | 0 | case AVCFilePAL: |
305 | 0 | case AVCFileRPL: |
306 | 0 | pszLine = AVCE00GenPal(psInfo, (AVCPal *)psObj, bCont); |
307 | 0 | break; |
308 | 0 | case AVCFileCNT: |
309 | 0 | pszLine = AVCE00GenCnt(psInfo, (AVCCnt *)psObj, bCont); |
310 | 0 | break; |
311 | 0 | case AVCFileLAB: |
312 | 0 | pszLine = AVCE00GenLab(psInfo, (AVCLab *)psObj, bCont); |
313 | 0 | break; |
314 | 0 | case AVCFileTOL: |
315 | 0 | pszLine = AVCE00GenTol(psInfo, (AVCTol *)psObj, bCont); |
316 | 0 | break; |
317 | 0 | case AVCFileTXT: |
318 | 0 | pszLine = AVCE00GenTxt(psInfo, (AVCTxt *)psObj, bCont); |
319 | 0 | break; |
320 | 0 | case AVCFileTX6: |
321 | 0 | pszLine = AVCE00GenTx6(psInfo, (AVCTxt *)psObj, bCont); |
322 | 0 | break; |
323 | 0 | case AVCFilePRJ: |
324 | 0 | pszLine = AVCE00GenPrj(psInfo, (char **)psObj, bCont); |
325 | 0 | break; |
326 | 0 | case AVCFileRXP: |
327 | 0 | pszLine = AVCE00GenRxp(psInfo, (AVCRxp *)psObj, bCont); |
328 | 0 | break; |
329 | 0 | default: |
330 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
331 | 0 | "AVCE00GenObject(): Unsupported file type!"); |
332 | 0 | } |
333 | | |
334 | 0 | return pszLine; |
335 | 0 | } |
336 | | |
337 | | /*===================================================================== |
338 | | ARC stuff |
339 | | =====================================================================*/ |
340 | | |
341 | | /********************************************************************** |
342 | | * AVCE00GenArc() |
343 | | * |
344 | | * Generate the next line of an E00 ARC. |
345 | | * |
346 | | * This function should be called once with bCont=FALSE to get the |
347 | | * first E00 line for the current ARC, and then call with bCont=TRUE |
348 | | * to get all the other lines for this ARC. |
349 | | * |
350 | | * The function returns nullptr when there are no more lines to generate |
351 | | * for this ARC. |
352 | | **********************************************************************/ |
353 | | const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont) |
354 | 0 | { |
355 | 0 | if (bCont == FALSE) |
356 | 0 | { |
357 | | /* Initialize the psInfo structure with info about the |
358 | | * current ARC. |
359 | | */ |
360 | 0 | psInfo->iCurItem = 0; |
361 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
362 | 0 | psInfo->numItems = psArc->numVertices; |
363 | 0 | else |
364 | 0 | psInfo->numItems = (psArc->numVertices + 1) / 2; |
365 | | |
366 | | /* And return the ARC header line |
367 | | */ |
368 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
369 | 0 | "%10d%10d%10d%10d%10d%10d%10d", psArc->nArcId, psArc->nUserId, |
370 | 0 | psArc->nFNode, psArc->nTNode, psArc->nLPoly, psArc->nRPoly, |
371 | 0 | psArc->numVertices); |
372 | 0 | } |
373 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
374 | 0 | { |
375 | 0 | int iVertex; |
376 | | |
377 | | /* return the next set of vertices for the ARC. |
378 | | */ |
379 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
380 | 0 | { |
381 | 0 | iVertex = psInfo->iCurItem; |
382 | |
|
383 | 0 | psInfo->pszBuf[0] = '\0'; |
384 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
385 | 0 | psInfo->nPrecision, AVCFileARC, |
386 | 0 | psArc->pasVertices[iVertex].x); |
387 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
388 | 0 | psInfo->nPrecision, AVCFileARC, |
389 | 0 | psArc->pasVertices[iVertex].y); |
390 | 0 | } |
391 | 0 | else |
392 | 0 | { |
393 | 0 | iVertex = psInfo->iCurItem * 2; |
394 | |
|
395 | 0 | psInfo->pszBuf[0] = '\0'; |
396 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
397 | 0 | psInfo->nPrecision, AVCFileARC, |
398 | 0 | psArc->pasVertices[iVertex].x); |
399 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
400 | 0 | psInfo->nPrecision, AVCFileARC, |
401 | 0 | psArc->pasVertices[iVertex].y); |
402 | | |
403 | | /* Check because if we have a odd number of vertices then |
404 | | * the last line contains only one pair of vertices. |
405 | | */ |
406 | 0 | if (iVertex + 1 < psArc->numVertices) |
407 | 0 | { |
408 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
409 | 0 | psInfo->nPrecision, AVCFileARC, |
410 | 0 | psArc->pasVertices[iVertex + 1].x); |
411 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
412 | 0 | psInfo->nPrecision, AVCFileARC, |
413 | 0 | psArc->pasVertices[iVertex + 1].y); |
414 | 0 | } |
415 | 0 | } |
416 | 0 | psInfo->iCurItem++; |
417 | 0 | } |
418 | 0 | else |
419 | 0 | { |
420 | | /* No more lines to generate for this ARC. |
421 | | */ |
422 | 0 | return nullptr; |
423 | 0 | } |
424 | | |
425 | 0 | return psInfo->pszBuf; |
426 | 0 | } |
427 | | |
428 | | /*===================================================================== |
429 | | PAL stuff |
430 | | =====================================================================*/ |
431 | | |
432 | | /********************************************************************** |
433 | | * AVCE00GenPal() |
434 | | * |
435 | | * Generate the next line of an E00 PAL (Polygon Arc List) entry. |
436 | | * |
437 | | * This function should be called once with bCont=FALSE to get the |
438 | | * first E00 line for the current PAL, and then call with bCont=TRUE |
439 | | * to get all the other lines for this PAL. |
440 | | * |
441 | | * The function returns nullptr when there are no more lines to generate |
442 | | * for this PAL entry. |
443 | | **********************************************************************/ |
444 | | const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont) |
445 | 0 | { |
446 | 0 | if (bCont == FALSE) |
447 | 0 | { |
448 | | /* Initialize the psInfo structure with info about the |
449 | | * current PAL. (Number of lines excluding header) |
450 | | */ |
451 | 0 | psInfo->numItems = (psPal->numArcs + 1) / 2; |
452 | | |
453 | | /* And return the PAL header line. |
454 | | */ |
455 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psPal->numArcs); |
456 | |
|
457 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
458 | 0 | AVCFilePAL, psPal->sMin.x); |
459 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
460 | 0 | AVCFilePAL, psPal->sMin.y); |
461 | | |
462 | | /* Double precision PAL entries have their header on 2 lines! |
463 | | */ |
464 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
465 | 0 | { |
466 | 0 | psInfo->iCurItem = -1; /* Means 1 line left in header */ |
467 | 0 | } |
468 | 0 | else |
469 | 0 | { |
470 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
471 | 0 | psInfo->nPrecision, AVCFilePAL, psPal->sMax.x); |
472 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
473 | 0 | psInfo->nPrecision, AVCFilePAL, psPal->sMax.y); |
474 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
475 | 0 | } |
476 | 0 | } |
477 | 0 | else if (psInfo->iCurItem == -1) |
478 | 0 | { |
479 | | /* Second (and last) header line for double precision coverages |
480 | | */ |
481 | 0 | psInfo->pszBuf[0] = '\0'; |
482 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
483 | 0 | AVCFilePAL, psPal->sMax.x); |
484 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
485 | 0 | AVCFilePAL, psPal->sMax.y); |
486 | |
|
487 | 0 | if (psInfo->numItems == 0) |
488 | 0 | { |
489 | 0 | psInfo->iCurItem = -2; /* We have a 0-arc polygon, which needs |
490 | | an arc list with one "0 0 0" element */ |
491 | 0 | } |
492 | 0 | else |
493 | 0 | { |
494 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
495 | 0 | } |
496 | 0 | } |
497 | 0 | else if (psInfo->iCurItem == -2) |
498 | 0 | { |
499 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", 0, 0, 0); |
500 | 0 | psInfo->iCurItem = 0; /* Next thing = first Arc entry */ |
501 | 0 | } |
502 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
503 | 0 | { |
504 | | /* Return PAL Arc entries... |
505 | | */ |
506 | 0 | int iArc; |
507 | |
|
508 | 0 | iArc = psInfo->iCurItem * 2; |
509 | | |
510 | | /* If we have a odd number of arcs then |
511 | | * the last line contains only one arc entry. |
512 | | */ |
513 | 0 | if (iArc + 1 < psPal->numArcs) |
514 | 0 | { |
515 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
516 | 0 | "%10d%10d%10d%10d%10d%10d", psPal->pasArcs[iArc].nArcId, |
517 | 0 | psPal->pasArcs[iArc].nFNode, psPal->pasArcs[iArc].nAdjPoly, |
518 | 0 | psPal->pasArcs[iArc + 1].nArcId, |
519 | 0 | psPal->pasArcs[iArc + 1].nFNode, |
520 | 0 | psPal->pasArcs[iArc + 1].nAdjPoly); |
521 | 0 | } |
522 | 0 | else |
523 | 0 | { |
524 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", |
525 | 0 | psPal->pasArcs[iArc].nArcId, psPal->pasArcs[iArc].nFNode, |
526 | 0 | psPal->pasArcs[iArc].nAdjPoly); |
527 | 0 | } |
528 | 0 | psInfo->iCurItem++; |
529 | 0 | } |
530 | 0 | else |
531 | 0 | { |
532 | | /* No more lines to generate for this PAL. |
533 | | */ |
534 | 0 | return nullptr; |
535 | 0 | } |
536 | | |
537 | 0 | return psInfo->pszBuf; |
538 | 0 | } |
539 | | |
540 | | /*===================================================================== |
541 | | CNT stuff |
542 | | =====================================================================*/ |
543 | | |
544 | | /********************************************************************** |
545 | | * AVCE00GenCnt() |
546 | | * |
547 | | * Generate the next line of an E00 CNT (Polygon Centroid) entry. |
548 | | * |
549 | | * This function should be called once with bCont=FALSE to get the |
550 | | * first E00 line for the current CNT, and then call with bCont=TRUE |
551 | | * to get all the other lines for this CNT. |
552 | | * |
553 | | * The function returns nullptr when there are no more lines to generate |
554 | | * for this CNT entry. |
555 | | **********************************************************************/ |
556 | | const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont) |
557 | 0 | { |
558 | 0 | if (bCont == FALSE) |
559 | 0 | { |
560 | | /* Initialize the psInfo structure with info about the |
561 | | * current CNT. |
562 | | */ |
563 | 0 | psInfo->iCurItem = 0; |
564 | 0 | psInfo->numItems = (psCnt->numLabels + 7) / 8; |
565 | | |
566 | | /* And return the CNT header line. |
567 | | */ |
568 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d", psCnt->numLabels); |
569 | |
|
570 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
571 | 0 | AVCFileCNT, psCnt->sCoord.x); |
572 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
573 | 0 | AVCFileCNT, psCnt->sCoord.y); |
574 | 0 | } |
575 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
576 | 0 | { |
577 | | /* Return CNT Label Ids, 8 label Ids per line... |
578 | | */ |
579 | 0 | int i, nFirstLabel, numLabels; |
580 | |
|
581 | 0 | nFirstLabel = psInfo->iCurItem * 8; |
582 | 0 | numLabels = MIN(8, (psCnt->numLabels - nFirstLabel)); |
583 | |
|
584 | 0 | psInfo->pszBuf[0] = '\0'; |
585 | 0 | for (i = 0; i < numLabels; i++) |
586 | 0 | { |
587 | 0 | snprintf(psInfo->pszBuf + strlen(psInfo->pszBuf), |
588 | 0 | psInfo->nBufSize - strlen(psInfo->pszBuf), "%10d", |
589 | 0 | psCnt->panLabelIds[nFirstLabel + i]); |
590 | 0 | } |
591 | |
|
592 | 0 | psInfo->iCurItem++; |
593 | 0 | } |
594 | 0 | else |
595 | 0 | { |
596 | | /* No more lines to generate for this CNT. |
597 | | */ |
598 | 0 | return nullptr; |
599 | 0 | } |
600 | | |
601 | 0 | return psInfo->pszBuf; |
602 | 0 | } |
603 | | |
604 | | /*===================================================================== |
605 | | LAB stuff |
606 | | =====================================================================*/ |
607 | | |
608 | | /********************************************************************** |
609 | | * AVCE00GenLab() |
610 | | * |
611 | | * Generate the next line of an E00 LAB (Label) entry. |
612 | | * |
613 | | * This function should be called once with bCont=FALSE to get the |
614 | | * first E00 line for the current LAB, and then call with bCont=TRUE |
615 | | * to get all the other lines for this LAB. |
616 | | * |
617 | | * The function returns nullptr when there are no more lines to generate |
618 | | * for this LAB entry. |
619 | | **********************************************************************/ |
620 | | const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont) |
621 | 0 | { |
622 | 0 | if (bCont == FALSE) |
623 | 0 | { |
624 | | /* Initialize the psInfo structure with info about the |
625 | | * current LAB. (numItems = Number of lines excluding header) |
626 | | */ |
627 | 0 | psInfo->iCurItem = 0; |
628 | 0 | if (psInfo->nPrecision == AVC_DOUBLE_PREC) |
629 | 0 | psInfo->numItems = 2; |
630 | 0 | else |
631 | 0 | psInfo->numItems = 1; |
632 | | |
633 | | /* And return the LAB header line. |
634 | | */ |
635 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psLab->nValue, |
636 | 0 | psLab->nPolyId); |
637 | |
|
638 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
639 | 0 | AVCFileLAB, psLab->sCoord1.x); |
640 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
641 | 0 | AVCFileLAB, psLab->sCoord1.y); |
642 | 0 | } |
643 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
644 | 0 | { |
645 | | /* Return next Label coordinates... |
646 | | */ |
647 | 0 | if (psInfo->nPrecision != AVC_DOUBLE_PREC) |
648 | 0 | { |
649 | | /* Single precision, all on the same line |
650 | | */ |
651 | 0 | psInfo->pszBuf[0] = '\0'; |
652 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
653 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); |
654 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
655 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); |
656 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
657 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); |
658 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
659 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); |
660 | 0 | } |
661 | 0 | else if (psInfo->iCurItem == 0) |
662 | 0 | { |
663 | | /* 2nd line, in a double precision coverage |
664 | | */ |
665 | 0 | psInfo->pszBuf[0] = '\0'; |
666 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
667 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x); |
668 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
669 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y); |
670 | 0 | } |
671 | 0 | else |
672 | 0 | { |
673 | | /* 3rd line, in a double precision coverage |
674 | | */ |
675 | 0 | psInfo->pszBuf[0] = '\0'; |
676 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
677 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x); |
678 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
679 | 0 | psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y); |
680 | 0 | } |
681 | |
|
682 | 0 | psInfo->iCurItem++; |
683 | 0 | } |
684 | 0 | else |
685 | 0 | { |
686 | | /* No more lines to generate for this LAB. |
687 | | */ |
688 | 0 | return nullptr; |
689 | 0 | } |
690 | | |
691 | 0 | return psInfo->pszBuf; |
692 | 0 | } |
693 | | |
694 | | /*===================================================================== |
695 | | TOL stuff |
696 | | =====================================================================*/ |
697 | | |
698 | | /********************************************************************** |
699 | | * AVCE00GenTol() |
700 | | * |
701 | | * Generate the next line of an E00 TOL (Tolerance) entry. |
702 | | * |
703 | | * This function should be called once with bCont=FALSE to get the |
704 | | * first E00 line for the current TOL, and then call with bCont=TRUE |
705 | | * to get all the other lines for this TOL. |
706 | | * |
707 | | * The function returns nullptr when there are no more lines to generate |
708 | | * for this TOL entry. |
709 | | **********************************************************************/ |
710 | | const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont) |
711 | 0 | { |
712 | 0 | if (bCont == TRUE) |
713 | 0 | { |
714 | | /*--------------------------------------------------------- |
715 | | * TOL entries are only 1 line, we support the bCont flag |
716 | | * only for compatibility with the other AVCE00Gen*() functions. |
717 | | *--------------------------------------------------------*/ |
718 | 0 | return nullptr; |
719 | 0 | } |
720 | | |
721 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psTol->nIndex, |
722 | 0 | psTol->nFlag); |
723 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
724 | 0 | AVCFileTOL, psTol->dValue); |
725 | |
|
726 | 0 | return psInfo->pszBuf; |
727 | 0 | } |
728 | | |
729 | | /*===================================================================== |
730 | | PRJ stuff |
731 | | =====================================================================*/ |
732 | | |
733 | | /********************************************************************** |
734 | | * AVCE00GenPrj() |
735 | | * |
736 | | * Generate the next line of an E00 PRJ (Projection) section. |
737 | | * |
738 | | * This function should be called once with bCont=FALSE to get the |
739 | | * first E00 line for the current PRJ, and then call with bCont=TRUE |
740 | | * to get all the other lines for this PRJ. |
741 | | * |
742 | | * The function returns nullptr when there are no more lines to generate |
743 | | * for this PRJ entry. |
744 | | **********************************************************************/ |
745 | | const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont) |
746 | 0 | { |
747 | 0 | if (bCont == FALSE) |
748 | 0 | { |
749 | | /*--------------------------------------------------------- |
750 | | * Initialize the psInfo structure with info about the |
751 | | * current PRJ. (numItems = Number of lines to output) |
752 | | *--------------------------------------------------------*/ |
753 | 0 | psInfo->iCurItem = 0; |
754 | 0 | psInfo->numItems = CSLCount(papszPrj) * 2; |
755 | 0 | } |
756 | |
|
757 | 0 | if (psInfo->iCurItem < psInfo->numItems) |
758 | 0 | { |
759 | | /*--------------------------------------------------------- |
760 | | * Return the next PRJ section line. Note that every |
761 | | * second line of the output is only a "~". |
762 | | *--------------------------------------------------------*/ |
763 | |
|
764 | 0 | if (psInfo->iCurItem % 2 == 0) |
765 | 0 | { |
766 | | /*----------------------------------------------------- |
767 | | * In theory we should split lines longer than 80 chars on |
768 | | * several lines, but I won't do it for now since I never |
769 | | * saw any projection line longer than 80 chars. |
770 | | *----------------------------------------------------*/ |
771 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s", |
772 | 0 | papszPrj[psInfo->iCurItem / 2]); |
773 | 0 | } |
774 | 0 | else |
775 | 0 | { |
776 | | /*----------------------------------------------------- |
777 | | * Every second line in a PRJ section contains only a "~", |
778 | | * this is a way to tell that the previous line was complete. |
779 | | *----------------------------------------------------*/ |
780 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "~"); |
781 | 0 | } |
782 | |
|
783 | 0 | psInfo->iCurItem++; |
784 | 0 | } |
785 | 0 | else |
786 | 0 | { |
787 | | /* No more lines to generate for this PRJ. |
788 | | */ |
789 | 0 | return nullptr; |
790 | 0 | } |
791 | | |
792 | 0 | return psInfo->pszBuf; |
793 | 0 | } |
794 | | |
795 | | /*===================================================================== |
796 | | TXT stuff |
797 | | =====================================================================*/ |
798 | | |
799 | | /********************************************************************** |
800 | | * AVCE00GenTxt() |
801 | | * |
802 | | * Generate the next line of an E00 TXT (Annotation) entry. |
803 | | * |
804 | | * This function should be called once with bCont=FALSE to get the |
805 | | * first E00 line for the current TXT, and then call with bCont=TRUE |
806 | | * to get all the other lines for this TXT. |
807 | | * |
808 | | * The function returns nullptr when there are no more lines to generate |
809 | | * for this TXT entry. |
810 | | **********************************************************************/ |
811 | | const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) |
812 | 0 | { |
813 | 0 | int numFixedLines; |
814 | | |
815 | | /* numFixedLines is the number of lines to generate before the line(s) |
816 | | * with the text string |
817 | | */ |
818 | 0 | if (psInfo->nPrecision == AVC_SINGLE_PREC) |
819 | 0 | numFixedLines = 4; |
820 | 0 | else |
821 | 0 | numFixedLines = 6; |
822 | |
|
823 | 0 | if (bCont == FALSE) |
824 | 0 | { |
825 | | /*------------------------------------------------------------- |
826 | | * Initialize the psInfo structure with info about the |
827 | | * current TXT. (numItems = Number of lines excluding header) |
828 | | *------------------------------------------------------------*/ |
829 | 0 | psInfo->iCurItem = 0; |
830 | 0 | psInfo->numItems = numFixedLines + ((psTxt->numChars - 1) / 80 + 1); |
831 | | |
832 | | /* And return the TXT header line. |
833 | | */ |
834 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d%10d%10d", |
835 | 0 | psTxt->nLevel, psTxt->numVerticesLine - 1, |
836 | 0 | psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars); |
837 | 0 | } |
838 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
839 | 0 | psInfo->iCurItem < numFixedLines - 1) |
840 | 0 | { |
841 | | /*------------------------------------------------------------- |
842 | | * Return next line of coordinates... start by placing the coord. |
843 | | * values in the order that they should appear, and then generate the |
844 | | * current line |
845 | | * (This is a little bit less efficient, but will give much easier |
846 | | * code to read ;-) |
847 | | *------------------------------------------------------------*/ |
848 | 0 | double dXY[15] = {0.0}; |
849 | 0 | int i, nFirstValue, numValuesPerLine; |
850 | |
|
851 | 0 | dXY[14] = psTxt->dHeight; |
852 | | |
853 | | /* note that the first vertex in the vertices list is never exported |
854 | | */ |
855 | 0 | for (i = 0; i < 4 && i < (psTxt->numVerticesLine - 1); i++) |
856 | 0 | { |
857 | 0 | dXY[i] = psTxt->pasVertices[i + 1].x; |
858 | 0 | dXY[i + 4] = psTxt->pasVertices[i + 1].y; |
859 | 0 | } |
860 | 0 | for (i = 0; i < 3 && i < ABS(psTxt->numVerticesArrow); i++) |
861 | 0 | { |
862 | 0 | dXY[i + 8] = psTxt->pasVertices[i + psTxt->numVerticesLine].x; |
863 | 0 | dXY[i + 11] = psTxt->pasVertices[i + psTxt->numVerticesLine].y; |
864 | 0 | } |
865 | | |
866 | | /* OK, now that we prepared the coord. values, return the next line |
867 | | * of coordinates. The only difference between double and single |
868 | | * precision is the number of coordinates per line. |
869 | | */ |
870 | 0 | if (psInfo->nPrecision != AVC_DOUBLE_PREC) |
871 | 0 | { |
872 | | /* Single precision |
873 | | */ |
874 | 0 | numValuesPerLine = 5; |
875 | 0 | } |
876 | 0 | else |
877 | 0 | { |
878 | | /* Double precision |
879 | | */ |
880 | 0 | numValuesPerLine = 3; |
881 | 0 | } |
882 | |
|
883 | 0 | nFirstValue = psInfo->iCurItem * numValuesPerLine; |
884 | 0 | psInfo->pszBuf[0] = '\0'; |
885 | 0 | for (i = 0; i < numValuesPerLine; i++) |
886 | 0 | { |
887 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, |
888 | 0 | psInfo->nPrecision, AVCFileTXT, |
889 | 0 | dXY[nFirstValue + i]); |
890 | 0 | } |
891 | |
|
892 | 0 | psInfo->iCurItem++; |
893 | 0 | } |
894 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
895 | 0 | psInfo->iCurItem == numFixedLines - 1) |
896 | 0 | { |
897 | | /*------------------------------------------------------------- |
898 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
899 | | *------------------------------------------------------------*/ |
900 | 0 | psInfo->pszBuf[0] = '\0'; |
901 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC, |
902 | 0 | AVCFileTXT, psTxt->f_1e2); |
903 | 0 | psInfo->iCurItem++; |
904 | 0 | } |
905 | 0 | else if (psInfo->iCurItem < psInfo->numItems && |
906 | 0 | psInfo->iCurItem >= numFixedLines) |
907 | 0 | { |
908 | | /*------------------------------------------------------------- |
909 | | * Last line, contains the text string |
910 | | * Strings longer than 80 chars have to be in 80 chars chunks |
911 | | *------------------------------------------------------------*/ |
912 | 0 | int numLines, iLine; |
913 | 0 | numLines = (psTxt->numChars - 1) / 80 + 1; |
914 | 0 | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
915 | |
|
916 | 0 | if ((int)strlen((char *)psTxt->pszText) > (iLine * 80)) |
917 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s", |
918 | 0 | psTxt->pszText + (iLine * 80)); |
919 | 0 | else |
920 | 0 | psInfo->pszBuf[0] = '\0'; |
921 | |
|
922 | 0 | psInfo->iCurItem++; |
923 | 0 | } |
924 | 0 | else |
925 | 0 | { |
926 | | /* No more lines to generate for this TXT. |
927 | | */ |
928 | 0 | return nullptr; |
929 | 0 | } |
930 | | |
931 | 0 | return psInfo->pszBuf; |
932 | 0 | } |
933 | | |
934 | | /*===================================================================== |
935 | | TX6 stuff |
936 | | =====================================================================*/ |
937 | | |
938 | | /********************************************************************** |
939 | | * AVCE00GenTx6() |
940 | | * |
941 | | * Generate the next line of an E00 TX6 (Annotation) entry. |
942 | | * |
943 | | * This function should be called once with bCont=FALSE to get the |
944 | | * first E00 line for the current TX6, and then call with bCont=TRUE |
945 | | * to get all the other lines for this TX6. |
946 | | * |
947 | | * Note that E00 files can also contain TX7 sections, they seem identical |
948 | | * to TX6 sections, except for one value in each entry, and it was |
949 | | * impossible to find where this value comes from... so we will always |
950 | | * generate TX6 sections and not bother with TX7. |
951 | | * |
952 | | * The function returns nullptr when there are no more lines to generate |
953 | | * for this TX6 entry. |
954 | | **********************************************************************/ |
955 | | const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont) |
956 | 0 | { |
957 | 0 | if (bCont == FALSE) |
958 | 0 | { |
959 | | /*------------------------------------------------------------- |
960 | | * Initialize the psInfo structure with info about the |
961 | | * current TX6. (numItems = Number of lines excluding header) |
962 | | *------------------------------------------------------------*/ |
963 | 0 | psInfo->iCurItem = 0; |
964 | 0 | psInfo->numItems = 8 + psTxt->numVerticesLine + |
965 | 0 | ABS(psTxt->numVerticesArrow) + |
966 | 0 | ((psTxt->numChars - 1) / 80 + 1); |
967 | | |
968 | | /* And return the TX6 header line. |
969 | | */ |
970 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
971 | 0 | "%10d%10d%10d%10d%10d%10d%10d", psTxt->nUserId, psTxt->nLevel, |
972 | 0 | psTxt->numVerticesLine, psTxt->numVerticesArrow, |
973 | 0 | psTxt->nSymbol, psTxt->n28, psTxt->numChars); |
974 | 0 | } |
975 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6) |
976 | 0 | { |
977 | | /*------------------------------------------------------------- |
978 | | * Text Justification stuff... 2 sets of 20 int16 values. |
979 | | *------------------------------------------------------------*/ |
980 | 0 | GInt16 *pValue; |
981 | |
|
982 | 0 | if (psInfo->iCurItem == 0 || psInfo->iCurItem == 1) |
983 | 0 | { |
984 | 0 | pValue = psTxt->anJust2 + psInfo->iCurItem * 7; |
985 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
986 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
987 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
988 | 0 | } |
989 | 0 | else if (psInfo->iCurItem == 2) |
990 | 0 | { |
991 | 0 | pValue = psTxt->anJust2 + psInfo->iCurItem * 7; |
992 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
993 | 0 | "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
994 | 0 | pValue[2], pValue[3], pValue[4], pValue[5]); |
995 | 0 | } |
996 | 0 | else if (psInfo->iCurItem == 3) |
997 | 0 | { |
998 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
999 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1000 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1001 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
1002 | 0 | } |
1003 | 0 | else if (psInfo->iCurItem == 4) |
1004 | 0 | { |
1005 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1006 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1007 | 0 | "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1008 | 0 | pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]); |
1009 | 0 | } |
1010 | 0 | else |
1011 | 0 | { |
1012 | 0 | assert(psInfo->iCurItem == 5); |
1013 | 0 | pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7; |
1014 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1015 | 0 | "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1], |
1016 | 0 | pValue[2], pValue[3], pValue[4], pValue[5]); |
1017 | 0 | } |
1018 | | |
1019 | 0 | psInfo->iCurItem++; |
1020 | 0 | } |
1021 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6) |
1022 | 0 | { |
1023 | | /*------------------------------------------------------------- |
1024 | | * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!! |
1025 | | *------------------------------------------------------------*/ |
1026 | 0 | psInfo->pszBuf[0] = '\0'; |
1027 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC, |
1028 | 0 | AVCFileTX6, psTxt->f_1e2); |
1029 | 0 | psInfo->iCurItem++; |
1030 | 0 | } |
1031 | 0 | else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7) |
1032 | 0 | { |
1033 | | /*------------------------------------------------------------- |
1034 | | * Line with 3 values, 1st value is probably text height. |
1035 | | *------------------------------------------------------------*/ |
1036 | 0 | psInfo->pszBuf[0] = '\0'; |
1037 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1038 | 0 | AVCFileTX6, psTxt->dHeight); |
1039 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1040 | 0 | AVCFileTX6, psTxt->dV2); |
1041 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1042 | 0 | AVCFileTX6, psTxt->dV3); |
1043 | 0 | psInfo->iCurItem++; |
1044 | 0 | } |
1045 | 0 | else if (psInfo->iCurItem < |
1046 | 0 | psInfo->numItems - ((psTxt->numChars - 1) / 80 + 1)) |
1047 | 0 | { |
1048 | | /*------------------------------------------------------------- |
1049 | | * One line for each pair of X,Y coordinates |
1050 | | *------------------------------------------------------------*/ |
1051 | 0 | psInfo->pszBuf[0] = '\0'; |
1052 | |
|
1053 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1054 | 0 | AVCFileTX6, |
1055 | 0 | psTxt->pasVertices[psInfo->iCurItem - 8].x); |
1056 | 0 | AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision, |
1057 | 0 | AVCFileTX6, |
1058 | 0 | psTxt->pasVertices[psInfo->iCurItem - 8].y); |
1059 | |
|
1060 | 0 | psInfo->iCurItem++; |
1061 | 0 | } |
1062 | 0 | else if (psInfo->iCurItem < psInfo->numItems /* && |
1063 | 0 | psInfo->iCurItem >= psInfo->numItems-((psTxt->numChars-1)/80 + 1) */ ) |
1064 | 0 | { |
1065 | | /*------------------------------------------------------------- |
1066 | | * Last line, contains the text string |
1067 | | * Strings longer than 80 chars have to be in 80 chars chunks |
1068 | | *------------------------------------------------------------*/ |
1069 | 0 | int numLines, iLine; |
1070 | 0 | numLines = (psTxt->numChars - 1) / 80 + 1; |
1071 | 0 | iLine = numLines - (psInfo->numItems - psInfo->iCurItem); |
1072 | |
|
1073 | 0 | if ((int)strlen((char *)psTxt->pszText) > (iLine * 80)) |
1074 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s", |
1075 | 0 | psTxt->pszText + (iLine * 80)); |
1076 | 0 | else |
1077 | 0 | psInfo->pszBuf[0] = '\0'; |
1078 | |
|
1079 | 0 | psInfo->iCurItem++; |
1080 | 0 | } |
1081 | 0 | else |
1082 | 0 | { |
1083 | | /* No more lines to generate for this TX6. |
1084 | | */ |
1085 | 0 | return nullptr; |
1086 | 0 | } |
1087 | | |
1088 | 0 | return psInfo->pszBuf; |
1089 | 0 | } |
1090 | | |
1091 | | /*===================================================================== |
1092 | | RXP stuff |
1093 | | =====================================================================*/ |
1094 | | |
1095 | | /********************************************************************** |
1096 | | * AVCE00GenRxp() |
1097 | | * |
1098 | | * Generate the next line of an E00 RXP entry (RXPs are related to regions). |
1099 | | * |
1100 | | * This function should be called once with bCont=FALSE to get the |
1101 | | * first E00 line for the current RXP, and then call with bCont=TRUE |
1102 | | * to get all the other lines for this RXP. |
1103 | | * |
1104 | | * The function returns nullptr when there are no more lines to generate |
1105 | | * for this RXP entry. |
1106 | | **********************************************************************/ |
1107 | | const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont) |
1108 | 0 | { |
1109 | 0 | if (bCont == TRUE) |
1110 | 0 | { |
1111 | | /*--------------------------------------------------------- |
1112 | | * RXP entries are only 1 line, we support the bCont flag |
1113 | | * only for compatibility with the other AVCE00Gen*() functions. |
1114 | | *--------------------------------------------------------*/ |
1115 | 0 | return nullptr; |
1116 | 0 | } |
1117 | | |
1118 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psRxp->n1, |
1119 | 0 | psRxp->n2); |
1120 | |
|
1121 | 0 | return psInfo->pszBuf; |
1122 | 0 | } |
1123 | | |
1124 | | /*===================================================================== |
1125 | | TABLE stuff |
1126 | | =====================================================================*/ |
1127 | | |
1128 | | /********************************************************************** |
1129 | | * AVCE00GenTableHdr() |
1130 | | * |
1131 | | * Generate the next line of an E00 Table header. |
1132 | | * |
1133 | | * This function should be called once with bCont=FALSE to get the |
1134 | | * first E00 line for the current table header, and then call with |
1135 | | * bCont=TRUE to get all the other lines. |
1136 | | * |
1137 | | * The function returns nullptr when there are no more lines to generate. |
1138 | | **********************************************************************/ |
1139 | | const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef, |
1140 | | GBool bCont) |
1141 | 0 | { |
1142 | 0 | if (bCont == FALSE) |
1143 | 0 | { |
1144 | 0 | int nRecSize; |
1145 | | /* Initialize the psInfo structure with info about the |
1146 | | * current Table Header |
1147 | | */ |
1148 | 0 | psInfo->iCurItem = 0; |
1149 | 0 | psInfo->numItems = psDef->numFields; |
1150 | |
|
1151 | 0 | nRecSize = psDef->nRecSize; |
1152 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1153 | | { |
1154 | | /* Adjust Table record size if we're remapping type 40 fields */ |
1155 | | int i; |
1156 | | for (i = 0; i < psDef->numFields; i++) |
1157 | | { |
1158 | | if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM && |
1159 | | psDef->pasFieldDef[i].nSize > 8) |
1160 | | { |
1161 | | nRecSize -= psDef->pasFieldDef[i].nSize; |
1162 | | nRecSize += 8; |
1163 | | } |
1164 | | } |
1165 | | nRecSize = ((nRecSize + 1) / 2) * 2; |
1166 | | } |
1167 | | #endif |
1168 | | |
1169 | | /* And return the header's header line(!). |
1170 | | */ |
1171 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-32.32s%s%4d%4d%4d%10d", |
1172 | 0 | psDef->szTableName, psDef->szExternal, psDef->numFields, |
1173 | 0 | psDef->numFields, nRecSize, psDef->numRecords); |
1174 | 0 | } |
1175 | 0 | else if (psInfo->iCurItem < psInfo->numItems) |
1176 | 0 | { |
1177 | 0 | int nSize, nType, nOffset; |
1178 | |
|
1179 | 0 | nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize; |
1180 | 0 | nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10; |
1181 | 0 | nOffset = psDef->pasFieldDef[psInfo->iCurItem].nOffset; |
1182 | |
|
1183 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1184 | | /* Type 40 fields with more than 12 digits written to E00 by Arc/Info |
1185 | | * will lose some digits of precision (and we starts losing them at 8 |
1186 | | * with the way AVC lib writes type 40). This (optional) hack will |
1187 | | * remap type 40 fields with more than 8 digits to double precision |
1188 | | * floats which can carry up to 18 digits of precision. (bug 599) |
1189 | | */ |
1190 | | if (nType == AVC_FT_FIXNUM && nSize > 8) |
1191 | | { |
1192 | | /* Remap to double-precision float */ |
1193 | | nType = AVC_FT_BINFLOAT; |
1194 | | nSize = 8; |
1195 | | } |
1196 | | |
1197 | | /* Adjust field offset if this field is preceded by any type40 fields |
1198 | | * that were remapped. |
1199 | | */ |
1200 | | { |
1201 | | int i; |
1202 | | for (i = 0; i < psInfo->iCurItem; i++) |
1203 | | { |
1204 | | if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM && |
1205 | | psDef->pasFieldDef[i].nSize > 8) |
1206 | | { |
1207 | | nOffset -= psDef->pasFieldDef[i].nSize; |
1208 | | nOffset += 8; |
1209 | | } |
1210 | | } |
1211 | | } |
1212 | | #endif |
1213 | | /* Return next Field definition line |
1214 | | */ |
1215 | 0 | snprintf(psInfo->pszBuf, psInfo->nBufSize, |
1216 | 0 | "%-16.16s%3d%2d%4d%1d%2d%4d%2d%3d%2d%4d%4d%2d%-16.16s%4d-", |
1217 | 0 | psDef->pasFieldDef[psInfo->iCurItem].szName, nSize, |
1218 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v2, nOffset, |
1219 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v4, |
1220 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v5, |
1221 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nFmtWidth, |
1222 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nFmtPrec, nType, |
1223 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v10, |
1224 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v11, |
1225 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v12, |
1226 | 0 | psDef->pasFieldDef[psInfo->iCurItem].v13, |
1227 | 0 | psDef->pasFieldDef[psInfo->iCurItem].szAltName, |
1228 | 0 | psDef->pasFieldDef[psInfo->iCurItem].nIndex); |
1229 | |
|
1230 | 0 | psInfo->iCurItem++; |
1231 | 0 | } |
1232 | 0 | else |
1233 | 0 | { |
1234 | | /* No more lines to generate. |
1235 | | */ |
1236 | 0 | return nullptr; |
1237 | 0 | } |
1238 | | |
1239 | 0 | return psInfo->pszBuf; |
1240 | 0 | } |
1241 | | |
1242 | | /********************************************************************** |
1243 | | * AVCE00GenTableRec() |
1244 | | * |
1245 | | * Generate the next line of an E00 Table Data Record. |
1246 | | * |
1247 | | * This function should be called once with bCont=FALSE to get the |
1248 | | * first E00 line for the current table record, and then call with |
1249 | | * bCont=TRUE to get all the other lines. |
1250 | | * |
1251 | | * The function returns nullptr when there are no more lines to generate. |
1252 | | **********************************************************************/ |
1253 | | const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields, |
1254 | | AVCFieldInfo *pasDef, AVCField *pasFields, |
1255 | | GBool bCont) |
1256 | 0 | { |
1257 | 0 | int i, nSize, nType, nLen; |
1258 | 0 | char *pszBuf2; |
1259 | |
|
1260 | 0 | if (bCont == FALSE) |
1261 | 0 | { |
1262 | | /*------------------------------------------------------------- |
1263 | | * Initialize the psInfo structure to be ready to process this |
1264 | | * new Table Record |
1265 | | *------------------------------------------------------------*/ |
1266 | 0 | psInfo->iCurItem = 0; |
1267 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1268 | | psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE); |
1269 | | #else |
1270 | 0 | psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, FALSE); |
1271 | 0 | #endif |
1272 | | |
1273 | | /*------------------------------------------------------------- |
1274 | | * First, we need to make sure that the output buffer is big |
1275 | | * enough to hold the whole record, plus 81 chars to hold |
1276 | | * the line that we'll return to the caller. |
1277 | | *------------------------------------------------------------*/ |
1278 | 0 | nSize = psInfo->numItems + 1 + 81; |
1279 | |
|
1280 | 0 | if (psInfo->nBufSize < nSize) |
1281 | 0 | { |
1282 | 0 | psInfo->pszBuf = |
1283 | 0 | (char *)CPLRealloc(psInfo->pszBuf, nSize * sizeof(char)); |
1284 | 0 | psInfo->nBufSize = nSize; |
1285 | 0 | } |
1286 | | |
1287 | | /*------------------------------------------------------------- |
1288 | | * Generate the whole record now, and we'll return it to the |
1289 | | * caller by chunks of 80 chars. |
1290 | | * The first 80 chars of the buffer will be used to return |
1291 | | * one line at a time, and the rest of the buffer is used to |
1292 | | * hold the whole record. |
1293 | | *------------------------------------------------------------*/ |
1294 | 0 | pszBuf2 = psInfo->pszBuf + 81; |
1295 | |
|
1296 | 0 | for (i = 0; i < numFields; i++) |
1297 | 0 | { |
1298 | 0 | nType = pasDef[i].nType1 * 10; |
1299 | 0 | nSize = pasDef[i].nSize; |
1300 | |
|
1301 | 0 | if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR || |
1302 | 0 | nType == AVC_FT_FIXINT) |
1303 | 0 | { |
1304 | 0 | memcpy(pszBuf2, pasFields[i].pszStr, nSize * sizeof(char)); |
1305 | 0 | pszBuf2 += nSize; |
1306 | 0 | } |
1307 | | #ifdef AVC_MAP_TYPE40_TO_DOUBLE |
1308 | | /* See explanation in AVCE00GenTableHdr() about this hack to remap |
1309 | | * type 40 fields to double precision floats. |
1310 | | */ |
1311 | | else if (nType == AVC_FT_FIXNUM && nSize > 8) |
1312 | | { |
1313 | | pszBuf2[0] = '\0'; |
1314 | | /* NOTE: The E00 representation for a binary float is |
1315 | | * defined by its binary size, not by the coverage's |
1316 | | * precision. |
1317 | | */ |
1318 | | nLen = AVCPrintRealValue( |
1319 | | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1320 | | AVC_DOUBLE_PREC, AVCFileTABLE, |
1321 | | CPLAtof((char *)pasFields[i].pszStr)); |
1322 | | pszBuf2 += nLen; |
1323 | | } |
1324 | | #endif |
1325 | 0 | else if (nType == AVC_FT_FIXNUM) |
1326 | 0 | { |
1327 | | /* TYPE 40 attributes are stored with 1 byte per digit |
1328 | | * in binary format, and as single precision floats in |
1329 | | * E00 tables, even in double precision coverages. |
1330 | | */ |
1331 | 0 | pszBuf2[0] = '\0'; |
1332 | 0 | nLen = AVCPrintRealValue( |
1333 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1334 | 0 | AVC_SINGLE_PREC, AVCFileTABLE, |
1335 | 0 | CPLAtof((char *)pasFields[i].pszStr)); |
1336 | 0 | pszBuf2 += nLen; |
1337 | 0 | } |
1338 | 0 | else if (nType == AVC_FT_BININT && nSize == 4) |
1339 | 0 | { |
1340 | 0 | snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1341 | 0 | "%11d", pasFields[i].nInt32); |
1342 | 0 | pszBuf2 += 11; |
1343 | 0 | } |
1344 | 0 | else if (nType == AVC_FT_BININT && nSize == 2) |
1345 | 0 | { |
1346 | 0 | snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1347 | 0 | "%6d", pasFields[i].nInt16); |
1348 | 0 | pszBuf2 += 6; |
1349 | 0 | } |
1350 | 0 | else if (nType == AVC_FT_BINFLOAT && nSize == 4) |
1351 | 0 | { |
1352 | 0 | pszBuf2[0] = '\0'; |
1353 | | /* NOTE: The E00 representation for a binary float is |
1354 | | * defined by its binary size, not by the coverage's |
1355 | | * precision. |
1356 | | */ |
1357 | 0 | nLen = AVCPrintRealValue( |
1358 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1359 | 0 | AVC_SINGLE_PREC, AVCFileTABLE, pasFields[i].fFloat); |
1360 | 0 | pszBuf2 += nLen; |
1361 | 0 | } |
1362 | 0 | else if (nType == AVC_FT_BINFLOAT && nSize == 8) |
1363 | 0 | { |
1364 | 0 | pszBuf2[0] = '\0'; |
1365 | | /* NOTE: The E00 representation for a binary float is |
1366 | | * defined by its binary size, not by the coverage's |
1367 | | * precision. |
1368 | | */ |
1369 | 0 | nLen = AVCPrintRealValue( |
1370 | 0 | pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf), |
1371 | 0 | AVC_DOUBLE_PREC, AVCFileTABLE, pasFields[i].dDouble); |
1372 | 0 | pszBuf2 += nLen; |
1373 | 0 | } |
1374 | 0 | else |
1375 | 0 | { |
1376 | | /*----------------------------------------------------- |
1377 | | * Hummm... unsupported field type... |
1378 | | *----------------------------------------------------*/ |
1379 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1380 | 0 | "Unsupported field type: (type=%d, size=%d)", nType, |
1381 | 0 | nSize); |
1382 | 0 | return nullptr; |
1383 | 0 | } |
1384 | 0 | } |
1385 | | |
1386 | 0 | *pszBuf2 = '\0'; |
1387 | | |
1388 | | /* Make sure that we remove any embedded NUL characters from the |
1389 | | * data line before returning it, otherwise we may be accidentally |
1390 | | * truncating results. |
1391 | | */ |
1392 | 0 | while (--pszBuf2 >= psInfo->pszBuf + 81) |
1393 | 0 | { |
1394 | 0 | if (*pszBuf2 == '\0') |
1395 | 0 | { |
1396 | 0 | *pszBuf2 = ' '; |
1397 | 0 | } |
1398 | 0 | } |
1399 | 0 | } |
1400 | | |
1401 | 0 | if (psInfo->iCurItem < psInfo->numItems) |
1402 | 0 | { |
1403 | | /*------------------------------------------------------------- |
1404 | | * Return the next 80 chars chunk. |
1405 | | * The first 80 chars of the buffer is used to return |
1406 | | * one line at a time, and the rest of the buffer (chars 81+) |
1407 | | * is used to hold the whole record. |
1408 | | *------------------------------------------------------------*/ |
1409 | 0 | nLen = psInfo->numItems - psInfo->iCurItem; |
1410 | |
|
1411 | 0 | if (nLen > 80) |
1412 | 0 | nLen = 80; |
1413 | |
|
1414 | 0 | strncpy(psInfo->pszBuf, psInfo->pszBuf + (81 + psInfo->iCurItem), nLen); |
1415 | 0 | psInfo->pszBuf[nLen] = '\0'; |
1416 | |
|
1417 | 0 | psInfo->iCurItem += nLen; |
1418 | | |
1419 | | /*------------------------------------------------------------- |
1420 | | * Arc/Info removes spaces at the end of the lines... let's |
1421 | | * remove them as well since it can reduce the E00 file size. |
1422 | | *------------------------------------------------------------*/ |
1423 | 0 | nLen--; |
1424 | 0 | while (nLen >= 0 && psInfo->pszBuf[nLen] == ' ') |
1425 | 0 | { |
1426 | 0 | psInfo->pszBuf[nLen] = '\0'; |
1427 | 0 | nLen--; |
1428 | 0 | } |
1429 | 0 | } |
1430 | 0 | else |
1431 | 0 | { |
1432 | | /* No more lines to generate. |
1433 | | */ |
1434 | 0 | return nullptr; |
1435 | 0 | } |
1436 | | |
1437 | 0 | return psInfo->pszBuf; |
1438 | 0 | } |