1 /* $Id: avc_binwr.c,v 1.17 2006/06/14 16:31:28 daniel Exp $
2 *
3 * Name: avc_binwr.c
4 * Project: Arc/Info vector coverage (AVC) E00->BIN conversion library
5 * Language: ANSI C
6 * Purpose: Binary files access functions (write mode).
7 * Author: Daniel Morissette, dmorissette@dmsolutions.ca
8 *
9 **********************************************************************
10 * Copyright (c) 1999-2001, Daniel Morissette
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 **********************************************************************
30 *
31 * $Log: avc_binwr.c,v $
32 * Revision 1.17 2006/06/14 16:31:28 daniel
33 * Added support for AVCCoverPC2 type (bug 1491)
34 *
35 * Revision 1.16 2005/06/03 03:49:58 daniel
36 * Update email address, website url, and copyright dates
37 *
38 * Revision 1.15 2001/07/06 05:09:33 daniel
39 * Removed #ifdef around fseek to fix NT4 drive problem since ANSI-C requires
40 * an fseek() between read and write operations so this applies to Unix too.
41 *
42 * Revision 1.14 2001/07/06 04:25:00 daniel
43 * Fixed a problem writing arc.dir on NT4 networked drives in an empty dir.
44 *
45 * Revision 1.13 2000/10/16 16:13:29 daniel
46 * Fixed sHeader.nPrecision when writing PC TXT files
47 *
48 * Revision 1.12 2000/09/26 21:40:18 daniel
49 * Fixed writing of PC Coverage TXT... they're different from V7 TXT
50 *
51 * Revision 1.11 2000/09/26 20:21:04 daniel
52 * Added AVCCoverPC write
53 *
54 * Revision 1.10 2000/09/22 19:45:20 daniel
55 * Switch to MIT-style license
56 *
57 * Revision 1.9 2000/05/29 15:31:30 daniel
58 * Added Japanese DBCS support
59 *
60 * Revision 1.8 2000/01/10 02:55:12 daniel
61 * Added call to AVCAdjustCaseSensitiveFilename() when creating tables
62 *
63 * Revision 1.7 1999/12/24 07:18:34 daniel
64 * Added PC Arc/Info coverages support
65 *
66 * Revision 1.6 1999/08/26 17:26:09 daniel
67 * Removed printf() messages used in Windows tests
68 *
69 * Revision 1.5 1999/08/23 18:18:51 daniel
70 * Fixed memory leak and some VC++ warnings
71 *
72 * Revision 1.4 1999/06/08 22:08:14 daniel
73 * Modified CreateTable() to overwrite existing arc.dir entries if necessary
74 *
75 * Revision 1.3 1999/06/08 18:24:32 daniel
76 * Fixed some problems with '/' vs '\\' on Windows
77 *
78 * Revision 1.2 1999/05/17 16:17:36 daniel
79 * Added RXP + TXT/TX6/TX7 write support
80 *
81 * Revision 1.1 1999/05/11 02:34:46 daniel
82 * Initial revision
83 *
84 **********************************************************************/
85
86 #include "avc.h"
87
88 #include <ctype.h> /* tolower() */
89
90 /*=====================================================================
91 * Stuff related to writing the binary coverage files
92 *====================================================================*/
93
94 static void _AVCBinWriteCloseTable(AVCBinFile *psFile);
95
96 static AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath,
97 const char *pszCoverName,
98 AVCTableDef *psSrcTableDef,
99 AVCCoverType eCoverType,
100 int nPrecision,
101 AVCDBCSInfo *psDBCSInfo);
102
103 /**********************************************************************
104 * AVCBinWriteCreate()
105 *
106 * Open a coverage file for writing, write a header if applicable, and
107 * initialize the handle to be ready to write objects to the file.
108 *
109 * pszPath is the coverage (or info directory) path, terminated by
110 * a '/' or a '\\'
111 * pszName is the name of the file to create relative to this directory.
112 *
113 * Note: For most file types except tables, passing pszPath="" and
114 * including the coverage path as part of pszName instead would work.
115 *
116 * Returns a valid AVCBinFile handle, or NULL if the file could
117 * not be created.
118 *
119 * AVCBinClose() will eventually have to be called to release the
120 * resources used by the AVCBinFile structure.
121 **********************************************************************/
AVCBinWriteCreate(const char * pszPath,const char * pszName,AVCCoverType eCoverType,AVCFileType eType,int nPrecision,AVCDBCSInfo * psDBCSInfo)122 AVCBinFile *AVCBinWriteCreate(const char *pszPath, const char *pszName,
123 AVCCoverType eCoverType,
124 AVCFileType eType, int nPrecision,
125 AVCDBCSInfo *psDBCSInfo)
126 {
127 AVCBinFile *psFile;
128 char *pszFname = NULL, *pszExt;
129 GBool bCreateIndex = FALSE;
130 int nLen;
131
132 /*-----------------------------------------------------------------
133 * Make sure precision value is valid (AVC_DEFAULT_PREC is NOT valid)
134 *----------------------------------------------------------------*/
135 if (nPrecision!=AVC_SINGLE_PREC && nPrecision!=AVC_DOUBLE_PREC)
136 {
137 CPLError(CE_Failure, CPLE_IllegalArg,
138 "AVCBinWriteCreate(): Invalid precision parameter "
139 "(value must be AVC_SINGLE_PREC or AVC_DOUBLE_PREC)");
140 return NULL;
141 }
142
143 /*-----------------------------------------------------------------
144 * The case of INFO tables is a bit different...
145 * tables have to be created through a separate function.
146 *----------------------------------------------------------------*/
147 if (eType == AVCFileTABLE)
148 {
149 CPLError(CE_Failure, CPLE_AssertionFailed,
150 "AVCBinWriteCreate(): TABLEs must be created using "
151 "AVCBinWriteCreateTable()");
152 return NULL;
153 }
154
155 /*-----------------------------------------------------------------
156 * Alloc and init the AVCBinFile struct.
157 *----------------------------------------------------------------*/
158 psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile));
159
160 psFile->eFileType = eType;
161 psFile->nPrecision = nPrecision;
162
163 psFile->pszFilename = (char*)CPLMalloc((strlen(pszPath)+strlen(pszName)+1)*
164 sizeof(char));
165 sprintf(psFile->pszFilename, "%s%s", pszPath, pszName);
166
167 psFile->eCoverType = eCoverType;
168
169 /*-----------------------------------------------------------------
170 * PRJ files are text files... we won't use the AVCRawBin*()
171 * functions for them... the file will be created and closed
172 * inside AVCBinWritePrj().
173 *----------------------------------------------------------------*/
174 if (eType == AVCFilePRJ)
175 {
176 return psFile;
177 }
178
179 /*-----------------------------------------------------------------
180 * All other file types share a very similar creation method.
181 *----------------------------------------------------------------*/
182 psFile->psRawBinFile = AVCRawBinOpen(psFile->pszFilename, "w",
183 AVC_COVER_BYTE_ORDER(psFile->eCoverType),
184 psDBCSInfo);
185
186 if (psFile->psRawBinFile == NULL)
187 {
188 /* Failed to open file... just return NULL since an error message
189 * has already been issued by AVCRawBinOpen()
190 */
191 CPLFree(psFile->pszFilename);
192 CPLFree(psFile);
193 return NULL;
194 }
195
196 /*-----------------------------------------------------------------
197 * Create an Index file if applicable for current file type.
198 * Yep, we'll have a problem if filenames come in as uppercase, but
199 * this should not happen in a normal situation.
200 * For each type there is 3 possibilities, e.g. "pal", "pal.adf", "ttt.pal"
201 *----------------------------------------------------------------*/
202 pszFname = CPLStrdup(psFile->pszFilename);
203 nLen = strlen(pszFname);
204 if (eType == AVCFileARC &&
205 ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "arc", 3)) ||
206 (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "arc.adf", 7)) ) )
207 {
208 strncpy(pszExt, "arx", 3);
209 bCreateIndex = TRUE;
210 }
211 else if ((eType == AVCFilePAL || eType == AVCFileRPL) &&
212 ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "pal", 3)) ||
213 (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "pal.adf", 7)) ) )
214 {
215 strncpy(pszExt, "pax", 3);
216 bCreateIndex = TRUE;
217 }
218 else if (eType == AVCFileCNT &&
219 ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "cnt", 3)) ||
220 (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "cnt.adf", 7)) ) )
221 {
222 strncpy(pszExt, "cnx", 3);
223 bCreateIndex = TRUE;
224 }
225 else if ((eType == AVCFileTXT || eType == AVCFileTX6) &&
226 ( (nLen>=3 && EQUALN((pszExt=pszFname+nLen-3), "txt", 3)) ||
227 (nLen>=7 && EQUALN((pszExt=pszFname+nLen-7), "txt.adf", 7)) ) )
228 {
229 strncpy(pszExt, "txx", 3);
230 bCreateIndex = TRUE;
231 }
232
233 if (bCreateIndex)
234 {
235 psFile->psIndexFile = AVCRawBinOpen(pszFname, "w",
236 AVC_COVER_BYTE_ORDER(psFile->eCoverType),
237 psDBCSInfo);
238 }
239
240 CPLFree(pszFname);
241
242 /*-----------------------------------------------------------------
243 * Generate the appropriate headers for the main file and its index
244 * if one was created.
245 *----------------------------------------------------------------*/
246 if (AVCBinWriteHeader(psFile) == -1)
247 {
248 /* Failed! Return NULL */
249 AVCBinWriteClose(psFile);
250 psFile = NULL;
251 }
252
253 return psFile;
254 }
255
256
257 /**********************************************************************
258 * _AVCBinWriteHeader()
259 *
260 * (This function is for internal library use... external calls should
261 * go to AVCBinWriteHeader() instead)
262 *
263 * Generate a 100 bytes header using the info in psHeader.
264 *
265 * Note: PC Coverage files have an initial 256 bytes header followed by the
266 * regular 100 bytes header.
267 *
268 * This function assumes that the file pointer is currently located at
269 * the beginning of the file.
270 *
271 * Returns 0 on success or -1 on error.
272 **********************************************************************/
_AVCBinWriteHeader(AVCRawBinFile * psFile,AVCBinHeader * psHeader,AVCCoverType eCoverType)273 int _AVCBinWriteHeader(AVCRawBinFile *psFile, AVCBinHeader *psHeader,
274 AVCCoverType eCoverType)
275 {
276 int nStatus = 0;
277
278 if (eCoverType == AVCCoverPC)
279 {
280 /* PC Coverage header starts with an initial 256 bytes header
281 */
282 AVCRawBinWriteInt16(psFile, 0x0400); /* Signature??? */
283 AVCRawBinWriteInt32(psFile, psHeader->nLength);
284
285 AVCRawBinWriteZeros(psFile, 250);
286 }
287
288 AVCRawBinWriteInt32(psFile, psHeader->nSignature);
289 AVCRawBinWriteInt32(psFile, psHeader->nPrecision);
290 AVCRawBinWriteInt32(psFile, psHeader->nRecordSize);
291 AVCRawBinWriteZeros(psFile, 12);
292 AVCRawBinWriteInt32(psFile, psHeader->nLength);
293
294 /* Pad the rest of the header with zeros
295 */
296 AVCRawBinWriteZeros(psFile, 72);
297
298 if (CPLGetLastErrorNo() != 0)
299 nStatus = -1;
300
301 return nStatus;
302 }
303
304
305 /**********************************************************************
306 * AVCBinWriteHeader()
307 *
308 * Write a header to the specified file using the values that apply to
309 * this file's type. The function simply does nothing if it is called
310 * for a file type that requires no header.
311 *
312 * Returns 0 on success or -1 on error.
313 **********************************************************************/
AVCBinWriteHeader(AVCBinFile * psFile)314 int AVCBinWriteHeader(AVCBinFile *psFile)
315 {
316 AVCBinHeader sHeader;
317 int nStatus=0;
318 GBool bHeader = TRUE;
319
320 /*-----------------------------------------------------------------
321 * Set the appropriate header information for this file type.
322 *----------------------------------------------------------------*/
323 sHeader.nPrecision = sHeader.nRecordSize = sHeader.nLength = 0;
324 sHeader.nSignature = 9994;
325 switch(psFile->eFileType)
326 {
327 case AVCFileARC:
328 sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -1 : 1;
329 break;
330 case AVCFilePAL:
331 case AVCFileRPL:
332 sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -11 : 11;
333 break;
334 case AVCFileLAB:
335 sHeader.nSignature = 9993;
336 sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -2 : 2;
337 sHeader.nRecordSize = (psFile->nPrecision == AVC_DOUBLE_PREC)? 28 : 16;
338 break;
339 case AVCFileCNT:
340 sHeader.nPrecision = (psFile->nPrecision == AVC_DOUBLE_PREC)? -14 : 14;
341 break;
342 case AVCFileTOL:
343 /* single prec: tol.adf has no header
344 * double prec: par.adf has a header
345 */
346 if (psFile->nPrecision == AVC_DOUBLE_PREC)
347 {
348 sHeader.nSignature = 9993;
349 sHeader.nPrecision = 40;
350 sHeader.nRecordSize = 8;
351 }
352 else
353 {
354 bHeader = FALSE;
355 }
356 break;
357 case AVCFileTXT:
358 case AVCFileTX6:
359 if (psFile->eCoverType == AVCCoverPC)
360 sHeader.nPrecision = 1;
361 else
362 sHeader.nPrecision = (psFile->nPrecision==AVC_DOUBLE_PREC)? -67:67;
363 break;
364 default:
365 /* Other file types don't need a header */
366 bHeader = FALSE;
367 }
368
369 /*-----------------------------------------------------------------
370 * Write a header only if applicable.
371 *----------------------------------------------------------------*/
372 if (bHeader)
373 nStatus = _AVCBinWriteHeader(psFile->psRawBinFile, &sHeader,
374 psFile->eCoverType);
375
376 /*-----------------------------------------------------------------
377 * Write a header for the index file... it is identical to the main
378 * file's header.
379 *----------------------------------------------------------------*/
380 if (nStatus == 0 && bHeader && psFile->psIndexFile)
381 nStatus = _AVCBinWriteHeader(psFile->psIndexFile, &sHeader,
382 psFile->eCoverType);
383
384 return nStatus;
385 }
386
387 /**********************************************************************
388 * AVCBinWriteClose()
389 *
390 * Close a coverage file opened for wirting, and release all memory
391 * (object strcut., buffers, etc.) associated with this file.
392 **********************************************************************/
393
AVCBinWriteClose(AVCBinFile * psFile)394 void AVCBinWriteClose(AVCBinFile *psFile)
395 {
396 if (psFile->eFileType == AVCFileTABLE)
397 {
398 _AVCBinWriteCloseTable(psFile);
399 return;
400 }
401
402 /*-----------------------------------------------------------------
403 * Write the file size (nbr of 2 byte words) in the header at
404 * byte 24 in the 100 byte header (only if applicable)
405 * (And write the same value at byte 2-5 in the first header of PC Cover)
406 *----------------------------------------------------------------*/
407 if (psFile->psRawBinFile &&
408 (psFile->eFileType == AVCFileARC ||
409 psFile->eFileType == AVCFilePAL ||
410 psFile->eFileType == AVCFileRPL ||
411 psFile->eFileType == AVCFileLAB ||
412 psFile->eFileType == AVCFileCNT ||
413 psFile->eFileType == AVCFileTXT ||
414 psFile->eFileType == AVCFileTX6 ||
415 (psFile->eFileType == AVCFileTOL &&
416 psFile->nPrecision == AVC_DOUBLE_PREC) ) )
417 {
418 GInt32 n32Size;
419 n32Size = psFile->psRawBinFile->nCurPos/2;
420
421 if (psFile->eCoverType == AVCCoverPC)
422 {
423 /* PC Cover... Pad to multiple of 512 bytes and write 2 headers
424 * extra bytes at EOF are not included in the size written in
425 * header.
426 * The first 256 bytes header is not counted in the file size
427 * written in both headers
428 */
429 n32Size -= 128; /* minus 256 bytes */
430
431 if (psFile->psRawBinFile->nCurPos%512 != 0)
432 AVCRawBinWriteZeros(psFile->psRawBinFile,
433 512 - psFile->psRawBinFile->nCurPos%512);
434
435 VSIFSeek(psFile->psRawBinFile->fp, 2, SEEK_SET);
436 AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size);
437
438 VSIFSeek(psFile->psRawBinFile->fp, 256+24, SEEK_SET);
439 AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size);
440 }
441 else
442 {
443 /* V7 Cover ... only 1 header */
444 VSIFSeek(psFile->psRawBinFile->fp, 24, SEEK_SET);
445 AVCRawBinWriteInt32(psFile->psRawBinFile, n32Size);
446 }
447 }
448
449 AVCRawBinClose(psFile->psRawBinFile);
450 psFile->psRawBinFile = NULL;
451
452 /*-----------------------------------------------------------------
453 * Same for the index file if it exists.
454 *----------------------------------------------------------------*/
455 if (psFile->psIndexFile)
456 {
457 GInt32 n32Size;
458 n32Size = psFile->psIndexFile->nCurPos/2;
459
460 if (psFile->eCoverType == AVCCoverPC)
461 {
462 /* PC Cover... Pad to multiple of 512 bytes and write 2 headers
463 * extra bytes at EOF are not included in the size written in
464 * header
465 */
466 n32Size -= 128; /* minus 256 bytes */
467
468 if (psFile->psIndexFile->nCurPos%512 != 0)
469 AVCRawBinWriteZeros(psFile->psIndexFile,
470 512 - psFile->psIndexFile->nCurPos%512);
471
472 VSIFSeek(psFile->psIndexFile->fp, 2, SEEK_SET);
473 AVCRawBinWriteInt32(psFile->psIndexFile, n32Size);
474
475 VSIFSeek(psFile->psIndexFile->fp, 256+24, SEEK_SET);
476 AVCRawBinWriteInt32(psFile->psIndexFile, n32Size);
477 }
478 else
479 {
480 /* V7 Cover ... only 1 header */
481 VSIFSeek(psFile->psIndexFile->fp, 24, SEEK_SET);
482 AVCRawBinWriteInt32(psFile->psIndexFile, n32Size);
483 }
484
485 AVCRawBinClose(psFile->psIndexFile);
486 psFile->psIndexFile = NULL;
487 }
488
489 CPLFree(psFile->pszFilename);
490
491 CPLFree(psFile);
492 }
493
494
495
496 /**********************************************************************
497 * _AVCBinWriteIndexEntry()
498 *
499 * (This function is for internal library use... the index entries
500 * are automatically handled by the AVCBinWrite*() functions)
501 *
502 * Write an Index Entry at the current position in the file.
503 *
504 * Position is relative to the beginning of the file, including the header.
505 * Both position and size are specified in number of 2 byte words.
506 *
507 * Returns 0 on success or -1 on error.
508 **********************************************************************/
_AVCBinWriteIndexEntry(AVCRawBinFile * psFile,int nPosition,int nSize)509 int _AVCBinWriteIndexEntry(AVCRawBinFile *psFile,
510 int nPosition, int nSize)
511 {
512 AVCRawBinWriteInt32(psFile, nPosition);
513 AVCRawBinWriteInt32(psFile, nSize);
514
515 if (CPLGetLastErrorNo() != 0)
516 return -1;
517
518 return 0;
519 }
520
521 /**********************************************************************
522 * AVCBinWriteObject()
523 *
524 * Write a CNT (Polygon Centroid) structure to the fin object to a
525 * coverage file.
526 *
527 * Simply redirects the call to the right function based on the value
528 * of psFile->eFileType.
529 *
530 * Returns 0 on success or -1 on error.
531 *
532 * If a problem happens, then CPLError() will be called by the lower-level
533 * functions and CPLGetLastErrorNo() can be used to find out what happened.
534 **********************************************************************/
AVCBinWriteObject(AVCBinFile * psFile,void * psObj)535 int AVCBinWriteObject(AVCBinFile *psFile, void *psObj)
536 {
537 int nStatus = 0;
538 switch(psFile->eFileType)
539 {
540 case AVCFileARC:
541 nStatus = AVCBinWriteArc(psFile, (AVCArc *)psObj);
542 break;
543 case AVCFilePAL:
544 case AVCFileRPL:
545 nStatus = AVCBinWritePal(psFile, (AVCPal *)psObj);
546 break;
547 case AVCFileCNT:
548 nStatus = AVCBinWriteCnt(psFile, (AVCCnt *)psObj);
549 break;
550 case AVCFileLAB:
551 nStatus = AVCBinWriteLab(psFile, (AVCLab *)psObj);
552 break;
553 case AVCFileTOL:
554 nStatus = AVCBinWriteTol(psFile, (AVCTol *)psObj);
555 break;
556 case AVCFilePRJ:
557 nStatus = AVCBinWritePrj(psFile, (char **)psObj);
558 break;
559 case AVCFileTXT:
560 case AVCFileTX6:
561 nStatus = AVCBinWriteTxt(psFile, (AVCTxt *)psObj);
562 break;
563 case AVCFileRXP:
564 nStatus = AVCBinWriteRxp(psFile, (AVCRxp *)psObj);
565 break;
566 case AVCFileTABLE:
567 nStatus = AVCBinWriteTableRec(psFile, (AVCField *)psObj);
568 break;
569 default:
570 CPLError(CE_Failure, CPLE_IllegalArg,
571 "AVCBinWriteObject(): Unsupported file type!");
572 nStatus = -1;
573 }
574
575 return nStatus;
576 }
577
578
579 /*=====================================================================
580 * ARC
581 *====================================================================*/
582
583 /**********************************************************************
584 * _AVCBinWriteArc()
585 *
586 * (This function is for internal library use... external calls should
587 * go to AVCBinWriteNextArc() instead)
588 *
589 * Write an Arc structure to the file.
590 *
591 * The contents of the psArc structure is assumed to be valid... this
592 * function performs no validation on the consistency of what it is
593 * given as input.
594 *
595 * Returns 0 on success or -1 on error.
596 **********************************************************************/
_AVCBinWriteArc(AVCRawBinFile * psFile,AVCArc * psArc,int nPrecision,AVCRawBinFile * psIndexFile)597 int _AVCBinWriteArc(AVCRawBinFile *psFile, AVCArc *psArc,
598 int nPrecision, AVCRawBinFile *psIndexFile)
599 {
600 int i, nRecSize, nCurPos;
601
602 nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */
603
604 AVCRawBinWriteInt32(psFile, psArc->nArcId);
605 if (CPLGetLastErrorNo() != 0)
606 return -1;
607
608 /*-----------------------------------------------------------------
609 * Record size is expressed in 2 byte words, and does not count the
610 * first 8 bytes of the ARC entry.
611 *----------------------------------------------------------------*/
612 nRecSize = (6 * 4 + psArc->numVertices*2 *
613 ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2;
614 AVCRawBinWriteInt32(psFile, nRecSize);
615 AVCRawBinWriteInt32(psFile, psArc->nUserId);
616 AVCRawBinWriteInt32(psFile, psArc->nFNode);
617 AVCRawBinWriteInt32(psFile, psArc->nTNode);
618 AVCRawBinWriteInt32(psFile, psArc->nLPoly);
619 AVCRawBinWriteInt32(psFile, psArc->nRPoly);
620 AVCRawBinWriteInt32(psFile, psArc->numVertices);
621
622 if (nPrecision == AVC_SINGLE_PREC)
623 {
624 for(i=0; i<psArc->numVertices; i++)
625 {
626 AVCRawBinWriteFloat(psFile, (float)psArc->pasVertices[i].x);
627 AVCRawBinWriteFloat(psFile, (float)psArc->pasVertices[i].y);
628 }
629 }
630 else
631 {
632 for(i=0; i<psArc->numVertices; i++)
633 {
634 AVCRawBinWriteDouble(psFile, psArc->pasVertices[i].x);
635 AVCRawBinWriteDouble(psFile, psArc->pasVertices[i].y);
636 }
637
638 }
639
640 /*-----------------------------------------------------------------
641 * Write index entry (arx.adf)
642 *----------------------------------------------------------------*/
643 if (psIndexFile)
644 {
645 _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize);
646 }
647
648 if (CPLGetLastErrorNo() != 0)
649 return -1;
650
651 return 0;
652 }
653
654 /**********************************************************************
655 * AVCBinWriteArc()
656 *
657 * Write the next Arc structure to the file.
658 *
659 * The contents of the psArc structure is assumed to be valid... this
660 * function performs no validation on the consistency of what it is
661 * given as input.
662 *
663 * Returns 0 on success or -1 on error.
664 *
665 * If a problem happens, then CPLError() will be called by the lower-level
666 * functions and CPLGetLastErrorNo() can be used to find out what happened.
667 **********************************************************************/
AVCBinWriteArc(AVCBinFile * psFile,AVCArc * psArc)668 int AVCBinWriteArc(AVCBinFile *psFile, AVCArc *psArc)
669 {
670 if (psFile->eFileType != AVCFileARC)
671 return -1;
672
673 return _AVCBinWriteArc(psFile->psRawBinFile, psArc,
674 psFile->nPrecision, psFile->psIndexFile);
675 }
676
677
678 /*=====================================================================
679 * PAL
680 *====================================================================*/
681
682 /**********************************************************************
683 * _AVCBinWritePal()
684 *
685 * (This function is for internal library use... external calls should
686 * go to AVCBinWritePal() instead)
687 *
688 * Write a PAL (Polygon Arc List) structure to the file.
689 *
690 * The contents of the psPal structure is assumed to be valid... this
691 * function performs no validation on the consistency of what it is
692 * given as input.
693 *
694 * Returns 0 on success or -1 on error.
695 **********************************************************************/
_AVCBinWritePal(AVCRawBinFile * psFile,AVCPal * psPal,int nPrecision,AVCRawBinFile * psIndexFile)696 int _AVCBinWritePal(AVCRawBinFile *psFile, AVCPal *psPal,
697 int nPrecision, AVCRawBinFile *psIndexFile)
698 {
699 int i, nRecSize, nCurPos;
700
701 nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */
702
703 AVCRawBinWriteInt32(psFile, psPal->nPolyId);
704 if (CPLGetLastErrorNo() != 0)
705 return -1;
706
707 /*-----------------------------------------------------------------
708 * Record size is expressed in 2 byte words, and does not count the
709 * first 8 bytes of the PAL entry.
710 *----------------------------------------------------------------*/
711 nRecSize = ( 4 + psPal->numArcs*3 * 4 +
712 4 * ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2;
713
714 AVCRawBinWriteInt32(psFile, nRecSize);
715
716 if (nPrecision == AVC_SINGLE_PREC)
717 {
718 AVCRawBinWriteFloat(psFile, (float)psPal->sMin.x);
719 AVCRawBinWriteFloat(psFile, (float)psPal->sMin.y);
720 AVCRawBinWriteFloat(psFile, (float)psPal->sMax.x);
721 AVCRawBinWriteFloat(psFile, (float)psPal->sMax.y);
722 }
723 else
724 {
725 AVCRawBinWriteDouble(psFile, psPal->sMin.x);
726 AVCRawBinWriteDouble(psFile, psPal->sMin.y);
727 AVCRawBinWriteDouble(psFile, psPal->sMax.x);
728 AVCRawBinWriteDouble(psFile, psPal->sMax.y);
729 }
730
731 AVCRawBinWriteInt32(psFile, psPal->numArcs);
732
733 for(i=0; i<psPal->numArcs; i++)
734 {
735 AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nArcId);
736 AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nFNode);
737 AVCRawBinWriteInt32(psFile, psPal->pasArcs[i].nAdjPoly);
738 }
739
740 /*-----------------------------------------------------------------
741 * Write index entry (pax.adf)
742 *----------------------------------------------------------------*/
743 if (psIndexFile)
744 {
745 _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize);
746 }
747
748 if (CPLGetLastErrorNo() != 0)
749 return -1;
750
751 return 0;
752 }
753
754 /**********************************************************************
755 * AVCBinWritePal()
756 *
757 * Write a PAL (Polygon Arc List) structure to the file.
758 *
759 * The contents of the psPal structure is assumed to be valid... this
760 * function performs no validation on the consistency of what it is
761 * given as input.
762 *
763 * Returns 0 on success or -1 on error.
764 *
765 * If a problem happens, then CPLError() will be called by the lower-level
766 * functions and CPLGetLastErrorNo() can be used to find out what happened.
767 **********************************************************************/
AVCBinWritePal(AVCBinFile * psFile,AVCPal * psPal)768 int AVCBinWritePal(AVCBinFile *psFile, AVCPal *psPal)
769 {
770 if (psFile->eFileType != AVCFilePAL && psFile->eFileType != AVCFileRPL)
771 return -1;
772
773 return _AVCBinWritePal(psFile->psRawBinFile, psPal,
774 psFile->nPrecision, psFile->psIndexFile);
775 }
776
777 /*=====================================================================
778 * CNT
779 *====================================================================*/
780
781 /**********************************************************************
782 * _AVCBinWriteCnt()
783 *
784 * (This function is for internal library use... external calls should
785 * go to AVCBinWriteCnt() instead)
786 *
787 * Write a CNT (Polygon Centroid) structure to the file.
788 *
789 * Returns 0 on success or -1 on error.
790 **********************************************************************/
_AVCBinWriteCnt(AVCRawBinFile * psFile,AVCCnt * psCnt,int nPrecision,AVCRawBinFile * psIndexFile)791 int _AVCBinWriteCnt(AVCRawBinFile *psFile, AVCCnt *psCnt,
792 int nPrecision, AVCRawBinFile *psIndexFile)
793 {
794 int i, nRecSize, nCurPos;
795
796 nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */
797
798 AVCRawBinWriteInt32(psFile, psCnt->nPolyId);
799 if (CPLGetLastErrorNo() != 0)
800 return -1;
801
802 /*-----------------------------------------------------------------
803 * Record size is expressed in 2 byte words, and does not count the
804 * first 8 bytes of the CNT entry.
805 *----------------------------------------------------------------*/
806 nRecSize = ( 4 + psCnt->numLabels * 4 +
807 2 * ((nPrecision == AVC_SINGLE_PREC)? 4 : 8)) / 2;
808
809 AVCRawBinWriteInt32(psFile, nRecSize);
810
811 if (nPrecision == AVC_SINGLE_PREC)
812 {
813 AVCRawBinWriteFloat(psFile, (float)psCnt->sCoord.x);
814 AVCRawBinWriteFloat(psFile, (float)psCnt->sCoord.y);
815 }
816 else
817 {
818 AVCRawBinWriteDouble(psFile, psCnt->sCoord.x);
819 AVCRawBinWriteDouble(psFile, psCnt->sCoord.y);
820 }
821
822 AVCRawBinWriteInt32(psFile, psCnt->numLabels);
823
824 for(i=0; i<psCnt->numLabels; i++)
825 {
826 AVCRawBinWriteInt32(psFile, psCnt->panLabelIds[i]);
827 }
828
829 /*-----------------------------------------------------------------
830 * Write index entry (cnx.adf)
831 *----------------------------------------------------------------*/
832 if (psIndexFile)
833 {
834 _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize);
835 }
836
837 if (CPLGetLastErrorNo() != 0)
838 return -1;
839
840 return 0;
841 }
842
843 /**********************************************************************
844 * AVCBinWriteCnt()
845 *
846 * Write a CNT (Polygon Centroid) structure to the file.
847 *
848 * The contents of the psCnt structure is assumed to be valid... this
849 * function performs no validation on the consistency of what it is
850 * given as input.
851 *
852 * Returns 0 on success or -1 on error.
853 *
854 * If a problem happens, then CPLError() will be called by the lower-level
855 * functions and CPLGetLastErrorNo() can be used to find out what happened.
856 **********************************************************************/
AVCBinWriteCnt(AVCBinFile * psFile,AVCCnt * psCnt)857 int AVCBinWriteCnt(AVCBinFile *psFile, AVCCnt *psCnt)
858 {
859 if (psFile->eFileType != AVCFileCNT)
860 return -1;
861
862 return _AVCBinWriteCnt(psFile->psRawBinFile, psCnt,
863 psFile->nPrecision, psFile->psIndexFile);
864 }
865
866 /*=====================================================================
867 * LAB
868 *====================================================================*/
869
870 /**********************************************************************
871 * _AVCBinWriteLab()
872 *
873 * (This function is for internal library use... external calls should
874 * go to AVCBinWriteLab() instead)
875 *
876 * Write a LAB (Centroid Label) structure to the file.
877 *
878 * The contents of the psLab structure is assumed to be valid... this
879 * function performs no validation on the consistency of what it is
880 * given as input.
881 *
882 * Returns 0 on success or -1 on error.
883 **********************************************************************/
_AVCBinWriteLab(AVCRawBinFile * psFile,AVCLab * psLab,int nPrecision)884 int _AVCBinWriteLab(AVCRawBinFile *psFile, AVCLab *psLab,
885 int nPrecision)
886 {
887
888 AVCRawBinWriteInt32(psFile, psLab->nValue);
889 if (CPLGetLastErrorNo() != 0)
890 return -1;
891
892 AVCRawBinWriteInt32(psFile, psLab->nPolyId);
893
894 if (nPrecision == AVC_SINGLE_PREC)
895 {
896 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord1.x);
897 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord1.y);
898 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord2.x);
899 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord2.y);
900 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord3.x);
901 AVCRawBinWriteFloat(psFile, (float)psLab->sCoord3.y);
902 }
903 else
904 {
905 AVCRawBinWriteDouble(psFile, psLab->sCoord1.x);
906 AVCRawBinWriteDouble(psFile, psLab->sCoord1.y);
907 AVCRawBinWriteDouble(psFile, psLab->sCoord2.x);
908 AVCRawBinWriteDouble(psFile, psLab->sCoord2.y);
909 AVCRawBinWriteDouble(psFile, psLab->sCoord3.x);
910 AVCRawBinWriteDouble(psFile, psLab->sCoord3.y);
911 }
912
913 if (CPLGetLastErrorNo() != 0)
914 return -1;
915
916 return 0;
917 }
918
919
920 /**********************************************************************
921 * AVCBinWriteLab()
922 *
923 * Write a LAB (Centroid Label) structure to the file.
924 *
925 * The contents of the psLab structure is assumed to be valid... this
926 * function performs no validation on the consistency of what it is
927 * given as input.
928 *
929 * Returns 0 on success or -1 on error.
930 *
931 * If a problem happens, then CPLError() will be called by the lower-level
932 * functions and CPLGetLastErrorNo() can be used to find out what happened.
933 **********************************************************************/
AVCBinWriteLab(AVCBinFile * psFile,AVCLab * psLab)934 int AVCBinWriteLab(AVCBinFile *psFile, AVCLab *psLab)
935 {
936 if (psFile->eFileType != AVCFileLAB)
937 return -1;
938
939 return _AVCBinWriteLab(psFile->psRawBinFile, psLab,
940 psFile->nPrecision);
941 }
942
943 /*=====================================================================
944 * TOL
945 *====================================================================*/
946
947 /**********************************************************************
948 * _AVCBinWriteTol()
949 *
950 * (This function is for internal library use... external calls should
951 * go to AVCBinWriteTol() instead)
952 *
953 * Write a TOL (tolerance) structure to the file.
954 *
955 * The contents of the psTol structure is assumed to be valid... this
956 * function performs no validation on the consistency of what it is
957 * given as input.
958 *
959 * Returns 0 on success or -1 on error.
960 **********************************************************************/
_AVCBinWriteTol(AVCRawBinFile * psFile,AVCTol * psTol,int nPrecision)961 int _AVCBinWriteTol(AVCRawBinFile *psFile, AVCTol *psTol,
962 int nPrecision)
963 {
964
965 AVCRawBinWriteInt32(psFile, psTol->nIndex);
966 if (CPLGetLastErrorNo() != 0)
967 return -1;
968
969 AVCRawBinWriteInt32(psFile, psTol->nFlag);
970
971 if (nPrecision == AVC_SINGLE_PREC)
972 {
973 AVCRawBinWriteFloat(psFile, (float)psTol->dValue);
974 }
975 else
976 {
977 AVCRawBinWriteDouble(psFile, psTol->dValue);
978 }
979
980 if (CPLGetLastErrorNo() != 0)
981 return -1;
982
983 return 0;
984 }
985
986 /**********************************************************************
987 * AVCBinWriteTol()
988 *
989 * Write a TOL (tolerance) structure to the file.
990 *
991 * The contents of the psTol structure is assumed to be valid... this
992 * function performs no validation on the consistency of what it is
993 * given as input.
994 *
995 * Returns 0 on success or -1 on error.
996 *
997 * If a problem happens, then CPLError() will be called by the lower-level
998 * functions and CPLGetLastErrorNo() can be used to find out what happened.
999 **********************************************************************/
AVCBinWriteTol(AVCBinFile * psFile,AVCTol * psTol)1000 int AVCBinWriteTol(AVCBinFile *psFile, AVCTol *psTol)
1001 {
1002 if (psFile->eFileType != AVCFileTOL)
1003 return -1;
1004
1005 return _AVCBinWriteTol(psFile->psRawBinFile, psTol,
1006 psFile->nPrecision);
1007 }
1008
1009 /*=====================================================================
1010 * PRJ
1011 *====================================================================*/
1012
1013 /**********************************************************************
1014 * AVCBinWritePrj()
1015 *
1016 * Write a PRJ (Projection info) to the file.
1017 *
1018 * Since a PRJ file is a simple text file and there is only ONE projection
1019 * info per prj.adf file, this function behaves differently from the
1020 * other ones... all the job is done here, including creating and closing
1021 * the output file.
1022 *
1023 * The contents of the papszPrj is assumed to be valid... this
1024 * function performs no validation on the consistency of what it is
1025 * given as input.
1026 *
1027 * Returns 0 on success or -1 on error.
1028 *
1029 * If a problem happens, then CPLError() will be called by the lower-level
1030 * functions and CPLGetLastErrorNo() can be used to find out what happened.
1031 **********************************************************************/
AVCBinWritePrj(AVCBinFile * psFile,char ** papszPrj)1032 int AVCBinWritePrj(AVCBinFile *psFile, char **papszPrj)
1033 {
1034 if (psFile->eFileType != AVCFilePRJ)
1035 return -1;
1036
1037 CSLSave(papszPrj, psFile->pszFilename);
1038
1039 if (CPLGetLastErrorNo() != 0)
1040 return -1;
1041
1042 return 0;
1043 }
1044
1045
1046 /*=====================================================================
1047 * TXT/TX6/TX7
1048 *====================================================================*/
1049
1050 /**********************************************************************
1051 * _AVCBinWriteTxt()
1052 *
1053 * (This function is for internal library use... external calls should
1054 * go to AVCBinWriteTxt() instead)
1055 *
1056 * Write a TXT/TX6/TX7 (Annotation) structure to the file.
1057 *
1058 * The contents of the psTxt structure is assumed to be valid... this
1059 * function performs no validation on the consistency of what it is
1060 * given as input.
1061 *
1062 * Returns 0 on success or -1 on error.
1063 **********************************************************************/
_AVCBinWriteTxt(AVCRawBinFile * psFile,AVCTxt * psTxt,int nPrecision,AVCRawBinFile * psIndexFile)1064 int _AVCBinWriteTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
1065 int nPrecision, AVCRawBinFile *psIndexFile)
1066 {
1067 int i, nRecSize, nCurPos, nStrLen, numVertices;
1068
1069 nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */
1070
1071 AVCRawBinWriteInt32(psFile, psTxt->nTxtId);
1072 if (CPLGetLastErrorNo() != 0)
1073 return -1;
1074
1075 /*-----------------------------------------------------------------
1076 * Record size is expressed in 2 byte words, and does not count the
1077 * first 8 bytes of the TXT entry.
1078 *----------------------------------------------------------------*/
1079 /* String uses a multiple of 4 bytes of storage */
1080 if (psTxt->pszText)
1081 nStrLen = ((strlen(psTxt->pszText) + 3)/4)*4;
1082 else
1083 nStrLen = 0;
1084
1085 numVertices = ABS(psTxt->numVerticesLine) + ABS(psTxt->numVerticesArrow);
1086 nRecSize = (112 + 8 + nStrLen +
1087 (numVertices*2+3)* ((nPrecision == AVC_SINGLE_PREC)?4:8)) / 2;
1088
1089 AVCRawBinWriteInt32(psFile, nRecSize);
1090
1091 AVCRawBinWriteInt32(psFile, psTxt->nUserId );
1092 AVCRawBinWriteInt32(psFile, psTxt->nLevel );
1093 AVCRawBinWriteFloat(psFile, psTxt->f_1e2 );
1094 AVCRawBinWriteInt32(psFile, psTxt->nSymbol );
1095 AVCRawBinWriteInt32(psFile, psTxt->numVerticesLine );
1096 AVCRawBinWriteInt32(psFile, psTxt->n28 );
1097 AVCRawBinWriteInt32(psFile, psTxt->numChars );
1098 AVCRawBinWriteInt32(psFile, psTxt->numVerticesArrow );
1099
1100 for(i=0; i<20; i++)
1101 {
1102 AVCRawBinWriteInt16(psFile, psTxt->anJust1[i] );
1103 }
1104 for(i=0; i<20; i++)
1105 {
1106 AVCRawBinWriteInt16(psFile, psTxt->anJust2[i] );
1107 }
1108
1109 if (nPrecision == AVC_SINGLE_PREC)
1110 {
1111 AVCRawBinWriteFloat(psFile, (float)psTxt->dHeight);
1112 AVCRawBinWriteFloat(psFile, (float)psTxt->dV2);
1113 AVCRawBinWriteFloat(psFile, (float)psTxt->dV3);
1114 }
1115 else
1116 {
1117 AVCRawBinWriteDouble(psFile, psTxt->dHeight);
1118 AVCRawBinWriteDouble(psFile, psTxt->dV2);
1119 AVCRawBinWriteDouble(psFile, psTxt->dV3);
1120 }
1121
1122 if (nStrLen > 0)
1123 AVCRawBinWritePaddedString(psFile, nStrLen, psTxt->pszText);
1124
1125 if (nPrecision == AVC_SINGLE_PREC)
1126 {
1127 for(i=0; i<numVertices; i++)
1128 {
1129 AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i].x);
1130 AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i].y);
1131 }
1132 }
1133 else
1134 {
1135 for(i=0; i<numVertices; i++)
1136 {
1137 AVCRawBinWriteDouble(psFile, psTxt->pasVertices[i].x);
1138 AVCRawBinWriteDouble(psFile, psTxt->pasVertices[i].y);
1139 }
1140 }
1141
1142 AVCRawBinWriteZeros(psFile, 8);
1143
1144 /*-----------------------------------------------------------------
1145 * Write index entry (cnx.adf)
1146 *----------------------------------------------------------------*/
1147 if (psIndexFile)
1148 {
1149 _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize);
1150 }
1151
1152 if (CPLGetLastErrorNo() != 0)
1153 return -1;
1154
1155 return 0;
1156 }
1157
1158 /**********************************************************************
1159 * _AVCBinWritePCCoverageTxt()
1160 *
1161 * (This function is for internal library use... external calls should
1162 * go to AVCBinWriteTxt() instead)
1163 *
1164 * Write a TXT (Annotation) structure to a AVCCoverPC file.
1165 *
1166 * The contents of the psTxt structure is assumed to be valid... this
1167 * function performs no validation on the consistency of what it is
1168 * given as input.
1169 *
1170 * This function assumes that PC Coverages are always single precision.
1171 *
1172 * Returns 0 on success or -1 on error.
1173 **********************************************************************/
_AVCBinWritePCCoverageTxt(AVCRawBinFile * psFile,AVCTxt * psTxt,int nPrecision,AVCRawBinFile * psIndexFile)1174 int _AVCBinWritePCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
1175 int nPrecision, AVCRawBinFile *psIndexFile)
1176 {
1177 int i, nRecSize, nCurPos, nStrLen, numVertices;
1178
1179 CPLAssert(nPrecision == AVC_SINGLE_PREC);
1180
1181 nCurPos = psFile->nCurPos/2; /* Value in 2 byte words */
1182
1183 AVCRawBinWriteInt32(psFile, psTxt->nTxtId);
1184 if (CPLGetLastErrorNo() != 0)
1185 return -1;
1186
1187 /*-----------------------------------------------------------------
1188 * Record size is expressed in 2 byte words, and does not count the
1189 * first 8 bytes of the TXT entry.
1190 *----------------------------------------------------------------*/
1191 /* String uses a multiple of 4 bytes of storage,
1192 * And if text is already a multiple of 4 bytes then we include 4 extra
1193 * spaces anyways (was probably a bug in the software!).
1194 */
1195 if (psTxt->pszText)
1196 nStrLen = ((strlen(psTxt->pszText) + 4)/4)*4;
1197 else
1198 nStrLen = 4;
1199
1200 nRecSize = (92 - 8 + nStrLen) / 2;
1201
1202 AVCRawBinWriteInt32(psFile, nRecSize);
1203 AVCRawBinWriteInt32(psFile, psTxt->nLevel );
1204
1205 /*-----------------------------------------------------------------
1206 * Number of vertices to write:
1207 * Note that because of the way V7 binary TXT files work, the rest of the
1208 * lib expects to receive duplicate coords for the first vertex, so
1209 * we will also receive an additional vertex for that but we won't write
1210 * it. We also ignore the arrow vertices if there is any.
1211 *----------------------------------------------------------------*/
1212 numVertices = ABS(psTxt->numVerticesLine) -1;
1213 numVertices = MIN(4, numVertices); /* Maximum of 4 points */
1214
1215 AVCRawBinWriteInt32(psFile, numVertices );
1216
1217 for(i=0; i<numVertices; i++)
1218 {
1219 AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i+1].x);
1220 AVCRawBinWriteFloat(psFile, (float)psTxt->pasVertices[i+1].y);
1221 }
1222
1223 AVCRawBinWriteZeros(psFile, (4-numVertices)*4*2 + 28);
1224
1225 AVCRawBinWriteFloat(psFile, (float)psTxt->dHeight);
1226 AVCRawBinWriteFloat(psFile, psTxt->f_1e2 );
1227 AVCRawBinWriteInt32(psFile, psTxt->nSymbol );
1228 AVCRawBinWriteInt32(psFile, psTxt->numChars );
1229
1230 if (nStrLen > 0)
1231 AVCRawBinWritePaddedString(psFile, nStrLen, psTxt->pszText);
1232
1233 /*-----------------------------------------------------------------
1234 * Write index entry (cnx.adf)
1235 *----------------------------------------------------------------*/
1236 if (psIndexFile)
1237 {
1238 _AVCBinWriteIndexEntry(psIndexFile, nCurPos, nRecSize);
1239 }
1240
1241 if (CPLGetLastErrorNo() != 0)
1242 return -1;
1243
1244 return 0;
1245 }
1246
1247
1248 /**********************************************************************
1249 * AVCBinWriteTxt()
1250 *
1251 * Write a TXT/TX6/TX7 (Annotation) structure to the file.
1252 *
1253 * The contents of the psTxt structure is assumed to be valid... this
1254 * function performs no validation on the consistency of what it is
1255 * given as input.
1256 *
1257 * Returns 0 on success or -1 on error.
1258 *
1259 * If a problem happens, then CPLError() will be called by the lower-level
1260 * functions and CPLGetLastErrorNo() can be used to find out what happened.
1261 **********************************************************************/
AVCBinWriteTxt(AVCBinFile * psFile,AVCTxt * psTxt)1262 int AVCBinWriteTxt(AVCBinFile *psFile, AVCTxt *psTxt)
1263 {
1264 if (psFile->eFileType != AVCFileTXT && psFile->eFileType != AVCFileTX6)
1265 return -1;
1266
1267 /* AVCCoverPC and AVCCoverWeird have a different TXT format than AVCCoverV7
1268 */
1269 if (psFile->eCoverType == AVCCoverPC ||
1270 psFile->eCoverType == AVCCoverWeird)
1271 {
1272 return _AVCBinWritePCCoverageTxt(psFile->psRawBinFile, psTxt,
1273 psFile->nPrecision,
1274 psFile->psIndexFile);
1275 }
1276 else
1277 {
1278 return _AVCBinWriteTxt(psFile->psRawBinFile, psTxt,
1279 psFile->nPrecision, psFile->psIndexFile);
1280 }
1281 }
1282
1283 /*=====================================================================
1284 * RXP
1285 *====================================================================*/
1286
1287 /**********************************************************************
1288 * _AVCBinWriteRxp()
1289 *
1290 * (This function is for internal library use... external calls should
1291 * go to AVCBinWriteRxp() instead)
1292 *
1293 * Write a RXP (Region something...) structure to the file.
1294 *
1295 * The contents of the psRxp structure is assumed to be valid... this
1296 * function performs no validation on the consistency of what it is
1297 * given as input.
1298 *
1299 * Returns 0 on success or -1 on error.
1300 **********************************************************************/
_AVCBinWriteRxp(AVCRawBinFile * psFile,AVCRxp * psRxp,int nPrecision)1301 int _AVCBinWriteRxp(AVCRawBinFile *psFile, AVCRxp *psRxp,
1302 int nPrecision)
1303 {
1304
1305 AVCRawBinWriteInt32(psFile, psRxp->n1);
1306 if (CPLGetLastErrorNo() != 0)
1307 return -1;
1308
1309 AVCRawBinWriteInt32(psFile, psRxp->n2);
1310
1311 if (CPLGetLastErrorNo() != 0)
1312 return -1;
1313
1314 return 0;
1315 }
1316
1317 /**********************************************************************
1318 * AVCBinWriteRxp()
1319 *
1320 * Write a RXP (Region something...) structure to the file.
1321 *
1322 * The contents of the psRxp structure is assumed to be valid... this
1323 * function performs no validation on the consistency of what it is
1324 * given as input.
1325 *
1326 * Returns 0 on success or -1 on error.
1327 *
1328 * If a problem happens, then CPLError() will be called by the lower-level
1329 * functions and CPLGetLastErrorNo() can be used to find out what happened.
1330 **********************************************************************/
AVCBinWriteRxp(AVCBinFile * psFile,AVCRxp * psRxp)1331 int AVCBinWriteRxp(AVCBinFile *psFile, AVCRxp *psRxp)
1332 {
1333 if (psFile->eFileType != AVCFileRXP)
1334 return -1;
1335
1336 return _AVCBinWriteRxp(psFile->psRawBinFile, psRxp,
1337 psFile->nPrecision);
1338 }
1339
1340
1341 /*=====================================================================
1342 * TABLES
1343 *====================================================================*/
1344
1345 /**********************************************************************
1346 * _AVCBinWriteArcDir()
1347 *
1348 * (This function is for internal library use... external calls should
1349 * go to AVCBinWriteCreateTable() instead)
1350 *
1351 * Write an ARC.DIR entry at the current position in file.
1352 *
1353 * The contents of the psTableDef structure is assumed to be valid... this
1354 * function performs no validation on the consistency of what it is
1355 * given as input.
1356 *
1357 * Returns 0 on success or -1 on error.
1358 **********************************************************************/
_AVCBinWriteArcDir(AVCRawBinFile * psFile,AVCTableDef * psTableDef)1359 int _AVCBinWriteArcDir(AVCRawBinFile *psFile, AVCTableDef *psTableDef)
1360 {
1361 /* STRING values MUST be padded with spaces.
1362 */
1363 AVCRawBinWritePaddedString(psFile, 32, psTableDef->szTableName);
1364 if (CPLGetLastErrorNo() != 0)
1365 return -1;
1366
1367 AVCRawBinWritePaddedString(psFile, 8, psTableDef->szInfoFile);
1368
1369 AVCRawBinWriteInt16(psFile, psTableDef->numFields);
1370
1371 /* Record size must be a multiple of 2 bytes */
1372 AVCRawBinWriteInt16(psFile, (GInt16)(((psTableDef->nRecSize+1)/2)*2));
1373
1374 /* ??? Unknown values ??? */
1375 AVCRawBinWritePaddedString(psFile, 16, " ");
1376 AVCRawBinWriteInt16(psFile, 132);
1377 AVCRawBinWriteInt16(psFile, 0);
1378
1379 AVCRawBinWriteInt32(psFile, psTableDef->numRecords);
1380
1381 AVCRawBinWriteZeros(psFile, 10);
1382
1383 AVCRawBinWritePaddedString(psFile, 2, psTableDef->szExternal);
1384
1385 AVCRawBinWriteZeros(psFile, 238);
1386 AVCRawBinWritePaddedString(psFile, 8, " ");
1387 AVCRawBinWriteZeros(psFile, 54);
1388
1389 if (CPLGetLastErrorNo() != 0)
1390 return -1;
1391
1392 return 0;
1393 }
1394
1395
1396 /**********************************************************************
1397 * _AVCBinWriteArcNit()
1398 *
1399 * (This function is for internal library use... external calls should
1400 * go to AVCBinWriteCreateTable() instead)
1401 *
1402 * Write an ARC####.NIT entry at the current position in file.
1403 *
1404 * The contents of the psTableDef structure is assumed to be valid... this
1405 * function performs no validation on the consistency of what it is
1406 * given as input.
1407 *
1408 * Returns 0 on success or -1 on error.
1409 **********************************************************************/
_AVCBinWriteArcNit(AVCRawBinFile * psFile,AVCFieldInfo * psField)1410 int _AVCBinWriteArcNit(AVCRawBinFile *psFile, AVCFieldInfo *psField)
1411 {
1412 /* STRING values MUST be padded with spaces.
1413 */
1414 AVCRawBinWritePaddedString(psFile, 16, psField->szName);
1415 if (CPLGetLastErrorNo() != 0)
1416 return -1;
1417
1418 AVCRawBinWriteInt16(psFile, psField->nSize);
1419 AVCRawBinWriteInt16(psFile, psField->v2);
1420 AVCRawBinWriteInt16(psFile, psField->nOffset);
1421 AVCRawBinWriteInt16(psFile, psField->v4);
1422 AVCRawBinWriteInt16(psFile, psField->v5);
1423 AVCRawBinWriteInt16(psFile, psField->nFmtWidth);
1424 AVCRawBinWriteInt16(psFile, psField->nFmtPrec);
1425 AVCRawBinWriteInt16(psFile, psField->nType1);
1426 AVCRawBinWriteInt16(psFile, psField->nType2);
1427 AVCRawBinWriteInt16(psFile, psField->v10);
1428 AVCRawBinWriteInt16(psFile, psField->v11);
1429 AVCRawBinWriteInt16(psFile, psField->v12);
1430 AVCRawBinWriteInt16(psFile, psField->v13);
1431
1432 AVCRawBinWritePaddedString(psFile, 16, psField->szAltName);
1433
1434 AVCRawBinWriteZeros(psFile, 56);
1435
1436 AVCRawBinWriteInt16(psFile, psField->nIndex);
1437
1438 AVCRawBinWriteZeros(psFile, 28);
1439
1440 if (CPLGetLastErrorNo() != 0)
1441 return -1;
1442
1443 return 0;
1444 }
1445
1446
1447 /**********************************************************************
1448 * _AVCBinWriteCreateArcDirEntry()
1449 *
1450 * Add an entry in the ARC.DIR for the table defined in psSrcTableDef.
1451 *
1452 * If an entry with the same table name already exists then this entry
1453 * will be reused and overwritten.
1454 *
1455 * Note: there could be a problem if 2 processes try to add an entry
1456 * at the exact same time... does Arc/Info do any locking on that file???
1457 *
1458 * Returns an integer value corresponding to the new table index (ARC####)
1459 * or -1 if something failed.
1460 **********************************************************************/
1461
1462 /* Prototype for _AVCBinReadNextArcDir() from avc_bin.c
1463 */
1464 int _AVCBinReadNextArcDir(AVCRawBinFile *psFile, AVCTableDef *psArcDir);
1465
_AVCBinWriteCreateArcDirEntry(const char * pszArcDirFile,AVCTableDef * psTableDef,AVCDBCSInfo * psDBCSInfo)1466 int _AVCBinWriteCreateArcDirEntry(const char *pszArcDirFile,
1467 AVCTableDef *psTableDef,
1468 AVCDBCSInfo *psDBCSInfo)
1469 {
1470 int iEntry, numDirEntries=0, nTableIndex = 0;
1471 VSIStatBuf sStatBuf;
1472 AVCRawBinFile *hRawBinFile;
1473 GBool bFound;
1474 AVCTableDef sEntry;
1475
1476 /*-----------------------------------------------------------------
1477 * Open and Scan the ARC.DIR to establish the table index (ARC####)
1478 *----------------------------------------------------------------*/
1479 #ifdef _WIN32
1480 /*-----------------------------------------------------------------
1481 * Note, DM, 20010507 - We used to use VSIFStat() to establish the
1482 * size of arc.dir, but when working on a WinNT4 networked drive, the
1483 * stat() information was not always right, and we sometimes ended
1484 * up overwriting arc.dir entries. The solution: open and scan arc.dir
1485 * until EOF to establish its size.
1486 * That trick also seems to fix another network buffer problem: when
1487 * writing a coverage in a new empty dir (with no info dir yet), we
1488 * would get an error in fwrite() while writing the 3rd arc.dir
1489 * entry of the coverage. That second problem could also have been
1490 * fixed by forcing a VSIFSeek() before the first fwrite()... we've
1491 * added it below.
1492 *----------------------------------------------------------------*/
1493 FILE *fp;
1494 if ((fp = VSIFOpen(pszArcDirFile, "r")) != NULL)
1495 {
1496 char buf[380];
1497 while (!VSIFEof(fp))
1498 {
1499 if (VSIFRead(buf, 380, 1, fp) == 1)
1500 numDirEntries++;
1501 }
1502 VSIFClose(fp);
1503 hRawBinFile = AVCRawBinOpen(pszArcDirFile, "r+",
1504 AVC_COVER_BYTE_ORDER(AVCCoverV7),
1505 psDBCSInfo);
1506 }
1507 else
1508 #endif
1509 /* On Unix we can still use fstat() */
1510 if ( VSIStat(pszArcDirFile, &sStatBuf) != -1 )
1511 {
1512 numDirEntries = sStatBuf.st_size/380;
1513 hRawBinFile = AVCRawBinOpen(pszArcDirFile, "r+",
1514 AVC_COVER_BYTE_ORDER(AVCCoverV7),
1515 psDBCSInfo);
1516 }
1517 else
1518 {
1519 numDirEntries = 0;
1520 hRawBinFile = AVCRawBinOpen(pszArcDirFile, "w",
1521 AVC_COVER_BYTE_ORDER(AVCCoverV7),
1522 psDBCSInfo);
1523 }
1524
1525 if (hRawBinFile == NULL)
1526 {
1527 /* Failed to open file... just return -1 since an error message
1528 * has already been issued by AVCRawBinOpen()
1529 */
1530 return -1;
1531 }
1532
1533 /* Init nTableIndex at -1 so that first table created should have
1534 * index 0
1535 */
1536 nTableIndex = -1;
1537 iEntry = 0;
1538 bFound = FALSE;
1539 while(!bFound && iEntry<numDirEntries &&
1540 _AVCBinReadNextArcDir(hRawBinFile, &sEntry) == 0)
1541 {
1542 nTableIndex = atoi(sEntry.szInfoFile+3);
1543 if (EQUALN(psTableDef->szTableName, sEntry.szTableName,
1544 strlen(psTableDef->szTableName)))
1545 {
1546 bFound = TRUE;
1547 break;
1548 }
1549 iEntry++;
1550 }
1551
1552 /*-----------------------------------------------------------------
1553 * Reposition the file pointer and write the entry.
1554 *
1555 * We use VSIFSeek() directly since the AVCRawBin*() functions do
1556 * not support random access yet... it is OK to do so here since the
1557 * ARC.DIR does not have a header and we will close it right away.
1558 *----------------------------------------------------------------*/
1559 if (bFound)
1560 VSIFSeek(hRawBinFile->fp, iEntry*380, SEEK_SET);
1561 else
1562 {
1563 /* Not found... Use the next logical table index */
1564 nTableIndex++;
1565
1566 /* We're already at EOF so we shouldn't need to fseek here, but
1567 * ANSI-C requires that a file positioning function be called
1568 * between read and writes... this had never been a problem before
1569 * on any system except with NT4 network drives.
1570 */
1571 VSIFSeek(hRawBinFile->fp, numDirEntries*380, SEEK_SET);
1572 }
1573
1574 sprintf(psTableDef->szInfoFile, "ARC%4.4d", nTableIndex);
1575 _AVCBinWriteArcDir(hRawBinFile, psTableDef);
1576
1577 AVCRawBinClose(hRawBinFile);
1578
1579 return nTableIndex;
1580 }
1581
1582
1583 /**********************************************************************
1584 * AVCBinWriteCreateTable()
1585 *
1586 * Open an INFO table for writing:
1587 *
1588 * - Add an entry for the new table in the info/arc.dir
1589 * - Write the attributes definitions to the info/arc####.nit
1590 * - Create the data file, ready to write data records to it
1591 * - If necessary, set the arc####.dat to point to the location of
1592 * the data file.
1593 *
1594 * pszInfoPath is the info directory path, terminated by a '/' or a '\\'
1595 * It is assumed that this 'info' directory already exists and is writable.
1596 *
1597 * psTableDef should contain a valid table definition for this coverage.
1598 * This function will create and maintain its own copy of the structure.
1599 *
1600 * The name of the file to create and its location will be based on the
1601 * table name and the external ("XX") flag values in the psTableDef
1602 * structure, so you have to make sure that these values are valid.
1603 *
1604 * If a table with the same name is already present in the arc.dir, then
1605 * the same arc.dir entry will be used and overwritten. This happens
1606 * when a coverage directory is deleted by hand. The behavior implemented
1607 * here correspond to Arc/Info's behavior.
1608 *
1609 * For internal tables, the data file goes directly in the info directory, so
1610 * there is not much to worry about.
1611 *
1612 * For external tables, the table name is composed of 3 parts:
1613 *
1614 * <COVERNAME>.<EXT><SUBCLASSNAME>
1615 *
1616 * - <COVERNAME>:
1617 * The first part of the table name (before the '.') is the
1618 * name of the coverage to which the table belongs, and the data file
1619 * will be created in this coverage's directory... so it is assumed that
1620 * the directory "../<covername>" already exists and is writable.
1621 * - <EXT>:
1622 * The coverage name is followed by a 3 chars extension that will be
1623 * used to build the name of the external table to create.
1624 * - <SUBCLASSNAME>:
1625 * For some table types, the extension is followed by a subclass name.
1626 *
1627 * When <SUBCLASSNAME> is present, then the data file name will be:
1628 * "../<covername>/<subclassname>.<ext>"
1629 *
1630 * e.g. The table named "TEST.PATCOUNTY" would be stored in the file
1631 * "../test/county.pat" (this path is realtive to the info directory)
1632 *
1633 * When the <SUBCLASSNAME> is not present, then the name of the data file
1634 * will be the "../<covername>/<ext>.adf"
1635 *
1636 * e.g. The table named "TEST.PAT" would be stored in the file
1637 * "../test/pat.adf"
1638 *
1639 * Of course, it would be too easy if there were no exceptions to these
1640 * rules! Single precision ".TIC" and ".BND" follow the above rules and
1641 * will be named "tic.adf" and "bnd.adf" but in double precision coverages,
1642 * they will be named "dbltic.adf" and "dblbnd.adf".
1643 *
1644 * Returns a valid AVCBinFile handle, or NULL if the table could
1645 * not be created.
1646 *
1647 * AVCBinClose() will eventually have to be called to release the
1648 * resources used by the AVCBinFile structure.
1649 **********************************************************************/
AVCBinWriteCreateTable(const char * pszInfoPath,const char * pszCoverName,AVCTableDef * psSrcTableDef,AVCCoverType eCoverType,int nPrecision,AVCDBCSInfo * psDBCSInfo)1650 AVCBinFile *AVCBinWriteCreateTable(const char *pszInfoPath,
1651 const char *pszCoverName,
1652 AVCTableDef *psSrcTableDef,
1653 AVCCoverType eCoverType,
1654 int nPrecision, AVCDBCSInfo *psDBCSInfo)
1655 {
1656 AVCBinFile *psFile;
1657 AVCRawBinFile *hRawBinFile;
1658 AVCTableDef *psTableDef = NULL;
1659 char *pszFname = NULL, szInfoFile[8]="";
1660 int i, nTableIndex = 0;
1661
1662 if (eCoverType == AVCCoverPC || eCoverType == AVCCoverPC2)
1663 return _AVCBinWriteCreateDBFTable(pszInfoPath, pszCoverName,
1664 psSrcTableDef, eCoverType,
1665 nPrecision, psDBCSInfo);
1666
1667 /*-----------------------------------------------------------------
1668 * Make sure precision value is valid (AVC_DEFAULT_PREC is NOT valid)
1669 *----------------------------------------------------------------*/
1670 if (nPrecision!=AVC_SINGLE_PREC && nPrecision!=AVC_DOUBLE_PREC)
1671 {
1672 CPLError(CE_Failure, CPLE_IllegalArg,
1673 "AVCBinWriteCreateTable(): Invalid precision parameter "
1674 "(value must be AVC_SINGLE_PREC or AVC_DOUBLE_PREC)");
1675 return NULL;
1676 }
1677
1678 /* Alloc a buffer big enough for the longest possible filename...
1679 */
1680 pszFname = (char*)CPLMalloc((strlen(pszInfoPath)+81)*sizeof(char));
1681
1682
1683 /*-----------------------------------------------------------------
1684 * Alloc and init the AVCBinFile struct.
1685 *----------------------------------------------------------------*/
1686 psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile));
1687
1688 psFile->eFileType = AVCFileTABLE;
1689 /* Precision is not important for tables */
1690 psFile->nPrecision = nPrecision;
1691 psFile->eCoverType = eCoverType;
1692
1693 psFile->hdr.psTableDef = psTableDef = _AVCDupTableDef(psSrcTableDef);
1694
1695 /*-----------------------------------------------------------------
1696 * Add a record for this table in the "arc.dir"
1697 * Note: there could be a problem if 2 processes try to add an entry
1698 * at the exact same time... does Arc/Info do any locking on that file???
1699 *----------------------------------------------------------------*/
1700 sprintf(pszFname, "%sarc.dir", pszInfoPath);
1701
1702 nTableIndex = _AVCBinWriteCreateArcDirEntry(pszFname, psTableDef,
1703 psDBCSInfo);
1704
1705 if (nTableIndex < 0)
1706 {
1707 /* Failed to add arc.dir entry... just return NULL since an error
1708 * message has already been issued by _AVCBinWriteCreateArcDirEntry()
1709 */
1710 _AVCDestroyTableDef(psTableDef);
1711 CPLFree(psFile);
1712 CPLFree(pszFname);
1713 return NULL;
1714 }
1715
1716 sprintf(szInfoFile, "arc%4.4d", nTableIndex);
1717
1718 /*-----------------------------------------------------------------
1719 * Create the "arc####.nit" with the attribute definitions.
1720 *----------------------------------------------------------------*/
1721 sprintf(pszFname, "%s%s.nit", pszInfoPath, szInfoFile);
1722
1723 hRawBinFile = AVCRawBinOpen(pszFname, "w",
1724 AVC_COVER_BYTE_ORDER(AVCCoverV7),
1725 psDBCSInfo);
1726
1727 if (hRawBinFile == NULL)
1728 {
1729 /* Failed to open file... just return NULL since an error message
1730 * has already been issued by AVCRawBinOpen()
1731 */
1732 _AVCDestroyTableDef(psTableDef);
1733 CPLFree(psFile);
1734 CPLFree(pszFname);
1735 return NULL;
1736 }
1737
1738 for(i=0; i<psTableDef->numFields; i++)
1739 {
1740 _AVCBinWriteArcNit(hRawBinFile, &(psTableDef->pasFieldDef[i]));
1741 }
1742
1743 AVCRawBinClose(hRawBinFile);
1744 hRawBinFile = NULL;
1745
1746 /*-----------------------------------------------------------------
1747 * The location of the data file depends on the external flag.
1748 *----------------------------------------------------------------*/
1749 if (EQUAL(psTableDef->szExternal, " "))
1750 {
1751 /*-------------------------------------------------------------
1752 * Internal table: data goes directly in "arc####.dat"
1753 *------------------------------------------------------------*/
1754 psTableDef->szDataFile[0] = '\0';
1755 sprintf(pszFname, "%s%s.dat", pszInfoPath, szInfoFile);
1756 psFile->pszFilename = CPLStrdup(pszFname);
1757 }
1758 else
1759 {
1760 /*-------------------------------------------------------------
1761 * External table: data stored in the coverage directory, and
1762 * the path to the data file is written to "arc####.dat"
1763 *... start by extracting the info to build the data file name...
1764 *------------------------------------------------------------*/
1765 char szCoverName[40]="", szExt[4]="", szSubclass[40]="", *pszPtr;
1766 int nLen;
1767 FILE *fpOut;
1768
1769 nLen = strlen(psTableDef->szTableName);
1770 CPLAssert(nLen <= 32);
1771 if (nLen > 32) return NULL;
1772 pszPtr = psTableDef->szTableName;
1773
1774 for(i=0; *pszPtr!='\0' && *pszPtr!='.' && *pszPtr!=' '; i++, pszPtr++)
1775 {
1776 szCoverName[i] = tolower(*pszPtr);
1777 }
1778 szCoverName[i] = '\0';
1779
1780 if (*pszPtr == '.')
1781 pszPtr++;
1782
1783 for(i=0; i<3 && *pszPtr!='\0' && *pszPtr!=' '; i++, pszPtr++)
1784 {
1785 szExt[i] = tolower(*pszPtr);
1786 }
1787 szExt[i] = '\0';
1788
1789 for(i=0; *pszPtr!='\0' && *pszPtr!=' '; i++, pszPtr++)
1790 {
1791 szSubclass[i] = tolower(*pszPtr);
1792 }
1793 szSubclass[i] = '\0';
1794
1795 /*-------------------------------------------------------------
1796 * ... and build the data file name based on what we extracted
1797 *------------------------------------------------------------*/
1798 if (strlen(szSubclass) == 0)
1799 {
1800 if (nPrecision == AVC_DOUBLE_PREC &&
1801 (EQUAL(szExt, "TIC") || EQUAL(szExt, "BND")) )
1802 {
1803 /* "../<covername>/dbl<ext>.adf" */
1804 sprintf(psTableDef->szDataFile,
1805 "../%s/dbl%s.adf", szCoverName, szExt);
1806 }
1807 else
1808 {
1809 /* "../<covername>/<ext>.adf" */
1810 sprintf(psTableDef->szDataFile,
1811 "../%s/%s.adf", szCoverName, szExt);
1812 }
1813 }
1814 else
1815 {
1816 /* "../<covername>/<subclass>.<ext>" */
1817 sprintf(psTableDef->szDataFile,
1818 "../%s/%s.%s", szCoverName, szSubclass, szExt);
1819 }
1820
1821 /*-------------------------------------------------------------
1822 * Write it to the arc####.dat
1823 * Note that the path that is written in the arc####.dat contains
1824 * '/' as a directory delimiter, even on Windows systems.
1825 *------------------------------------------------------------*/
1826 sprintf(pszFname, "%s%s.dat", pszInfoPath, szInfoFile);
1827 fpOut = VSIFOpen(pszFname, "wt");
1828 if (fpOut)
1829 {
1830 VSIFPrintf(fpOut, "%-80.80s", psTableDef->szDataFile);
1831 VSIFClose(fpOut);
1832 }
1833 else
1834 {
1835 CPLError(CE_Failure, CPLE_OpenFailed,
1836 "Failed creating file %s.", pszFname);
1837 CPLFree(pszFname);
1838 _AVCDestroyTableDef(psTableDef);
1839 CPLFree(psFile);
1840 return NULL;
1841 }
1842
1843 sprintf(pszFname, "%s%s",
1844 pszInfoPath, psTableDef->szDataFile);
1845 psFile->pszFilename = CPLStrdup(pszFname);
1846
1847 #ifdef WIN32
1848 /*-------------------------------------------------------------
1849 * On a Windows system, we have to change the '/' to '\\' in the
1850 * data file path.
1851 *------------------------------------------------------------*/
1852 for(i=0; psFile->pszFilename[i] != '\0'; i++)
1853 if (psFile->pszFilename[i] == '/')
1854 psFile->pszFilename[i] = '\\';
1855 #endif /* WIN32 */
1856
1857 }/* if "XX" */
1858
1859 /*-----------------------------------------------------------------
1860 * OK, now we're ready to create the actual data file.
1861 *----------------------------------------------------------------*/
1862 AVCAdjustCaseSensitiveFilename(psFile->pszFilename);
1863 psFile->psRawBinFile = AVCRawBinOpen(psFile->pszFilename, "w",
1864 AVC_COVER_BYTE_ORDER(AVCCoverV7),
1865 psDBCSInfo);
1866
1867 if (psFile->psRawBinFile == NULL)
1868 {
1869 /* Failed to open file... just return NULL since an error message
1870 * has already been issued by AVCRawBinOpen()
1871 */
1872 CPLFree(pszFname);
1873 CPLFree(psFile->pszFilename);
1874 _AVCDestroyTableDef(psTableDef);
1875 CPLFree(psFile);
1876 return NULL;
1877 }
1878
1879 CPLFree(pszFname);
1880
1881 return psFile;
1882 }
1883
1884
1885 /**********************************************************************
1886 * _AVCBinWriteCreateDBFTable()
1887 *
1888 * Create a table (DBF file) in a PC Coverage and write the attribute defns to
1889 * the file. The file will then be ready to write records to.
1890 *
1891 * In PC Coverages, only the following tables appear to be supported:
1892 * - TEST.AAT -> AAT.DBF
1893 * - TEST.PAT -> PAT.DBF
1894 * - TEST.BND -> BND.DBF
1895 * - TEST.TIC -> TIC.DBF
1896 *
1897 * However, this function will not fail if it is passed a table name not
1898 * supported by PC Arc/Info.
1899 * e.g. TEST.PATCOUNTY would be written as PATCOUNTY.DBF even if PC Arc/Info
1900 * would probably not recognize that name.
1901 *
1902 * Returns a valid AVCBinFile handle, or NULL if the table could
1903 * not be created.
1904 *
1905 * AVCBinClose() will eventually have to be called to release the
1906 * resources used by the AVCBinFile structure.
1907 **********************************************************************/
_AVCBinWriteCreateDBFTable(const char * pszPath,const char * pszCoverName,AVCTableDef * psSrcTableDef,AVCCoverType eCoverType,int nPrecision,AVCDBCSInfo * psDBCSInfo)1908 AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath,
1909 const char *pszCoverName,
1910 AVCTableDef *psSrcTableDef,
1911 AVCCoverType eCoverType,
1912 int nPrecision, AVCDBCSInfo *psDBCSInfo)
1913 {
1914 AVCBinFile *psFile;
1915 AVCTableDef *psTableDef = NULL;
1916 AVCFieldInfo *pasDef;
1917 char *pszDBFBasename, szFieldName[12];
1918 int i, j, nType;
1919
1920 /*-----------------------------------------------------------------
1921 * Alloc and init the AVCBinFile struct.
1922 *----------------------------------------------------------------*/
1923 psFile = (AVCBinFile*)CPLCalloc(1, sizeof(AVCBinFile));
1924
1925 psFile->eFileType = AVCFileTABLE;
1926 /* Precision is not important for tables */
1927 psFile->nPrecision = nPrecision;
1928 psFile->eCoverType = eCoverType;
1929
1930 psFile->hdr.psTableDef = psTableDef = _AVCDupTableDef(psSrcTableDef);
1931
1932 /* nCurDBFRecord is used to keep track of the 0-based index of the
1933 * last record we read from the DBF file... this is to emulate
1934 * sequential access which is assumed by the rest of the lib.
1935 * Since the first record (record 0) has not been written yet, then
1936 * we init the index at -1.
1937 */
1938 psFile->nCurDBFRecord = -1;
1939
1940 /*-----------------------------------------------------------------
1941 * Establish name of file to create.
1942 *----------------------------------------------------------------*/
1943 psFile->pszFilename = (char*)CPLCalloc(strlen(psSrcTableDef->szTableName)+
1944 strlen(pszPath)+10, sizeof(char));
1945
1946 if (EQUALN(psSrcTableDef->szTableName, pszCoverName, strlen(pszCoverName))
1947 && psSrcTableDef->szTableName[strlen(pszCoverName)] == '.')
1948 {
1949 pszDBFBasename = psSrcTableDef->szTableName + strlen(pszCoverName)+1;
1950 }
1951 else
1952 {
1953 pszDBFBasename = psSrcTableDef->szTableName;
1954 }
1955
1956 strcpy(psFile->pszFilename, pszPath);
1957
1958 for(i=strlen(psFile->pszFilename); *pszDBFBasename; i++, pszDBFBasename++)
1959 {
1960 psFile->pszFilename[i] = tolower(*pszDBFBasename);
1961 }
1962
1963 strcat(psFile->pszFilename, ".dbf");
1964
1965 /*-----------------------------------------------------------------
1966 * OK, let's try to create the DBF file.
1967 *----------------------------------------------------------------*/
1968 AVCAdjustCaseSensitiveFilename(psFile->pszFilename);
1969 psFile->hDBFFile = DBFCreate(psFile->pszFilename);
1970
1971 if (psFile->hDBFFile == NULL)
1972 {
1973 CPLError(CE_Failure, CPLE_OpenFailed,
1974 "Failed creating file %s.", psFile->pszFilename);
1975 CPLFree(psFile->pszFilename);
1976 _AVCDestroyTableDef(psTableDef);
1977 CPLFree(psFile);
1978 return NULL;
1979 }
1980
1981 /*-----------------------------------------------------------------
1982 * Create fields.
1983 *----------------------------------------------------------------*/
1984 pasDef = psTableDef->pasFieldDef;
1985 for(i=0; i<psTableDef->numFields; i++)
1986 {
1987 nType = pasDef[i].nType1*10;
1988
1989 /*-------------------------------------------------------------
1990 * Special characters '#' and '-' in field names have to be replaced
1991 * with '_'. PC Field names are limited to 10 chars.
1992 *------------------------------------------------------------*/
1993 strncpy(szFieldName, pasDef[i].szName, 10);
1994 szFieldName[10] = '\0';
1995 for(j=0; szFieldName[j]; j++)
1996 {
1997 if (szFieldName[j] == '#' || szFieldName[j] == '-')
1998 szFieldName[j] = '_';
1999 }
2000
2001 if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR)
2002 {
2003 /*---------------------------------------------------------
2004 * Values stored as strings
2005 *--------------------------------------------------------*/
2006 DBFAddField(psFile->hDBFFile, szFieldName, FTString,
2007 pasDef[i].nSize, 0);
2008 }
2009 else if (nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
2010 {
2011 /*---------------------------------------------------------
2012 * Numerics (internally stored as strings)
2013 *--------------------------------------------------------*/
2014 DBFAddField(psFile->hDBFFile, szFieldName, FTDouble,
2015 pasDef[i].nSize, pasDef[i].nFmtPrec);
2016 }
2017 else if (nType == AVC_FT_BININT)
2018 {
2019 /*---------------------------------------------------------
2020 * Integers (16 and 32 bits)
2021 *--------------------------------------------------------*/
2022 DBFAddField(psFile->hDBFFile, szFieldName, FTInteger, 11, 0);
2023 }
2024 else if (nType == AVC_FT_BINFLOAT)
2025 {
2026 /*---------------------------------------------------------
2027 * Single + Double precision floats
2028 * Set them as width=13, prec=6 in the header like PC/Arc does
2029 *--------------------------------------------------------*/
2030 DBFAddField(psFile->hDBFFile, szFieldName, FTDouble,
2031 13, 6);
2032 }
2033 else
2034 {
2035 /*---------------------------------------------------------
2036 * Hummm... unsupported field type...
2037 *--------------------------------------------------------*/
2038 CPLError(CE_Failure, CPLE_NotSupported,
2039 "Unsupported field type: (field=%s, type=%d, size=%d)",
2040 szFieldName, nType, pasDef[i].nSize);
2041 _AVCBinWriteCloseTable(psFile);
2042 return NULL;
2043 }
2044 }
2045
2046 return psFile;
2047 }
2048
2049
2050 /**********************************************************************
2051 * _AVCBinWriteCloseTable()
2052 *
2053 * (This function is for internal library use... external calls should
2054 * go to AVCBinWriteClose() instead)
2055 *
2056 * Close an info table opened for wirting, and release all memory
2057 * (object struct., buffers, etc.) associated with this file.
2058 **********************************************************************/
_AVCBinWriteCloseTable(AVCBinFile * psFile)2059 static void _AVCBinWriteCloseTable(AVCBinFile *psFile)
2060 {
2061 if (psFile->eFileType != AVCFileTABLE)
2062 return;
2063
2064 /*-----------------------------------------------------------------
2065 * Close the data file
2066 *----------------------------------------------------------------*/
2067 if (psFile->hDBFFile)
2068 {
2069 /*-------------------------------------------------------------
2070 * The case of DBF files is simple!
2071 *------------------------------------------------------------*/
2072 DBFClose(psFile->hDBFFile);
2073 psFile->hDBFFile = NULL;
2074 }
2075 else if (psFile->psRawBinFile)
2076 {
2077 /*-------------------------------------------------------------
2078 * __TODO__ make sure ARC.DIR entry contains accurate info about the
2079 * number of records written, etc.
2080 *------------------------------------------------------------*/
2081 AVCRawBinClose(psFile->psRawBinFile);
2082 psFile->psRawBinFile = NULL;
2083 }
2084
2085 /*-----------------------------------------------------------------
2086 * Release other memory
2087 *----------------------------------------------------------------*/
2088 _AVCDestroyTableDef(psFile->hdr.psTableDef);
2089
2090 CPLFree(psFile->pszFilename);
2091
2092 CPLFree(psFile);
2093 }
2094
2095
2096 /**********************************************************************
2097 * _AVCBinWriteTableRec()
2098 *
2099 * (This function is for internal library use... external calls should
2100 * go to AVCBinWriteTableRec() instead)
2101 *
2102 * Write a table data record at the current position in file.
2103 *
2104 * The contents of the pasDef and pasFields structures is assumed to
2105 * be valid... this function performs no validation on the consistency
2106 * of what it is given as input.
2107 *
2108 * Returns 0 on success or -1 on error.
2109 **********************************************************************/
_AVCBinWriteTableRec(AVCRawBinFile * psFile,int nFields,AVCFieldInfo * pasDef,AVCField * pasFields,int nRecordSize,const char * pszFname)2110 int _AVCBinWriteTableRec(AVCRawBinFile *psFile, int nFields,
2111 AVCFieldInfo *pasDef, AVCField *pasFields,
2112 int nRecordSize, const char *pszFname)
2113 {
2114 int i, nType, nBytesWritten=0;
2115
2116 if (psFile == NULL)
2117 return -1;
2118
2119 for(i=0; i<nFields; i++)
2120 {
2121 if (CPLGetLastErrorNo() != 0)
2122 return -1;
2123
2124 nType = pasDef[i].nType1*10;
2125
2126 if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR ||
2127 nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
2128 {
2129 /*---------------------------------------------------------
2130 * Values stored as strings (MUST be padded with spaces)
2131 *--------------------------------------------------------*/
2132 AVCRawBinWritePaddedString(psFile, pasDef[i].nSize,
2133 pasFields[i].pszStr);
2134 }
2135 else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
2136 {
2137 /*---------------------------------------------------------
2138 * 32 bit binary integers
2139 *--------------------------------------------------------*/
2140 AVCRawBinWriteInt32(psFile, pasFields[i].nInt32);
2141 }
2142 else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
2143 {
2144 /*---------------------------------------------------------
2145 * 16 bit binary integers
2146 *--------------------------------------------------------*/
2147 AVCRawBinWriteInt16(psFile, pasFields[i].nInt16);
2148 }
2149 else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 4)
2150 {
2151 /*---------------------------------------------------------
2152 * Single precision floats
2153 *--------------------------------------------------------*/
2154 AVCRawBinWriteFloat(psFile, pasFields[i].fFloat);
2155 }
2156 else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
2157 {
2158 /*---------------------------------------------------------
2159 * Double precision floats
2160 *--------------------------------------------------------*/
2161 AVCRawBinWriteDouble(psFile, pasFields[i].dDouble);
2162 }
2163 else
2164 {
2165 /*---------------------------------------------------------
2166 * Hummm... unsupported field type...
2167 *--------------------------------------------------------*/
2168 CPLError(CE_Failure, CPLE_NotSupported,
2169 "Unsupported field type in %s: (type=%d, size=%d)",
2170 pszFname, nType, pasDef[i].nSize);
2171 return -1;
2172 }
2173
2174 nBytesWritten += pasDef[i].nSize;
2175 }
2176
2177 /*-----------------------------------------------------------------
2178 * Record size is rounded to a multiple of 2 bytes.
2179 * Check the number of bytes written, and pad with zeros if
2180 * necessary.
2181 *----------------------------------------------------------------*/
2182 nRecordSize = ((nRecordSize+1)/2)*2;
2183 if (nBytesWritten < nRecordSize)
2184 AVCRawBinWriteZeros(psFile, nRecordSize - nBytesWritten);
2185
2186 if (CPLGetLastErrorNo() != 0)
2187 return -1;
2188
2189 return 0;
2190 }
2191
2192 /**********************************************************************
2193 * _AVCBinWriteDBFTableRec()
2194 *
2195 * (This function is for internal library use... external calls should
2196 * go to AVCBinWriteTableRec() instead)
2197 *
2198 * Write a table data record at the current position in DBF file.
2199 *
2200 * The contents of the pasDef and pasFields structures is assumed to
2201 * be valid... this function performs no validation on the consistency
2202 * of what it is given as input.
2203 *
2204 * Returns 0 on success or -1 on error.
2205 **********************************************************************/
_AVCBinWriteDBFTableRec(DBFHandle hDBFFile,int nFields,AVCFieldInfo * pasDef,AVCField * pasFields,int * nCurDBFRecord,const char * pszFname)2206 int _AVCBinWriteDBFTableRec(DBFHandle hDBFFile, int nFields,
2207 AVCFieldInfo *pasDef, AVCField *pasFields,
2208 int *nCurDBFRecord, const char *pszFname)
2209 {
2210 int i, nType, nStatus = FALSE;
2211
2212 if (hDBFFile == NULL)
2213 return -1;
2214
2215 (*nCurDBFRecord)++;
2216
2217 for(i=0; i<nFields; i++)
2218 {
2219 if (CPLGetLastErrorNo() != 0)
2220 return -1;
2221
2222 nType = pasDef[i].nType1*10;
2223
2224 if (nType == AVC_FT_DATE || nType == AVC_FT_CHAR)
2225 {
2226 /*---------------------------------------------------------
2227 * Values stored as strings
2228 *--------------------------------------------------------*/
2229 nStatus = DBFWriteStringAttribute(hDBFFile, *nCurDBFRecord, i,
2230 pasFields[i].pszStr);
2231 }
2232 else if (nType == AVC_FT_FIXINT || nType == AVC_FT_FIXNUM)
2233 {
2234 /*---------------------------------------------------------
2235 * Numbers stored as strings
2236 *--------------------------------------------------------*/
2237 nStatus = DBFWriteAttributeDirectly(hDBFFile, *nCurDBFRecord, i,
2238 pasFields[i].pszStr);
2239 }
2240 else if (nType == AVC_FT_BININT && pasDef[i].nSize == 4)
2241 {
2242 /*---------------------------------------------------------
2243 * 32 bit binary integers
2244 *--------------------------------------------------------*/
2245 nStatus = DBFWriteIntegerAttribute(hDBFFile, *nCurDBFRecord, i,
2246 pasFields[i].nInt32);
2247 }
2248 else if (nType == AVC_FT_BININT && pasDef[i].nSize == 2)
2249 {
2250 /*---------------------------------------------------------
2251 * 16 bit binary integers
2252 *--------------------------------------------------------*/
2253 nStatus = DBFWriteIntegerAttribute(hDBFFile, *nCurDBFRecord, i,
2254 pasFields[i].nInt16);
2255 }
2256 else if (nType == AVC_FT_BINFLOAT)
2257 {
2258 /*---------------------------------------------------------
2259 * Single+double precision floats
2260 *--------------------------------------------------------*/
2261 char szBuf[32] = "";
2262 int nLen;
2263
2264 if (pasDef[i].nSize == 4)
2265 nLen = AVCPrintRealValue(szBuf, AVC_FORMAT_DBF_FLOAT,
2266 AVCFileTABLE, pasFields[i].fFloat);
2267 else
2268 nLen = AVCPrintRealValue(szBuf, AVC_FORMAT_DBF_FLOAT,
2269 AVCFileTABLE, pasFields[i].dDouble);
2270
2271 szBuf[nLen] = '\0';
2272
2273 nStatus = DBFWriteAttributeDirectly(hDBFFile, *nCurDBFRecord, i,
2274 szBuf);
2275 }
2276 else
2277 {
2278 /*---------------------------------------------------------
2279 * Hummm... unsupported field type...
2280 *--------------------------------------------------------*/
2281 CPLError(CE_Failure, CPLE_NotSupported,
2282 "Unsupported field type in %s: (type=%d, size=%d)",
2283 pszFname, nType, pasDef[i].nSize);
2284 return -1;
2285 }
2286
2287 if (nStatus != TRUE)
2288 {
2289 CPLError(CE_Failure, CPLE_FileIO,
2290 "Failed writing table field %d to record %d in %s",
2291 i, *nCurDBFRecord, pszFname);
2292 return -1;
2293 }
2294
2295 }
2296
2297 return 0;
2298 }
2299
2300 /**********************************************************************
2301 * AVCBinWriteTableRec()
2302 *
2303 * Write a table data record at the current position in file.
2304 *
2305 * The contents of the pasDef and pasFields structures is assumed to
2306 * be valid... this function performs no validation on the consistency
2307 * of what it is given as input.
2308 *
2309 * Returns 0 on success or -1 on error.
2310 *
2311 * If a problem happens, then CPLError() will be called by the lower-level
2312 * functions and CPLGetLastErrorNo() can be used to find out what happened.
2313 **********************************************************************/
AVCBinWriteTableRec(AVCBinFile * psFile,AVCField * pasFields)2314 int AVCBinWriteTableRec(AVCBinFile *psFile, AVCField *pasFields)
2315 {
2316 if (psFile->eFileType != AVCFileTABLE||
2317 psFile->hdr.psTableDef->numRecords == 0)
2318 return -1;
2319
2320 if (psFile->eCoverType == AVCCoverPC || psFile->eCoverType == AVCCoverPC2)
2321 return _AVCBinWriteDBFTableRec(psFile->hDBFFile,
2322 psFile->hdr.psTableDef->numFields,
2323 psFile->hdr.psTableDef->pasFieldDef,
2324 pasFields,
2325 &(psFile->nCurDBFRecord),
2326 psFile->pszFilename);
2327 else
2328 return _AVCBinWriteTableRec(psFile->psRawBinFile,
2329 psFile->hdr.psTableDef->numFields,
2330 psFile->hdr.psTableDef->pasFieldDef,
2331 pasFields,
2332 psFile->hdr.psTableDef->nRecSize,
2333 psFile->pszFilename);
2334 }
2335
2336