source: subversion/applications/utils/export/osm2pgsql/input.c @ 15118

Last change on this file since 15118 was 14847, checked in by zere, 11 years ago

Fixed bug in bzip handling near end-of-file, plus better error reporting.

File size: 5.3 KB
Line 
1#define _FILE_OFFSET_BITS 64
2#define _LARGEFILE64_SOURCE
3
4#include <stdio.h>
5#include <unistd.h>
6#include <string.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10#include <zlib.h>
11#include <bzlib.h>
12
13#include "sanitizer.h"
14#include "input.h"
15
16struct Input {
17  char *name;
18  enum { plainFile, gzipFile, bzip2File } type;
19  void *fileHandle;
20  // needed by bzip2 when decompressing from multiple streams. other
21  // decompressors must ignore it.
22  FILE *systemHandle; 
23  int eof;
24  char buf[4096];
25  int buf_ptr, buf_fill;
26};
27
28// tries to re-open the bz stream at the next stream start.
29// returns 0 on success, -1 on failure.
30int bzReOpen(struct Input *ctx, int *error) {
31  // for copying out the last unused part of the block which
32  // has an EOS token in it. needed for re-initialising the
33  // next stream.
34  unsigned char unused[BZ_MAX_UNUSED];
35  void *unused_tmp_ptr = NULL;
36  int nUnused, i;
37
38  BZ2_bzReadGetUnused(error, (BZFILE *)(ctx->fileHandle), &unused_tmp_ptr, &nUnused);
39  if (*error != BZ_OK) return -1;
40             
41  // when bzReadClose is called the unused buffer is deallocated,
42  // so it needs to be copied somewhere safe first.
43  for (i = 0; i < nUnused; ++i)
44    unused[i] = ((unsigned char *)unused_tmp_ptr)[i];
45 
46  BZ2_bzReadClose(error, (BZFILE *)(ctx->fileHandle));
47  if (*error != BZ_OK) return -1;
48
49  // reassign the file handle
50  ctx->fileHandle = BZ2_bzReadOpen(error, ctx->systemHandle, 0, 0, unused, nUnused);
51  if (ctx->fileHandle == NULL || *error != BZ_OK) return -1;
52
53  return 0;
54}
55
56int readFile(void *context, char * buffer, int len)
57{
58    struct Input *ctx = context;
59    void *f = ctx->fileHandle;
60    int l = 0, error = 0;
61
62    if (ctx->eof || (len == 0))
63        return 0;
64 
65    switch(ctx->type) {
66        case plainFile:
67            l = read(*(int *)f, buffer, len);
68            if (l <= 0) ctx->eof = 1;
69            break;
70        case gzipFile:
71            l = gzread((gzFile)f, buffer, len);
72            if (l <= 0) ctx->eof = 1;
73            break;
74        case bzip2File:
75          l = BZ2_bzRead(&error, (BZFILE *)f, buffer, len);
76
77          // error codes BZ_OK and BZ_STREAM_END are both "OK", but the stream
78          // end means the reader needs to be reset from the original handle.
79          if (error != BZ_OK) {
80            // for stream errors, try re-opening the stream before admitting defeat.
81            if (error != BZ_STREAM_END || bzReOpen(ctx, &error) != 0) {
82              l = 0;
83              ctx->eof = 1;
84            }
85          }
86          break;
87        default:
88            fprintf(stderr, "Bad file type\n");
89            break;
90    }
91
92    if (l < 0) {
93      fprintf(stderr, "File reader received error %d (%d)\n", l, error);
94        l = 0;
95    }
96
97    return l;
98}
99
100char inputGetChar(void *context)
101{
102    struct Input *ctx = context;
103
104    if (ctx->buf_ptr == ctx->buf_fill) {
105        ctx->buf_fill = readFile(context, &ctx->buf[0], sizeof(ctx->buf));
106        ctx->buf_ptr = 0;
107        if (ctx->buf_fill == 0)
108            return 0;
109        if (ctx->buf_fill < 0) {
110            perror("Error while reading file");
111            exit(1);
112        }
113    }
114    //readFile(context, &c, 1);
115    return ctx->buf[ctx->buf_ptr++];
116}
117
118int inputEof(void *context)
119{
120    return ((struct Input *)context)->eof;
121}
122
123
124void *inputOpen(const char *name)
125{
126    const char *ext = strrchr(name, '.');
127    struct Input *ctx = malloc (sizeof(*ctx));
128
129    if (!ctx)
130        return NULL;
131
132    memset(ctx, 0, sizeof(*ctx));
133
134    ctx->name = strdup(name);
135
136    if (ext && !strcmp(ext, ".gz")) {
137        ctx->fileHandle = (void *)gzopen(name, "rb");
138        ctx->type = gzipFile;
139    } else if (ext && !strcmp(ext, ".bz2")) {
140      int error = 0;
141      ctx->systemHandle = fopen(name, "rb");
142      if (!ctx->systemHandle) {
143        fprintf(stderr, "error while opening file %s\n", name);
144        exit(10);
145      }
146
147      ctx->fileHandle = (void *)BZ2_bzReadOpen(&error, ctx->systemHandle, 0, 0, NULL, 0);
148      ctx->type = bzip2File;
149     
150    } else {
151        int *pfd = malloc(sizeof(pfd));
152        if (pfd) {
153            if (!strcmp(name, "-")) {
154                *pfd = STDIN_FILENO;
155            } else {
156                int flags = O_RDONLY;
157#ifdef O_LARGEFILE
158                flags |= O_LARGEFILE;
159#endif
160                *pfd = open(name, flags);
161                if (*pfd < 0) {
162                    free(pfd);
163                    pfd = NULL;
164                }
165            }
166        }
167        ctx->fileHandle = (void *)pfd;
168        ctx->type = plainFile;
169    }
170    if (!ctx->fileHandle) {
171        fprintf(stderr, "error while opening file %s\n", name);
172        exit(10);
173    }
174    ctx->buf_ptr = 0;
175    ctx->buf_fill = 0;
176    return (void *)ctx;
177}
178
179int inputClose(void *context)
180{
181    struct Input *ctx = context;
182    void *f = ctx->fileHandle;
183
184    switch(ctx->type) {
185        case plainFile:
186            close(*(int *)f);
187            free(f);
188            break;
189        case gzipFile:
190            gzclose((gzFile)f);
191            break;
192        case bzip2File:
193            BZ2_bzclose((BZFILE *)f);
194            break;
195        default:
196            fprintf(stderr, "Bad file type\n");
197            break;
198    }
199
200    free(ctx->name);
201    free(ctx);
202    return 0;
203}
204
205xmlTextReaderPtr inputUTF8(const char *name)
206{
207    void *ctx = inputOpen(name);
208
209    if (!ctx) {
210        fprintf(stderr, "Input reader create failed for: %s\n", name);
211        return NULL;
212    }
213
214    return xmlReaderForIO(readFile, inputClose, (void *)ctx, NULL, NULL, 0);
215}
Note: See TracBrowser for help on using the repository browser.