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