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