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