Fix:maptool:Another name for faroe islands
[navit-package] / navit / file.c
index db157d7..b41d269 100644 (file)
@@ -1,3 +1,22 @@
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
 #define _FILE_OFFSET_BITS 64
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
@@ -12,7 +31,9 @@
 #include <glib.h>
 #include <zlib.h>
 #include "debug.h"
+#include "cache.h"
 #include "file.h"
+#include "atom.h"
 #include "config.h"
 
 #ifndef O_LARGEFILE
 #define O_BINARY 0
 #endif
 
-static struct file *file_list;
+#ifdef CACHE_SIZE
+static GHashTable *file_name_hash;
+#endif
+
+static struct cache *file_cache;
+
+struct file_cache_id {
+       long long offset;
+       int size;
+       int file_name_id;
+       int method;
+} __attribute__ ((packed));
 
 struct file *
-file_create(char *name)
+file_create(char *name, enum file_flags flags)
 {
        struct stat stat;
        struct file *file= g_new0(struct file,1);
 
-       if (! file)
-               return file;
        file->fd=open(name, O_RDONLY|O_LARGEFILE | O_BINARY);
-       if (file->fd < 0) {
+       if (file->fd == -1) {
                g_free(file);
                return NULL;
        }
+       dbg(1,"fd=%d\n", file->fd);
        fstat(file->fd, &stat);
        file->size=stat.st_size;
+       dbg(1,"size=%Ld\n", file->size);
        file->name = g_strdup(name);
-       g_assert(file != NULL);
-       file->next=file_list;
-       file_list=file;
+       file->name_id = (int)atom(name);
+       if (file_cache && !(flags & file_flag_nocache)) 
+               file->cache=1;
+       dbg_assert(file != NULL);
        return file;
 }
 
+#if 0
+struct file *
+file_create_url(char *url)
+{
+       struct file *file= g_new0(struct file,1);
+       char *cmd=g_strdup_printf("curl %s",url);
+       file->name = g_strdup(url);
+       file->stdfile=popen(cmd,"r");
+       file->fd=fileno(file->stdfile);
+       file->special=1;
+       g_free(cmd);
+       return file;
+}
+#endif
+
+int file_is_dir(char *name)
+{
+       struct stat buf;
+       if (! stat(name, &buf)) {
+               return S_ISDIR(buf.st_mode);
+       }
+       return 0;
+
+}
+
+long long
+file_size(struct file *file)
+{
+       return file->size;
+}
+
+int file_mkdir(char *name, int pflag)
+{
+       char buffer[strlen(name)+1];
+       int ret;
+       char *next;
+       dbg(1,"enter %s %d\n",name,pflag);
+       if (!pflag) {
+               if (file_is_dir(name))
+                       return 0;
+#ifdef HAVE_API_WIN32_BASE
+               return mkdir(name);
+#else
+               return mkdir(name, 0777);
+#endif
+       }
+       strcpy(buffer, name);
+       next=buffer;
+       while ((next=strchr(next, '/'))) {
+               *next='\0';
+               if (*buffer) {
+                       ret=file_mkdir(buffer, 0);
+                       if (ret)
+                               return ret;
+               }
+               *next++='/';
+       }
+       if (pflag == 2)
+               return 0;
+       return file_mkdir(buffer, 0);
+}
+
 int
 file_mmap(struct file *file)
 {
-#ifdef _WIN32
-    file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
+#if 0
+       int mmap_size=file->size+1024*1024;
+#else
+       int mmap_size=file->size;
+#endif
+#ifdef HAVE_API_WIN32_BASE
+       file->begin = (char*)mmap_readonly_win32( file->name, &file->map_handle, &file->map_file );
 #else
-       file->begin=mmap(NULL, file->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
-       g_assert(file->begin != NULL);
+       file->begin=mmap(NULL, mmap_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, file->fd, 0);
+       dbg_assert(file->begin != NULL);
        if (file->begin == (void *)0xffffffff) {
                perror("mmap");
                return 0;
        }
 #endif
-       g_assert(file->begin != (void *)0xffffffff);
+       dbg_assert(file->begin != (void *)0xffffffff);
+       file->mmap_end=file->begin+mmap_size;
        file->end=file->begin+file->size;
 
        return 1;
@@ -70,18 +171,73 @@ unsigned char *
 file_data_read(struct file *file, long long offset, int size)
 {
        void *ret;
+       if (file->special)
+               return NULL;
        if (file->begin)
                return file->begin+offset;
-       ret=g_malloc(size);
+       if (file_cache) {
+               struct file_cache_id id={offset,size,file->name_id,0};
+               ret=cache_lookup(file_cache,&id); 
+               if (ret)
+                       return ret;
+               ret=cache_insert_new(file_cache,&id,size);
+       } else
+               ret=g_malloc(size);
        lseek(file->fd, offset, SEEK_SET);
        if (read(file->fd, ret, size) != size) {
-               g_free(ret);
+               file_data_free(file, ret);
                ret=NULL;
        }
        return ret;
 
 }
 
+unsigned char *
+file_data_read_special(struct file *file, int size, int *size_ret)
+{
+       void *ret;
+       if (!file->special)
+               return NULL;
+       ret=g_malloc(size);
+       *size_ret=read(file->fd, ret, size);
+       return ret;
+}
+
+unsigned char *
+file_data_read_all(struct file *file)
+{
+       return file_data_read(file, 0, file->size);
+}
+
+int
+file_data_write(struct file *file, long long offset, int size, unsigned char *data)
+{
+       if (file_cache) {
+               struct file_cache_id id={offset,size,file->name_id,0};
+               cache_flush(file_cache,&id);
+       }
+       lseek(file->fd, offset, SEEK_SET);
+       if (write(file->fd, data, size) != size)
+               return 0;
+       if (file->size < offset+size)
+               file->size=offset+size;
+       return 1;
+}
+
+int
+file_get_contents(char *name, unsigned char **buffer, int *size)
+{
+       struct file *file;
+       file=file_create(name, 0);
+       if (!file)
+               return 0;
+       *size=file_size(file);
+       *buffer=file_data_read_all(file);
+       file_destroy(file);
+       return 1;       
+}
+
+
 static int
 uncompress_int(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)
 {
@@ -116,11 +272,20 @@ unsigned char *
 file_data_read_compressed(struct file *file, long long offset, int size, int size_uncomp)
 {
        void *ret;
-       char buffer[size];
+       char *buffer = 0;
        uLongf destLen=size_uncomp;
 
-       ret=g_malloc(size_uncomp);
+       if (file_cache) {
+               struct file_cache_id id={offset,size,file->name_id,1};
+               ret=cache_lookup(file_cache,&id); 
+               if (ret)
+                       return ret;
+               ret=cache_insert_new(file_cache,&id,size_uncomp);
+       } else 
+               ret=g_malloc(size_uncomp);
        lseek(file->fd, offset, SEEK_SET);
+
+       buffer = (char *)g_malloc(size);
        if (read(file->fd, buffer, size) != size) {
                g_free(ret);
                ret=NULL;
@@ -131,15 +296,24 @@ file_data_read_compressed(struct file *file, long long offset, int size, int siz
                        ret=NULL;
                }
        }
+       g_free(buffer);
+
        return ret;
 }
 
 void
 file_data_free(struct file *file, unsigned char *data)
 {
-       if (file->begin && data >= file->begin && data < file->end)
-               return;
-       g_free(data);
+       if (file->begin) {
+               if (data == file->begin)
+                       return;
+               if (data >= file->begin && data < file->end)
+                       return;
+       }       
+       if (file->cache && data) {
+               cache_entry_destroy(file_cache, data);
+       } else
+               g_free(data);
 }
 
 int
@@ -154,7 +328,7 @@ file_exists(char *name)
 void
 file_remap_readonly(struct file *f)
 {
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CEGCC__)
 #else
        void *begin;
        munmap(f->begin, f->size);
@@ -165,41 +339,15 @@ file_remap_readonly(struct file *f)
 }
 
 void
-file_remap_readonly_all(void)
-{
-       struct file *f=file_list;
-       int limit=1000;
-
-       while (f && limit-- > 0) {
-               file_remap_readonly(f);
-               f=f->next;
-       }
-}
-
-void
 file_unmap(struct file *f)
 {
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CEGCC__)
     mmap_unmap_win32( f->begin, f->map_handle , f->map_file );
 #else
        munmap(f->begin, f->size);
 #endif
 }
 
-void
-file_unmap_all(void)
-{
-       struct file *f=file_list;
-       int limit=1000;
-
-       while (f && limit-- > 0) {
-               file_unmap(f);
-               f=f->next;
-       }
-}
-
-
-
 void *
 file_opendir(char *dir)
 {
@@ -224,7 +372,7 @@ file_closedir(void *hnd)
 }
 
 struct file *
-file_create_caseinsensitive(char *name)
+file_create_caseinsensitive(char *name, enum file_flags flags)
 {
        char dirname[strlen(name)+1];
        char *filename;
@@ -232,7 +380,7 @@ file_create_caseinsensitive(char *name)
        void *d;
        struct file *ret;
 
-       ret=file_create(name);
+       ret=file_create(name, flags);
        if (ret)
                return ret;
 
@@ -250,7 +398,7 @@ file_create_caseinsensitive(char *name)
                while ((filename=file_readdir(d))) {
                        if (!strcasecmp(filename, p)) {
                                strcpy(p, filename);
-                               ret=file_create(dirname);
+                               ret=file_create(dirname, flags);
                                if (ret)
                                        break;
                        }
@@ -263,7 +411,16 @@ file_create_caseinsensitive(char *name)
 void
 file_destroy(struct file *f)
 {
-       close(f->fd);
+       switch (f->special) {
+       case 0:
+               close(f->fd);
+               break;
+#if 0
+       case 1:
+               pclose(f->stdfile);
+               break;
+#endif
+       }
 
     if ( f->begin != NULL )
     {
@@ -319,3 +476,52 @@ file_get_param(struct file *file, struct param_list *param, int count)
        param_add_hex("Size", file->size, &param, &count);
        return i-count;
 }
+
+int
+file_version(struct file *file, int mode)
+{
+#ifndef HAVE_API_WIN32_BASE
+       struct stat st;
+       int error;
+       if (mode == 3) {
+               long long size=lseek(file->fd, 0, SEEK_END);
+               if (file->begin && file->begin+size > file->mmap_end) {
+                       file->version++;
+               } else {
+                       file->size=size;
+                       if (file->begin)
+                               file->end=file->begin+file->size;
+               }
+       } else {
+               if (mode == 2)
+                       error=stat(file->name, &st);
+               else
+                       error=fstat(file->fd, &st);
+               if (error || !file->version || file->mtime != st.st_mtime || file->ctime != st.st_ctime) {
+                       file->mtime=st.st_mtime;
+                       file->ctime=st.st_ctime;
+                       file->version++;
+                       dbg(1,"%s now version %d\n", file->name, file->version);
+               }
+       }
+       return file->version;
+#else
+       return 0;
+#endif
+}
+
+void *
+file_get_os_handle(struct file *file)
+{
+       return GINT_TO_POINTER(file->fd);
+}
+
+void
+file_init(void)
+{
+#ifdef CACHE_SIZE
+       file_name_hash=g_hash_table_new(g_str_hash, g_str_equal);
+       file_cache=cache_new(sizeof(struct file_cache_id), CACHE_SIZE);
+#endif
+}
+