~ubuntu-branches/ubuntu/karmic/e00compr/karmic

« back to all changes in this revision

Viewing changes to e00read.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Wise
  • Date: 2005-11-15 15:43:39 UTC
  • Revision ID: james.westby@ubuntu.com-20051115154339-tmt82iiu3dwtk94a
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
 * $Id: e00read.c,v 1.9 2005/09/17 14:22:05 daniel Exp $
 
3
 *
 
4
 * Name:     e00read.c
 
5
 * Project:  Compressed E00 Read/Write library
 
6
 * Language: ANSI C
 
7
 * Purpose:  Functions to read Compressed E00 files and return a stream 
 
8
 *           of uncompressed lines.
 
9
 * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
 
10
 *
 
11
 * $Log: e00read.c,v $
 
12
 * Revision 1.9  2005/09/17 14:22:05  daniel
 
13
 * Switch to MIT license, update refs to website and email address, and
 
14
 * prepare for 1.0.0 release.
 
15
 *
 
16
 * Revision 1.8  1999/02/25 18:45:56  daniel
 
17
 * Now use CPL for Error handling, Memory allocation, and File access
 
18
 *
 
19
 * Revision 1.7  1999/01/08 17:39:08  daniel
 
20
 * Added E00ReadCallbackOpen()
 
21
 *
 
22
 * Revision 1.6  1998/11/13 16:34:08  daniel
 
23
 * Fixed '\r' problem when reading E00 files from a PC under Unix
 
24
 *
 
25
 * Revision 1.5  1998/11/13 15:48:08  daniel
 
26
 * Simplified the decoding of the compression codes for numbers
 
27
 * (use a logical rule instead of going case by case)
 
28
 *
 
29
 * Revision 1.4  1998/11/02 18:34:29  daniel
 
30
 * Added E00ErrorReset() calls.  Replace "EXP  1" by "EXP  0" on read.
 
31
 *
 
32
 * Revision 1.1  1998/10/29 13:26:00  daniel
 
33
 * Initial revision
 
34
 *
 
35
 **********************************************************************
 
36
 * Copyright (c) 1998-2005, Daniel Morissette
 
37
 *
 
38
 * Permission is hereby granted, free of charge, to any person obtaining a
 
39
 * copy of this software and associated documentation files (the "Software"),
 
40
 * to deal in the Software without restriction, including without limitation
 
41
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
42
 * and/or sell copies of the Software, and to permit persons to whom the
 
43
 * Software is furnished to do so, subject to the following conditions:
 
44
 *
 
45
 * The above copyright notice and this permission notice shall be included
 
46
 * in all copies or substantial portions of the Software.
 
47
 *
 
48
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
49
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
50
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
51
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
52
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
53
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
54
 * DEALINGS IN THE SOFTWARE.
 
55
 * 
 
56
 **********************************************************************/
 
57
 
 
58
#include <stdlib.h>
 
59
#include <string.h>
 
60
#include <ctype.h>
 
61
#include <errno.h>
 
62
 
 
63
#include "e00compr.h"
 
64
 
 
65
static void _ReadNextSourceLine(E00ReadPtr psInfo);
 
66
static const char *_UncompressNextLine(E00ReadPtr psInfo);
 
67
 
 
68
/**********************************************************************
 
69
 *                          _E00ReadTestOpen()
 
70
 *
 
71
 * Given a pre-initialized E00ReadPtr, this function will make sure
 
72
 * that the file is really a E00 file, and also establish if it is
 
73
 * compressed or not... setting the structure members by the same way.
 
74
 *
 
75
 * Returns NULL (and destroys the E00ReadPtr) if the file does not
 
76
 * appear to be a valid E00 file.
 
77
 **********************************************************************/
 
78
static E00ReadPtr  _E00ReadTestOpen(E00ReadPtr psInfo)
 
79
{
 
80
 
 
81
    /* Check that the file is in E00 format.
 
82
     */
 
83
    _ReadNextSourceLine(psInfo);
 
84
    if (!psInfo->bEOF && strncmp(psInfo->szInBuf, "EXP ", 4) == 0)
 
85
    {
 
86
        /* We should be in presence of a valid E00 file... 
 
87
         * Is the file compressed or not?
 
88
         *
 
89
         * Note: we cannot really rely on the number that follows the EXP to
 
90
         * establish if the file is compressed since we sometimes encounter
 
91
         * uncompressed files that start with a "EXP 1" line!!!
 
92
         *
 
93
         * The best test is to read the first non-empty line: if the file is
 
94
         * compressed, the first line of data should be 79 or 80 characters 
 
95
         * long and contain several '~' characters.
 
96
         */
 
97
        do
 
98
        {
 
99
            _ReadNextSourceLine(psInfo);
 
100
        }while(!psInfo->bEOF && 
 
101
               (psInfo->szInBuf[0] == '\0' || isspace(psInfo->szInBuf[0])) );
 
102
 
 
103
         if (!psInfo->bEOF && 
 
104
             (strlen(psInfo->szInBuf)==79 || strlen(psInfo->szInBuf)==80) &&
 
105
             strchr(psInfo->szInBuf, '~') != NULL )
 
106
             psInfo->bIsCompressed = 1;
 
107
 
 
108
         /* Move the Read ptr ready to read at the beginning of the file
 
109
          */
 
110
         E00ReadRewind(psInfo);
 
111
    }
 
112
    else
 
113
    {
 
114
        CPLFree(psInfo);
 
115
        psInfo = NULL;
 
116
    }
 
117
 
 
118
    return psInfo;
 
119
}
 
120
 
 
121
/**********************************************************************
 
122
 *                          E00ReadOpen()
 
123
 *
 
124
 * Try to open a E00 file given its filename and return a E00ReadPtr handle.
 
125
 *
 
126
 * Returns NULL if the file could not be opened or if it does not 
 
127
 * appear to be a valid E00 file.
 
128
 **********************************************************************/
 
129
E00ReadPtr  E00ReadOpen(const char *pszFname)
 
130
{
 
131
    E00ReadPtr  psInfo = NULL;
 
132
    FILE        *fp;
 
133
 
 
134
    CPLErrorReset();
 
135
 
 
136
    /* Open the file 
 
137
     */
 
138
    fp = VSIFOpen(pszFname, "rt");
 
139
    if (fp == NULL)
 
140
    {
 
141
        CPLError(CE_Failure, CPLE_OpenFailed,
 
142
                 "Failed to open %s: %s", pszFname, strerror(errno));
 
143
        return NULL;
 
144
    }
 
145
 
 
146
    /* File was succesfully opened, allocate and initialize a 
 
147
     * E00ReadPtr handle and check that the file is valid.
 
148
     */
 
149
    psInfo = (E00ReadPtr)CPLCalloc(1, sizeof(struct _E00ReadInfo));
 
150
 
 
151
    psInfo->fp = fp;
 
152
 
 
153
    psInfo = _E00ReadTestOpen(psInfo);
 
154
 
 
155
    if (psInfo == NULL)
 
156
    {
 
157
        CPLError(CE_Failure, CPLE_OpenFailed,
 
158
                 "%s is not a valid E00 file.", pszFname);
 
159
    }
 
160
 
 
161
    return psInfo;
 
162
}
 
163
 
 
164
/**********************************************************************
 
165
 *                          E00ReadCallbackOpen()
 
166
 *
 
167
 * This is an alternative to E00ReadOpen() for cases where you want to
 
168
 * do all the file management yourself.  You open/close the file yourself
 
169
 * and provide 2 callback functions: to read from the file and rewind the
 
170
 * file pointer.  pRefData is your handle on the physical file and can
 
171
 * be whatever you want... it is not used by the library, it will be
 
172
 * passed directly to your 2 callback functions when they are called.
 
173
 *
 
174
 * The callback functions must have the following C prototype:
 
175
 *
 
176
 *   const char *myReadNextLine(void *pRefData);
 
177
 *   void        myReadRewind(void *pRefData);
 
178
 *
 
179
 *   myReadNextLine() should return a reference to its own internal 
 
180
 *   buffer, or NULL if an error happens or EOF is reached.
 
181
 *
 
182
 * E00ReadCallbackOpen() returns a E00ReadPtr handle or NULL if the file
 
183
 * does not appear to be a valid E00 file.
 
184
 **********************************************************************/
 
185
E00ReadPtr  E00ReadCallbackOpen(void *pRefData,
 
186
                                const char * (*pfnReadNextLine)(void *),
 
187
                                void (*pfnReadRewind)(void *))
 
188
{
 
189
    E00ReadPtr  psInfo = NULL;
 
190
 
 
191
    CPLErrorReset();
 
192
 
 
193
    /* Make sure we received valid function pointers
 
194
     */
 
195
    if (pfnReadNextLine == NULL || pfnReadRewind == NULL)
 
196
    {
 
197
        CPLError(CE_Failure, CPLE_IllegalArg,
 
198
                 "Invalid function pointers!");
 
199
        return NULL;
 
200
    }
 
201
 
 
202
    /* Allocate and initialize a 
 
203
     * E00ReadPtr handle and check that the file is valid.
 
204
     */
 
205
    psInfo = (E00ReadPtr)CPLCalloc(1, sizeof(struct _E00ReadInfo));
 
206
 
 
207
    psInfo->pRefData = pRefData;
 
208
    psInfo->pfnReadNextLine = pfnReadNextLine;
 
209
    psInfo->pfnReadRewind = pfnReadRewind;
 
210
 
 
211
    psInfo = _E00ReadTestOpen(psInfo);
 
212
 
 
213
    if (psInfo == NULL)
 
214
    {
 
215
        CPLError(CE_Failure, CPLE_OpenFailed,
 
216
                 "This is not a valid E00 file.");
 
217
    }
 
218
 
 
219
    return psInfo;
 
220
}
 
221
 
 
222
/**********************************************************************
 
223
 *                          E00ReadClose()
 
224
 *
 
225
 * Close input file and release any memory used by the E00ReadPtr.
 
226
 **********************************************************************/
 
227
void    E00ReadClose(E00ReadPtr psInfo)
 
228
{
 
229
    CPLErrorReset();
 
230
 
 
231
    if (psInfo)
 
232
    {
 
233
        if (psInfo->fp)
 
234
            VSIFClose(psInfo->fp);
 
235
        CPLFree(psInfo);
 
236
    }
 
237
}
 
238
 
 
239
/**********************************************************************
 
240
 *                          E00ReadRewind()
 
241
 *
 
242
 * Rewind the E00ReadPtr.  Allows to start another read pass on the 
 
243
 * input file.
 
244
 **********************************************************************/
 
245
void    E00ReadRewind(E00ReadPtr psInfo)
 
246
{
 
247
    CPLErrorReset();
 
248
 
 
249
    psInfo->szInBuf[0] = psInfo->szOutBuf[0] = '\0';
 
250
    psInfo->iInBufPtr = 0;
 
251
 
 
252
    psInfo->nInputLineNo = 0;
 
253
 
 
254
    if (psInfo->pfnReadRewind == NULL)
 
255
        VSIRewind(psInfo->fp);
 
256
    else
 
257
        psInfo->pfnReadRewind(psInfo->pRefData);
 
258
 
 
259
    psInfo->bEOF = 0;
 
260
}
 
261
 
 
262
/**********************************************************************
 
263
 *                          E00ReadNextLine()
 
264
 *
 
265
 * Return the next line of input from the E00 file or NULL if we reached EOF.
 
266
 *
 
267
 * Returns a reference to an internal buffer whose contents will be valid
 
268
 * only until the next call to this function.
 
269
 **********************************************************************/
 
270
const char *E00ReadNextLine(E00ReadPtr psInfo)
 
271
{
 
272
    const char *pszLine = NULL;
 
273
    char *pszPtr;
 
274
 
 
275
    CPLErrorReset();
 
276
 
 
277
    if (psInfo && !psInfo->bEOF)
 
278
    {
 
279
        if (!psInfo->bIsCompressed)
 
280
        {
 
281
            /* Uncompressed file... return line directly. 
 
282
             */
 
283
            _ReadNextSourceLine(psInfo);
 
284
            pszLine = psInfo->szInBuf;
 
285
        }
 
286
        else if (psInfo->bIsCompressed && psInfo->nInputLineNo == 0)
 
287
        {
 
288
            /* Header line in a compressed file... return line 
 
289
             * after replacing "EXP  1" with "EXP  0".  E00ReadOpen()
 
290
             * has already verified that this line starts with "EXP "
 
291
             */
 
292
            _ReadNextSourceLine(psInfo);
 
293
            if ( (pszPtr = strstr(psInfo->szInBuf, " 1")) != NULL)
 
294
                pszPtr[1] = '0';
 
295
            pszLine = psInfo->szInBuf;
 
296
        }
 
297
        else
 
298
        {
 
299
            if (psInfo->nInputLineNo == 1)
 
300
            {
 
301
                /* We just read the header line... reload the input buffer
 
302
                 */
 
303
                _ReadNextSourceLine(psInfo);
 
304
            }
 
305
 
 
306
            /* Uncompress the next line of input and return it 
 
307
             */
 
308
            pszLine = _UncompressNextLine(psInfo);
 
309
        }
 
310
 
 
311
        /* If we just reached EOF then make sure we don't add an extra
 
312
         * empty line at the end of the uncompressed oputput.
 
313
         */
 
314
        if (psInfo->bEOF && strlen(pszLine) == 0)
 
315
            pszLine = NULL;
 
316
    }
 
317
 
 
318
    return pszLine;
 
319
}
 
320
 
 
321
/**********************************************************************
 
322
 *                          _ReadNextSourceLine()
 
323
 *
 
324
 * Loads the next line from the source file in psInfo.
 
325
 *
 
326
 * psInfo->bEOF should be checked after this call.
 
327
 **********************************************************************/
 
328
static void _ReadNextSourceLine(E00ReadPtr psInfo)
 
329
{
 
330
    if (!psInfo->bEOF)
 
331
    {
 
332
        psInfo->iInBufPtr = 0;
 
333
        psInfo->szInBuf[0] = '\0';
 
334
 
 
335
        /* Read either using fgets() or psInfo->pfnReadNextLine() 
 
336
         * depending on the way the file was opened...
 
337
         */
 
338
        if (psInfo->pfnReadNextLine == NULL)
 
339
        {
 
340
            if (VSIFGets(psInfo->szInBuf,E00_READ_BUF_SIZE,psInfo->fp) == NULL)
 
341
            {
 
342
                /* We reached EOF
 
343
                 */
 
344
                psInfo->bEOF = 1;
 
345
            }
 
346
        }
 
347
        else
 
348
        {
 
349
            const char *pszLine;
 
350
            pszLine = psInfo->pfnReadNextLine(psInfo->pRefData);
 
351
            if (pszLine)
 
352
            {
 
353
                strncpy(psInfo->szInBuf, pszLine, E00_READ_BUF_SIZE);
 
354
            }
 
355
            else
 
356
            {
 
357
                /* We reached EOF
 
358
                 */
 
359
                psInfo->bEOF = 1;
 
360
            }
 
361
        }
 
362
 
 
363
        if (!psInfo->bEOF)
 
364
        {
 
365
            /* A new line was succesfully read.  Remove trailing '\n' if any.
 
366
             * (Note: For Unix systems, we also have to check for '\r')
 
367
             */
 
368
            int nLen;
 
369
            nLen = strlen(psInfo->szInBuf);
 
370
            while(nLen > 0 && (psInfo->szInBuf[nLen-1] == '\n' ||
 
371
                               psInfo->szInBuf[nLen-1] == '\r'   ) )
 
372
            {
 
373
                nLen--;
 
374
                psInfo->szInBuf[nLen] = '\0';
 
375
            }
 
376
 
 
377
            psInfo->nInputLineNo++;
 
378
        }
 
379
    }
 
380
}
 
381
 
 
382
 
 
383
/**********************************************************************
 
384
 *                          _GetNextSourceChar()
 
385
 *
 
386
 * Returns the next char from the source file input buffer... and 
 
387
 * reload the input buffer when necessary... this function makes the
 
388
 * whole input file appear as one huge null-terminated string with
 
389
 * no line delimiters.
 
390
 *
 
391
 * Will return '\0' when EOF is reached.
 
392
 **********************************************************************/
 
393
static char _GetNextSourceChar(E00ReadPtr psInfo)
 
394
{
 
395
    char c = '\0';
 
396
 
 
397
    if (!psInfo->bEOF)
 
398
    {
 
399
        if (psInfo->szInBuf[psInfo->iInBufPtr] == '\0')
 
400
        {
 
401
            _ReadNextSourceLine(psInfo);
 
402
            c = _GetNextSourceChar(psInfo);
 
403
        }
 
404
        else
 
405
        {
 
406
            c = psInfo->szInBuf[psInfo->iInBufPtr++];
 
407
        }
 
408
    }
 
409
 
 
410
    return c;
 
411
}
 
412
 
 
413
/**********************************************************************
 
414
 *                          _UngetSourceChar()
 
415
 *
 
416
 * Reverse the effect of the previous call to _GetNextSourceChar() by
 
417
 * moving the input buffer pointer back 1 character.
 
418
 *
 
419
 * This function can be called only once per call to _GetNextSourceChar()
 
420
 * (i.e. you cannot unget more than one character) otherwise the pointer
 
421
 * could move before the beginning of the input buffer.
 
422
 **********************************************************************/
 
423
static void _UngetSourceChar(E00ReadPtr psInfo)
 
424
{
 
425
    if (psInfo->iInBufPtr > 0)
 
426
        psInfo->iInBufPtr--;
 
427
    else
 
428
    {
 
429
        /* This error can happen only if _UngetSourceChar() is called
 
430
         * twice in a row (which should never happen!).
 
431
         */
 
432
        CPLError(CE_Failure, CPLE_AssertionFailed,
 
433
                 "UNEXPECTED INTERNAL ERROR: _UngetSourceChar() "
 
434
                      "failed while reading line %d.", psInfo->nInputLineNo);
 
435
    }
 
436
}
 
437
 
 
438
/**********************************************************************
 
439
 *                          _UncompressNextLine()
 
440
 *
 
441
 * Uncompress one line of input and return a reference to an internal
 
442
 * buffer containing the uncompressed output.
 
443
 **********************************************************************/
 
444
static const char *_UncompressNextLine(E00ReadPtr psInfo)
 
445
{
 
446
    char    c;
 
447
    int     bEOL = 0;   /* Set to 1 when End of Line reached */
 
448
    int     iOutBufPtr = 0, i, n;
 
449
    int     iDecimalPoint, bOddNumDigits, iCurDigit;
 
450
    char    *pszExp;
 
451
    int     bPreviousCodeWasNumeric = 0;
 
452
 
 
453
    while(!bEOL && (c=_GetNextSourceChar(psInfo)) != '\0')
 
454
    {
 
455
        if (c != '~')
 
456
        {
 
457
            /* Normal character... just copy it 
 
458
             */
 
459
            psInfo->szOutBuf[iOutBufPtr++] = c;
 
460
            bPreviousCodeWasNumeric = 0;
 
461
        }
 
462
        else /* c == '~' */
 
463
        {
 
464
            /* ========================================================
 
465
             * Found an encoded sequence.
 
466
             * =======================================================*/
 
467
            c = _GetNextSourceChar(psInfo);
 
468
 
 
469
            /* --------------------------------------------------------
 
470
             * Compression level 1: only spaces, '~' and '\n' are encoded
 
471
             * -------------------------------------------------------*/
 
472
            if (c == ' ')
 
473
            {
 
474
                /* "~ " followed by number of spaces
 
475
                 */
 
476
                c = _GetNextSourceChar(psInfo);
 
477
                n = c - ' ';
 
478
                for(i=0; i<n; i++)
 
479
                    psInfo->szOutBuf[iOutBufPtr++] = ' ';
 
480
                bPreviousCodeWasNumeric = 0;
 
481
            }
 
482
            else if (c == '}')
 
483
            {
 
484
                /* "~}" == '\n'
 
485
                 */
 
486
                bEOL = 1;
 
487
                bPreviousCodeWasNumeric = 0;
 
488
            }
 
489
            else if (bPreviousCodeWasNumeric)
 
490
            {
 
491
                /* If the previous code was numeric, then the only valid code
 
492
                 * sequences are the ones above: "~ " and "~}".  If we end up
 
493
                 * here, it is because the number was followed by a '~' but
 
494
                 * this '~' was not a code, it only marked the end of a 
 
495
                 * number that was not followed by any space.
 
496
                 *
 
497
                 * We should simply ignore the '~' and return the character
 
498
                 * that follows it directly.
 
499
                 */
 
500
                psInfo->szOutBuf[iOutBufPtr++] = c;
 
501
                bPreviousCodeWasNumeric = 0;
 
502
            }
 
503
            else if (c == '~' || c == '-')
 
504
            {
 
505
                /* "~~" and "~-" are simple escape sequences for '~' and '-'
 
506
                 */
 
507
                psInfo->szOutBuf[iOutBufPtr++] = c;
 
508
            }
 
509
            /* --------------------------------------------------------
 
510
             * Compression level 2: numeric values are encoded.
 
511
             *
 
512
             * All codes for this level are in the form "~ c0 c1 c2 ... cn"
 
513
             * where:
 
514
             *
 
515
             *  ~             marks the beginning of a new code sequence
 
516
             *
 
517
             *  c0            is a single character code defining the format
 
518
             *                of the number (decimal position, exponent, 
 
519
             *                and even or odd number of digits)
 
520
             *
 
521
             *  c1 c2 ... cn  each of these characters represent a pair of 
 
522
             *                digits of the encoded value with '!' == 00
 
523
             *                values 92..99 are encoded on 2 chars that
 
524
             *                must be added to each other 
 
525
             *                (i.e. 92 == }!, 93 == }", ...)
 
526
             *
 
527
             *  The sequence ends with a ' ' or a '~' character
 
528
             * -------------------------------------------------------*/
 
529
            else if (c >= '!' && c <= 'z')
 
530
            {
 
531
                /* The format code defines 3 characteristics of the final number:
 
532
                 * - Presence of a decimal point and its position
 
533
                 * - Presence of an exponent, and its sign
 
534
                 * - Odd or even number of digits
 
535
                 */
 
536
                n = c - '!';
 
537
                iDecimalPoint = n % 15; /* 0 = no decimal point         */
 
538
                bOddNumDigits = n / 45; /* 0 = even num.digits, 1 = odd */
 
539
                n = n / 15;
 
540
                if ( n % 3 == 1 )
 
541
                    pszExp = "E+";
 
542
                else if (n % 3 == 2 )
 
543
                    pszExp = "E-";
 
544
                else 
 
545
                    pszExp = NULL;
 
546
 
 
547
                /* Decode the c1 c2 ... cn value and apply the format.
 
548
                 * Read characters until we encounter a ' ' or a '~'
 
549
                 */
 
550
                iCurDigit = 0;
 
551
                while((c=_GetNextSourceChar(psInfo)) != '\0' && 
 
552
                      c != ' ' && c != '~')
 
553
                {
 
554
                    n = c - '!';
 
555
                    if (n == 92 && (c=_GetNextSourceChar(psInfo)) != '\0')
 
556
                        n += c - '!';
 
557
 
 
558
                    psInfo->szOutBuf[iOutBufPtr++] = '0' + n/10;
 
559
 
 
560
                    if (++iCurDigit == iDecimalPoint)
 
561
                        psInfo->szOutBuf[iOutBufPtr++] = '.';
 
562
 
 
563
                    psInfo->szOutBuf[iOutBufPtr++] = '0' + n%10;
 
564
 
 
565
                    if (++iCurDigit == iDecimalPoint)
 
566
                        psInfo->szOutBuf[iOutBufPtr++] = '.';
 
567
                }
 
568
 
 
569
                if (c == '~' || c == ' ')
 
570
                {
 
571
                    bPreviousCodeWasNumeric = 1;
 
572
                    _UngetSourceChar(psInfo);
 
573
                }
 
574
 
 
575
                /* If odd number of digits, then flush the last one
 
576
                 */
 
577
                if (bOddNumDigits)
 
578
                    iOutBufPtr--;
 
579
 
 
580
                /* Insert the exponent string before the 2 last digits
 
581
                 * (we assume the exponent string is 2 chars. long)
 
582
                 */
 
583
                if (pszExp)
 
584
                {
 
585
                    for(i=0; i<2;i++)
 
586
                    {
 
587
                        psInfo->szOutBuf[iOutBufPtr] = 
 
588
                                   psInfo->szOutBuf[iOutBufPtr-2];
 
589
                        psInfo->szOutBuf[iOutBufPtr-2] = pszExp[i];
 
590
                        iOutBufPtr++;
 
591
                    }
 
592
                }
 
593
            }
 
594
            else
 
595
            {
 
596
                /* Unsupported code sequence... this is a possibility
 
597
                 * given the fact that this library was written by 
 
598
                 * reverse-engineering the format!
 
599
                 *
 
600
                 * Send an error to the user and abort.
 
601
                 *
 
602
                 * If this error ever happens, and you are convinced that
 
603
                 * the input file is not corrupted, then please report it to
 
604
                 * me at dmorissette@dmsolutions.ca, quoting the section of the input
 
605
                 * file that produced it, and I'll do my best to add support
 
606
                 * for this code sequence.
 
607
                 */
 
608
                CPLError(CE_Failure, CPLE_NotSupported,
 
609
                         "Unexpected code \"~%c\" encountered in line %d.",
 
610
                          c, psInfo->nInputLineNo);
 
611
    
 
612
                /* Force the program to abort by simulating a EOF 
 
613
                 */
 
614
                psInfo->bEOF = 1;
 
615
                bEOL = 1;
 
616
            }
 
617
 
 
618
        }/* if c == '~' */
 
619
 
 
620
        /* E00 lines should NEVER be longer than 80 chars.  if we passed
 
621
         * that limit, then the input file is likely corrupt.
 
622
         */
 
623
         if (iOutBufPtr > 80)
 
624
         {
 
625
            CPLError(CE_Failure, CPLE_FileIO,
 
626
                      "Uncompressed line longer than 80 chars. "
 
627
                      "Input file possibly corrupt around line %d.",
 
628
                      psInfo->nInputLineNo);
 
629
            /* Force the program to abort by simulating a EOF 
 
630
             */
 
631
            psInfo->bEOF = 1;
 
632
            bEOL = 1;
 
633
         }
 
634
 
 
635
    }/* while !EOL */
 
636
 
 
637
    psInfo->szOutBuf[iOutBufPtr++] = '\0';
 
638
 
 
639
    return psInfo->szOutBuf;
 
640
}
 
641
 
 
642