1 : /**********************************************************************
2 : * $Id: avc_e00gen.c,v 1.18 2008/07/23 20:51:38 dmorissette Exp $
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 embeded '\0' from data line in AVCE00GenTableRec()
39 : *
40 : * Revision 1.16 2005/06/03 03:49:58 daniel
41 : * Update email address, website url, and copyright dates
42 : *
43 : * Revision 1.15 2004/08/19 17:48:20 warmerda
44 : * Avoid uninitialized variable warnings.
45 : *
46 : * Revision 1.14 2001/11/25 21:15:23 daniel
47 : * Added hack (AVC_MAP_TYPE40_TO_DOUBLE) to map type 40 fields bigger than 8
48 : * digits to double precision as we generate E00 output (bug599)
49 : *
50 : * Revision 1.13 2001/11/19 20:39:48 daniel
51 : * Change to correctly format 0-arc PAL records, so that they have a
52 : * single "filler" arc record
53 : *
54 : * Revision 1.12 2000/09/26 20:21:04 daniel
55 : * Added AVCCoverPC write
56 : *
57 : * Revision 1.11 2000/09/22 19:45:20 daniel
58 : * Switch to MIT-style license
59 : *
60 : * Revision 1.10 2000/02/04 04:54:03 daniel
61 : * Fixed warnings
62 : *
63 : * Revision 1.9 2000/02/03 07:21:02 daniel
64 : * TXT/TX6 with string longer than 80 chars: split string in 80 chars chunks
65 : *
66 : * Revision 1.8 2000/02/02 04:28:00 daniel
67 : * Fixed support of TX6/RXP/RPL coming from "weird" coverages
68 : *
69 : * Revision 1.7 1999/08/23 18:20:49 daniel
70 : * Fixed support for attribute fields type 40
71 : *
72 : * Revision 1.6 1999/05/17 16:19:39 daniel
73 : * Made sure ACVE00GenTableRec() removes all spaces at the end of a
74 : * table record line (it used to leave one space)
75 : *
76 : * Revision 1.5 1999/05/11 02:08:17 daniel
77 : * Simple changes related to the addition of coverage write support.
78 : *
79 : * Revision 1.4 1999/03/03 02:06:38 daniel
80 : * Properly handle 8 bytes floats inside single precision tables.
81 : *
82 : * Revision 1.3 1999/02/25 17:01:58 daniel
83 : * Added support for 16 bit integers in INFO tables (type=50, size=2)
84 : *
85 : * Revision 1.2 1999/02/25 04:17:51 daniel
86 : * Added TXT, TX6/TX7, RXP and RPL support + some minor changes
87 : *
88 : * Revision 1.1 1999/01/29 16:28:52 daniel
89 : * Initial revision
90 : *
91 : **********************************************************************/
92 :
93 : #include "avc.h"
94 :
95 : #include <ctype.h> /* toupper() */
96 :
97 : /**********************************************************************
98 : * AVCE00GenInfoAlloc()
99 : *
100 : * Allocate and initialize a new AVCE00GenInfo structure.
101 : *
102 : * The structure will eventually have to be freed with AVCE00GenInfoFree().
103 : **********************************************************************/
104 : AVCE00GenInfo *AVCE00GenInfoAlloc(int nCoverPrecision)
105 1 : {
106 : AVCE00GenInfo *psInfo;
107 :
108 1 : 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 1 : psInfo->nBufSize = 2048;
115 1 : psInfo->pszBuf = (char *)CPLMalloc(psInfo->nBufSize*sizeof(char));
116 :
117 1 : psInfo->nPrecision = nCoverPrecision;
118 :
119 1 : return psInfo;
120 : }
121 :
122 : /**********************************************************************
123 : * AVCE00GenInfoFree()
124 : *
125 : * Free any memory associated with a AVCE00GenInfo structure.
126 : **********************************************************************/
127 : void AVCE00GenInfoFree(AVCE00GenInfo *psInfo)
128 1 : {
129 1 : if (psInfo)
130 1 : CPLFree(psInfo->pszBuf);
131 1 : CPLFree(psInfo);
132 1 : }
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 NULL.
140 : **********************************************************************/
141 : void AVCE00GenReset(AVCE00GenInfo *psInfo)
142 0 : {
143 : /* Reinitialize counters so that further calls with bCont = TRUE,
144 : * like AVCE00GenArc(psInfo, TRUE) would return NULL.
145 : */
146 0 : psInfo->iCurItem = psInfo->numItems = 0;
147 0 : }
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 : **********************************************************************/
156 : const char *AVCE00GenStartSection(AVCE00GenInfo *psInfo, AVCFileType eType,
157 : const char *pszClassName)
158 0 : {
159 0 : char *pszName = "UNK";
160 :
161 0 : AVCE00GenReset(psInfo);
162 :
163 0 : 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 0 : for(i=0; pszClassName[i] != '\0'; i++)
171 : {
172 0 : psInfo->pszBuf[i] = toupper(pszClassName[i]);
173 : }
174 0 : psInfo->pszBuf[i] = '\0';
175 : }
176 : else
177 : {
178 : /* In most cases, the section starts with a 3 letters code followed
179 : * by the precision code (2 or 3)
180 : */
181 0 : switch(eType)
182 : {
183 : case AVCFileARC:
184 0 : pszName = "ARC";
185 0 : break;
186 : case AVCFilePAL:
187 0 : pszName = "PAL";
188 0 : break;
189 : case AVCFileCNT:
190 0 : pszName = "CNT";
191 0 : break;
192 : case AVCFileLAB:
193 0 : pszName = "LAB";
194 0 : break;
195 : case AVCFileTOL:
196 0 : pszName = "TOL";
197 0 : break;
198 : case AVCFilePRJ:
199 0 : pszName = "PRJ";
200 0 : break;
201 : case AVCFileTXT:
202 0 : pszName = "TXT";
203 0 : break;
204 : default:
205 0 : CPLError(CE_Failure, CPLE_NotSupported,
206 : "Unsupported E00 section type!");
207 : }
208 :
209 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
210 0 : sprintf(psInfo->pszBuf, "%s 3", pszName);
211 : else
212 0 : sprintf(psInfo->pszBuf, "%s 2", pszName);
213 : }
214 :
215 0 : return psInfo->pszBuf;
216 : }
217 :
218 : /**********************************************************************
219 : * AVCE00GenEndSection()
220 : *
221 : * Generate the last line(s) of an E00 section.
222 : *
223 : * This function should be called once with bCont=FALSE to get the
224 : * first "end of section" line for the current section, and then call
225 : * with bCont=TRUE to get all the other lines.
226 : *
227 : * The function returns NULL when there are no more lines to generate
228 : * for this "end of section".
229 : **********************************************************************/
230 : const char *AVCE00GenEndSection(AVCE00GenInfo *psInfo, AVCFileType eType,
231 : GBool bCont)
232 0 : {
233 0 : if (bCont == FALSE)
234 : {
235 : /*-------------------------------------------------------------
236 : * Most section types end with only 1 line.
237 : *------------------------------------------------------------*/
238 0 : AVCE00GenReset(psInfo);
239 0 : psInfo->iCurItem = 0;
240 :
241 0 : if (eType == AVCFileARC ||
242 : eType == AVCFilePAL ||
243 : eType == AVCFileRPL ||
244 : eType == AVCFileCNT ||
245 : eType == AVCFileTOL ||
246 : eType == AVCFileTXT ||
247 : eType == AVCFileTX6 )
248 : {
249 0 : sprintf(psInfo->pszBuf,
250 : " -1 0 0 0 0 0 0");
251 : }
252 0 : else if (eType == AVCFileLAB)
253 : {
254 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
255 0 : sprintf(psInfo->pszBuf,
256 : " -1 0 0.00000000000000E+00 0.00000000000000E+00");
257 : else
258 0 : sprintf(psInfo->pszBuf,
259 : " -1 0 0.0000000E+00 0.0000000E+00");
260 : }
261 0 : else if (eType == AVCFilePRJ)
262 : {
263 0 : sprintf(psInfo->pszBuf, "EOP");
264 : }
265 0 : else if (eType == AVCFileRXP )
266 : {
267 0 : sprintf(psInfo->pszBuf," -1 0");
268 : }
269 : else
270 : {
271 0 : CPLError(CE_Failure, CPLE_NotSupported,
272 : "Unsupported E00 section type!");
273 0 : return NULL;
274 : }
275 : }
276 0 : 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 0 : sprintf(psInfo->pszBuf,
284 : " 0.00000000000000E+00 0.00000000000000E+00");
285 :
286 0 : psInfo->iCurItem++;
287 : }
288 : else
289 : {
290 : /*-----------------------------------------------------
291 : * All other section types end with only one line, and thus
292 : * we return NULL when bCont==TRUE
293 : *----------------------------------------------------*/
294 0 : return NULL;
295 : }
296 :
297 0 : 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 NULL when there are no more lines to generate
312 : * for this ARC.
313 : **********************************************************************/
314 : const char *AVCE00GenObject(AVCE00GenInfo *psInfo,
315 : AVCFileType eType, void *psObj, GBool bCont)
316 0 : {
317 0 : const char *pszLine = NULL;
318 :
319 0 : switch(eType)
320 : {
321 : case AVCFileARC:
322 0 : pszLine = AVCE00GenArc(psInfo, (AVCArc*)psObj, bCont);
323 0 : break;
324 : case AVCFilePAL:
325 : case AVCFileRPL:
326 0 : pszLine = AVCE00GenPal(psInfo, (AVCPal*)psObj, bCont);
327 0 : break;
328 : case AVCFileCNT:
329 0 : pszLine = AVCE00GenCnt(psInfo, (AVCCnt*)psObj, bCont);
330 0 : break;
331 : case AVCFileLAB:
332 0 : pszLine = AVCE00GenLab(psInfo, (AVCLab*)psObj, bCont);
333 0 : break;
334 : case AVCFileTOL:
335 0 : pszLine = AVCE00GenTol(psInfo, (AVCTol*)psObj, bCont);
336 0 : break;
337 : case AVCFileTXT:
338 0 : pszLine = AVCE00GenTxt(psInfo, (AVCTxt*)psObj, bCont);
339 0 : break;
340 : case AVCFileTX6:
341 0 : pszLine = AVCE00GenTx6(psInfo, (AVCTxt*)psObj, bCont);
342 0 : break;
343 : case AVCFilePRJ:
344 0 : pszLine = AVCE00GenPrj(psInfo, (char**)psObj, bCont);
345 0 : break;
346 : case AVCFileRXP:
347 0 : pszLine = AVCE00GenRxp(psInfo, (AVCRxp*)psObj, bCont);
348 0 : break;
349 : default:
350 0 : CPLError(CE_Failure, CPLE_NotSupported,
351 : "AVCE00GenObject(): Unsupported file type!");
352 : }
353 :
354 0 : 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 NULL when there are no more lines to generate
372 : * for this ARC.
373 : **********************************************************************/
374 : const char *AVCE00GenArc(AVCE00GenInfo *psInfo, AVCArc *psArc, GBool bCont)
375 0 : {
376 0 : if (bCont == FALSE)
377 : {
378 : /* Initialize the psInfo structure with info about the
379 : * current ARC.
380 : */
381 0 : psInfo->iCurItem = 0;
382 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
383 0 : psInfo->numItems = psArc->numVertices;
384 : else
385 0 : psInfo->numItems = (psArc->numVertices+1)/2;
386 :
387 : /* And return the ARC header line
388 : */
389 0 : sprintf(psInfo->pszBuf, "%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 0 : else if (psInfo->iCurItem < psInfo->numItems)
396 : {
397 : int iVertex;
398 :
399 : /* return the next set of vertices for the ARC.
400 : */
401 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
402 : {
403 0 : iVertex = psInfo->iCurItem;
404 :
405 0 : psInfo->pszBuf[0] = '\0';
406 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC,
407 : psArc->pasVertices[iVertex].x);
408 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC,
409 : psArc->pasVertices[iVertex].y);
410 : }
411 : else
412 : {
413 0 : iVertex = psInfo->iCurItem*2;
414 :
415 0 : psInfo->pszBuf[0] = '\0';
416 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileARC,
417 : psArc->pasVertices[iVertex].x);
418 0 : AVCPrintRealValue(psInfo->pszBuf, 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 0 : if (iVertex+1 < psArc->numVertices)
425 : {
426 0 : AVCPrintRealValue(psInfo->pszBuf,psInfo->nPrecision,AVCFileARC,
427 : psArc->pasVertices[iVertex+1].x);
428 0 : AVCPrintRealValue(psInfo->pszBuf,psInfo->nPrecision,AVCFileARC,
429 : psArc->pasVertices[iVertex+1].y);
430 : }
431 : }
432 0 : psInfo->iCurItem++;
433 : }
434 : else
435 : {
436 : /* No more lines to generate for this ARC.
437 : */
438 0 : return NULL;
439 : }
440 :
441 0 : return psInfo->pszBuf;
442 : }
443 :
444 : /*=====================================================================
445 : PAL stuff
446 : =====================================================================*/
447 :
448 : /**********************************************************************
449 : * AVCE00GenPal()
450 : *
451 : * Generate the next line of an E00 PAL (Polygon Arc List) entry.
452 : *
453 : * This function should be called once with bCont=FALSE to get the
454 : * first E00 line for the current PAL, and then call with bCont=TRUE
455 : * to get all the other lines for this PAL.
456 : *
457 : * The function returns NULL when there are no more lines to generate
458 : * for this PAL entry.
459 : **********************************************************************/
460 : const char *AVCE00GenPal(AVCE00GenInfo *psInfo, AVCPal *psPal, GBool bCont)
461 0 : {
462 0 : if (bCont == FALSE)
463 : {
464 : /* Initialize the psInfo structure with info about the
465 : * current PAL. (Number of lines excluding header)
466 : */
467 0 : psInfo->numItems = (psPal->numArcs+1)/2;
468 :
469 :
470 : /* And return the PAL header line.
471 : */
472 0 : sprintf(psInfo->pszBuf, "%10d", psPal->numArcs);
473 :
474 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
475 : psPal->sMin.x);
476 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
477 : psPal->sMin.y);
478 :
479 : /* Double precision PAL entries have their header on 2 lines!
480 : */
481 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
482 : {
483 0 : psInfo->iCurItem = -1; /* Means 1 line left in header */
484 : }
485 : else
486 : {
487 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
488 : psPal->sMax.x);
489 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
490 : psPal->sMax.y);
491 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
492 : }
493 :
494 : }
495 0 : else if (psInfo->iCurItem == -1)
496 : {
497 : /* Second (and last) header line for double precision coverages
498 : */
499 0 : psInfo->pszBuf[0] = '\0';
500 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
501 : psPal->sMax.x);
502 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFilePAL,
503 : psPal->sMax.y);
504 :
505 0 : if ( psInfo->numItems == 0 )
506 : {
507 0 : 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 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
513 : }
514 : }
515 0 : else if (psInfo->iCurItem == -2)
516 : {
517 0 : sprintf(psInfo->pszBuf, "%10d%10d%10d", 0, 0, 0);
518 0 : psInfo->iCurItem = 0; /* Next thing = first Arc entry */
519 : }
520 0 : else if (psInfo->iCurItem < psInfo->numItems)
521 : {
522 : /* Return PAL Arc entries...
523 : */
524 : int iArc;
525 :
526 0 : 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 0 : if (iArc+1 < psPal->numArcs)
532 : {
533 0 : sprintf(psInfo->pszBuf, "%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 0 : sprintf(psInfo->pszBuf, "%10d%10d%10d",
545 : psPal->pasArcs[iArc].nArcId,
546 : psPal->pasArcs[iArc].nFNode,
547 : psPal->pasArcs[iArc].nAdjPoly);
548 : }
549 0 : psInfo->iCurItem++;
550 : }
551 : else
552 : {
553 : /* No more lines to generate for this PAL.
554 : */
555 0 : return NULL;
556 : }
557 :
558 0 : 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 NULL when there are no more lines to generate
576 : * for this CNT entry.
577 : **********************************************************************/
578 : const char *AVCE00GenCnt(AVCE00GenInfo *psInfo, AVCCnt *psCnt, GBool bCont)
579 0 : {
580 0 : if (bCont == FALSE)
581 : {
582 : /* Initialize the psInfo structure with info about the
583 : * current CNT.
584 : */
585 0 : psInfo->iCurItem = 0;
586 0 : psInfo->numItems = (psCnt->numLabels+7)/8;
587 :
588 : /* And return the CNT header line.
589 : */
590 0 : sprintf(psInfo->pszBuf, "%10d", psCnt->numLabels);
591 :
592 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileCNT,
593 : psCnt->sCoord.x);
594 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileCNT,
595 : psCnt->sCoord.y);
596 :
597 : }
598 0 : 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 0 : nFirstLabel = psInfo->iCurItem * 8;
605 0 : numLabels = MIN(8, (psCnt->numLabels-nFirstLabel));
606 :
607 0 : psInfo->pszBuf[0] = '\0';
608 0 : for(i=0; i < numLabels; i++)
609 : {
610 0 : sprintf(psInfo->pszBuf + strlen(psInfo->pszBuf), "%10d",
611 : psCnt->panLabelIds[nFirstLabel+i] );
612 : }
613 :
614 0 : psInfo->iCurItem++;
615 : }
616 : else
617 : {
618 : /* No more lines to generate for this CNT.
619 : */
620 0 : return NULL;
621 : }
622 :
623 0 : return psInfo->pszBuf;
624 : }
625 :
626 :
627 : /*=====================================================================
628 : LAB stuff
629 : =====================================================================*/
630 :
631 : /**********************************************************************
632 : * AVCE00GenLab()
633 : *
634 : * Generate the next line of an E00 LAB (Label) entry.
635 : *
636 : * This function should be called once with bCont=FALSE to get the
637 : * first E00 line for the current LAB, and then call with bCont=TRUE
638 : * to get all the other lines for this LAB.
639 : *
640 : * The function returns NULL when there are no more lines to generate
641 : * for this LAB entry.
642 : **********************************************************************/
643 : const char *AVCE00GenLab(AVCE00GenInfo *psInfo, AVCLab *psLab, GBool bCont)
644 0 : {
645 0 : if (bCont == FALSE)
646 : {
647 : /* Initialize the psInfo structure with info about the
648 : * current LAB. (numItems = Number of lines excluding header)
649 : */
650 0 : psInfo->iCurItem = 0;
651 0 : if (psInfo->nPrecision == AVC_DOUBLE_PREC)
652 0 : psInfo->numItems = 2;
653 : else
654 0 : psInfo->numItems = 1;
655 :
656 : /* And return the LAB header line.
657 : */
658 0 : sprintf(psInfo->pszBuf, "%10d%10d", psLab->nValue, psLab->nPolyId);
659 :
660 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
661 : psLab->sCoord1.x);
662 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
663 : psLab->sCoord1.y);
664 :
665 : }
666 0 : else if (psInfo->iCurItem < psInfo->numItems)
667 : {
668 : /* Return next Label coordinates...
669 : */
670 0 : if (psInfo->nPrecision != AVC_DOUBLE_PREC)
671 : {
672 : /* Single precision, all on the same line
673 : */
674 0 : psInfo->pszBuf[0] = '\0';
675 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
676 : psLab->sCoord2.x);
677 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
678 : psLab->sCoord2.y);
679 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
680 : psLab->sCoord3.x);
681 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
682 : psLab->sCoord3.y);
683 :
684 : }
685 0 : else if (psInfo->iCurItem == 0)
686 : {
687 : /* 2nd line, in a double precision coverage
688 : */
689 0 : psInfo->pszBuf[0] = '\0';
690 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
691 : psLab->sCoord2.x);
692 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
693 : psLab->sCoord2.y);
694 : }
695 : else
696 : {
697 : /* 3rd line, in a double precision coverage
698 : */
699 0 : psInfo->pszBuf[0] = '\0';
700 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
701 : psLab->sCoord3.x);
702 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileLAB,
703 : psLab->sCoord3.y);
704 : }
705 :
706 0 : psInfo->iCurItem++;
707 : }
708 : else
709 : {
710 : /* No more lines to generate for this LAB.
711 : */
712 0 : return NULL;
713 : }
714 :
715 0 : return psInfo->pszBuf;
716 : }
717 :
718 : /*=====================================================================
719 : TOL stuff
720 : =====================================================================*/
721 :
722 : /**********************************************************************
723 : * AVCE00GenTol()
724 : *
725 : * Generate the next line of an E00 TOL (Tolerance) entry.
726 : *
727 : * This function should be called once with bCont=FALSE to get the
728 : * first E00 line for the current TOL, and then call with bCont=TRUE
729 : * to get all the other lines for this TOL.
730 : *
731 : * The function returns NULL when there are no more lines to generate
732 : * for this TOL entry.
733 : **********************************************************************/
734 : const char *AVCE00GenTol(AVCE00GenInfo *psInfo, AVCTol *psTol, GBool bCont)
735 0 : {
736 0 : if (bCont == TRUE)
737 : {
738 : /*---------------------------------------------------------
739 : * TOL entries are only 1 line, we support the bCont flag
740 : * only for compatibility with the other AVCE00Gen*() functions.
741 : *--------------------------------------------------------*/
742 0 : return NULL;
743 : }
744 :
745 0 : sprintf(psInfo->pszBuf, "%10d%10d", psTol->nIndex, psTol->nFlag);
746 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTOL,
747 : psTol->dValue);
748 :
749 0 : return psInfo->pszBuf;
750 : }
751 :
752 : /*=====================================================================
753 : PRJ stuff
754 : =====================================================================*/
755 :
756 : /**********************************************************************
757 : * AVCE00GenPrj()
758 : *
759 : * Generate the next line of an E00 PRJ (Projection) section.
760 : *
761 : * This function should be called once with bCont=FALSE to get the
762 : * first E00 line for the current PRJ, and then call with bCont=TRUE
763 : * to get all the other lines for this PRJ.
764 : *
765 : * The function returns NULL when there are no more lines to generate
766 : * for this PRJ entry.
767 : **********************************************************************/
768 : const char *AVCE00GenPrj(AVCE00GenInfo *psInfo, char **papszPrj, GBool bCont)
769 0 : {
770 0 : if (bCont == FALSE)
771 : {
772 : /*---------------------------------------------------------
773 : * Initialize the psInfo structure with info about the
774 : * current PRJ. (numItems = Number of lines to output)
775 : *--------------------------------------------------------*/
776 0 : psInfo->iCurItem = 0;
777 0 : psInfo->numItems = CSLCount(papszPrj) * 2;
778 : }
779 :
780 0 : if (psInfo->iCurItem < psInfo->numItems)
781 : {
782 : /*---------------------------------------------------------
783 : * Return the next PRJ section line. Note that every
784 : * second line of the output is only a "~".
785 : *--------------------------------------------------------*/
786 :
787 0 : if (psInfo->iCurItem % 2 == 0)
788 : {
789 : /*-----------------------------------------------------
790 : * In theory we should split lines longer than 80 chars on
791 : * several lines, but I won't do it for now since I never
792 : * saw any projection line longer than 80 chars.
793 : *----------------------------------------------------*/
794 0 : sprintf(psInfo->pszBuf, "%s", papszPrj[psInfo->iCurItem/2]);
795 : }
796 : else
797 : {
798 : /*-----------------------------------------------------
799 : * Every second line in a PRJ section contains only a "~",
800 : * this is a way to tell that the previous line was complete.
801 : *----------------------------------------------------*/
802 0 : sprintf(psInfo->pszBuf, "~");
803 : }
804 :
805 0 : psInfo->iCurItem++;
806 : }
807 : else
808 : {
809 : /* No more lines to generate for this PRJ.
810 : */
811 0 : return NULL;
812 : }
813 :
814 0 : return psInfo->pszBuf;
815 : }
816 :
817 :
818 : /*=====================================================================
819 : TXT stuff
820 : =====================================================================*/
821 :
822 : /**********************************************************************
823 : * AVCE00GenTxt()
824 : *
825 : * Generate the next line of an E00 TXT (Annotation) entry.
826 : *
827 : * This function should be called once with bCont=FALSE to get the
828 : * first E00 line for the current TXT, and then call with bCont=TRUE
829 : * to get all the other lines for this TXT.
830 : *
831 : * The function returns NULL when there are no more lines to generate
832 : * for this TXT entry.
833 : **********************************************************************/
834 : const char *AVCE00GenTxt(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
835 0 : {
836 : int numFixedLines;
837 :
838 : /* numFixedLines is the number of lines to generate before the line(s)
839 : * with the text string
840 : */
841 0 : if (psInfo->nPrecision == AVC_SINGLE_PREC)
842 0 : numFixedLines = 4;
843 : else
844 0 : numFixedLines = 6;
845 :
846 0 : if (bCont == FALSE)
847 : {
848 : /*-------------------------------------------------------------
849 : * Initialize the psInfo structure with info about the
850 : * current TXT. (numItems = Number of lines excluding header)
851 : *------------------------------------------------------------*/
852 0 : psInfo->iCurItem = 0;
853 0 : psInfo->numItems = numFixedLines + ((psTxt->numChars-1)/80 + 1);
854 :
855 : /* And return the TXT header line.
856 : */
857 0 : sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d",
858 : psTxt->nLevel, psTxt->numVerticesLine - 1,
859 : psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->numChars);
860 : }
861 0 : else if (psInfo->iCurItem < psInfo->numItems &&
862 : psInfo->iCurItem < numFixedLines-1)
863 : {
864 : /*-------------------------------------------------------------
865 : * Return next line of coordinates... start by placing the coord.
866 : * values in the order that they should appear, and then generate the
867 : * current line
868 : * (This is a little bit less efficient, but will give much easier
869 : * code to read ;-)
870 : *------------------------------------------------------------*/
871 : double dXY[15];
872 : int i, nFirstValue, numValuesPerLine;
873 0 : for(i=0; i<14; i++)
874 0 : dXY[i] = 0.0;
875 :
876 0 : dXY[14] = psTxt->dHeight;
877 :
878 : /* note that the first vertex in the vertices list is never exported
879 : */
880 0 : for(i=0; i < 4 && i< (psTxt->numVerticesLine-1); i++)
881 : {
882 0 : dXY[i] = psTxt->pasVertices[i+1].x;
883 0 : dXY[i+4] = psTxt->pasVertices[i+1].y;
884 : }
885 0 : for(i=0; i < 3 && i<ABS(psTxt->numVerticesArrow); i++)
886 : {
887 0 : dXY[i+8] = psTxt->pasVertices[i+psTxt->numVerticesLine].x;
888 0 : dXY[i+11] = psTxt->pasVertices[i+psTxt->numVerticesLine].y;
889 : }
890 :
891 : /* OK, now that we prepared the coord. values, return the next line
892 : * of coordinates. The only difference between double and single
893 : * precision is the number of coordinates per line.
894 : */
895 0 : if (psInfo->nPrecision != AVC_DOUBLE_PREC)
896 : {
897 : /* Single precision
898 : */
899 0 : numValuesPerLine = 5;
900 : }
901 : else
902 : {
903 : /* Double precision
904 : */
905 0 : numValuesPerLine = 3;
906 : }
907 :
908 0 : nFirstValue = psInfo->iCurItem*numValuesPerLine;
909 0 : psInfo->pszBuf[0] = '\0';
910 0 : for(i=0; i<numValuesPerLine; i++)
911 : {
912 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTXT,
913 : dXY[nFirstValue+i] );
914 : }
915 :
916 0 : psInfo->iCurItem++;
917 : }
918 0 : else if (psInfo->iCurItem < psInfo->numItems &&
919 : psInfo->iCurItem == numFixedLines-1)
920 : {
921 : /*-------------------------------------------------------------
922 : * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
923 : *------------------------------------------------------------*/
924 0 : psInfo->pszBuf[0] = '\0';
925 0 : AVCPrintRealValue(psInfo->pszBuf, AVC_SINGLE_PREC, AVCFileTXT,
926 : psTxt->f_1e2 );
927 0 : psInfo->iCurItem++;
928 : }
929 0 : else if (psInfo->iCurItem < psInfo->numItems &&
930 : psInfo->iCurItem >= numFixedLines )
931 : {
932 : /*-------------------------------------------------------------
933 : * Last line, contains the text string
934 : * Strings longer than 80 chars have to be in 80 chars chunks
935 : *------------------------------------------------------------*/
936 : int numLines, iLine;
937 0 : numLines = (psTxt->numChars-1)/80 + 1;
938 0 : iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
939 :
940 0 : if ((int)strlen((char*)psTxt->pszText) > (iLine*80))
941 0 : sprintf(psInfo->pszBuf, "%-.80s", psTxt->pszText + (iLine*80) );
942 : else
943 0 : psInfo->pszBuf[0] = '\0';
944 :
945 0 : psInfo->iCurItem++;
946 : }
947 : else
948 : {
949 : /* No more lines to generate for this TXT.
950 : */
951 0 : return NULL;
952 : }
953 :
954 0 : return psInfo->pszBuf;
955 : }
956 :
957 : /*=====================================================================
958 : TX6 stuff
959 : =====================================================================*/
960 :
961 : /**********************************************************************
962 : * AVCE00GenTx6()
963 : *
964 : * Generate the next line of an E00 TX6 (Annotation) entry.
965 : *
966 : * This function should be called once with bCont=FALSE to get the
967 : * first E00 line for the current TX6, and then call with bCont=TRUE
968 : * to get all the other lines for this TX6.
969 : *
970 : * Note that E00 files can also contain TX7 sections, they seem identical
971 : * to TX6 sections, except for one value in each entry, and it was
972 : * impossible to find where this value comes from... so we will always
973 : * generate TX6 sections and not bother with TX7.
974 : *
975 : * The function returns NULL when there are no more lines to generate
976 : * for this TX6 entry.
977 : **********************************************************************/
978 : const char *AVCE00GenTx6(AVCE00GenInfo *psInfo, AVCTxt *psTxt, GBool bCont)
979 0 : {
980 0 : if (bCont == FALSE)
981 : {
982 : /*-------------------------------------------------------------
983 : * Initialize the psInfo structure with info about the
984 : * current TX6. (numItems = Number of lines excluding header)
985 : *------------------------------------------------------------*/
986 0 : psInfo->iCurItem = 0;
987 0 : psInfo->numItems = 8 + psTxt->numVerticesLine +
988 : ABS(psTxt->numVerticesArrow) +
989 : ((psTxt->numChars-1)/80 + 1);
990 :
991 : /* And return the TX6 header line.
992 : */
993 0 : sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d%10d",
994 : psTxt->nUserId, psTxt->nLevel, psTxt->numVerticesLine,
995 : psTxt->numVerticesArrow, psTxt->nSymbol, psTxt->n28,
996 : psTxt->numChars);
997 : }
998 0 : else if (psInfo->iCurItem < psInfo->numItems &&
999 : psInfo->iCurItem < 6)
1000 : {
1001 : /*-------------------------------------------------------------
1002 : * Text Justification stuff... 2 sets of 20 int16 values.
1003 : *------------------------------------------------------------*/
1004 : GInt16 *pValue;
1005 :
1006 0 : if (psInfo->iCurItem < 3)
1007 0 : pValue = psTxt->anJust2 + psInfo->iCurItem * 7;
1008 : else
1009 0 : pValue = psTxt->anJust1 + (psInfo->iCurItem-3) * 7;
1010 :
1011 0 : if (psInfo->iCurItem == 2 || psInfo->iCurItem == 5)
1012 : {
1013 0 : sprintf(psInfo->pszBuf, "%10d%10d%10d%10d%10d%10d",
1014 : pValue[0], pValue[1], pValue[2],
1015 : pValue[3], pValue[4], pValue[5]);
1016 : }
1017 : else
1018 : {
1019 0 : sprintf(psInfo->pszBuf, "%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 0 : psInfo->iCurItem++;
1025 : }
1026 0 : 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 0 : psInfo->pszBuf[0] = '\0';
1033 0 : AVCPrintRealValue(psInfo->pszBuf, AVC_SINGLE_PREC, AVCFileTX6,
1034 : psTxt->f_1e2 );
1035 0 : psInfo->iCurItem++;
1036 : }
1037 0 : 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 0 : psInfo->pszBuf[0] = '\0';
1044 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6,
1045 : psTxt->dHeight );
1046 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6,
1047 : psTxt->dV2 );
1048 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6,
1049 : psTxt->dV3 );
1050 0 : psInfo->iCurItem++;
1051 : }
1052 0 : 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 0 : psInfo->pszBuf[0] = '\0';
1058 :
1059 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6,
1060 : psTxt->pasVertices[ psInfo->iCurItem-8 ].x );
1061 0 : AVCPrintRealValue(psInfo->pszBuf, psInfo->nPrecision, AVCFileTX6,
1062 : psTxt->pasVertices[ psInfo->iCurItem-8 ].y );
1063 :
1064 0 : psInfo->iCurItem++;
1065 : }
1066 0 : 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 0 : numLines = (psTxt->numChars-1)/80 + 1;
1075 0 : iLine = numLines - (psInfo->numItems - psInfo->iCurItem);
1076 :
1077 0 : if ((int)strlen((char*)psTxt->pszText) > (iLine*80))
1078 0 : sprintf(psInfo->pszBuf, "%-.80s", psTxt->pszText + (iLine*80) );
1079 : else
1080 0 : psInfo->pszBuf[0] = '\0';
1081 :
1082 0 : psInfo->iCurItem++;
1083 : }
1084 : else
1085 : {
1086 : /* No more lines to generate for this TX6.
1087 : */
1088 0 : return NULL;
1089 : }
1090 :
1091 0 : 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 NULL when there are no more lines to generate
1109 : * for this RXP entry.
1110 : **********************************************************************/
1111 : const char *AVCE00GenRxp(AVCE00GenInfo *psInfo, AVCRxp *psRxp, GBool bCont)
1112 0 : {
1113 0 : 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 0 : return NULL;
1120 : }
1121 :
1122 0 : sprintf(psInfo->pszBuf, "%10d%10d", psRxp->n1, psRxp->n2);
1123 :
1124 0 : 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 NULL when there are no more lines to generate.
1143 : **********************************************************************/
1144 : const char *AVCE00GenTableHdr(AVCE00GenInfo *psInfo, AVCTableDef *psDef,
1145 : GBool bCont)
1146 0 : {
1147 0 : if (bCont == FALSE)
1148 : {
1149 : int nRecSize;
1150 : /* Initialize the psInfo structure with info about the
1151 : * current Table Header
1152 : */
1153 0 : psInfo->iCurItem = 0;
1154 0 : psInfo->numItems = psDef->numFields;
1155 :
1156 0 : 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 0 : sprintf(psInfo->pszBuf, "%-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 0 : else if (psInfo->iCurItem < psInfo->numItems)
1185 : {
1186 : int nSize, nType, nOffset;
1187 :
1188 0 : nSize = psDef->pasFieldDef[psInfo->iCurItem].nSize;
1189 0 : nType = psDef->pasFieldDef[psInfo->iCurItem].nType1 * 10;
1190 0 : 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 0 : sprintf(psInfo->pszBuf,
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 0 : psInfo->iCurItem++;
1244 : }
1245 : else
1246 : {
1247 : /* No more lines to generate.
1248 : */
1249 0 : return NULL;
1250 : }
1251 :
1252 0 : 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 NULL when there are no more lines to generate.
1265 : **********************************************************************/
1266 : const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields,
1267 : AVCFieldInfo *pasDef, AVCField *pasFields,
1268 : GBool bCont)
1269 0 : {
1270 : int i, nSize, nType, nLen;
1271 : char *pszBuf2;
1272 :
1273 0 : if (bCont == FALSE)
1274 : {
1275 : /*-------------------------------------------------------------
1276 : * Initialize the psInfo structure to be ready to process this
1277 : * new Table Record
1278 : *------------------------------------------------------------*/
1279 0 : psInfo->iCurItem = 0;
1280 : #ifdef AVC_MAP_TYPE40_TO_DOUBLE
1281 : psInfo->numItems = _AVCE00ComputeRecSize(numFields, pasDef, TRUE);
1282 : #else
1283 0 : 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 0 : nSize = psInfo->numItems + 1 + 81;
1292 :
1293 0 : if (psInfo->nBufSize < nSize)
1294 : {
1295 0 : psInfo->pszBuf = (char*)CPLRealloc(psInfo->pszBuf,
1296 : nSize*sizeof(char));
1297 0 : 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 0 : pszBuf2 = psInfo->pszBuf+81;
1308 :
1309 0 : for(i=0; i<numFields; i++)
1310 : {
1311 0 : nType = pasDef[i].nType1*10;
1312 0 : nSize = pasDef[i].nSize;
1313 :
1314 0 : if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
1315 : nType == AVC_FT_FIXINT )
1316 : {
1317 0 : memcpy(pszBuf2, pasFields[i].pszStr, nSize * sizeof(char));
1318 0 : 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, AVC_DOUBLE_PREC,
1332 : AVCFileTABLE,
1333 : atof((char*)pasFields[i].pszStr));
1334 : pszBuf2 += nLen;
1335 : }
1336 : #endif
1337 0 : else if (nType == AVC_FT_FIXNUM)
1338 : {
1339 : /* TYPE 40 attributes are stored with 1 byte per digit
1340 : * in binary format, and as single precision floats in
1341 : * E00 tables, even in double precision coverages.
1342 : */
1343 0 : pszBuf2[0] = '\0';
1344 0 : nLen = AVCPrintRealValue(pszBuf2, AVC_SINGLE_PREC,
1345 : AVCFileTABLE,
1346 : atof((char*)pasFields[i].pszStr));
1347 0 : pszBuf2 += nLen;
1348 : }
1349 0 : else if (nType == AVC_FT_BININT && nSize == 4)
1350 : {
1351 0 : sprintf(pszBuf2, "%11d", pasFields[i].nInt32);
1352 0 : pszBuf2 += 11;
1353 : }
1354 0 : else if (nType == AVC_FT_BININT && nSize == 2)
1355 : {
1356 0 : sprintf(pszBuf2, "%6d", pasFields[i].nInt16);
1357 0 : pszBuf2 += 6;
1358 : }
1359 0 : else if (nType == AVC_FT_BINFLOAT && nSize == 4)
1360 : {
1361 0 : pszBuf2[0] = '\0';
1362 : /* NOTE: The E00 representation for a binary float is
1363 : * defined by its binary size, not by the coverage's
1364 : * precision.
1365 : */
1366 0 : nLen = AVCPrintRealValue(pszBuf2, AVC_SINGLE_PREC,
1367 : AVCFileTABLE,
1368 : pasFields[i].fFloat);
1369 0 : pszBuf2 += nLen;
1370 : }
1371 0 : else if (nType == AVC_FT_BINFLOAT && nSize == 8)
1372 : {
1373 0 : pszBuf2[0] = '\0';
1374 : /* NOTE: The E00 representation for a binary float is
1375 : * defined by its binary size, not by the coverage's
1376 : * precision.
1377 : */
1378 0 : nLen = AVCPrintRealValue(pszBuf2, AVC_DOUBLE_PREC,
1379 : AVCFileTABLE,
1380 : pasFields[i].dDouble);
1381 0 : pszBuf2 += nLen;
1382 : }
1383 : else
1384 : {
1385 : /*-----------------------------------------------------
1386 : * Hummm... unsupported field type...
1387 : *----------------------------------------------------*/
1388 0 : CPLError(CE_Failure, CPLE_NotSupported,
1389 : "Unsupported field type: (type=%d, size=%d)",
1390 : nType, nSize);
1391 0 : return NULL;
1392 : }
1393 : }
1394 :
1395 0 : *pszBuf2 = '\0';
1396 :
1397 : /* Make sure that we remove any embedded NUL characters from the
1398 : * data line before returning it, otherwise we may be accidentally
1399 : * truncating results.
1400 : */
1401 0 : while ( --pszBuf2 >= psInfo->pszBuf+81 )
1402 : {
1403 0 : if ( *pszBuf2 == '\0' )
1404 : {
1405 0 : *pszBuf2 = ' ';
1406 : }
1407 : }
1408 : }
1409 :
1410 0 : if (psInfo->iCurItem < psInfo->numItems)
1411 : {
1412 : /*-------------------------------------------------------------
1413 : * Return the next 80 chars chunk.
1414 : * The first 80 chars of the buffer is used to return
1415 : * one line at a time, and the rest of the buffer (chars 81+)
1416 : * is used to hold the whole record.
1417 : *------------------------------------------------------------*/
1418 0 : nLen = psInfo->numItems - psInfo->iCurItem;
1419 :
1420 0 : if (nLen > 80)
1421 0 : nLen = 80;
1422 :
1423 0 : strncpy(psInfo->pszBuf, psInfo->pszBuf+(81+psInfo->iCurItem), nLen);
1424 0 : psInfo->pszBuf[nLen] = '\0';
1425 :
1426 0 : psInfo->iCurItem += nLen;
1427 :
1428 : /*-------------------------------------------------------------
1429 : * Arc/Info removes spaces at the end of the lines... let's
1430 : * remove them as well since it can reduce the E00 file size.
1431 : *------------------------------------------------------------*/
1432 0 : nLen--;
1433 0 : while(nLen >= 0 && psInfo->pszBuf[nLen] == ' ')
1434 : {
1435 0 : psInfo->pszBuf[nLen] = '\0';
1436 0 : nLen--;
1437 : }
1438 : }
1439 : else
1440 : {
1441 : /* No more lines to generate.
1442 : */
1443 0 : return NULL;
1444 : }
1445 :
1446 0 : return psInfo->pszBuf;
1447 : }
1448 :
|