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 : AVCRawBinFile *AVCRawBinOpen(const char *pszFname, const char *pszAccess,
111 : AVCByteOrder eFileByteOrder,
112 : AVCDBCSInfo *psDBCSInfo)
113 10 : {
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 : void AVCRawBinClose(AVCRawBinFile *psFile)
191 11 : {
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 : void AVCRawBinSetFileDataSize(AVCRawBinFile *psFile, int nFileDataSize)
212 4 : {
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 : void AVCRawBinReadBytes(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
228 5510 : {
229 : /* Make sure file is opened with Read access
230 : */
231 5510 : if (psFile == NULL ||
232 : (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 5510 : if (psFile->nCurPos + nBytesToRead <= psFile->nCurSize)
243 : {
244 5474 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead);
245 5474 : psFile->nCurPos += nBytesToRead;
246 5474 : return;
247 : }
248 :
249 : /* This is the long method... it supports reading data that
250 : * overlaps the input buffer boundaries.
251 : */
252 107 : while(nBytesToRead > 0)
253 : {
254 : /* If we reached the end of our memory buffer then read another
255 : * chunk from the file
256 : */
257 36 : CPLAssert(psFile->nCurPos <= psFile->nCurSize);
258 36 : if (psFile->nCurPos == psFile->nCurSize)
259 : {
260 36 : psFile->nOffset += psFile->nCurSize;
261 36 : psFile->nCurSize = VSIFRead(psFile->abyBuf, sizeof(GByte),
262 : AVCRAWBIN_READBUFSIZE, psFile->fp);
263 36 : psFile->nCurPos = 0;
264 : }
265 :
266 36 : 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 whils it is testing
272 : * for EOF.
273 : */
274 1 : if (bDisableReadBytesEOFError == FALSE)
275 0 : CPLError(CE_Failure, CPLE_FileIO,
276 : "Attempt to read past EOF in %s.", psFile->pszFname);
277 1 : return;
278 : }
279 :
280 : /* If the requested bytes are not all in the current buffer then
281 : * just read the part that's in memory for now... the loop will
282 : * take care of the rest.
283 : */
284 35 : if (psFile->nCurPos + nBytesToRead > psFile->nCurSize)
285 : {
286 : int nBytes;
287 0 : nBytes = psFile->nCurSize-psFile->nCurPos;
288 0 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytes);
289 0 : psFile->nCurPos += nBytes;
290 0 : pBuf += nBytes;
291 0 : nBytesToRead -= nBytes;
292 : }
293 : else
294 : {
295 : /* All the requested bytes are now in the buffer...
296 : * simply copy them and return.
297 : */
298 35 : memcpy(pBuf, psFile->abyBuf+psFile->nCurPos, nBytesToRead);
299 35 : psFile->nCurPos += nBytesToRead;
300 :
301 35 : nBytesToRead = 0; /* Terminate the loop */
302 : }
303 : }
304 : }
305 :
306 : /**********************************************************************
307 : * AVCRawBinReadString()
308 : *
309 : * Same as AVCRawBinReadBytes() except that the string is run through
310 : * the DBCS conversion function.
311 : *
312 : * pBuf should be allocated with a size of at least nBytesToRead+1 bytes.
313 : **********************************************************************/
314 : void AVCRawBinReadString(AVCRawBinFile *psFile, int nBytesToRead, GByte *pBuf)
315 22 : {
316 : const GByte *pszConvBuf;
317 :
318 22 : AVCRawBinReadBytes(psFile, nBytesToRead, pBuf);
319 :
320 22 : pBuf[nBytesToRead] = '\0';
321 :
322 22 : pszConvBuf = AVCE00ConvertFromArcDBCS(psFile->psDBCSInfo,
323 : pBuf,
324 : nBytesToRead);
325 :
326 22 : if (pszConvBuf != pBuf)
327 : {
328 0 : memcpy(pBuf, pszConvBuf, nBytesToRead);
329 : }
330 22 : }
331 :
332 : /**********************************************************************
333 : * AVCRawBinFSeek()
334 : *
335 : * Move the read pointer to the specified location.
336 : *
337 : * As with fseek(), the specified position can be relative to the
338 : * beginning of the file (SEEK_SET), or the current position (SEEK_CUR).
339 : * SEEK_END is not supported.
340 : **********************************************************************/
341 : void AVCRawBinFSeek(AVCRawBinFile *psFile, int nOffset, int nFrom)
342 53 : {
343 53 : int nTarget = 0;
344 :
345 53 : CPLAssert(nFrom == SEEK_SET || nFrom == SEEK_CUR);
346 :
347 : /* Supported only with read access for now
348 : */
349 53 : CPLAssert(psFile && psFile->eAccess != AVCWrite);
350 53 : if (psFile == NULL || psFile->eAccess == AVCWrite)
351 0 : return;
352 :
353 : /* Compute destination relative to current memory buffer
354 : */
355 53 : if (nFrom == SEEK_SET)
356 10 : nTarget = nOffset - psFile->nOffset;
357 43 : else if (nFrom == SEEK_CUR)
358 43 : nTarget = nOffset + psFile->nCurPos;
359 :
360 : /* Is the destination located inside the current buffer?
361 : */
362 89 : if (nTarget > 0 && nTarget <= psFile->nCurSize)
363 : {
364 : /* Requested location is already in memory... just move the
365 : * read pointer
366 : */
367 36 : psFile->nCurPos = nTarget;
368 : }
369 : else
370 : {
371 : /* Requested location is not part of the memory buffer...
372 : * move the FILE * to the right location and be ready to
373 : * read from there.
374 : */
375 17 : VSIFSeek(psFile->fp, psFile->nOffset+nTarget, SEEK_SET);
376 17 : psFile->nCurPos = 0;
377 17 : psFile->nCurSize = 0;
378 17 : psFile->nOffset = psFile->nOffset+nTarget;
379 : }
380 :
381 : }
382 :
383 : /**********************************************************************
384 : * AVCRawBinEOF()
385 : *
386 : * Return TRUE if there is no more data to read from the file or
387 : * FALSE otherwise.
388 : **********************************************************************/
389 : GBool AVCRawBinEOF(AVCRawBinFile *psFile)
390 7966 : {
391 7966 : if (psFile == NULL || psFile->fp == NULL)
392 0 : return TRUE;
393 :
394 : /* In write access mode, always return TRUE, since we always write
395 : * at EOF for now.
396 : */
397 7966 : if (psFile->eAccess != AVCRead && psFile->eAccess != AVCReadWrite)
398 0 : return TRUE;
399 :
400 : /* If file data size was specified, then check that we have not
401 : * passed that point yet...
402 : */
403 7966 : if (psFile->nFileDataSize > 0 &&
404 : (psFile->nOffset+psFile->nCurPos) >= psFile->nFileDataSize)
405 1 : return TRUE;
406 :
407 : /* If the file pointer has been moved by AVCRawBinFSeek(), then
408 : * we may be at a position past EOF, but VSIFeof() would still
409 : * return FALSE.
410 : * To prevent this situation, if the memory buffer is empty,
411 : * we will try to read 1 byte from the file to force the next
412 : * chunk of data to be loaded (and we'll move the the read pointer
413 : * back by 1 char after of course!).
414 : * If we are at the end of the file, this will trigger the EOF flag.
415 : */
416 7965 : if (psFile->nCurPos == 0 && psFile->nCurSize == 0)
417 : {
418 : GByte c;
419 : /* Set bDisableReadBytesEOFError=TRUE to temporarily disable
420 : * the EOF error message from AVCRawBinReadBytes().
421 : */
422 5 : bDisableReadBytesEOFError = TRUE;
423 5 : AVCRawBinReadBytes(psFile, 1, &c);
424 5 : bDisableReadBytesEOFError = FALSE;
425 :
426 5 : if (psFile->nCurPos > 0)
427 4 : AVCRawBinFSeek(psFile, -1, SEEK_CUR);
428 : }
429 :
430 7965 : return (psFile->nCurPos == psFile->nCurSize &&
431 : VSIFEof(psFile->fp));
432 : }
433 :
434 :
435 : /**********************************************************************
436 : * AVCRawBinRead<datatype>()
437 : *
438 : * Arc/Info files are binary files with MSB first (Motorola) byte
439 : * ordering. The following functions will read from the input file
440 : * and return a value with the bytes ordered properly for the current
441 : * platform.
442 : **********************************************************************/
443 : GInt16 AVCRawBinReadInt16(AVCRawBinFile *psFile)
444 55 : {
445 : GInt16 n16Value;
446 :
447 55 : AVCRawBinReadBytes(psFile, 2, (GByte*)(&n16Value));
448 :
449 55 : if (psFile->eByteOrder != geSystemByteOrder)
450 : {
451 55 : return (GInt16)CPL_SWAP16(n16Value);
452 : }
453 :
454 0 : return n16Value;
455 : }
456 :
457 : GInt32 AVCRawBinReadInt32(AVCRawBinFile *psFile)
458 5374 : {
459 : GInt32 n32Value;
460 :
461 5374 : AVCRawBinReadBytes(psFile, 4, (GByte*)(&n32Value));
462 :
463 5374 : if (psFile->eByteOrder != geSystemByteOrder)
464 : {
465 5374 : return (GInt32)CPL_SWAP32(n32Value);
466 : }
467 :
468 0 : return n32Value;
469 : }
470 :
471 : float AVCRawBinReadFloat(AVCRawBinFile *psFile)
472 44 : {
473 : float fValue;
474 :
475 44 : AVCRawBinReadBytes(psFile, 4, (GByte*)(&fValue));
476 :
477 44 : if (psFile->eByteOrder != geSystemByteOrder)
478 : {
479 44 : CPL_SWAP32PTR( &fValue );
480 : }
481 :
482 44 : return fValue;
483 : }
484 :
485 : double AVCRawBinReadDouble(AVCRawBinFile *psFile)
486 0 : {
487 : double dValue;
488 :
489 0 : AVCRawBinReadBytes(psFile, 8, (GByte*)(&dValue));
490 :
491 0 : if (psFile->eByteOrder != geSystemByteOrder)
492 : {
493 0 : CPL_SWAPDOUBLE(&dValue);
494 : }
495 :
496 0 : return dValue;
497 : }
498 :
499 :
500 :
501 : /**********************************************************************
502 : * AVCRawBinWriteBytes()
503 : *
504 : * Write the number of bytes from the buffer to the file.
505 : *
506 : * If a problem happens, then CPLError() will be called and
507 : * CPLGetLastErrNo() can be used to test if a write operation was
508 : * succesful.
509 : **********************************************************************/
510 : void AVCRawBinWriteBytes(AVCRawBinFile *psFile, int nBytesToWrite,
511 : const GByte *pBuf)
512 0 : {
513 : /*----------------------------------------------------------------
514 : * Make sure file is opened with Write access
515 : *---------------------------------------------------------------*/
516 0 : if (psFile == NULL ||
517 : (psFile->eAccess != AVCWrite && psFile->eAccess != AVCReadWrite))
518 : {
519 0 : CPLError(CE_Failure, CPLE_FileIO,
520 : "AVCRawBinWriteBytes(): call not compatible with access mode.");
521 0 : return;
522 : }
523 :
524 0 : if (VSIFWrite((void*)pBuf, nBytesToWrite, 1, psFile->fp) != 1)
525 0 : CPLError(CE_Failure, CPLE_FileIO,
526 : "Writing to %s failed.", psFile->pszFname);
527 :
528 : /*----------------------------------------------------------------
529 : * In write mode, we keep track of current file position ( =nbr of
530 : * bytes written) through psFile->nCurPos
531 : *---------------------------------------------------------------*/
532 0 : psFile->nCurPos += nBytesToWrite;
533 : }
534 :
535 :
536 : /**********************************************************************
537 : * AVCRawBinWrite<datatype>()
538 : *
539 : * Arc/Info files are binary files with MSB first (Motorola) byte
540 : * ordering. The following functions will reorder the byte for the
541 : * value properly and write that to the output file.
542 : *
543 : * If a problem happens, then CPLError() will be called and
544 : * CPLGetLastErrNo() can be used to test if a write operation was
545 : * succesful.
546 : **********************************************************************/
547 : void AVCRawBinWriteInt16(AVCRawBinFile *psFile, GInt16 n16Value)
548 0 : {
549 0 : if (psFile->eByteOrder != geSystemByteOrder)
550 : {
551 0 : n16Value = (GInt16)CPL_SWAP16(n16Value);
552 : }
553 :
554 0 : AVCRawBinWriteBytes(psFile, 2, (GByte*)&n16Value);
555 0 : }
556 :
557 : void AVCRawBinWriteInt32(AVCRawBinFile *psFile, GInt32 n32Value)
558 0 : {
559 0 : if (psFile->eByteOrder != geSystemByteOrder)
560 : {
561 0 : n32Value = (GInt32)CPL_SWAP32(n32Value);
562 : }
563 :
564 0 : AVCRawBinWriteBytes(psFile, 4, (GByte*)&n32Value);
565 0 : }
566 :
567 : void AVCRawBinWriteFloat(AVCRawBinFile *psFile, float fValue)
568 0 : {
569 0 : if (psFile->eByteOrder != geSystemByteOrder)
570 : {
571 0 : CPL_SWAP32PTR( &fValue );
572 : }
573 :
574 0 : AVCRawBinWriteBytes(psFile, 4, (GByte*)&fValue);
575 0 : }
576 :
577 : void AVCRawBinWriteDouble(AVCRawBinFile *psFile, double dValue)
578 0 : {
579 0 : if (psFile->eByteOrder != geSystemByteOrder)
580 : {
581 0 : CPL_SWAPDOUBLE(&dValue);
582 : }
583 :
584 0 : AVCRawBinWriteBytes(psFile, 8, (GByte*)&dValue);
585 0 : }
586 :
587 :
588 : /**********************************************************************
589 : * AVCRawBinWriteZeros()
590 : *
591 : * Write a number of zeros (sepcified in bytes) at the current position
592 : * in the file.
593 : *
594 : * If a problem happens, then CPLError() will be called and
595 : * CPLGetLastErrNo() can be used to test if a write operation was
596 : * succesful.
597 : **********************************************************************/
598 : void AVCRawBinWriteZeros(AVCRawBinFile *psFile, int nBytesToWrite)
599 0 : {
600 0 : char acZeros[8] = {0, 0, 0, 0, 0, 0, 0, 0};
601 : int i;
602 :
603 : /* Write by 8 bytes chunks. The last chunk may be less than 8 bytes
604 : */
605 0 : for(i=0; i< nBytesToWrite; i+=8)
606 : {
607 0 : AVCRawBinWriteBytes(psFile, MIN(8,(nBytesToWrite-i)),
608 : (GByte*)acZeros);
609 : }
610 0 : }
611 :
612 : /**********************************************************************
613 : * AVCRawBinWritePaddedString()
614 : *
615 : * Write a string and pad the end of the field (up to nFieldSize) with
616 : * spaces number of spaces at the current position in the file.
617 : *
618 : * If a problem happens, then CPLError() will be called and
619 : * CPLGetLastErrNo() can be used to test if a write operation was
620 : * succesful.
621 : **********************************************************************/
622 : void AVCRawBinWritePaddedString(AVCRawBinFile *psFile, int nFieldSize,
623 : const GByte *pszString)
624 0 : {
625 0 : char acSpaces[8] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
626 : int i, nLen, numSpaces;
627 :
628 : /* If we're on a system with a multibyte codepage then we have to
629 : * convert strings to the proper multibyte encoding.
630 : */
631 0 : pszString = AVCE00Convert2ArcDBCS(psFile->psDBCSInfo,
632 : pszString, nFieldSize);
633 :
634 0 : nLen = strlen((const char *)pszString);
635 0 : nLen = MIN(nLen, nFieldSize);
636 0 : numSpaces = nFieldSize - nLen;
637 :
638 0 : if (nLen > 0)
639 0 : AVCRawBinWriteBytes(psFile, nLen, pszString);
640 :
641 : /* Write spaces by 8 bytes chunks. The last chunk may be less than 8 bytes
642 : */
643 0 : for(i=0; i< numSpaces; i+=8)
644 : {
645 0 : AVCRawBinWriteBytes(psFile, MIN(8,(numSpaces-i)),
646 : (GByte*)acSpaces);
647 : }
648 0 : }
649 :
|