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