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