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