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