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