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