Line data Source code
1 : /**********************************************************************
2 : * $Id$
3 : *
4 : * Name: avc_e00gen.c
5 : * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library
6 : * Language: ANSI C
7 : * Purpose: Functions to generate ASCII E00 lines form binary structures.
8 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999-2005, Daniel Morissette
12 : *
13 : * SPDX-License-Identifier: MIT
14 : **********************************************************************
15 : *
16 : * $Log: avc_e00gen.c,v $
17 : * Revision 1.18 2008/07/23 20:51:38 dmorissette
18 : * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
19 : * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
20 : *
21 : * Revision 1.17 2006/06/14 15:01:33 daniel
22 : * Remove any embedded '\0' from data line in AVCE00GenTableRec()
23 : *
24 : * Revision 1.16 2005/06/03 03:49:58 daniel
25 : * Update email address, website url, and copyright dates
26 : *
27 : * Revision 1.15 2004/08/19 17:48:20 warmerda
28 : * Avoid uninitialized variable warnings.
29 : *
30 : * Revision 1.14 2001/11/25 21:15:23 daniel
31 : * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
32 : * digits to double precision as we generate E00 output (bug599)
33 : *
34 : * Revision 1.13 2001/11/19 20:39:48 daniel
35 : * Change to correctly format 0-arc PAL records, so that they have a
36 : * single "filler" arc record
37 : *
38 : * Revision 1.12 2000/09/26 20:21:04 daniel
39 : * Added AVCCoverPC write
40 : *
41 : * Revision 1.11 2000/09/22 19:45:20 daniel
42 : * Switch to MIT-style license
43 : *
44 : * Revision 1.10 2000/02/04 04:54:03 daniel
45 : * Fixed warnings
46 : *
47 : * Revision 1.9 2000/02/03 07:21:02 daniel
48 : * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks
49 : *
50 : * Revision 1.8 2000/02/02 04:28:00 daniel
51 : * Fixed support of TX6/RXP/RPL coming from "weird" coverages
52 : *
53 : * Revision 1.7 1999/08/23 18:20:49 daniel
54 : * Fixed support for attribute fields type 40
55 : *
56 : * Revision 1.6 1999/05/17 16:19:39 daniel
57 : * Made sure ACVE00GenTableRec() removes all spaces at the end of a
58 : * table record line (it used to leave one space)
59 : *
60 : * Revision 1.5 1999/05/11 02:08:17 daniel
61 : * Simple changes related to the addition of coverage write support.
62 : *
63 : * Revision 1.4 1999/03/03 02:06:38 daniel
64 : * Properly handle 8 bytes floats inside single precision tables.
65 : *
66 : * Revision 1.3 1999/02/25 17:01:58 daniel
67 : * Added support for 16 bit integers in INFO tables (type=50, size=2)
68 : *
69 : * Revision 1.2 1999/02/25 04:17:51 daniel
70 : * Added TXT, TX6/TX7, RXP and RPL support + some minor changes
71 : *
72 : * Revision 1.1 1999/01/29 16:28:52 daniel
73 : * Initial revision
74 : *
75 : **********************************************************************/
76 :
77 : #include "avc.h"
78 :
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 3 : AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision)
89 : {
90 : AVCE00GenInfo *psInfo;
91 :
92 3 : 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 3 : psInfo->nBufSize = 2048;
99 3 : psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize * sizeof(char));
100 :
101 3 : psInfo->nPrecision = nCoverPrecision;
102 :
103 3 : return psInfo;
104 : }
105 :
106 : /**********************************************************************
107 : * AVCE00GenInfoFree()
108 : *
109 : * Free any memory associated with a AVCE00GenInfo structure.
110 : **********************************************************************/
111 3 : void AVCE00GenInfoFree(AVCE00GenInfo *psInfo)
112 : {
113 3 : if (psInfo)
114 3 : CPLFree(psInfo->pszBuf);
115 3 : CPLFree(psInfo);
116 3 : }
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 0 : void AVCE00GenReset(AVCE00GenInfo *psInfo)
125 : {
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 0 : const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType,
140 : const char *pszClassName)
141 : {
142 0 : const char *pszName = "UNK";
143 :
144 0 : AVCE00GenReset(psInfo);
145 :
146 0 : if (eType == AVCFileTX6 || eType == AVCFileRXP || eType == AVCFileRPL)
147 : {
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 : int i;
153 0 : for (i = 0; pszClassName[i] != '\0'; i++)
154 : {
155 0 : psInfo->pszBuf[i] =
156 0 : (char)CPLToupper(static_cast<unsigned char>(pszClassName[i]));
157 : }
158 0 : psInfo->pszBuf[i] = '\0';
159 : }
160 : else
161 : {
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 : {
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 : "Unsupported E00 section type!");
191 : }
192 :
193 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
194 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 3", pszName);
195 : else
196 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%s 2", pszName);
197 : }
198 :
199 0 : return psInfo->pszBuf;
200 : }
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 0 : const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType,
215 : GBool bCont)
216 : {
217 0 : if (bCont == FALSE)
218 : {
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 : eType == AVCFileTX6)
228 : {
229 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
230 : " -1 0 0 0 0 "
231 : " 0 0");
232 : }
233 0 : else if (eType == AVCFileLAB)
234 : {
235 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
236 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
237 : " -1 0 0.00000000000000E+00 "
238 : "0.00000000000000E+00");
239 : else
240 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
241 : " -1 0 0.0000000E+00 0.0000000E+00");
242 : }
243 0 : else if (eType == AVCFilePRJ)
244 : {
245 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "EOP");
246 : }
247 0 : else if (eType == AVCFileRXP)
248 : {
249 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, " -1 0");
250 : }
251 : else
252 : {
253 0 : CPLError(CE_Failure, CPLE_NotSupported,
254 : "Unsupported E00 section type!");
255 0 : return nullptr;
256 : }
257 : }
258 0 : else if (psInfo->iCurItem == 0 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
259 0 : (eType == AVCFilePAL || eType == AVCFileRPL))
260 : {
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.00000000000000E+00 0.00000000000000E+00");
266 :
267 0 : psInfo->iCurItem++;
268 : }
269 : else
270 : {
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 : }
277 :
278 0 : return psInfo->pszBuf;
279 : }
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 0 : const char *AVCE00GenObject(AVCE00GenInfo *psInfo, AVCFileType eType,
295 : void *psObj, GBool bCont)
296 : {
297 0 : const char *pszLine = nullptr;
298 :
299 0 : switch (eType)
300 : {
301 0 : case AVCFileARC:
302 0 : pszLine = AVCE00GenArc(psInfo, (AVCArc *)psObj, bCont);
303 0 : break;
304 0 : case AVCFilePAL:
305 : 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 : "AVCE00GenObject(): Unsupported file type!");
332 : }
333 :
334 0 : return pszLine;
335 : }
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 0 : const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont)
354 : {
355 0 : if (bCont == FALSE)
356 : {
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 : 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 : "%10d%10d%10d%10d%10d%10d%10d", psArc->nArcId, psArc->nUserId,
370 : psArc->nFNode, psArc->nTNode, psArc->nLPoly, psArc->nRPoly,
371 : psArc->numVertices);
372 : }
373 0 : else if (psInfo->iCurItem < psInfo->numItems)
374 : {
375 : int iVertex;
376 :
377 : /* return the next set of vertices for the ARC.
378 : */
379 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
380 : {
381 0 : iVertex = psInfo->iCurItem;
382 :
383 0 : psInfo->pszBuf[0] = '\0';
384 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
385 : psInfo->nPrecision, AVCFileARC,
386 0 : psArc->pasVertices[iVertex].x);
387 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
388 : psInfo->nPrecision, AVCFileARC,
389 0 : psArc->pasVertices[iVertex].y);
390 : }
391 : else
392 : {
393 0 : iVertex = psInfo->iCurItem * 2;
394 :
395 0 : psInfo->pszBuf[0] = '\0';
396 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
397 : psInfo->nPrecision, AVCFileARC,
398 0 : psArc->pasVertices[iVertex].x);
399 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
400 : 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 : {
408 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
409 : psInfo->nPrecision, AVCFileARC,
410 0 : psArc->pasVertices[iVertex + 1].x);
411 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
412 : psInfo->nPrecision, AVCFileARC,
413 0 : psArc->pasVertices[iVertex + 1].y);
414 : }
415 : }
416 0 : psInfo->iCurItem++;
417 : }
418 : else
419 : {
420 : /* No more lines to generate for this ARC.
421 : */
422 0 : return nullptr;
423 : }
424 :
425 0 : return psInfo->pszBuf;
426 : }
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 0 : const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont)
445 : {
446 0 : if (bCont == FALSE)
447 : {
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 : AVCFilePAL, psPal->sMin.x);
459 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
460 : 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 : {
466 0 : psInfo->iCurItem = -1; /* Means 1 line left in header */
467 : }
468 : else
469 : {
470 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
471 : psInfo->nPrecision, AVCFilePAL, psPal->sMax.x);
472 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
473 : psInfo->nPrecision, AVCFilePAL, psPal->sMax.y);
474 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
475 : }
476 : }
477 0 : else if (psInfo->iCurItem == -1)
478 : {
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 : AVCFilePAL, psPal->sMax.x);
484 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
485 : AVCFilePAL, psPal->sMax.y);
486 :
487 0 : if (psInfo->numItems == 0)
488 : {
489 0 : psInfo->iCurItem = -2; /* We have a 0-arc polygon, which needs
490 : an arc list with one "0 0 0" element */
491 : }
492 : else
493 : {
494 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
495 : }
496 : }
497 0 : else if (psInfo->iCurItem == -2)
498 : {
499 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d%10d", 0, 0, 0);
500 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
501 : }
502 0 : else if (psInfo->iCurItem < psInfo->numItems)
503 : {
504 : /* Return PAL Arc entries...
505 : */
506 : 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 : {
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 : }
522 : else
523 : {
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 : }
528 0 : psInfo->iCurItem++;
529 : }
530 : else
531 : {
532 : /* No more lines to generate for this PAL.
533 : */
534 0 : return nullptr;
535 : }
536 :
537 0 : return psInfo->pszBuf;
538 : }
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 0 : const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont)
557 : {
558 0 : if (bCont == FALSE)
559 : {
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 : AVCFileCNT, psCnt->sCoord.x);
572 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
573 : AVCFileCNT, psCnt->sCoord.y);
574 : }
575 0 : else if (psInfo->iCurItem < psInfo->numItems)
576 : {
577 : /* Return CNT Label Ids, 8 label Ids per line...
578 : */
579 : 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 : {
587 0 : snprintf(psInfo->pszBuf + strlen(psInfo->pszBuf),
588 0 : psInfo->nBufSize - strlen(psInfo->pszBuf), "%10d",
589 0 : psCnt->panLabelIds[nFirstLabel + i]);
590 : }
591 :
592 0 : psInfo->iCurItem++;
593 : }
594 : else
595 : {
596 : /* No more lines to generate for this CNT.
597 : */
598 0 : return nullptr;
599 : }
600 :
601 0 : return psInfo->pszBuf;
602 : }
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 0 : const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont)
621 : {
622 0 : if (bCont == FALSE)
623 : {
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 : 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 : psLab->nPolyId);
637 :
638 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
639 : AVCFileLAB, psLab->sCoord1.x);
640 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
641 : AVCFileLAB, psLab->sCoord1.y);
642 : }
643 0 : else if (psInfo->iCurItem < psInfo->numItems)
644 : {
645 : /* Return next Label coordinates...
646 : */
647 0 : if (psInfo->nPrecision != AVC_DOUBLE_PREC)
648 : {
649 : /* Single precision, all on the same line
650 : */
651 0 : psInfo->pszBuf[0] = '\0';
652 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
653 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x);
654 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
655 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y);
656 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
657 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x);
658 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
659 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y);
660 : }
661 0 : else if (psInfo->iCurItem == 0)
662 : {
663 : /* 2nd line, in a double precision coverage
664 : */
665 0 : psInfo->pszBuf[0] = '\0';
666 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
667 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.x);
668 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
669 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord2.y);
670 : }
671 : else
672 : {
673 : /* 3rd line, in a double precision coverage
674 : */
675 0 : psInfo->pszBuf[0] = '\0';
676 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
677 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.x);
678 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
679 : psInfo->nPrecision, AVCFileLAB, psLab->sCoord3.y);
680 : }
681 :
682 0 : psInfo->iCurItem++;
683 : }
684 : else
685 : {
686 : /* No more lines to generate for this LAB.
687 : */
688 0 : return nullptr;
689 : }
690 :
691 0 : return psInfo->pszBuf;
692 : }
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 0 : const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont)
711 : {
712 0 : if (bCont == TRUE)
713 : {
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 : }
720 :
721 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psTol->nIndex,
722 : psTol->nFlag);
723 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
724 : AVCFileTOL, psTol->dValue);
725 :
726 0 : return psInfo->pszBuf;
727 : }
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 0 : const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont)
746 : {
747 0 : if (bCont == FALSE)
748 : {
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 : }
756 :
757 0 : if (psInfo->iCurItem < psInfo->numItems)
758 : {
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 : {
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 : }
774 : else
775 : {
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 : }
782 :
783 0 : psInfo->iCurItem++;
784 : }
785 : else
786 : {
787 : /* No more lines to generate for this PRJ.
788 : */
789 0 : return nullptr;
790 : }
791 :
792 0 : return psInfo->pszBuf;
793 : }
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 0 : const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
812 : {
813 : 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 : else
821 0 : numFixedLines = 6;
822 :
823 0 : if (bCont == FALSE)
824 : {
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 : psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars);
837 : }
838 0 : else if (psInfo->iCurItem < psInfo->numItems &&
839 0 : psInfo->iCurItem < numFixedLines - 1)
840 : {
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 : 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 : {
857 0 : dXY[i] = psTxt->pasVertices[i + 1].x;
858 0 : dXY[i + 4] = psTxt->pasVertices[i + 1].y;
859 : }
860 0 : for (i = 0; i < 3 && i < ABS(psTxt->numVerticesArrow); i++)
861 : {
862 0 : dXY[i + 8] = psTxt->pasVertices[i + psTxt->numVerticesLine].x;
863 0 : dXY[i + 11] = psTxt->pasVertices[i + psTxt->numVerticesLine].y;
864 : }
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 : {
872 : /* Single precision
873 : */
874 0 : numValuesPerLine = 5;
875 : }
876 : else
877 : {
878 : /* Double precision
879 : */
880 0 : numValuesPerLine = 3;
881 : }
882 :
883 0 : nFirstValue = psInfo->iCurItem * numValuesPerLine;
884 0 : psInfo->pszBuf[0] = '\0';
885 0 : for (i = 0; i < numValuesPerLine; i++)
886 : {
887 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize,
888 : psInfo->nPrecision, AVCFileTXT,
889 0 : dXY[nFirstValue + i]);
890 : }
891 :
892 0 : psInfo->iCurItem++;
893 : }
894 0 : else if (psInfo->iCurItem < psInfo->numItems &&
895 0 : psInfo->iCurItem == numFixedLines - 1)
896 : {
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 : }
905 0 : else if (psInfo->iCurItem < psInfo->numItems &&
906 0 : psInfo->iCurItem >= numFixedLines)
907 : {
908 : /*-------------------------------------------------------------
909 : * Last line, contains the text string
910 : * Strings longer than 80 chars have to be in 80 chars chunks
911 : *------------------------------------------------------------*/
912 : 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 : else
920 0 : psInfo->pszBuf[0] = '\0';
921 :
922 0 : psInfo->iCurItem++;
923 : }
924 : else
925 : {
926 : /* No more lines to generate for this TXT.
927 : */
928 0 : return nullptr;
929 : }
930 :
931 0 : return psInfo->pszBuf;
932 : }
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 0 : const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
956 : {
957 0 : if (bCont == FALSE)
958 : {
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 : "%10d%10d%10d%10d%10d%10d%10d", psTxt->nUserId, psTxt->nLevel,
972 : psTxt->numVerticesLine, psTxt->numVerticesArrow,
973 : psTxt->nSymbol, psTxt->n28, psTxt->numChars);
974 : }
975 0 : else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem < 6)
976 : {
977 : /*-------------------------------------------------------------
978 : * Text Justification stuff... 2 sets of 20 int16 values.
979 : *------------------------------------------------------------*/
980 : GInt16 *pValue;
981 :
982 0 : if (psInfo->iCurItem < 3)
983 0 : pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
984 : else
985 0 : pValue = psTxt->anJust1 + (psInfo->iCurItem - 3) * 7;
986 :
987 0 : if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5)
988 : {
989 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
990 0 : "%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
991 0 : pValue[2], pValue[3], pValue[4], pValue[5]);
992 : }
993 : else
994 : {
995 : /* coverity[overrun-local] */
996 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
997 0 : "%10d%10d%10d%10d%10d%10d%10d", pValue[0], pValue[1],
998 0 : pValue[2], pValue[3], pValue[4], pValue[5], pValue[6]);
999 : }
1000 :
1001 0 : psInfo->iCurItem++;
1002 : }
1003 0 : else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 6)
1004 : {
1005 : /*-------------------------------------------------------------
1006 : * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
1007 : *------------------------------------------------------------*/
1008 0 : psInfo->pszBuf[0] = '\0';
1009 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, AVC_SINGLE_PREC,
1010 0 : AVCFileTX6, psTxt->f_1e2);
1011 0 : psInfo->iCurItem++;
1012 : }
1013 0 : else if (psInfo->iCurItem < psInfo->numItems && psInfo->iCurItem == 7)
1014 : {
1015 : /*-------------------------------------------------------------
1016 : * Line with 3 values, 1st value is probably text height.
1017 : *------------------------------------------------------------*/
1018 0 : psInfo->pszBuf[0] = '\0';
1019 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
1020 : AVCFileTX6, psTxt->dHeight);
1021 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
1022 : AVCFileTX6, psTxt->dV2);
1023 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
1024 : AVCFileTX6, psTxt->dV3);
1025 0 : psInfo->iCurItem++;
1026 : }
1027 0 : else if (psInfo->iCurItem <
1028 0 : psInfo->numItems - ((psTxt->numChars - 1) / 80 + 1))
1029 : {
1030 : /*-------------------------------------------------------------
1031 : * One line for each pair of X,Y coordinates
1032 : *------------------------------------------------------------*/
1033 0 : psInfo->pszBuf[0] = '\0';
1034 :
1035 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
1036 : AVCFileTX6,
1037 0 : psTxt->pasVertices[psInfo->iCurItem - 8].x);
1038 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nBufSize, psInfo->nPrecision,
1039 : AVCFileTX6,
1040 0 : psTxt->pasVertices[psInfo->iCurItem - 8].y);
1041 :
1042 0 : psInfo->iCurItem++;
1043 : }
1044 0 : else if (psInfo->iCurItem < psInfo->numItems /* &&
1045 : psInfo->iCurItem >= psInfo->numItems-((psTxt->numChars-1)/80 + 1) */ )
1046 : {
1047 : /*-------------------------------------------------------------
1048 : * Last line, contains the text string
1049 : * Strings longer than 80 chars have to be in 80 chars chunks
1050 : *------------------------------------------------------------*/
1051 : int numLines, iLine;
1052 0 : numLines = (psTxt->numChars - 1) / 80 + 1;
1053 0 : iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1054 :
1055 0 : if ((int)strlen((char *)psTxt->pszText) > (iLine * 80))
1056 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-.80s",
1057 0 : psTxt->pszText + (iLine * 80));
1058 : else
1059 0 : psInfo->pszBuf[0] = '\0';
1060 :
1061 0 : psInfo->iCurItem++;
1062 : }
1063 : else
1064 : {
1065 : /* No more lines to generate for this TX6.
1066 : */
1067 0 : return nullptr;
1068 : }
1069 :
1070 0 : return psInfo->pszBuf;
1071 : }
1072 :
1073 : /*=====================================================================
1074 : RXP stuff
1075 : =====================================================================*/
1076 :
1077 : /**********************************************************************
1078 : * AVCE00GenRxp()
1079 : *
1080 : * Generate the next line of an E00 RXP entry (RXPs are related to regions).
1081 : *
1082 : * This function should be called once with bCont=FALSE to get the
1083 : * first E00 line for the current RXP, and then call with bCont=TRUE
1084 : * to get all the other lines for this RXP.
1085 : *
1086 : * The function returns nullptr when there are no more lines to generate
1087 : * for this RXP entry.
1088 : **********************************************************************/
1089 0 : const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont)
1090 : {
1091 0 : if (bCont == TRUE)
1092 : {
1093 : /*---------------------------------------------------------
1094 : * RXP entries are only 1 line, we support the bCont flag
1095 : * only for compatibility with the other AVCE00Gen*() functions.
1096 : *--------------------------------------------------------*/
1097 0 : return nullptr;
1098 : }
1099 :
1100 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%10d%10d", psRxp->n1,
1101 : psRxp->n2);
1102 :
1103 0 : return psInfo->pszBuf;
1104 : }
1105 :
1106 : /*=====================================================================
1107 : TABLE stuff
1108 : =====================================================================*/
1109 :
1110 : /**********************************************************************
1111 : * AVCE00GenTableHdr()
1112 : *
1113 : * Generate the next line of an E00 Table header.
1114 : *
1115 : * This function should be called once with bCont=FALSE to get the
1116 : * first E00 line for the current table header, and then call with
1117 : * bCont=TRUE to get all the other lines.
1118 : *
1119 : * The function returns nullptr when there are no more lines to generate.
1120 : **********************************************************************/
1121 0 : const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef,
1122 : GBool bCont)
1123 : {
1124 0 : if (bCont == FALSE)
1125 : {
1126 : int nRecSize;
1127 : /* Initialize the psInfo structure with info about the
1128 : * current Table Header
1129 : */
1130 0 : psInfo->iCurItem = 0;
1131 0 : psInfo->numItems = psDef->numFields;
1132 :
1133 0 : nRecSize = psDef->nRecSize;
1134 : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
1135 : {
1136 : /* Adjust Table record size if we're remapping type 40 fields */
1137 : int i;
1138 : for (i = 0; i < psDef->numFields; i++)
1139 : {
1140 : if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM &&
1141 : psDef->pasFieldDef[i].nSize > 8)
1142 : {
1143 : nRecSize -= psDef->pasFieldDef[i].nSize;
1144 : nRecSize += 8;
1145 : }
1146 : }
1147 : nRecSize = ((nRecSize + 1) / 2) * 2;
1148 : }
1149 : #endif
1150 :
1151 : /* And return the header's header line(!).
1152 : */
1153 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize, "%-32.32s%s%4d%4d%4d%10d",
1154 0 : psDef->szTableName, psDef->szExternal, psDef->numFields,
1155 0 : psDef->numFields, nRecSize, psDef->numRecords);
1156 : }
1157 0 : else if (psInfo->iCurItem < psInfo->numItems)
1158 : {
1159 : int nSize, nType, nOffset;
1160 :
1161 0 : nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize;
1162 0 : nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10;
1163 0 : nOffset = psDef->pasFieldDef[psInfo->iCurItem].nOffset;
1164 :
1165 : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
1166 : /* Type 40 fields with more than 12 digits written to E00 by Arc/Info
1167 : * will lose some digits of precision (and we starts losing them at 8
1168 : * with the way AVC lib writes type 40). This (optional) hack will
1169 : * remap type 40 fields with more than 8 digits to double precision
1170 : * floats which can carry up to 18 digits of precision. (bug 599)
1171 : */
1172 : if (nType == AVC_FT_FIXNUM && nSize > 8)
1173 : {
1174 : /* Remap to double-precision float */
1175 : nType = AVC_FT_BINFLOAT;
1176 : nSize = 8;
1177 : }
1178 :
1179 : /* Adjust field offset if this field is preceded by any type40 fields
1180 : * that were remapped.
1181 : */
1182 : {
1183 : int i;
1184 : for (i = 0; i < psInfo->iCurItem; i++)
1185 : {
1186 : if (psDef->pasFieldDef[i].nType1 * 10 == AVC_FT_FIXNUM &&
1187 : psDef->pasFieldDef[i].nSize > 8)
1188 : {
1189 : nOffset -= psDef->pasFieldDef[i].nSize;
1190 : nOffset += 8;
1191 : }
1192 : }
1193 : }
1194 : #endif
1195 : /* Return next Field definition line
1196 : */
1197 0 : snprintf(psInfo->pszBuf, psInfo->nBufSize,
1198 : "%-16.16s%3d%2d%4d%1d%2d%4d%2d%3d%2d%4d%4d%2d%-16.16s%4d-",
1199 0 : psDef->pasFieldDef[psInfo->iCurItem].szName, nSize,
1200 0 : psDef->pasFieldDef[psInfo->iCurItem].v2, nOffset,
1201 0 : psDef->pasFieldDef[psInfo->iCurItem].v4,
1202 0 : psDef->pasFieldDef[psInfo->iCurItem].v5,
1203 0 : psDef->pasFieldDef[psInfo->iCurItem].nFmtWidth,
1204 0 : psDef->pasFieldDef[psInfo->iCurItem].nFmtPrec, nType,
1205 0 : psDef->pasFieldDef[psInfo->iCurItem].v10,
1206 0 : psDef->pasFieldDef[psInfo->iCurItem].v11,
1207 0 : psDef->pasFieldDef[psInfo->iCurItem].v12,
1208 0 : psDef->pasFieldDef[psInfo->iCurItem].v13,
1209 0 : psDef->pasFieldDef[psInfo->iCurItem].szAltName,
1210 0 : psDef->pasFieldDef[psInfo->iCurItem].nIndex);
1211 :
1212 0 : psInfo->iCurItem++;
1213 : }
1214 : else
1215 : {
1216 : /* No more lines to generate.
1217 : */
1218 0 : return nullptr;
1219 : }
1220 :
1221 0 : return psInfo->pszBuf;
1222 : }
1223 :
1224 : /**********************************************************************
1225 : * AVCE00GenTableRec()
1226 : *
1227 : * Generate the next line of an E00 Table Data Record.
1228 : *
1229 : * This function should be called once with bCont=FALSE to get the
1230 : * first E00 line for the current table record, and then call with
1231 : * bCont=TRUE to get all the other lines.
1232 : *
1233 : * The function returns nullptr when there are no more lines to generate.
1234 : **********************************************************************/
1235 0 : const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields,
1236 : AVCFieldInfo *pasDef, AVCField *pasFields,
1237 : GBool bCont)
1238 : {
1239 : int i, nSize, nType, nLen;
1240 : char *pszBuf2;
1241 :
1242 0 : if (bCont == FALSE)
1243 : {
1244 : /*-------------------------------------------------------------
1245 : * Initialize the psInfo structure to be ready to process this
1246 : * new Table Record
1247 : *------------------------------------------------------------*/
1248 0 : psInfo->iCurItem = 0;
1249 : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
1250 : psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE);
1251 : #else
1252 0 : psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, FALSE);
1253 : #endif
1254 :
1255 : /*-------------------------------------------------------------
1256 : * First, we need to make sure that the output buffer is big
1257 : * enough to hold the whole record, plus 81 chars to hold
1258 : * the line that we'll return to the caller.
1259 : *------------------------------------------------------------*/
1260 0 : nSize = psInfo->numItems + 1 + 81;
1261 :
1262 0 : if (psInfo->nBufSize < nSize)
1263 : {
1264 0 : psInfo->pszBuf =
1265 0 : (char *)CPLRealloc(psInfo->pszBuf, nSize * sizeof(char));
1266 0 : psInfo->nBufSize = nSize;
1267 : }
1268 :
1269 : /*-------------------------------------------------------------
1270 : * Generate the whole record now, and we'll return it to the
1271 : * caller by chunks of 80 chars.
1272 : * The first 80 chars of the buffer will be used to return
1273 : * one line at a time, and the rest of the buffer is used to
1274 : * hold the whole record.
1275 : *------------------------------------------------------------*/
1276 0 : pszBuf2 = psInfo->pszBuf + 81;
1277 :
1278 0 : for (i = 0; i < numFields; i++)
1279 : {
1280 0 : nType = pasDef[i].nType1 * 10;
1281 0 : nSize = pasDef[i].nSize;
1282 :
1283 0 : if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
1284 : nType == AVC_FT_FIXINT)
1285 : {
1286 0 : memcpy(pszBuf2, pasFields[i].pszStr, nSize * sizeof(char));
1287 0 : pszBuf2 += nSize;
1288 : }
1289 : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
1290 : /* See explanation in AVCE00GenTableHdr() about this hack to remap
1291 : * type 40 fields to double precision floats.
1292 : */
1293 : else if (nType == AVC_FT_FIXNUM && nSize > 8)
1294 : {
1295 : pszBuf2[0] = '\0';
1296 : /* NOTE: The E00 representation for a binary float is
1297 : * defined by its binary size, not by the coverage's
1298 : * precision.
1299 : */
1300 : nLen = AVCPrintRealValue(
1301 : pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1302 : AVC_DOUBLE_PREC, AVCFileTABLE,
1303 : CPLAtof((char *)pasFields[i].pszStr));
1304 : pszBuf2 += nLen;
1305 : }
1306 : #endif
1307 0 : else if (nType == AVC_FT_FIXNUM)
1308 : {
1309 : /* TYPE 40 attributes are stored with 1 byte per digit
1310 : * in binary format, and as single precision floats in
1311 : * E00 tables, even in double precision coverages.
1312 : */
1313 0 : pszBuf2[0] = '\0';
1314 0 : nLen = AVCPrintRealValue(
1315 0 : pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1316 : AVC_SINGLE_PREC, AVCFileTABLE,
1317 0 : CPLAtof((char *)pasFields[i].pszStr));
1318 0 : pszBuf2 += nLen;
1319 : }
1320 0 : else if (nType == AVC_FT_BININT && nSize == 4)
1321 : {
1322 0 : snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1323 0 : "%11d", pasFields[i].nInt32);
1324 0 : pszBuf2 += 11;
1325 : }
1326 0 : else if (nType == AVC_FT_BININT && nSize == 2)
1327 : {
1328 0 : snprintf(pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1329 0 : "%6d", pasFields[i].nInt16);
1330 0 : pszBuf2 += 6;
1331 : }
1332 0 : else if (nType == AVC_FT_BINFLOAT && nSize == 4)
1333 : {
1334 0 : pszBuf2[0] = '\0';
1335 : /* NOTE: The E00 representation for a binary float is
1336 : * defined by its binary size, not by the coverage's
1337 : * precision.
1338 : */
1339 0 : nLen = AVCPrintRealValue(
1340 0 : pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1341 0 : AVC_SINGLE_PREC, AVCFileTABLE, pasFields[i].fFloat);
1342 0 : pszBuf2 += nLen;
1343 : }
1344 0 : else if (nType == AVC_FT_BINFLOAT && nSize == 8)
1345 : {
1346 0 : pszBuf2[0] = '\0';
1347 : /* NOTE: The E00 representation for a binary float is
1348 : * defined by its binary size, not by the coverage's
1349 : * precision.
1350 : */
1351 0 : nLen = AVCPrintRealValue(
1352 0 : pszBuf2, psInfo->nBufSize - (pszBuf2 - psInfo->pszBuf),
1353 0 : AVC_DOUBLE_PREC, AVCFileTABLE, pasFields[i].dDouble);
1354 0 : pszBuf2 += nLen;
1355 : }
1356 : else
1357 : {
1358 : /*-----------------------------------------------------
1359 : * Hummm... unsupported field type...
1360 : *----------------------------------------------------*/
1361 0 : CPLError(CE_Failure, CPLE_NotSupported,
1362 : "Unsupported field type: (type=%d, size=%d)", nType,
1363 : nSize);
1364 0 : return nullptr;
1365 : }
1366 : }
1367 :
1368 0 : *pszBuf2 = '\0';
1369 :
1370 : /* Make sure that we remove any embedded NUL characters from the
1371 : * data line before returning it, otherwise we may be accidentally
1372 : * truncating results.
1373 : */
1374 0 : while (--pszBuf2 >= psInfo->pszBuf + 81)
1375 : {
1376 0 : if (*pszBuf2 == '\0')
1377 : {
1378 0 : *pszBuf2 = ' ';
1379 : }
1380 : }
1381 : }
1382 :
1383 0 : if (psInfo->iCurItem < psInfo->numItems)
1384 : {
1385 : /*-------------------------------------------------------------
1386 : * Return the next 80 chars chunk.
1387 : * The first 80 chars of the buffer is used to return
1388 : * one line at a time, and the rest of the buffer (chars 81+)
1389 : * is used to hold the whole record.
1390 : *------------------------------------------------------------*/
1391 0 : nLen = psInfo->numItems - psInfo->iCurItem;
1392 :
1393 0 : if (nLen > 80)
1394 0 : nLen = 80;
1395 :
1396 0 : strncpy(psInfo->pszBuf, psInfo->pszBuf + (81 + psInfo->iCurItem), nLen);
1397 0 : psInfo->pszBuf[nLen] = '\0';
1398 :
1399 0 : psInfo->iCurItem += nLen;
1400 :
1401 : /*-------------------------------------------------------------
1402 : * Arc/Info removes spaces at the end of the lines... let's
1403 : * remove them as well since it can reduce the E00 file size.
1404 : *------------------------------------------------------------*/
1405 0 : nLen--;
1406 0 : while (nLen >= 0 && psInfo->pszBuf[nLen] == ' ')
1407 : {
1408 0 : psInfo->pszBuf[nLen] = '\0';
1409 0 : nLen--;
1410 : }
1411 : }
1412 : else
1413 : {
1414 : /* No more lines to generate.
1415 : */
1416 0 : return nullptr;
1417 : }
1418 :
1419 0 : return psInfo->pszBuf;
1420 : }
|