1 : /**********************************************************************
2 : * $Id: avc_rawbin.c,v 1.14 2008/07/23 20:51:38 dmorissette Exp $
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 nned 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 NULL 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 10 : AVCRawBinFile *AVCRawBinOpen(const char *pszFname, const char *pszAccess,
111 : AVCByteOrder eFileByteOrder,
112 : AVCDBCSInfo *psDBCSInfo)
113 : {
114 : AVCRawBinFile *psFile;
115 :
116 10 : 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 10 : if (EQUALN(pszAccess, "r+", 2))
127 : {
128 0 : psFile->eAccess = AVCReadWrite;
129 0 : psFile->fp = VSIFOpen(pszFname, "r+b");
130 : }
131 10 : else if (EQUALN(pszAccess, "r", 1))
132 : {
133 10 : psFile->eAccess = AVCRead;
134 10 : psFile->fp = VSIFOpen(pszFname, "rb");
135 : }
136 0 : else if (EQUALN(pszAccess, "w", 1))
137 : {
138 0 : psFile->eAccess = AVCWrite;
139 0 : psFile->fp = VSIFOpen(pszFname, "wb");
140 : }
141 0 : else if (EQUALN(pszAccess, "a", 1))
142 : {
143 0 : psFile->eAccess = AVCWrite;
144 0 : psFile->fp = VSIFOpen(pszFname, "ab");
145 : }
146 : else
147 : {
148 0 : CPLError(CE_Failure, CPLE_IllegalArg,
149 : "Acces mode \"%s\" not supported.", pszAccess);
150 0 : CPLFree(psFile);
151 0 : return NULL;
152 : }
153 :
154 : /*-----------------------------------------------------------------
155 : * Check that file was opened succesfully, and init struct.
156 : *----------------------------------------------------------------*/
157 10 : if (psFile->fp == NULL)
158 : {
159 0 : CPLError(CE_Failure, CPLE_OpenFailed,
160 : "Failed to open file %s", pszFname);
161 0 : CPLFree(psFile);
162 0 : return NULL;
163 : }
164 :
165 : /*-----------------------------------------------------------------
166 : * OK... Init psFile struct
167 : *----------------------------------------------------------------*/
168 10 : psFile->pszFname = CPLStrdup(pszFname);
169 :
170 10 : psFile->eByteOrder = eFileByteOrder;
171 10 : 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 10 : psFile->nFileDataSize = -1;
180 :
181 10 : 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 11 : void AVCRawBinClose(AVCRawBinFile *psFile)
191 : {
192 11 : if (psFile)
193 : {
194 10 : if (psFile->fp)
195 10 : VSIFClose(psFile->fp);
196 10 : CPLFree(psFile->pszFname);
197 10 : CPLFree(psFile);
198 : }
199 11 : }
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 4 : void AVCRawBinSetFileDataSize(AVCRawBinFile *psFile, int nFileDataSize)
212 : {
213 4 : if (psFile)
214 : {
215 4 : psFile->nFileDataSize = nFileDataSize;
216 : }
217 4 : }
218 :
219 : /**********************************************************************
220 : * AVCRawBinReadBytes()
221 : *
222 : * Copy the number of bytes from the input file to the specified
223 : * memory location.
224 : **********************************************************************/
225 : static GBool bDisableReadBytesEOFError = FALSE;
226 :
227 5550 : void AVCRawBinReadBytes(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
228 : {
229 5550 : int nTotalBytesToRead = nBytesToRead;
230 :
231 : /* Make sure file is opened with Read access
232 : */
233 11100 : if (psFile == NULL ||
234 5550 : (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite))
235 : {
236 0 : CPLError(CE_Failure, CPLE_FileIO,
237 : "AVCRawBinReadBytes(): call not compatible with access mode.");
238 0 : return;
239 : }
240 :
241 : /* Quick method: check to see if we can satisfy the request with a
242 : * simple memcpy... most calls should take this path.
243 : */
244 5550 : if (psFile->nCurPos + nBytesToRead <= psFile->nCurSize)
245 : {
246 5474 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead);
247 5474 : psFile->nCurPos += nBytesToRead;
248 5474 : return;
249 : }
250 :
251 : /* This is the long method... it supports reading data that
252 : * overlaps the input buffer boundaries.
253 : */
254 227 : while(nBytesToRead > 0)
255 : {
256 : /* If we reached the end of our memory buffer then read another
257 : * chunk from the file
258 : */
259 76 : CPLAssert(psFile->nCurPos <= psFile->nCurSize);
260 76 : if (psFile->nCurPos == psFile->nCurSize)
261 : {
262 76 : psFile->nOffset += psFile->nCurSize;
263 76 : psFile->nCurSize = VSIFRead(psFile->abyBuf, sizeof(GByte),
264 : AVCRAWBIN_READBUFSIZE, psFile->fp);
265 76 : psFile->nCurPos = 0;
266 : }
267 :
268 76 : if (psFile->nCurSize == 0)
269 : {
270 : /* Attempt to read past EOF... generate an error.
271 : *
272 : * Note: AVCRawBinEOF() can set bDisableReadBytesEOFError=TRUE
273 : * to disable the error message whils it is testing
274 : * for EOF.
275 : *
276 : * TODO: We are not resetting the buffer. Also, there is no easy
277 : * way to recover from the situation.
278 : */
279 1 : if (bDisableReadBytesEOFError == FALSE)
280 0 : CPLError(CE_Failure, CPLE_FileIO,
281 : "EOF encountered in %s after reading %d bytes while "
282 : "trying to read %d bytes. File may be corrupt.",
283 : psFile->pszFname, nTotalBytesToRead-nBytesToRead,
284 : nTotalBytesToRead);
285 1 : return;
286 : }
287 :
288 : /* If the requested bytes are not all in the current buffer then
289 : * just read the part that's in memory for now... the loop will
290 : * take care of the rest.
291 : */
292 75 : if (psFile->nCurPos + nBytesToRead > psFile->nCurSize)
293 : {
294 : int nBytes;
295 0 : nBytes = psFile->nCurSize-psFile->nCurPos;
296 0 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytes);
297 0 : psFile->nCurPos += nBytes;
298 0 : pBuf += nBytes;
299 0 : nBytesToRead -= nBytes;
300 : }
301 : else
302 : {
303 : /* All the requested bytes are now in the buffer...
304 : * simply copy them and return.
305 : */
306 75 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead);
307 75 : psFile->nCurPos += nBytesToRead;
308 :
309 75 : nBytesToRead = 0; /* Terminate the loop */
310 : }
311 : }
312 : }
313 :
314 : /**********************************************************************
315 : * AVCRawBinReadString()
316 : *
317 : * Same as AVCRawBinReadBytes() except that the string is run through
318 : * the DBCS conversion function.
319 : *
320 : * pBuf should be allocated with a size of at least nBytesToRead+1 bytes.
321 : **********************************************************************/
322 22 : void AVCRawBinReadString(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
323 : {
324 : const GByte *pszConvBuf;
325 :
326 22 : AVCRawBinReadBytes(psFile, nBytesToRead, pBuf);
327 :
328 22 : pBuf[nBytesToRead] = '\0';
329 :
330 22 : pszConvBuf = AVCE00ConvertFromArcDBCS(psFile->psDBCSInfo,
331 : pBuf,
332 : nBytesToRead);
333 :
334 22 : if (pszConvBuf != pBuf)
335 : {
336 0 : memcpy(pBuf, pszConvBuf, nBytesToRead);
337 : }
338 22 : }
339 :
340 : /**********************************************************************
341 : * AVCRawBinFSeek()
342 : *
343 : * Move the read pointer to the specified location.
344 : *
345 : * As with fseek(), the specified position can be relative to the
346 : * beginning of the file (SEEK_SET), or the current position (SEEK_CUR).
347 : * SEEK_END is not supported.
348 : **********************************************************************/
349 93 : void AVCRawBinFSeek(AVCRawBinFile *psFile, int nOffset, int nFrom)
350 : {
351 93 : int nTarget = 0;
352 :
353 93 : CPLAssert(nFrom == SEEK_SET || nFrom == SEEK_CUR);
354 :
355 : /* Supported only with read access for now
356 : */
357 93 : CPLAssert(psFile && psFile->eAccess != AVCWrite);
358 93 : if (psFile == NULL || psFile->eAccess == AVCWrite)
359 0 : return;
360 :
361 : /* Compute destination relative to current memory buffer
362 : */
363 93 : if (nFrom == SEEK_SET)
364 10 : nTarget = nOffset - psFile->nOffset;
365 83 : else if (nFrom == SEEK_CUR)
366 83 : nTarget = nOffset + psFile->nCurPos;
367 :
368 : /* Is the destination located inside the current buffer?
369 : */
370 129 : if (nTarget > 0 && nTarget <= psFile->nCurSize)
371 : {
372 : /* Requested location is already in memory... just move the
373 : * read pointer
374 : */
375 36 : psFile->nCurPos = nTarget;
376 : }
377 : else
378 : {
379 : /* Requested location is not part of the memory buffer...
380 : * move the FILE * to the right location and be ready to
381 : * read from there.
382 : */
383 57 : VSIFSeek(psFile->fp, psFile->nOffset+nTarget, SEEK_SET);
384 57 : psFile->nCurPos = 0;
385 57 : psFile->nCurSize = 0;
386 57 : psFile->nOffset = psFile->nOffset+nTarget;
387 : }
388 :
389 : }
390 :
391 : /**********************************************************************
392 : * AVCRawBinEOF()
393 : *
394 : * Return TRUE if there is no more data to read from the file or
395 : * FALSE otherwise.
396 : **********************************************************************/
397 7966 : GBool AVCRawBinEOF(AVCRawBinFile *psFile)
398 : {
399 7966 : if (psFile == NULL || psFile->fp == NULL)
400 0 : return TRUE;
401 :
402 : /* In write access mode, always return TRUE, since we always write
403 : * at EOF for now.
404 : */
405 7966 : if (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite)
406 0 : return TRUE;
407 :
408 : /* If file data size was specified, then check that we have not
409 : * passed that point yet...
410 : */
411 7983 : if (psFile->nFileDataSize > 0 &&
412 17 : (psFile->nOffset+psFile->nCurPos) >= psFile->nFileDataSize)
413 1 : return TRUE;
414 :
415 : /* If the file pointer has been moved by AVCRawBinFSeek(), then
416 : * we may be at a position past EOF, but VSIFeof() would still
417 : * return FALSE. It also returns false if we have read just upto
418 : * the end of the file. EOF marker would not have been set unless
419 : * we try to read past that.
420 : *
421 : * To prevent this situation, if the memory buffer is empty,
422 : * we will try to read 1 byte from the file to force the next
423 : * chunk of data to be loaded (and we'll move the the read pointer
424 : * back by 1 char after of course!).
425 : * If we are at the end of the file, this will trigger the EOF flag.
426 : */
427 15925 : if ((psFile->nCurPos == 0 && psFile->nCurSize == 0) ||
428 7940 : (psFile->nCurPos == AVCRAWBIN_READBUFSIZE &&
429 20 : psFile->nCurSize == AVCRAWBIN_READBUFSIZE))
430 : {
431 : GByte c;
432 : /* Set bDisableReadBytesEOFError=TRUE to temporarily disable
433 : * the EOF error message from AVCRawBinReadBytes().
434 : */
435 45 : bDisableReadBytesEOFError = TRUE;
436 45 : AVCRawBinReadBytes(psFile, 1, &c);
437 45 : bDisableReadBytesEOFError = FALSE;
438 :
439 45 : if (psFile->nCurPos > 0)
440 44 : AVCRawBinFSeek(psFile, -1, SEEK_CUR);
441 : }
442 :
443 8011 : return (psFile->nCurPos == psFile->nCurSize &&
444 46 : VSIFEof(psFile->fp));
445 : }
446 :
447 :
448 : /**********************************************************************
449 : * AVCRawBinRead<datatype>()
450 : *
451 : * Arc/Info files are binary files with MSB first (Motorola) byte
452 : * ordering. The following functions will read from the input file
453 : * and return a value with the bytes ordered properly for the current
454 : * platform.
455 : **********************************************************************/
456 55 : GInt16 AVCRawBinReadInt16(AVCRawBinFile *psFile)
457 : {
458 : GInt16 n16Value;
459 :
460 55 : AVCRawBinReadBytes(psFile, 2, (GByte*)(&n16Value));
461 :
462 55 : if (psFile->eByteOrder != geSystemByteOrder)
463 : {
464 55 : return (GInt16)CPL_SWAP16(n16Value);
465 : }
466 :
467 0 : return n16Value;
468 : }
469 :
470 5374 : GInt32 AVCRawBinReadInt32(AVCRawBinFile *psFile)
471 : {
472 : GInt32 n32Value;
473 :
474 5374 : AVCRawBinReadBytes(psFile, 4, (GByte*)(&n32Value));
475 :
476 5374 : if (psFile->eByteOrder != geSystemByteOrder)
477 : {
478 5374 : return (GInt32)CPL_SWAP32(n32Value);
479 : }
480 :
481 0 : return n32Value;
482 : }
483 :
484 44 : float AVCRawBinReadFloat(AVCRawBinFile *psFile)
485 : {
486 : float fValue;
487 :
488 44 : AVCRawBinReadBytes(psFile, 4, (GByte*)(&fValue));
489 :
490 44 : if (psFile->eByteOrder != geSystemByteOrder)
491 : {
492 44 : CPL_SWAP32PTR( &fValue );
493 : }
494 :
495 44 : return fValue;
496 : }
497 :
498 0 : double AVCRawBinReadDouble(AVCRawBinFile *psFile)
499 : {
500 : double dValue;
501 :
502 0 : AVCRawBinReadBytes(psFile, 8, (GByte*)(&dValue));
503 :
504 0 : if (psFile->eByteOrder != geSystemByteOrder)
505 : {
506 0 : CPL_SWAPDOUBLE(&dValue);
507 : }
508 :
509 0 : return dValue;
510 : }
511 :
512 :
513 :
514 : /**********************************************************************
515 : * AVCRawBinWriteBytes()
516 : *
517 : * Write the number of bytes from the buffer to the file.
518 : *
519 : * If a problem happens, then CPLError() will be called and
520 : * CPLGetLastErrNo() can be used to test if a write operation was
521 : * succesful.
522 : **********************************************************************/
523 0 : void AVCRawBinWriteBytes(AVCRawBinFile *psFile, int nBytesToWrite,
524 : const GByte *pBuf)
525 : {
526 : /*----------------------------------------------------------------
527 : * Make sure file is opened with Write access
528 : *---------------------------------------------------------------*/
529 0 : if (psFile == NULL ||
530 0 : (psFile->eAccess != AVCWrite && psFile->eAccess != AVCReadWrite))
531 : {
532 0 : CPLError(CE_Failure, CPLE_FileIO,
533 : "AVCRawBinWriteBytes(): call not compatible with access mode.");
534 0 : return;
535 : }
536 :
537 0 : if (VSIFWrite((void*)pBuf, nBytesToWrite, 1, psFile->fp) != 1)
538 0 : CPLError(CE_Failure, CPLE_FileIO,
539 : "Writing to %s failed.", psFile->pszFname);
540 :
541 : /*----------------------------------------------------------------
542 : * In write mode, we keep track of current file position ( =nbr of
543 : * bytes written) through psFile->nCurPos
544 : *---------------------------------------------------------------*/
545 0 : psFile->nCurPos += nBytesToWrite;
546 : }
547 :
548 :
549 : /**********************************************************************
550 : * AVCRawBinWrite<datatype>()
551 : *
552 : * Arc/Info files are binary files with MSB first (Motorola) byte
553 : * ordering. The following functions will reorder the byte for the
554 : * value properly and write that to the output file.
555 : *
556 : * If a problem happens, then CPLError() will be called and
557 : * CPLGetLastErrNo() can be used to test if a write operation was
558 : * succesful.
559 : **********************************************************************/
560 0 : void AVCRawBinWriteInt16(AVCRawBinFile *psFile, GInt16 n16Value)
561 : {
562 0 : if (psFile->eByteOrder != geSystemByteOrder)
563 : {
564 0 : n16Value = (GInt16)CPL_SWAP16(n16Value);
565 : }
566 :
567 0 : AVCRawBinWriteBytes(psFile, 2, (GByte*)&n16Value);
568 0 : }
569 :
570 0 : void AVCRawBinWriteInt32(AVCRawBinFile *psFile, GInt32 n32Value)
571 : {
572 0 : if (psFile->eByteOrder != geSystemByteOrder)
573 : {
574 0 : n32Value = (GInt32)CPL_SWAP32(n32Value);
575 : }
576 :
577 0 : AVCRawBinWriteBytes(psFile, 4, (GByte*)&n32Value);
578 0 : }
579 :
580 0 : void AVCRawBinWriteFloat(AVCRawBinFile *psFile, float fValue)
581 : {
582 0 : if (psFile->eByteOrder != geSystemByteOrder)
583 : {
584 0 : CPL_SWAP32PTR( &fValue );
585 : }
586 :
587 0 : AVCRawBinWriteBytes(psFile, 4, (GByte*)&fValue);
588 0 : }
589 :
590 0 : void AVCRawBinWriteDouble(AVCRawBinFile *psFile, double dValue)
591 : {
592 0 : if (psFile->eByteOrder != geSystemByteOrder)
593 : {
594 0 : CPL_SWAPDOUBLE(&dValue);
595 : }
596 :
597 0 : AVCRawBinWriteBytes(psFile, 8, (GByte*)&dValue);
598 0 : }
599 :
600 :
601 : /**********************************************************************
602 : * AVCRawBinWriteZeros()
603 : *
604 : * Write a number of zeros (sepcified in bytes) at the current position
605 : * in the file.
606 : *
607 : * If a problem happens, then CPLError() will be called and
608 : * CPLGetLastErrNo() can be used to test if a write operation was
609 : * succesful.
610 : **********************************************************************/
611 0 : void AVCRawBinWriteZeros(AVCRawBinFile *psFile, int nBytesToWrite)
612 : {
613 0 : char acZeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
614 : int i;
615 :
616 : /* Write by 8 bytes chunks. The last chunk may be less than 8 bytes
617 : */
618 0 : for(i=0; i< nBytesToWrite; i+=8)
619 : {
620 0 : AVCRawBinWriteBytes(psFile, MIN(8,(nBytesToWrite-i)),
621 : (GByte*)acZeros);
622 : }
623 0 : }
624 :
625 : /**********************************************************************
626 : * AVCRawBinWritePaddedString()
627 : *
628 : * Write a string and pad the end of the field (up to nFieldSize) with
629 : * spaces number of spaces at the current position in the file.
630 : *
631 : * If a problem happens, then CPLError() will be called and
632 : * CPLGetLastErrNo() can be used to test if a write operation was
633 : * succesful.
634 : **********************************************************************/
635 0 : void AVCRawBinWritePaddedString(AVCRawBinFile *psFile, int nFieldSize,
636 : const GByte *pszString)
637 : {
638 0 : char acSpaces[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
639 : int i, nLen, numSpaces;
640 :
641 : /* If we're on a system with a multibyte codepage then we have to
642 : * convert strings to the proper multibyte encoding.
643 : */
644 0 : pszString = AVCE00Convert2ArcDBCS(psFile->psDBCSInfo,
645 : pszString, nFieldSize);
646 :
647 0 : nLen = strlen((const char *)pszString);
648 0 : nLen = MIN(nLen, nFieldSize);
649 0 : numSpaces = nFieldSize - nLen;
650 :
651 0 : if (nLen > 0)
652 0 : AVCRawBinWriteBytes(psFile, nLen, pszString);
653 :
654 : /* Write spaces by 8 bytes chunks. The last chunk may be less than 8 bytes
655 : */
656 0 : for(i=0; i< numSpaces; i+=8)
657 : {
658 0 : AVCRawBinWriteBytes(psFile, MIN(8,(numSpaces-i)),
659 : (GByte*)acSpaces);
660 : }
661 0 : }
662 :
|