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