Fix:Core:Replaced g_file_get_contents with navit version
[navit-package] / navit / file.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #define _FILE_OFFSET_BITS 64
21 #define _LARGEFILE_SOURCE
22 #define _LARGEFILE64_SOURCE
23 #include <unistd.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/mman.h>
28 #include <dirent.h>
29 #include <stdio.h>
30 #include <wordexp.h>
31 #include <glib.h>
32 #include <zlib.h>
33 #include "debug.h"
34 #include "cache.h"
35 #include "file.h"
36 #include "config.h"
37
38 #ifndef O_LARGEFILE
39 #define O_LARGEFILE 0
40 #endif
41
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
45
46 #ifdef CACHE_SIZE
47 static GHashTable *file_name_hash;
48 #endif
49
50 static struct cache *file_cache;
51
52 struct file_cache_id {
53         long long offset;
54         int size;
55         int file_name_id;
56         int method;
57 } __attribute__ ((packed));
58
59 struct file *
60 file_create(char *name)
61 {
62         struct stat stat;
63         struct file *file= g_new0(struct file,1);
64
65         file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
66         if (file->fd == -1) {
67                 g_free(file);
68                 return NULL;
69         }
70         dbg(1,"fd=%d\n", file->fd);
71         fstat(file->fd, &stat);
72         file->size=stat.st_size;
73         dbg(1,"size=%Ld\n", file->size);
74         file->name = g_strdup(name);
75         dbg_assert(file != NULL);
76         return file;
77 }
78
79 int file_is_dir(char *name)
80 {
81         struct stat buf;
82         if (! stat(name, &buf)) {
83                 return S_ISDIR(buf.st_mode);
84         }
85         return 0;
86
87 }
88
89 int
90 file_size(struct file *file)
91 {
92         return file->size;
93 }
94
95 int file_mkdir(char *name, int pflag)
96 {
97         char buffer[strlen(name)+1];
98         int ret;
99         char *next;
100         dbg(1,"enter %s %d\n",name,pflag);
101         if (!pflag) {
102                 if (file_is_dir(name))
103                         return 0;
104 #ifdef HAVE_API_WIN32_BASE
105                 return mkdir(name);
106 #else
107                 return mkdir(name, 0777);
108 #endif
109         }
110         strcpy(buffer, name);
111         next=buffer;
112         while ((next=strchr(next, '/'))) {
113                 *next='\0';
114                 if (*buffer) {
115                         ret=file_mkdir(buffer, 0);
116                         if (ret)
117                                 return ret;
118                 }
119                 *next++='/';
120         }
121         if (pflag == 2)
122                 return 0;
123         return file_mkdir(buffer, 0);
124 }
125
126 int
127 file_mmap(struct file *file)
128 {
129 #if defined(_WIN32) || defined(__CEGCC__)
130     file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
131 #else
132         file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
133         dbg_assert(file->begin != NULL);
134         if (file->begin == (void *)0xffffffff) {
135                 perror("mmap");
136                 return 0;
137         }
138 #endif
139         dbg_assert(file->begin != (void *)0xffffffff);
140         file->end=file->begin+file->size;
141
142         return 1;
143 }
144
145 unsigned char *
146 file_data_read(struct file *file, long long offset, int size)
147 {
148         void *ret;
149         if (file->begin)
150                 return file->begin+offset;
151         if (file_cache) {
152                 struct file_cache_id id={offset,size,file->name_id,0};
153                 ret=cache_lookup(file_cache,&id); 
154                 if (ret)
155                         return ret;
156                 ret=cache_insert_new(file_cache,&id,size);
157         } else
158                 ret=g_malloc(size);
159         lseek(file->fd, offset, SEEK_SET);
160         if (read(file->fd, ret, size) != size) {
161                 file_data_free(file, ret);
162                 ret=NULL;
163         }
164         return ret;
165
166 }
167
168 unsigned char *
169 file_data_read_all(struct file *file)
170 {
171         return file_data_read(file, 0, file->size);
172 }
173
174 int
175 file_get_contents(char *name, unsigned char **buffer, int *size)
176 {
177         struct file *file;
178         file=file_create(name);
179         if (!file)
180                 return 0;
181         *size=file_size(file);
182         *buffer=file_data_read_all(file);
183         file_destroy(file);
184         return 1;       
185 }
186
187
188 static int
189 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
190 {
191         z_stream stream;
192         int err;
193
194         stream.next_in = (Bytef*)source;
195         stream.avail_in = (uInt)sourceLen;
196         stream.next_out = dest;
197         stream.avail_out = (uInt)*destLen;
198
199         stream.zalloc = (alloc_func)0;
200         stream.zfree = (free_func)0;
201
202         err = inflateInit2(&stream, -MAX_WBITS);
203         if (err != Z_OK) return err;
204
205         err = inflate(&stream, Z_FINISH);
206         if (err != Z_STREAM_END) {
207         inflateEnd(&stream);
208         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
209                 return Z_DATA_ERROR;
210                 return err;
211         }
212         *destLen = stream.total_out;
213
214         err = inflateEnd(&stream);
215         return err;
216 }
217
218 unsigned char *
219 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
220 {
221         void *ret;
222         char buffer[size];
223         uLongf destLen=size_uncomp;
224
225         if (file_cache) {
226                 struct file_cache_id id={offset,size,file->name_id,1};
227                 ret=cache_lookup(file_cache,&id); 
228                 if (ret)
229                         return ret;
230                 ret=cache_insert_new(file_cache,&id,size_uncomp);
231         } else 
232                 ret=g_malloc(size_uncomp);
233         lseek(file->fd, offset, SEEK_SET);
234         if (read(file->fd, buffer, size) != size) {
235                 g_free(ret);
236                 ret=NULL;
237         } else {
238                 if (uncompress_int(ret, &destLen, (Bytef *)buffer, size) != Z_OK) {
239                         dbg(0,"uncompress failed\n");
240                         g_free(ret);
241                         ret=NULL;
242                 }
243         }
244         return ret;
245 }
246
247 void
248 file_data_free(struct file *file, unsigned char *data)
249 {
250         if (file->begin && data >= file->begin && data < file->end)
251                 return;
252         if (file_cache) {
253                 cache_entry_destroy(file_cache, data);
254         } else
255                 g_free(data);
256 }
257
258 int
259 file_exists(char *name)
260 {
261         struct stat buf;
262         if (! stat(name, &buf))
263                 return 1;
264         return 0;
265 }
266
267 void
268 file_remap_readonly(struct file *f)
269 {
270 #if defined(_WIN32) || defined(__CEGCC__)
271 #else
272         void *begin;
273         munmap(f->begin, f->size);
274         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
275         if (f->begin != begin)
276                 printf("remap failed\n");
277 #endif
278 }
279
280 void
281 file_unmap(struct file *f)
282 {
283 #if defined(_WIN32) || defined(__CEGCC__)
284     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
285 #else
286         munmap(f->begin, f->size);
287 #endif
288 }
289
290 void *
291 file_opendir(char *dir)
292 {
293         return opendir(dir);
294 }
295
296 char *
297 file_readdir(void *hnd)
298 {
299         struct dirent *ent;
300
301         ent=readdir(hnd);
302         if (! ent)
303                 return NULL;
304         return ent->d_name;
305 }
306
307 void
308 file_closedir(void *hnd)
309 {
310         closedir(hnd);
311 }
312
313 struct file *
314 file_create_caseinsensitive(char *name)
315 {
316         char dirname[strlen(name)+1];
317         char *filename;
318         char *p;
319         void *d;
320         struct file *ret;
321
322         ret=file_create(name);
323         if (ret)
324                 return ret;
325
326         strcpy(dirname, name);
327         p=dirname+strlen(name);
328         while (p > dirname) {
329                 if (*p == '/')
330                         break;
331                 p--;
332         }
333         *p=0;
334         d=file_opendir(dirname);
335         if (d) {
336                 *p++='/';
337                 while ((filename=file_readdir(d))) {
338                         if (!strcasecmp(filename, p)) {
339                                 strcpy(p, filename);
340                                 ret=file_create(dirname);
341                                 if (ret)
342                                         break;
343                         }
344                 }
345                 file_closedir(d);
346         }
347         return ret;
348 }
349
350 void
351 file_destroy(struct file *f)
352 {
353         close(f->fd);
354
355     if ( f->begin != NULL )
356     {
357         file_unmap( f );
358     }
359
360         g_free(f->name);
361         g_free(f);
362 }
363
364 struct file_wordexp {
365         int err;
366         wordexp_t we;
367 };
368
369 struct file_wordexp *
370 file_wordexp_new(const char *pattern)
371 {
372         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
373
374         ret->err=wordexp(pattern, &ret->we, 0);
375         if (ret->err)
376                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
377         return ret;
378 }
379
380 int
381 file_wordexp_get_count(struct file_wordexp *wexp)
382 {
383         return wexp->we.we_wordc;
384 }
385
386 char **
387 file_wordexp_get_array(struct file_wordexp *wexp)
388 {
389         return wexp->we.we_wordv;
390 }
391
392 void
393 file_wordexp_destroy(struct file_wordexp *wexp)
394 {
395         if (! wexp->err)
396                 wordfree(&wexp->we);
397         g_free(wexp);
398 }
399
400
401 int
402 file_get_param(struct file *file, struct param_list *param, int count)
403 {
404         int i=count;
405         param_add_string("Filename", file->name, &param, &count);
406         param_add_hex("Size", file->size, &param, &count);
407         return i-count;
408 }
409
410 int
411 file_version(struct file *file, int byname)
412 {
413 #ifndef __CEGCC__
414         struct stat st;
415         int error;
416         if (byname)
417                 error=stat(file->name, &st);
418         else
419                 error=fstat(file->fd, &st);
420         if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
421                 file->mtime=st.st_mtime;
422                 file->ctime=st.st_ctime;
423                 file->version++;
424                 dbg(0,"%s now version %d\n", file->name, file->version);
425         }
426         return file->version;
427 #else
428         return 0;
429 #endif
430 }
431
432 void *
433 file_get_os_handle(struct file *file)
434 {
435         return (void *)(file->fd);
436 }
437
438 void
439 file_init(void)
440 {
441 #ifdef CACHE_SIZE
442         file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
443         file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
444 #endif
445 }
446