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