Line data Source code
1 : /**********************************************************************
2 : * $Id$
3 : *
4 : * Name: avc_rawbin.c
5 : * Project: Arc/Info vector coverage (AVC) BIN->E00 conversion library
6 : * Language: ANSI C
7 : * Purpose: Raw Binary file access functions.
8 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999-2005, Daniel Morissette
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : **********************************************************************
31 : *
32 : * $Log: avc_rawbin.c,v $
33 : * Revision 1.14 2008/07/23 20:51:38 dmorissette
34 : * Fixed GCC 4.1.x compile warnings related to use of char vs unsigned char
35 : * (GDAL/OGR ticket http://trac.osgeo.org/gdal/ticket/2495)
36 : *
37 : * Revision 1.13 2005/06/03 03:49:59 daniel
38 : * Update email address, website url, and copyright dates
39 : *
40 : * Revision 1.12 2004/08/19 23:41:04 warmerda
41 : * fixed pointer aliasing optimization bug
42 : *
43 : * Revision 1.11 2000/09/22 19:45:21 daniel
44 : * Switch to MIT-style license
45 : *
46 : * Revision 1.10 2000/05/29 15:36:07 daniel
47 : * Fixed compile warning
48 : *
49 : * Revision 1.9 2000/05/29 15:31:31 daniel
50 : * Added Japanese DBCS support
51 : *
52 : * Revision 1.8 2000/01/10 02:59:11 daniel
53 : * Fixed problem in AVCRawBinOpen() when file not found
54 : *
55 : * Revision 1.7 1999/12/24 07:18:34 daniel
56 : * Added PC Arc/Info coverages support
57 : *
58 : * Revision 1.6 1999/08/29 15:05:43 daniel
59 : * Added source filename in "Attempt to read past EOF" error message
60 : *
61 : * Revision 1.5 1999/06/08 22:09:03 daniel
62 : * Allow opening file with "r+" (but no real random access support yet)
63 : *
64 : * Revision 1.4 1999/05/11 02:10:51 daniel
65 : * Added write support
66 : *
67 : * Revision 1.3 1999/03/03 19:55:21 daniel
68 : * Fixed syntax error in the CPL_MSB version of AVCRawBinReadInt32()
69 : *
70 : * Revision 1.2 1999/02/25 04:20:08 daniel
71 : * Modified AVCRawBinEOF() to detect EOF even if AVCRawBinFSeek() was used.
72 : *
73 : * Revision 1.1 1999/01/29 16:28:52 daniel
74 : * Initial revision
75 : *
76 : **********************************************************************/
77 :
78 : #include "avc.h"
79 : #include "avc_mbyte.h"
80 :
81 : /*---------------------------------------------------------------------
82 : * Define a static flag and set it with the byte ordering on this machine
83 : * we will then compare with this value to decide if we need to swap
84 : * bytes or not.
85 : *
86 : * CPL_MSB or CPL_LSB should be set in the makefile... the default is
87 : * CPL_LSB.
88 : *--------------------------------------------------------------------*/
89 : #ifndef CPL_LSB
90 : static AVCByteOrder geSystemByteOrder = AVCBigEndian;
91 : #else
92 : static AVCByteOrder geSystemByteOrder = AVCLittleEndian;
93 : #endif
94 :
95 : /*=====================================================================
96 : * Stuff related to buffered reading of raw binary files
97 : *====================================================================*/
98 :
99 : /**********************************************************************
100 : * AVCRawBinOpen()
101 : *
102 : * Open a binary file for reading with buffering, or writing.
103 : *
104 : * Returns a valid AVCRawBinFile structure, or nullptr if the file could
105 : * not be opened or created.
106 : *
107 : * AVCRawBinClose() will eventually have to be called to release the
108 : * resources used by the AVCRawBinFile structure.
109 : **********************************************************************/
110 49 : AVCRawBinFile *AVCRawBinOpen(const char *pszFname, const char *pszAccess,
111 : AVCByteOrder eFileByteOrder,
112 : AVCDBCSInfo *psDBCSInfo)
113 : {
114 : AVCRawBinFile *psFile;
115 :
116 49 : psFile = (AVCRawBinFile *)CPLCalloc(1, sizeof(AVCRawBinFile));
117 :
118 : /*-----------------------------------------------------------------
119 : * Validate access mode and open/create file.
120 : * For now we support only: "r" for read-only or "w" for write-only
121 : * or "a" for append.
122 : *
123 : * A case for "r+" is included here, but random access is not
124 : * properly supported yet... so this option should be used with care.
125 : *----------------------------------------------------------------*/
126 49 : if (STARTS_WITH_CI(pszAccess, "r+"))
127 : {
128 0 : psFile->eAccess = AVCReadWrite;
129 0 : psFile->fp = VSIFOpenL(pszFname, "r+b");
130 : }
131 49 : else if (STARTS_WITH_CI(pszAccess, "r"))
132 : {
133 49 : psFile->eAccess = AVCRead;
134 49 : psFile->fp = VSIFOpenL(pszFname, "rb");
135 : }
136 0 : else if (STARTS_WITH_CI(pszAccess, "w"))
137 : {
138 0 : psFile->eAccess = AVCWrite;
139 0 : psFile->fp = VSIFOpenL(pszFname, "wb");
140 : }
141 0 : else if (STARTS_WITH_CI(pszAccess, "a"))
142 : {
143 0 : psFile->eAccess = AVCWrite;
144 0 : psFile->fp = VSIFOpenL(pszFname, "ab");
145 : }
146 : else
147 : {
148 0 : CPLError(CE_Failure, CPLE_IllegalArg,
149 : "Access mode \"%s\" not supported.", pszAccess);
150 0 : CPLFree(psFile);
151 0 : return nullptr;
152 : }
153 :
154 : /*-----------------------------------------------------------------
155 : * Check that file was opened successfully, and init struct.
156 : *----------------------------------------------------------------*/
157 49 : if (psFile->fp == nullptr)
158 : {
159 0 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open file %s",
160 : pszFname);
161 0 : CPLFree(psFile);
162 0 : return nullptr;
163 : }
164 :
165 : /*-----------------------------------------------------------------
166 : * OK... Init psFile struct
167 : *----------------------------------------------------------------*/
168 49 : psFile->pszFname = CPLStrdup(pszFname);
169 :
170 49 : psFile->eByteOrder = eFileByteOrder;
171 49 : psFile->psDBCSInfo = psDBCSInfo; /* Handle on dataset DBCS info */
172 :
173 : /*-----------------------------------------------------------------
174 : * One can set nFileDataSize based on some header fields to force
175 : * EOF beyond a given point in the file. Useful for cases like
176 : * PC Arc/Info where the physical file size is always a multiple of
177 : * 256 bytes padded with some junk at the end.
178 : *----------------------------------------------------------------*/
179 49 : psFile->nFileDataSize = -1;
180 :
181 49 : return psFile;
182 : }
183 :
184 : /**********************************************************************
185 : * AVCRawBinClose()
186 : *
187 : * Close a binary file previously opened with AVCRawBinOpen() and release
188 : * any memory used by the handle.
189 : **********************************************************************/
190 51 : void AVCRawBinClose(AVCRawBinFile *psFile)
191 : {
192 51 : if (psFile)
193 : {
194 49 : if (psFile->fp)
195 49 : VSIFCloseL(psFile->fp);
196 49 : CPLFree(psFile->pszFname);
197 49 : CPLFree(psFile);
198 : }
199 51 : }
200 :
201 : /**********************************************************************
202 : * AVCRawBinSetFileDataSize()
203 : *
204 : * One can set nFileDataSize based on some header fields to force
205 : * EOF beyond a given point in the file. Useful for cases like
206 : * PC Arc/Info where the physical file size is always a multiple of
207 : * 256 bytes padded with some junk at the end.
208 : *
209 : * The default value is -1 which just looks for the real EOF.
210 : **********************************************************************/
211 14 : void AVCRawBinSetFileDataSize(AVCRawBinFile *psFile, int nFileDataSize)
212 : {
213 14 : if (psFile)
214 : {
215 14 : psFile->nFileDataSize = nFileDataSize;
216 : }
217 14 : }
218 :
219 : /**********************************************************************
220 : * AVCRawBinIsFileGreaterThan()
221 : *
222 : **********************************************************************/
223 0 : int AVCRawBinIsFileGreaterThan(AVCRawBinFile *psFile, vsi_l_offset nSize)
224 : {
225 0 : vsi_l_offset nCurPos = VSIFTellL(psFile->fp);
226 0 : VSIFSeekL(psFile->fp, 0, SEEK_END);
227 0 : bool bRet = VSIFTellL(psFile->fp) >= nSize;
228 0 : VSIFSeekL(psFile->fp, nCurPos, SEEK_SET);
229 0 : return bRet;
230 : }
231 :
232 : /**********************************************************************
233 : * AVCRawBinReadBytes()
234 : *
235 : * Copy the number of bytes from the input file to the specified
236 : * memory location.
237 : **********************************************************************/
238 : static GBool bDisableReadBytesEOFError = FALSE;
239 :
240 3573 : void AVCRawBinReadBytes(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
241 : {
242 3573 : int nTotalBytesToRead = nBytesToRead;
243 :
244 : /* Make sure file is opened with Read access
245 : */
246 3573 : if (psFile == nullptr ||
247 3573 : (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite))
248 : {
249 0 : CPLError(CE_Failure, CPLE_FileIO,
250 : "AVCRawBinReadBytes(): call not compatible with access mode.");
251 0 : return;
252 : }
253 :
254 : /* Quick method: check to see if we can satisfy the request with a
255 : * simple memcpy... most calls should take this path.
256 : */
257 3573 : if (psFile->nCurPos + nBytesToRead <= psFile->nCurSize)
258 : {
259 3487 : memcpy(pBuf, psFile->abyBuf + psFile->nCurPos, nBytesToRead);
260 3487 : psFile->nCurPos += nBytesToRead;
261 3487 : return;
262 : }
263 :
264 : /* This is the long method... it supports reading data that
265 : * overlaps the input buffer boundaries.
266 : */
267 174 : while (nBytesToRead > 0)
268 : {
269 : /* If we reached the end of our memory buffer then read another
270 : * chunk from the file
271 : */
272 90 : CPLAssert(psFile->nCurPos <= psFile->nCurSize);
273 90 : if (psFile->nCurPos == psFile->nCurSize)
274 : {
275 86 : psFile->nOffset += psFile->nCurSize;
276 86 : psFile->nCurSize =
277 86 : (int)VSIFReadL(psFile->abyBuf, sizeof(GByte),
278 : AVCRAWBIN_READBUFSIZE, psFile->fp);
279 86 : psFile->nCurPos = 0;
280 : }
281 :
282 90 : if (psFile->nCurSize == 0)
283 : {
284 : /* Attempt to read past EOF... generate an error.
285 : *
286 : * Note: AVCRawBinEOF() can set bDisableReadBytesEOFError=TRUE
287 : * to disable the error message while it is testing
288 : * for EOF.
289 : *
290 : * TODO: We are not resetting the buffer. Also, there is no easy
291 : * way to recover from the situation.
292 : */
293 2 : if (bDisableReadBytesEOFError == FALSE)
294 0 : CPLError(CE_Failure, CPLE_FileIO,
295 : "EOF encountered in %s after reading %d bytes while "
296 : "trying to read %d bytes. File may be corrupt.",
297 : psFile->pszFname, nTotalBytesToRead - nBytesToRead,
298 : nTotalBytesToRead);
299 2 : return;
300 : }
301 :
302 : /* If the requested bytes are not all in the current buffer then
303 : * just read the part that's in memory for now... the loop will
304 : * take care of the rest.
305 : */
306 88 : if (psFile->nCurPos + nBytesToRead > psFile->nCurSize)
307 : {
308 : int nBytes;
309 4 : nBytes = psFile->nCurSize - psFile->nCurPos;
310 4 : memcpy(pBuf, psFile->abyBuf + psFile->nCurPos, nBytes);
311 4 : psFile->nCurPos += nBytes;
312 4 : pBuf += nBytes;
313 4 : nBytesToRead -= nBytes;
314 : }
315 : else
316 : {
317 : /* All the requested bytes are now in the buffer...
318 : * simply copy them and return.
319 : */
320 84 : memcpy(pBuf, psFile->abyBuf + psFile->nCurPos, nBytesToRead);
321 84 : psFile->nCurPos += nBytesToRead;
322 :
323 84 : nBytesToRead = 0; /* Terminate the loop */
324 : }
325 : }
326 : }
327 :
328 : /**********************************************************************
329 : * AVCRawBinReadString()
330 : *
331 : * Same as AVCRawBinReadBytes() except that the string is run through
332 : * the DBCS conversion function.
333 : *
334 : * pBuf should be allocated with a size of at least nBytesToRead+1 bytes.
335 : **********************************************************************/
336 286 : void AVCRawBinReadString(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
337 : {
338 : const GByte *pszConvBuf;
339 :
340 286 : memset(pBuf, 0, nBytesToRead);
341 286 : AVCRawBinReadBytes(psFile, nBytesToRead, pBuf);
342 :
343 286 : pBuf[nBytesToRead] = '\0';
344 :
345 : pszConvBuf =
346 286 : AVCE00ConvertFromArcDBCS(psFile->psDBCSInfo, pBuf, nBytesToRead);
347 :
348 286 : if (pszConvBuf != pBuf)
349 : {
350 0 : memcpy(pBuf, pszConvBuf, nBytesToRead);
351 : }
352 286 : }
353 :
354 : /**********************************************************************
355 : * AVCRawBinFSeek()
356 : *
357 : * Move the read pointer to the specified location.
358 : *
359 : * As with fseek(), the specified position can be relative to the
360 : * beginning of the file (SEEK_SET), or the current position (SEEK_CUR).
361 : * SEEK_END is not supported.
362 : **********************************************************************/
363 467 : void AVCRawBinFSeek(AVCRawBinFile *psFile, int nOffset, int nFrom)
364 : {
365 467 : int nTarget = 0;
366 :
367 467 : CPLAssert(nFrom == SEEK_SET || nFrom == SEEK_CUR);
368 :
369 : /* Supported only with read access for now
370 : */
371 467 : CPLAssert(psFile && psFile->eAccess != AVCWrite);
372 467 : if (psFile == nullptr || psFile->eAccess == AVCWrite)
373 0 : return;
374 :
375 : /* Compute destination relative to current memory buffer
376 : */
377 : GIntBig nTargetBig;
378 467 : if (nFrom == SEEK_SET)
379 258 : nTargetBig = static_cast<GIntBig>(nOffset) - psFile->nOffset;
380 : else /* if (nFrom == SEEK_CUR) */
381 209 : nTargetBig = static_cast<GIntBig>(nOffset) + psFile->nCurPos;
382 467 : if (nTargetBig > INT_MAX)
383 0 : return;
384 467 : nTarget = static_cast<int>(nTargetBig);
385 :
386 : /* Is the destination located inside the current buffer?
387 : */
388 467 : if (nTarget > 0 && nTarget <= psFile->nCurSize)
389 : {
390 : /* Requested location is already in memory... just move the
391 : * read pointer
392 : */
393 394 : psFile->nCurPos = nTarget;
394 : }
395 : else
396 : {
397 73 : if ((nTarget > 0 && psFile->nOffset > INT_MAX - nTarget) ||
398 73 : psFile->nOffset + nTarget < 0)
399 : {
400 0 : return;
401 : }
402 :
403 : /* Requested location is not part of the memory buffer...
404 : * move the FILE * to the right location and be ready to
405 : * read from there.
406 : */
407 73 : psFile->nCurPos = 0;
408 73 : psFile->nCurSize = 0;
409 73 : psFile->nOffset = psFile->nOffset + nTarget;
410 73 : if (VSIFSeekL(psFile->fp, psFile->nOffset, SEEK_SET) < 0)
411 0 : return;
412 : }
413 : }
414 :
415 : /**********************************************************************
416 : * AVCRawBinEOF()
417 : *
418 : * Return TRUE if there is no more data to read from the file or
419 : * FALSE otherwise.
420 : **********************************************************************/
421 1731 : GBool AVCRawBinEOF(AVCRawBinFile *psFile)
422 : {
423 1731 : if (psFile == nullptr || psFile->fp == nullptr)
424 0 : return TRUE;
425 :
426 : /* In write access mode, always return TRUE, since we always write
427 : * at EOF for now.
428 : */
429 1731 : if (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite)
430 0 : return TRUE;
431 :
432 : /* If file data size was specified, then check that we have not
433 : * passed that point yet...
434 : */
435 1731 : if (psFile->nFileDataSize > 0 &&
436 441 : (psFile->nOffset + psFile->nCurPos) >= psFile->nFileDataSize)
437 5 : return TRUE;
438 :
439 : /* If the file pointer has been moved by AVCRawBinFSeek(), then
440 : * we may be at a position past EOF, but VSIFeof() would still
441 : * return FALSE. It also returns false if we have read just up to
442 : * the end of the file. EOF marker would not have been set unless
443 : * we try to read past that.
444 : *
445 : * To prevent this situation, if the memory buffer is empty,
446 : * we will try to read 1 byte from the file to force the next
447 : * chunk of data to be loaded (and we'll move the read pointer
448 : * back by 1 char after of course!).
449 : * If we are at the end of the file, this will trigger the EOF flag.
450 : */
451 1726 : if ((psFile->nCurPos == 0 && psFile->nCurSize == 0) ||
452 1703 : (psFile->nCurPos == AVCRAWBIN_READBUFSIZE &&
453 2 : psFile->nCurSize == AVCRAWBIN_READBUFSIZE))
454 : {
455 : GByte c;
456 : /* Set bDisableReadBytesEOFError=TRUE to temporarily disable
457 : * the EOF error message from AVCRawBinReadBytes().
458 : */
459 25 : bDisableReadBytesEOFError = TRUE;
460 25 : AVCRawBinReadBytes(psFile, 1, &c);
461 25 : bDisableReadBytesEOFError = FALSE;
462 :
463 25 : if (psFile->nCurPos > 0)
464 23 : AVCRawBinFSeek(psFile, -1, SEEK_CUR);
465 : }
466 :
467 1726 : return (psFile->nCurPos == psFile->nCurSize && VSIFEofL(psFile->fp));
468 : }
469 :
470 : /**********************************************************************
471 : * AVCRawBinRead<datatype>()
472 : *
473 : * Arc/Info files are binary files with MSB first (Motorola) byte
474 : * ordering. The following functions will read from the input file
475 : * and return a value with the bytes ordered properly for the current
476 : * platform.
477 : **********************************************************************/
478 530 : GInt16 AVCRawBinReadInt16(AVCRawBinFile *psFile)
479 : {
480 530 : GInt16 n16Value = 0;
481 :
482 530 : AVCRawBinReadBytes(psFile, 2, (GByte *)(&n16Value));
483 :
484 530 : if (psFile->eByteOrder != geSystemByteOrder)
485 : {
486 530 : return (GInt16)CPL_SWAP16(n16Value);
487 : }
488 :
489 0 : return n16Value;
490 : }
491 :
492 1177 : GInt32 AVCRawBinReadInt32(AVCRawBinFile *psFile)
493 : {
494 1177 : GInt32 n32Value = 0;
495 :
496 1177 : AVCRawBinReadBytes(psFile, 4, (GByte *)(&n32Value));
497 :
498 1177 : if (psFile->eByteOrder != geSystemByteOrder)
499 : {
500 1177 : return (GInt32)CPL_SWAP32(n32Value);
501 : }
502 :
503 0 : return n32Value;
504 : }
505 :
506 1516 : float AVCRawBinReadFloat(AVCRawBinFile *psFile)
507 : {
508 1516 : float fValue = 0.0f;
509 :
510 1516 : AVCRawBinReadBytes(psFile, 4, (GByte *)(&fValue));
511 :
512 1516 : if (psFile->eByteOrder != geSystemByteOrder)
513 : {
514 1516 : CPL_SWAP32PTR(&fValue);
515 : }
516 :
517 1516 : return fValue;
518 : }
519 :
520 0 : double AVCRawBinReadDouble(AVCRawBinFile *psFile)
521 : {
522 0 : double dValue = 0.0;
523 :
524 0 : AVCRawBinReadBytes(psFile, 8, (GByte *)(&dValue));
525 :
526 0 : if (psFile->eByteOrder != geSystemByteOrder)
527 : {
528 0 : CPL_SWAPDOUBLE(&dValue);
529 : }
530 :
531 0 : return dValue;
532 : }
533 :
534 : /**********************************************************************
535 : * AVCRawBinWriteBytes()
536 : *
537 : * Write the number of bytes from the buffer to the file.
538 : *
539 : * If a problem happens, then CPLError() will be called and
540 : * CPLGetLastErrNo() can be used to test if a write operation was
541 : * successful.
542 : **********************************************************************/
543 0 : void AVCRawBinWriteBytes(AVCRawBinFile *psFile, int nBytesToWrite,
544 : const GByte *pBuf)
545 : {
546 : /*----------------------------------------------------------------
547 : * Make sure file is opened with Write access
548 : *---------------------------------------------------------------*/
549 0 : if (psFile == nullptr ||
550 0 : (psFile->eAccess != AVCWrite && psFile->eAccess != AVCReadWrite))
551 : {
552 0 : CPLError(
553 : CE_Failure, CPLE_FileIO,
554 : "AVCRawBinWriteBytes(): call not compatible with access mode.");
555 0 : return;
556 : }
557 :
558 0 : if (VSIFWriteL((void *)pBuf, nBytesToWrite, 1, psFile->fp) != 1)
559 0 : CPLError(CE_Failure, CPLE_FileIO, "Writing to %s failed.",
560 : psFile->pszFname);
561 :
562 : /*----------------------------------------------------------------
563 : * In write mode, we keep track of current file position ( =nbr of
564 : * bytes written) through psFile->nCurPos
565 : *---------------------------------------------------------------*/
566 0 : psFile->nCurPos += nBytesToWrite;
567 : }
568 :
569 : /**********************************************************************
570 : * AVCRawBinWrite<datatype>()
571 : *
572 : * Arc/Info files are binary files with MSB first (Motorola) byte
573 : * ordering. The following functions will reorder the byte for the
574 : * value properly and write that to the output file.
575 : *
576 : * If a problem happens, then CPLError() will be called and
577 : * CPLGetLastErrNo() can be used to test if a write operation was
578 : * successful.
579 : **********************************************************************/
580 0 : void AVCRawBinWriteInt16(AVCRawBinFile *psFile, GInt16 n16Value)
581 : {
582 0 : if (psFile->eByteOrder != geSystemByteOrder)
583 : {
584 0 : n16Value = (GInt16)CPL_SWAP16(n16Value);
585 : }
586 :
587 0 : AVCRawBinWriteBytes(psFile, 2, (GByte *)&n16Value);
588 0 : }
589 :
590 0 : void AVCRawBinWriteInt32(AVCRawBinFile *psFile, GInt32 n32Value)
591 : {
592 0 : if (psFile->eByteOrder != geSystemByteOrder)
593 : {
594 0 : n32Value = (GInt32)CPL_SWAP32(n32Value);
595 : }
596 :
597 0 : AVCRawBinWriteBytes(psFile, 4, (GByte *)&n32Value);
598 0 : }
599 :
600 0 : void AVCRawBinWriteFloat(AVCRawBinFile *psFile, float fValue)
601 : {
602 0 : if (psFile->eByteOrder != geSystemByteOrder)
603 : {
604 0 : CPL_SWAP32PTR(&fValue);
605 : }
606 :
607 0 : AVCRawBinWriteBytes(psFile, 4, (GByte *)&fValue);
608 0 : }
609 :
610 0 : void AVCRawBinWriteDouble(AVCRawBinFile *psFile, double dValue)
611 : {
612 0 : if (psFile->eByteOrder != geSystemByteOrder)
613 : {
614 0 : CPL_SWAPDOUBLE(&dValue);
615 : }
616 :
617 0 : AVCRawBinWriteBytes(psFile, 8, (GByte *)&dValue);
618 0 : }
619 :
620 : /**********************************************************************
621 : * AVCRawBinWriteZeros()
622 : *
623 : * Write a number of zeros (specified in bytes) at the current position
624 : * in the file.
625 : *
626 : * If a problem happens, then CPLError() will be called and
627 : * CPLGetLastErrNo() can be used to test if a write operation was
628 : * successful.
629 : **********************************************************************/
630 0 : void AVCRawBinWriteZeros(AVCRawBinFile *psFile, int nBytesToWrite)
631 : {
632 0 : char acZeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
633 : int i;
634 :
635 : /* Write by 8 bytes chunks. The last chunk may be less than 8 bytes
636 : */
637 0 : for (i = 0; i < nBytesToWrite; i += 8)
638 : {
639 0 : AVCRawBinWriteBytes(psFile, MIN(8, (nBytesToWrite - i)),
640 : (GByte *)acZeros);
641 : }
642 0 : }
643 :
644 : /**********************************************************************
645 : * AVCRawBinWritePaddedString()
646 : *
647 : * Write a string and pad the end of the field (up to nFieldSize) with
648 : * spaces number of spaces at the current position in the file.
649 : *
650 : * If a problem happens, then CPLError() will be called and
651 : * CPLGetLastErrNo() can be used to test if a write operation was
652 : * successful.
653 : **********************************************************************/
654 0 : void AVCRawBinWritePaddedString(AVCRawBinFile *psFile, int nFieldSize,
655 : const GByte *pszString)
656 : {
657 0 : char acSpaces[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
658 : int i, nLen, numSpaces;
659 :
660 : /* If we're on a system with a multibyte codepage then we have to
661 : * convert strings to the proper multibyte encoding.
662 : */
663 : pszString =
664 0 : AVCE00Convert2ArcDBCS(psFile->psDBCSInfo, pszString, nFieldSize);
665 :
666 0 : nLen = (int)strlen((const char *)pszString);
667 0 : nLen = MIN(nLen, nFieldSize);
668 0 : numSpaces = nFieldSize - nLen;
669 :
670 0 : if (nLen > 0)
671 0 : AVCRawBinWriteBytes(psFile, nLen, pszString);
672 :
673 : /* Write spaces by 8 bytes chunks. The last chunk may be less than 8 bytes
674 : */
675 0 : for (i = 0; i < numSpaces; i += 8)
676 : {
677 0 : AVCRawBinWriteBytes(psFile, MIN(8, (numSpaces - i)), (GByte *)acSpaces);
678 : }
679 0 : }
|