Add:Various:Adding LZMA support to binfiles
[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 <LzmaTypes.h>
34 #include <LzmaDec.h>
35 #include "debug.h"
36 #include "cache.h"
37 #include "file.h"
38 #include "config.h"
39
40 #ifndef O_LARGEFILE
41 #define O_LARGEFILE 0
42 #endif
43
44 #ifndef O_BINARY
45 #define O_BINARY 0
46 #endif
47
48 #ifdef CACHE_SIZE
49 static GHashTable *file_name_hash;
50 #endif
51
52 static struct cache *file_cache;
53
54 struct file_cache_id {
55         long long offset;
56         int size;
57         int file_name_id;
58         int method;
59 } __attribute__ ((packed));
60
61 struct file *
62 file_create(char *name)
63 {
64         struct stat stat;
65         struct file *file= g_new0(struct file,1);
66
67         file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
68         if (file->fd == -1) {
69                 g_free(file);
70                 return NULL;
71         }
72         dbg(1,"fd=%d\n", file->fd);
73         fstat(file->fd, &stat);
74         file->size=stat.st_size;
75         dbg(1,"size=%Ld\n", file->size);
76         file->name = g_strdup(name);
77         dbg_assert(file != NULL);
78         return file;
79 }
80
81 int file_is_dir(char *name)
82 {
83         struct stat buf;
84         if (! stat(name, &buf)) {
85                 return S_ISDIR(buf.st_mode);
86         }
87         return 0;
88
89 }
90
91 int
92 file_size(struct file *file)
93 {
94         return file->size;
95 }
96
97 int file_mkdir(char *name, int pflag)
98 {
99         char buffer[strlen(name)+1];
100         int ret;
101         char *next;
102         dbg(1,"enter %s %d\n",name,pflag);
103         if (!pflag) {
104                 if (file_is_dir(name))
105                         return 0;
106 #ifdef HAVE_API_WIN32_BASE
107                 return mkdir(name);
108 #else
109                 return mkdir(name, 0777);
110 #endif
111         }
112         strcpy(buffer, name);
113         next=buffer;
114         while ((next=strchr(next, '/'))) {
115                 *next='\0';
116                 if (*buffer) {
117                         ret=file_mkdir(buffer, 0);
118                         if (ret)
119                                 return ret;
120                 }
121                 *next++='/';
122         }
123         if (pflag == 2)
124                 return 0;
125         return file_mkdir(buffer, 0);
126 }
127
128 int
129 file_mmap(struct file *file)
130 {
131 #if defined(_WIN32) || defined(__CEGCC__)
132     file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
133 #else
134         file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
135         dbg_assert(file->begin != NULL);
136         if (file->begin == (void *)0xffffffff) {
137                 perror("mmap");
138                 return 0;
139         }
140 #endif
141         dbg_assert(file->begin != (void *)0xffffffff);
142         file->end=file->begin+file->size;
143
144         return 1;
145 }
146
147 unsigned char *
148 file_data_read(struct file *file, long long offset, int size)
149 {
150         void *ret;
151         if (file->begin)
152                 return file->begin+offset;
153         if (file_cache) {
154                 struct file_cache_id id={offset,size,file->name_id,0};
155                 ret=cache_lookup(file_cache,&id); 
156                 if (ret)
157                         return ret;
158                 ret=cache_insert_new(file_cache,&id,size);
159         } else
160                 ret=g_malloc(size);
161         lseek(file->fd, offset, SEEK_SET);
162         if (read(file->fd, ret, size) != size) {
163                 file_data_free(file, ret);
164                 ret=NULL;
165         }
166         return ret;
167
168 }
169
170 unsigned char *
171 file_data_read_all(struct file *file)
172 {
173         return file_data_read(file, 0, file->size);
174 }
175
176 int
177 file_get_contents(char *name, unsigned char **buffer, int *size)
178 {
179         struct file *file;
180         file=file_create(name);
181         if (!file)
182                 return 0;
183         *size=file_size(file);
184         *buffer=file_data_read_all(file);
185         file_destroy(file);
186         return 1;       
187 }
188
189
190 static int
191 uncompress_int_zip(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
192 {
193         z_stream stream;
194         int err;
195
196         stream.next_in = (Bytef*)source;
197         stream.avail_in = (uInt)sourceLen;
198         stream.next_out = dest;
199         stream.avail_out = (uInt)*destLen;
200
201         stream.zalloc = (alloc_func)0;
202         stream.zfree = (free_func)0;
203
204         err = inflateInit2(&stream, -MAX_WBITS);
205         if (err != Z_OK) return err;
206
207         err = inflate(&stream, Z_FINISH);
208         if (err != Z_STREAM_END) {
209         inflateEnd(&stream);
210         if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
211                 return Z_DATA_ERROR;
212                 return err;
213         }
214         *destLen = stream.total_out;
215
216         err = inflateEnd(&stream);
217         return (err == Z_OK);
218 }
219
220 static int
221 uncompress_int_lzma(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
222 {
223         SRes res;
224         void *SzAlloc(void *p, size_t size) { p = p; return g_malloc(size); }
225         void SzFree(void *p, void *address) { p = p; g_free(address); }
226         ISzAlloc alloc = { SzAlloc, SzFree };
227         ELzmaStatus status;
228         size_t srcLen;
229
230         srcLen = (sourceLen - LZMA_PROPS_SIZE);
231
232         res = LzmaDecode(dest, destLen, (source + LZMA_PROPS_SIZE), &srcLen, source, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &alloc);
233
234         return ((res == SZ_OK) && (status != LZMA_STATUS_NOT_FINISHED));
235 }
236
237 unsigned char *
238 file_data_read_compressed(struct file *file, long long offset, int method, int size, int size_uncomp)
239 {
240         void *ret;
241         char *buffer = 0;
242         uLongf destLen=size_uncomp;
243
244         if (file_cache) {
245                 struct file_cache_id id={offset,size,file->name_id,1};
246                 ret=cache_lookup(file_cache,&id); 
247                 if (ret)
248                         return ret;
249                 ret=cache_insert_new(file_cache,&id,size_uncomp);
250         } else 
251                 ret=g_malloc(size_uncomp);
252         lseek(file->fd, offset, SEEK_SET);
253
254         buffer = (char *)g_malloc(size);
255         if (read(file->fd, buffer, size) != size) {
256                 g_free(ret);
257                 ret=NULL;
258         } else {
259                 switch (method) {
260                 case 8: // Deflate
261                         if (!uncompress_int_zip(ret, &destLen, (Bytef *)buffer, size)) {
262                                 dbg(0,"uncompress zip failed\n");
263                                 g_free(ret);
264                                 ret=NULL;
265                         }
266                         break;
267                 case 13: // LZMA
268                         if (!uncompress_int_lzma(ret, &destLen, (Bytef *)buffer, size)) {
269                                 dbg(0,"uncompress lzma failed\n");
270                                 g_free(ret);
271                                 ret=NULL;
272                         }
273                         break;
274                 default:
275                         dbg(0, "unknown compression method\n");
276                         g_free(ret);
277                         ret = NULL;
278                 }
279         }
280         g_free(buffer);
281
282         return ret;
283 }
284
285 void
286 file_data_free(struct file *file, unsigned char *data)
287 {
288         if (file->begin && data >= file->begin && data < file->end)
289                 return;
290         if (file_cache) {
291                 cache_entry_destroy(file_cache, data);
292         } else
293                 g_free(data);
294 }
295
296 int
297 file_exists(char *name)
298 {
299         struct stat buf;
300         if (! stat(name, &buf))
301                 return 1;
302         return 0;
303 }
304
305 void
306 file_remap_readonly(struct file *f)
307 {
308 #if defined(_WIN32) || defined(__CEGCC__)
309 #else
310         void *begin;
311         munmap(f->begin, f->size);
312         begin=mmap(f->begin, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
313         if (f->begin != begin)
314                 printf("remap failed\n");
315 #endif
316 }
317
318 void
319 file_unmap(struct file *f)
320 {
321 #if defined(_WIN32) || defined(__CEGCC__)
322     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
323 #else
324         munmap(f->begin, f->size);
325 #endif
326 }
327
328 void *
329 file_opendir(char *dir)
330 {
331         return opendir(dir);
332 }
333
334 char *
335 file_readdir(void *hnd)
336 {
337         struct dirent *ent;
338
339         ent=readdir(hnd);
340         if (! ent)
341                 return NULL;
342         return ent->d_name;
343 }
344
345 void
346 file_closedir(void *hnd)
347 {
348         closedir(hnd);
349 }
350
351 struct file *
352 file_create_caseinsensitive(char *name)
353 {
354         char dirname[strlen(name)+1];
355         char *filename;
356         char *p;
357         void *d;
358         struct file *ret;
359
360         ret=file_create(name);
361         if (ret)
362                 return ret;
363
364         strcpy(dirname, name);
365         p=dirname+strlen(name);
366         while (p > dirname) {
367                 if (*p == '/')
368                         break;
369                 p--;
370         }
371         *p=0;
372         d=file_opendir(dirname);
373         if (d) {
374                 *p++='/';
375                 while ((filename=file_readdir(d))) {
376                         if (!strcasecmp(filename, p)) {
377                                 strcpy(p, filename);
378                                 ret=file_create(dirname);
379                                 if (ret)
380                                         break;
381                         }
382                 }
383                 file_closedir(d);
384         }
385         return ret;
386 }
387
388 void
389 file_destroy(struct file *f)
390 {
391         close(f->fd);
392
393     if ( f->begin != NULL )
394     {
395         file_unmap( f );
396     }
397
398         g_free(f->name);
399         g_free(f);
400 }
401
402 struct file_wordexp {
403         int err;
404         wordexp_t we;
405 };
406
407 struct file_wordexp *
408 file_wordexp_new(const char *pattern)
409 {
410         struct file_wordexp *ret=g_new0(struct file_wordexp, 1);
411
412         ret->err=wordexp(pattern, &ret->we, 0);
413         if (ret->err)
414                 dbg(0,"wordexp('%s') returned %d\n", pattern, ret->err);
415         return ret;
416 }
417
418 int
419 file_wordexp_get_count(struct file_wordexp *wexp)
420 {
421         return wexp->we.we_wordc;
422 }
423
424 char **
425 file_wordexp_get_array(struct file_wordexp *wexp)
426 {
427         return wexp->we.we_wordv;
428 }
429
430 void
431 file_wordexp_destroy(struct file_wordexp *wexp)
432 {
433         if (! wexp->err)
434                 wordfree(&wexp->we);
435         g_free(wexp);
436 }
437
438
439 int
440 file_get_param(struct file *file, struct param_list *param, int count)
441 {
442         int i=count;
443         param_add_string("Filename", file->name, &param, &count);
444         param_add_hex("Size", file->size, &param, &count);
445         return i-count;
446 }
447
448 int
449 file_version(struct file *file, int byname)
450 {
451 #ifndef __CEGCC__
452         struct stat st;
453         int error;
454         if (byname)
455                 error=stat(file->name, &st);
456         else
457                 error=fstat(file->fd, &st);
458         if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
459                 file->mtime=st.st_mtime;
460                 file->ctime=st.st_ctime;
461                 file->version++;
462                 dbg(0,"%s now version %d\n", file->name, file->version);
463         }
464         return file->version;
465 #else
466         return 0;
467 #endif
468 }
469
470 void *
471 file_get_os_handle(struct file *file)
472 {
473         return (void *)(file->fd);
474 }
475
476 void
477 file_init(void)
478 {
479 #ifdef CACHE_SIZE
480         file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
481         file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
482 #endif
483 }
484