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