Moved poi_geodownload to data and made it working with the new api
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 11 Aug 2007 08:02:47 +0000 (08:02 +0000)
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 11 Aug 2007 08:02:47 +0000 (08:02 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@379 ffa7fe5e-494d-0410-b361-a75ebd5db220

44 files changed:
navit/configure.in
navit/src/attr.c
navit/src/attr.h
navit/src/attr_def.h
navit/src/country.c
navit/src/data/Makefile.am
navit/src/data/mg/map.c
navit/src/data/mg/mg.h
navit/src/data/poi_geodownload/Makefile.am [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/Makefile.am [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/backend.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/catalog.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/data.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/dump.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/file.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/iconv.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/include/mdbtools.h [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/index.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/kkd.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/like.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/map.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/mem.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/money.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/options.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/props.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/sargs.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/stats.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/table.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/worktable.c [new file with mode: 0644]
navit/src/data/poi_geodownload/libmdb/write.c [new file with mode: 0644]
navit/src/data/poi_geodownload/poi_geodownload.c [new file with mode: 0644]
navit/src/data/textfile/textfile.c
navit/src/graphics.c
navit/src/gui/gtk/destination.c
navit/src/item.c
navit/src/item.h
navit/src/item_def.h
navit/src/map.c
navit/src/map.h
navit/src/mapset.c
navit/src/navit.c
navit/src/plugin_def.h
navit/src/search.c
navit/src/xmlconfig.c

index 9abaac7..8b96e91 100644 (file)
@@ -253,6 +253,8 @@ src/data/Makefile
 src/data/mg/Makefile
 src/data/textfile/Makefile
 src/data/garmin_img/Makefile
+src/data/poi_geodownload/Makefile
+src/data/poi_geodownload/libmdb/Makefile
 src/fib-1.1/Makefile
 src/graphics/Makefile
 src/graphics/gtk_drawing_area/Makefile
index 0c6d58a..91d3f5a 100644 (file)
@@ -1,4 +1,7 @@
 #include <string.h>
+#include <glib.h>
+#include "debug.h"
+#include "item.h"
 #include "attr.h"
 
 struct attr_name {
@@ -38,3 +41,46 @@ attr_to_name(enum attr_type attr)
        }
        return NULL; 
 }
+
+struct attr *
+attr_new_from_text(char *name, char *value)
+{
+       enum attr_type attr;
+       struct attr *ret;
+
+       ret=g_new0(struct attr, 1);
+       dbg(0,"enter name='%s' value='%s'\n", name, value);
+       attr=attr_from_name(name);
+       ret->type=attr;
+       switch (attr) {
+       case attr_item_type:
+               ret->u.item_type=item_from_name(value);
+               break;
+       default:
+               dbg(0,"default\n");
+               g_free(ret);
+               ret=NULL;
+       }
+       return ret;
+}
+
+struct attr *
+attr_search(struct attr **attrs, struct attr *last, enum attr_type attr)
+{
+       dbg(0, "enter attrs=%p\n", attrs);
+       while (*attrs) {
+               dbg(0,"*attrs=%p\n", *attrs);
+               if ((*attrs)->type == attr) {
+                       return *attrs;
+               }
+               attrs++;
+       }
+       exit(0);
+       return NULL;
+}
+
+void
+attr_free(struct attr *attr)
+{
+       g_free(attr);
+}
index 83a12f5..356185c 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef ATTR_H
 #define ATTR_H
 
+enum item_type;
+
 enum attr_type {
 #define ATTR2(x,y) attr_##x=y,
 #define ATTR(x) attr_##x,
@@ -15,6 +17,7 @@ struct attr {
                char *str;
                int num;
                struct item *item;
+               enum item_type item_type;
        } u;
 };
 
index 1a2d472..0f25976 100644 (file)
@@ -7,6 +7,7 @@ ATTR(street_name_item)
 ATTR(street_name_numbers_item)
 ATTR(street_item)
 ATTR(street_number_item)
+ATTR(item_type)
 ATTR2(type_item_end,0x0001ffff)
 ATTR2(type_int_begin,0x00020000)
 ATTR(id)
index 42864da..f7f238f 100644 (file)
@@ -3,7 +3,6 @@
 #include <glib.h>
 #include <libintl.h>
 #include "debug.h"
-#include "attr.h"
 #include "item.h"
 #include "country.h"
 #include "search.h"
index 35a1135..8f7999b 100644 (file)
@@ -1 +1 @@
-SUBDIRS=mg textfile garmin_img
+SUBDIRS=mg textfile garmin_img poi_geodownload
index 20feb8f..6122b98 100644 (file)
@@ -7,7 +7,7 @@
 #include "mg.h"
 
 
-struct map_priv * map_new_mg(struct map_methods *meth, char *dirname, char **charset, enum projection *pro);
+struct map_priv * map_new_mg(struct map_methods *meth, char *dirname, struct attr **attrs, char **charset, enum projection *pro);
 
 static int map_id;
 
@@ -259,7 +259,7 @@ static struct map_methods map_methods_mg = {
 };
 
 struct map_priv *
-map_new_mg(struct map_methods *meth, char *dirname, char **charset, enum projection *pro)
+map_new_mg(struct map_methods *meth, char *dirname, struct attr **attrs, char **charset, enum projection *pro)
 {
        struct map_priv *m;
        int i,maybe_missing,len=strlen(dirname);
index c94a536..78f72c0 100644 (file)
@@ -1,8 +1,8 @@
 #include <glib.h>
+#include "item.h"
 #include "attr.h"
 #include "coord.h"
 #include "data.h"
-#include "item.h"
 #include "map.h"
 #include "file.h"
 
diff --git a/navit/src/data/poi_geodownload/Makefile.am b/navit/src/data/poi_geodownload/Makefile.am
new file mode 100644 (file)
index 0000000..d3412df
--- /dev/null
@@ -0,0 +1,6 @@
+SUBDIRS=libmdb
+include $(top_srcdir)/Makefile.inc
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -I$(top_srcdir)/src -Ilibmdb/include -DMODULE=\"data_poi_geodownload\"
+moduledata_LTLIBRARIES = libdata_poi_geodownload.la
+libdata_poi_geodownload_la_SOURCES = poi_geodownload.c
+libdata_poi_geodownload_la_LIBADD = -Llibmdb -lmdb
diff --git a/navit/src/data/poi_geodownload/libmdb/Makefile.am b/navit/src/data/poi_geodownload/libmdb/Makefile.am
new file mode 100644 (file)
index 0000000..6ff3fd6
--- /dev/null
@@ -0,0 +1,13 @@
+AUTOMAKE_OPTIONS = no-exeext
+AM_CPPFLAGS = @NAVIT_CFLAGS@ -Iinclude
+
+objdir=$(prefix)
+obj_PROGRAMS=libmdb.a
+INSTALL_PROGRAM=/bin/true
+
+libmdb_a_SOURCES=backend.c catalog.c data.c dump.c file.c iconv.c index.c kkd.c like.c map.c mem.c money.c options.c props.c sargs.c stats.c table.c worktable.c write.c
+
+libmdb.a: $(libmdb_a_OBJECTS)
+       ar r $@ $(libmdb_a_OBJECTS)
+
+
diff --git a/navit/src/data/poi_geodownload/libmdb/backend.c b/navit/src/data/poi_geodownload/libmdb/backend.c
new file mode 100644 (file)
index 0000000..e90f807
--- /dev/null
@@ -0,0 +1,301 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+** functions to deal with different backend database engines
+*/
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+static int is_init;
+static GHashTable *mdb_backends;
+
+   /*    Access data types */
+static MdbBackendType mdb_access_types[] = {
+               {"Unknown 0x00", 0,0,0 },
+               {"Boolean", 0,0,0},
+               {"Byte", 0,0,0},
+               {"Integer", 0,0,0},
+               {"Long Integer", 0,0,0},
+               {"Currency", 0,0,0},
+               {"Single", 0,0,0},
+               {"Double", 0,0,0},
+               {"DateTime (Short)", 0,0,1},
+               {"Unknown 0x09", 0,0,0},
+               {"Text", 1,0,1},
+               {"OLE", 1,0,1},
+               {"Memo/Hyperlink",1,0,1},
+               {"Unknown 0x0d",0,0,0},
+               {"Unknown 0x0e",0,0,0},
+               {"Replication ID",0,0,0},
+               {"Numeric",1,1,0}
+};
+
+/*    Oracle data types */
+static MdbBackendType mdb_oracle_types[] = {
+               {"Oracle_Unknown 0x00",0,0,0},
+               {"NUMBER",1,0,0},
+               {"NUMBER",1,0,0},
+               {"NUMBER",1,0,0},
+               {"NUMBER",1,0,0},
+               {"NUMBER",1,0,0},
+               {"FLOAT",0,0,0},
+               {"FLOAT",0,0,0},
+               {"DATE",0,0,0},
+               {"Oracle_Unknown 0x09",0,0,0},
+               {"VARCHAR2",1,0,1},
+               {"BLOB",1,0,1},
+               {"CLOB",1,0,1},
+               {"Oracle_Unknown 0x0d",0,0,0},
+               {"Oracle_Unknown 0x0e",0,0,0},
+               {"NUMBER",1,0,0},
+               {"NUMBER",1,0,0},
+};
+
+/*    Sybase/MSSQL data types */
+static MdbBackendType mdb_sybase_types[] = {
+               {"Sybase_Unknown 0x00",0,0,0},
+               {"bit",0,0,0},
+               {"char",1,0,1},
+               {"smallint",0,0,0},
+               {"int",0,0,0},
+               {"money",0,0,0},
+               {"real",0,0,0},
+               {"float",0,0,0},
+               {"smalldatetime",0,0,0},
+               {"Sybase_Unknown 0x09",0,0,0},
+               {"varchar",1,0,1},
+               {"varbinary",1,0,1},
+               {"text",1,0,1},
+               {"Sybase_Unknown 0x0d",0,0,0},
+               {"Sybase_Unknown 0x0e",0,0,0},
+               {"Sybase_Replication ID",0,0,0},
+               {"numeric",1,1,0},
+};
+
+/*    Postgres data types */
+static MdbBackendType mdb_postgres_types[] = {
+               {"Postgres_Unknown 0x00",0,0,0},
+               {"Bool",0,0,0},
+               {"Int2",0,0,0},
+               {"Int4",0,0,0},
+               {"Int8",0,0,0},
+               {"Money",0,0,0},
+               {"Float4",0,0,0},
+               {"Float8",0,0,0},
+               {"Timestamp",0,0,0},
+               {"Postgres_Unknown 0x09",0,0,0},
+               {"Char",1,0,1},
+               {"Postgres_Unknown 0x0b",0,0,0},
+               {"Postgres_Unknown 0x0c",0,0,0},
+               {"Postgres_Unknown 0x0d",0,0,0},
+               {"Postgres_Unknown 0x0e",0,0,0},
+               {"Serial",0,0,0},
+               {"Postgres_Unknown 0x10",0,0,0},
+};
+/*    MySQL data types */
+static MdbBackendType mdb_mysql_types[] = {
+               {"Text",1,0,1},
+               {"char",0,0,0},
+               {"int",0,0,0},
+               {"int",0,0,0},
+               {"int",0,0,0},
+               {"float",0,0,0},
+               {"float",0,0,0},
+               {"float",0,0,0},
+               {"date",0,0,1},
+               {"varchar",1,0,1},
+               {"varchar",1,0,1},
+               {"varchar",1,0,1},
+               {"text",1,0,1},
+               {"blob",0,0,0},
+               {"text",1,0,1},
+               {"numeric",1,1,0},
+               {"numeric",1,1,0},
+};
+
+static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data);
+
+char *mdb_get_coltype_string(MdbBackend *backend, int col_type)
+{
+       static char buf[16];
+
+       if (col_type > 0x10 ) {
+               // return NULL;
+               snprintf(buf,sizeof(buf), "type %04x", col_type);
+               return buf;
+       } else {
+               return backend->types_table[col_type].name;
+       }
+}
+
+int mdb_coltype_takes_length(MdbBackend *backend, int col_type)
+{
+       return backend->types_table[col_type].needs_length;
+}
+
+/**
+ * mdb_init_backends
+ *
+ * Initializes the mdb_backends hash and loads the builtin backends.
+ * Use mdb_remove_backends() to destroy this hash when done.
+ */
+void mdb_init_backends()
+{
+       mdb_backends = g_hash_table_new(g_str_hash, g_str_equal);
+
+       mdb_register_backend(mdb_access_types, "access");
+       mdb_register_backend(mdb_sybase_types, "sybase");
+       mdb_register_backend(mdb_oracle_types, "oracle");
+       mdb_register_backend(mdb_postgres_types, "postgres");
+       mdb_register_backend(mdb_mysql_types, "mysql");
+}
+void mdb_register_backend(MdbBackendType *backend_type, char *backend_name)
+{
+       MdbBackend *backend = (MdbBackend *) g_malloc0(sizeof(MdbBackend));
+       backend->types_table = backend_type;
+       g_hash_table_insert(mdb_backends, backend_name, backend);
+}
+
+/**
+ * mdb_remove_backends
+ *
+ * Removes all entries from and destroys the mdb_backends hash.
+ */
+void mdb_remove_backends()
+{
+       g_hash_table_foreach_remove(mdb_backends, mdb_drop_backend, NULL);
+       g_hash_table_destroy(mdb_backends);
+}
+static gboolean mdb_drop_backend(gpointer key, gpointer value, gpointer data)
+{
+       MdbBackend *backend = (MdbBackend *)value;
+       g_free (backend);
+       return TRUE;
+}
+
+/**
+ * mdb_set_default_backend
+ * @mdb: Handle to open MDB database file
+ * @backend_name: Name of the backend to set as default
+ *
+ * Sets the default backend of the handle @mdb to @backend_name.
+ *
+ * Returns: 1 if successful, 0 if unsuccessful.
+ */
+int mdb_set_default_backend(MdbHandle *mdb, char *backend_name)
+{
+       MdbBackend *backend;
+
+       backend = (MdbBackend *) g_hash_table_lookup(mdb_backends, backend_name);
+       if (backend) {
+               mdb->default_backend = backend;
+               mdb->backend_name = (char *) g_strdup(backend_name);
+               is_init = 0;
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/**
+ * mdb_get_relationships
+ * @mdb: Handle to open MDB database file
+ *
+ * Generates relationships by reading the MSysRelationships table.
+ *   'szColumn' contains the column name of the child table.
+ *   'szObject' contains the table name of the child table.
+ *   'szReferencedColumn' contains the column name of the parent table.
+ *   'szReferencedObject' contains the table name of the parent table.
+ *
+ * Returns: a string stating that relationships are not supported for the
+ *   selected backend, or a string containing SQL commands for setting up
+ *   the relationship, tailored for the selected backend.  The caller is
+ *   responsible for freeing this string.
+ */
+char *mdb_get_relationships(MdbHandle *mdb)
+{
+       unsigned int i;
+       gchar *text = NULL;  /* String to be returned */
+       static char *bound[4];  /* Bound values */
+       static MdbTableDef *table;  /* Relationships table */
+       int backend = 0;  /* Backends: 1=oracle */
+
+       if (strncmp(mdb->backend_name,"oracle",6) == 0) {
+               backend = 1;
+       } else {
+               if (is_init == 0) { /* the first time through */
+                       is_init = 1;
+                       return (char *) g_strconcat(
+                               "-- relationships are not supported for ",
+                               mdb->backend_name, NULL);
+               } else { /* the second time through */
+                       is_init = 0;
+                       return NULL;
+               }
+       }
+
+       if (is_init == 0) {
+               table = mdb_read_table_by_name(mdb, "MSysRelationships", MDB_TABLE);
+               if ((!table) || (table->num_rows == 0)) {
+                       return NULL;
+               }
+
+               mdb_read_columns(table);
+               for (i=0;i<4;i++) {
+                       bound[i] = (char *) g_malloc0(MDB_BIND_SIZE);
+               }
+               mdb_bind_column_by_name(table, "szColumn", bound[0]);
+               mdb_bind_column_by_name(table, "szObject", bound[1]);
+               mdb_bind_column_by_name(table, "szReferencedColumn", bound[2]);
+               mdb_bind_column_by_name(table, "szReferencedObject", bound[3]);
+               mdb_rewind_table(table);
+
+               is_init = 1;
+       }
+       else if (table->cur_row >= table->num_rows) {  /* past the last row */
+               for (i=0;i<4;i++)
+                       g_free(bound[i]);
+               is_init = 0;
+               return NULL;
+       }
+
+       if (!mdb_fetch_row(table)) {
+               for (i=0;i<4;i++)
+                       g_free(bound[i]);
+               is_init = 0;
+               return NULL;
+       }
+
+       switch (backend) {
+         case 1:  /* oracle */
+               text = g_strconcat("alter table ", bound[1],
+                       " add constraint ", bound[3], "_", bound[1],
+                       " foreign key (", bound[0], ")"
+                       " references ", bound[3], "(", bound[2], ")", NULL);
+               break;
+       }
+
+       return (char *)text;
+}
+
diff --git a/navit/src/data/poi_geodownload/libmdb/catalog.c b/navit/src/data/poi_geodownload/libmdb/catalog.c
new file mode 100644 (file)
index 0000000..dc08abd
--- /dev/null
@@ -0,0 +1,138 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+char *
+mdb_get_objtype_string(int obj_type)
+{
+static char *type_name[] = {"Form",
+                       "Table",
+                       "Macro",
+                       "System Table",
+                       "Report",
+                       "Query",
+                       "Linked Table",
+                       "Module",
+                       "Relationship",
+                       "Unknown 0x09",
+                       "Unknown 0x0a",
+                       "Database"
+               };
+
+       if (obj_type > 11) {
+               return NULL;
+       } else {
+               return type_name[obj_type]; 
+       }
+}
+
+void mdb_free_catalog(MdbHandle *mdb)
+{
+       unsigned int i;
+
+       if (!mdb->catalog) return;
+       for (i=0; i<mdb->catalog->len; i++)
+               g_free (g_ptr_array_index(mdb->catalog, i));
+       g_ptr_array_free(mdb->catalog, TRUE);
+       mdb->catalog = NULL;
+}
+
+GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
+{
+       MdbCatalogEntry *entry, msysobj;
+       MdbTableDef *table;
+       char obj_id[256];
+       char obj_name[256];
+       char obj_type[256];
+       char obj_flags[256];
+       int type;
+
+       if (mdb->catalog) mdb_free_catalog(mdb);
+       mdb->catalog = g_ptr_array_new();
+       mdb->num_catalog = 0;
+
+       /* dummy up a catalog entry so we may read the table def */
+       memset(&msysobj, 0, sizeof(MdbCatalogEntry));
+       msysobj.mdb = mdb;
+       msysobj.object_type = MDB_TABLE;
+       msysobj.table_pg = 2;
+       strcpy(msysobj.object_name, "MSysObjects");
+
+       /* mdb_table_dump(&msysobj); */
+
+       table = mdb_read_table(&msysobj);
+       if (!table) return NULL;
+
+       mdb_read_columns(table);
+
+       mdb_bind_column_by_name(table, "Id", obj_id);
+       mdb_bind_column_by_name(table, "Name", obj_name);
+       mdb_bind_column_by_name(table, "Type", obj_type);
+       mdb_bind_column_by_name(table, "Flags", obj_flags);
+
+       mdb_rewind_table(table);
+
+       while (mdb_fetch_row(table)) {
+               type = atoi(obj_type);
+               if (objtype==MDB_ANY || type == objtype) {
+                       // fprintf(stdout, "obj_id: %10ld objtype: %-3d obj_name: %s\n", 
+                       // (atol(obj_id) & 0x00FFFFFF), type, obj_name); 
+                       entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry));
+                       entry->mdb = mdb;
+                       strcpy(entry->object_name, obj_name);
+                       entry->object_type = (type & 0x7F);
+                       entry->table_pg = atol(obj_id) & 0x00FFFFFF;
+                       entry->flags = atol(obj_flags);
+                       mdb->num_catalog++;
+                       g_ptr_array_add(mdb->catalog, entry); 
+               }
+       }
+       //mdb_dump_catalog(mdb, MDB_TABLE);
+       mdb_free_tabledef(table);
+
+       return mdb->catalog;
+}
+
+void 
+mdb_dump_catalog(MdbHandle *mdb, int obj_type)
+{
+       unsigned int i;
+       MdbCatalogEntry *entry;
+
+       mdb_read_catalog(mdb, obj_type);
+       for (i=0;i<mdb->num_catalog;i++) {
+                entry = g_ptr_array_index(mdb->catalog,i);
+               if (obj_type==MDB_ANY || entry->object_type==obj_type) {
+                       fprintf(stdout,"Type: %-10s Name: %-18s T pg: %04x KKD pg: %04x row: %2d\n",
+                       mdb_get_objtype_string(entry->object_type),
+                       entry->object_name,
+                       (unsigned int) entry->table_pg,
+                       (unsigned int) entry->kkd_pg,
+                       entry->kkd_rowid);
+               }
+        }
+       return;
+}
+
diff --git a/navit/src/data/poi_geodownload/libmdb/data.c b/navit/src/data/poi_geodownload/libmdb/data.c
new file mode 100644 (file)
index 0000000..e50e57d
--- /dev/null
@@ -0,0 +1,856 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+#include "time.h"
+#include "math.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#define OFFSET_MASK 0x1fff
+
+char *mdb_money_to_string(MdbHandle *mdb, int start, char *s);
+static int _mdb_attempt_bind(MdbHandle *mdb, 
+       MdbColumn *col, unsigned char isnull, int offset, int len);
+static char *mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale);
+int mdb_copy_ole(MdbHandle *mdb, char *dest, int start, int size);
+
+static char date_fmt[64] = "%x %X";
+
+void mdb_set_date_fmt(const char *fmt)
+{
+               date_fmt[63] = 0; 
+               strncpy(date_fmt, fmt, 63);
+}
+
+void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr)
+{
+MdbColumn *col;
+
+       /* 
+       ** the column arrary is 0 based, so decrement to get 1 based parameter 
+       */
+       col=g_ptr_array_index(table->columns, col_num - 1);
+       col->bind_ptr = bind_ptr;
+}
+int
+mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr)
+{
+       unsigned int i;
+       int col_num = -1;
+       MdbColumn *col;
+       
+       for (i=0;i<table->num_cols;i++) {
+               col=g_ptr_array_index(table->columns,i);
+               if (!strcmp(col->name,col_name)) {
+                       col_num = col->col_num + 1;
+                       mdb_bind_column(table, col_num, bind_ptr);
+                       break;
+               }
+       }
+
+       return col_num;
+}
+void mdb_bind_len(MdbTableDef *table, int col_num, int *len_ptr)
+{
+MdbColumn *col;
+
+       col=g_ptr_array_index(table->columns, col_num - 1);
+       col->len_ptr = len_ptr;
+}
+
+/**
+ * mdb_find_pg_row
+ * @mdb: Database file handle
+ * @pg_row: Lower byte contains the row number, the upper three contain page
+ * @buf: Pointer for returning a pointer to the page
+ * @off: Pointer for returning an offset to the row
+ * @len: Pointer for returning the length of the row
+ * 
+ * Returns: 0 on success.  1 on failure.
+ */
+int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, int *len)
+{
+       unsigned int pg = pg_row >> 8;
+       unsigned int row = pg_row & 0xff;
+
+       if (mdb_read_alt_pg(mdb, pg) != mdb->fmt->pg_size)
+               return 1;
+       mdb_swap_pgbuf(mdb);
+       *off = mdb_pg_get_int16(mdb, mdb->fmt->row_count_offset + 2 + (row*2));
+       *len = mdb_find_end_of_row(mdb, row) - *off + 1;
+       mdb_swap_pgbuf(mdb);
+       *buf = mdb->alt_pg_buf;
+       return 0;
+}
+
+int 
+mdb_find_end_of_row(MdbHandle *mdb, int row)
+{
+       MdbFormatConstants *fmt = mdb->fmt;
+       int row_end;
+
+       /* Search the previous "row start" values for the first non-'lookupflag' one.
+       * If we don't find one, then the end of the page is the correct value.
+       */
+#if 1
+       if (row==0) {
+               row_end = fmt->pg_size - 1;
+       } else {
+               row_end = (mdb_pg_get_int16(mdb, ((fmt->row_count_offset + 2) + (row - 1) * 2)) & OFFSET_MASK) - 1;
+       }
+       return row_end;
+#else
+               int i, row_start;
+
+               /* if lookupflag is     not set, it's good (deleteflag is ok) */
+        for (i = row - 1; i >= 0; i--) {
+                row_start = mdb_pg_get_int16(mdb, ((fmt->row_count_offset + 2) + i * 2));
+                if (!(row_start & 0x8000)) {
+                        break;
+                }
+        }
+
+        if (i == -1) {
+                row_end = fmt->pg_size - 1;
+        } else {
+                row_end = (row_start & OFFSET_MASK) - 1;
+        }
+       return row_end;
+#endif
+}
+int mdb_is_null(unsigned char *null_mask, int col_num)
+{
+int byte_num = (col_num - 1) / 8;
+int bit_num = (col_num - 1) % 8;
+
+       if ((1 << bit_num) & null_mask[byte_num]) {
+               return 0;
+       } else {
+               return 1;
+       }
+}
+/* bool has to be handled specially because it uses the null bit to store its 
+** value*/
+static int 
+mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value)
+{
+       
+       col->cur_value_len = value;
+       if (col->bind_ptr) {
+               strcpy(col->bind_ptr,  value ? "0" : "1");
+       }
+
+       return 0;
+}
+static int mdb_xfer_bound_ole(MdbHandle *mdb, int start, MdbColumn *col, int len)
+{
+       int ret = 0;
+       if (len) {
+               col->cur_value_start = start;
+               col->cur_value_len = len;
+       } else {
+               col->cur_value_start = 0;
+               col->cur_value_len = 0;
+       }
+       if (col->bind_ptr || col->len_ptr) {
+               //ret = mdb_copy_ole(mdb, col->bind_ptr, start, len);
+               memcpy(col->bind_ptr, &mdb->pg_buf[start], MDB_MEMO_OVERHEAD);
+       }
+       if (col->len_ptr) {
+               *col->len_ptr = MDB_MEMO_OVERHEAD;
+       }
+       return ret;
+}
+static int mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len)
+{
+int ret;
+       //if (!strcmp("Name",col->name)) {
+               //printf("start %d %d\n",start, len);
+       //}
+       if (len) {
+               col->cur_value_start = start;
+               col->cur_value_len = len;
+       } else {
+               col->cur_value_start = 0;
+               col->cur_value_len = 0;
+       }
+       if (col->bind_ptr) {
+               if (!len) {
+                       strcpy(col->bind_ptr, "");
+               } else if (col->col_type == MDB_NUMERIC) {
+                       //fprintf(stdout,"len %d size %d\n",len, col->col_size);
+                       char *str = mdb_num_to_string(mdb, start, col->col_type,
+                               col->col_prec, col->col_scale);
+                       strcpy(col->bind_ptr, str);
+                       g_free(str);
+               } else {
+                       //fprintf(stdout,"len %d size %d\n",len, col->col_size);
+                       char *str = mdb_col_to_string(mdb, mdb->pg_buf, start,
+                               col->col_type, len);
+                       strcpy(col->bind_ptr, str);
+                       
+               }
+               ret = strlen(col->bind_ptr);
+               if (col->len_ptr) {
+                       *col->len_ptr = ret;
+               }
+               return ret;
+       }
+       return 0;
+}
+int mdb_read_row(MdbTableDef *table, unsigned int row)
+{
+       MdbHandle *mdb = table->entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       MdbColumn *col;
+       unsigned int i;
+       int rc;
+       int row_start, row_end;
+       int delflag, lookupflag;
+       MdbField fields[256];
+       int num_fields;
+
+       if (table->num_rows <= row) 
+               return 0;
+
+       row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (row*2)); 
+       row_end = mdb_find_end_of_row(mdb, row);
+
+       delflag = lookupflag = 0;
+       if (row_start & 0x8000) lookupflag++;
+       if (row_start & 0x4000) delflag++;
+       row_start &= OFFSET_MASK; /* remove flags */
+#if MDB_DEBUG
+       fprintf(stdout,"Row %d bytes %d to %d %s %s\n", 
+               row, row_start, row_end,
+               lookupflag ? "[lookup]" : "",
+               delflag ? "[delflag]" : "");
+#endif 
+
+       if (!table->noskip_del && delflag) {
+               row_end = row_start-1;
+               return 0;
+       }
+
+       num_fields = mdb_crack_row(table, row_start, row_end, fields);
+       if (!mdb_test_sargs(table, fields, num_fields)) return 0;
+       
+#if MDB_DEBUG
+       fprintf(stdout,"sarg test passed row %d \n", row);
+#endif 
+
+#if MDB_DEBUG
+       buffer_dump(mdb->pg_buf, row_start, row_end);
+#endif
+
+       /* take advantage of mdb_crack_row() to clean up binding */
+       /* use num_cols instead of num_fields -- bsb 03/04/02 */
+       for (i = 0; i < table->num_cols; i++) {
+               col = g_ptr_array_index(table->columns,fields[i].colnum);
+               rc = _mdb_attempt_bind(mdb, col, fields[i].is_null,
+                       fields[i].start, fields[i].siz);
+       }
+
+       return 1;
+}
+static int _mdb_attempt_bind(MdbHandle *mdb, 
+       MdbColumn *col, 
+       unsigned char isnull, 
+       int offset, 
+       int len)
+{
+       if (col->col_type == MDB_BOOL) {
+               mdb_xfer_bound_bool(mdb, col, isnull);
+       } else if (isnull) {
+               mdb_xfer_bound_data(mdb, 0, col, 0);
+       } else if (col->col_type == MDB_OLE) {
+               mdb_xfer_bound_ole(mdb, offset, col, len);
+       } else {
+               //if (!mdb_test_sargs(mdb, col, offset, len)) {
+                       //return 0;
+               //}
+               mdb_xfer_bound_data(mdb, offset, col, len);
+       }
+       return 1;
+}
+int mdb_read_next_dpg(MdbTableDef *table)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       int next_pg;
+
+#ifndef SLOW_READ
+       next_pg = mdb_map_find_next(mdb, table->usage_map,
+               table->map_sz, table->cur_phys_pg);
+
+       if (next_pg >= 0) {
+               if (mdb_read_pg(mdb, next_pg)) {
+                       table->cur_phys_pg = next_pg;
+                       return table->cur_phys_pg;
+               } else {
+                       return 0;
+               }
+       }
+       fprintf(stderr, "Warning: defaulting to brute force read\n");
+#endif 
+       /* can't do a fast read, go back to the old way */
+       do {
+               if (!mdb_read_pg(mdb, table->cur_phys_pg++))
+                       return 0;
+       } while (mdb->pg_buf[0]!=0x01 || mdb_pg_get_int32(mdb, 4)!=entry->table_pg);
+       /* fprintf(stderr,"returning new page %ld\n", table->cur_phys_pg); */
+       return table->cur_phys_pg;
+}
+int mdb_rewind_table(MdbTableDef *table)
+{
+       table->cur_pg_num=0;
+       table->cur_phys_pg=0;
+       table->cur_row=0;
+
+       return 0;
+}
+int 
+mdb_fetch_row(MdbTableDef *table)
+{
+       MdbHandle *mdb = table->entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       unsigned int rows;
+       int rc;
+       guint32 pg;
+
+       if (table->num_rows==0)
+               return 0;
+
+       /* initialize */
+       if (!table->cur_pg_num) {
+               table->cur_pg_num=1;
+               table->cur_row=0;
+               if ((!table->is_temp_table)&&(table->strategy!=MDB_INDEX_SCAN))
+                       if (!mdb_read_next_dpg(table)) return 0;
+       }
+
+       do {
+               if (table->is_temp_table) {
+                       GPtrArray *pages = table->temp_table_pages;
+                       rows = mdb_get_int16(
+                               g_ptr_array_index(pages, table->cur_pg_num-1),
+                               fmt->row_count_offset);
+                       if (table->cur_row >= rows) {
+                               table->cur_row = 0;
+                               table->cur_pg_num++;
+                               if (table->cur_pg_num > pages->len)
+                                       return 0;
+                       }
+                       memcpy(mdb->pg_buf,
+                               g_ptr_array_index(pages, table->cur_pg_num-1),
+                               fmt->pg_size);
+               } else if (table->strategy==MDB_INDEX_SCAN) {
+               
+                       if (!mdb_index_find_next(table->mdbidx, table->scan_idx, table->chain, &pg, (guint16 *) &(table->cur_row))) {
+                               mdb_index_scan_free(table);
+                               return 0;
+                       }
+                       mdb_read_pg(mdb, pg);
+               } else {
+                       rows = mdb_pg_get_int16(mdb,fmt->row_count_offset);
+
+                       /* if at end of page, find a new page */
+                       if (table->cur_row >= rows) {
+                               table->cur_row=0;
+       
+                               if (!mdb_read_next_dpg(table)) {
+                                       return 0;
+                               }
+                       }
+               }
+
+               /* printf("page %d row %d\n",table->cur_phys_pg, table->cur_row); */
+               rc = mdb_read_row(table, table->cur_row);
+               table->cur_row++;
+       } while (!rc);
+
+       return 1;
+}
+void mdb_data_dump(MdbTableDef *table)
+{
+       unsigned int i;
+       char *bound_values[MDB_MAX_COLS]; 
+
+       for (i=0;i<table->num_cols;i++) {
+               bound_values[i] = (char *) g_malloc(256);
+               mdb_bind_column(table, i+1, bound_values[i]);
+       }
+       mdb_rewind_table(table);
+       while (mdb_fetch_row(table)) {
+               for (i=0;i<table->num_cols;i++) {
+                       fprintf(stdout, "column %d is %s\n", i+1, bound_values[i]);
+               }
+       }
+       for (i=0;i<table->num_cols;i++) {
+               g_free(bound_values[i]);
+       }
+}
+
+int mdb_is_fixed_col(MdbColumn *col)
+{
+       return col->is_fixed;
+}
+#if 0
+static char *mdb_data_to_hex(MdbHandle *mdb, char *text, int start, int size) 
+{
+int i;
+
+       for (i=start; i<start+size; i++) {
+               sprintf(&text[(i-start)*2],"%02x", mdb->pg_buf[i]);
+       }
+       text[(i-start)*2]='\0';
+
+       return text;
+}
+#endif
+int 
+mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr)
+{
+       guint16 ole_len;
+       guint16 ole_flags;
+       char *buf;
+       int pg_row, row_start;
+       int len;
+
+       ole_len = mdb_get_int16(ole_ptr, 0);
+       ole_flags = mdb_get_int16(ole_ptr, 2);
+
+       if (ole_flags == 0x8000) {
+               /* inline fields don't have a next */
+               return 0;
+       } else if (ole_flags == 0x4000) {
+               /* 0x4000 flagged ole's are contained on one page and thus 
+                * should be handled entirely with mdb_ole_read() */
+               return 0;
+       } else if (ole_flags == 0x0000) {
+               pg_row = (col->cur_blob_pg << 8) & col->cur_blob_row;
+               if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) {
+                       return 0;
+               }
+               if (col->bind_ptr)
+                       memcpy(col->bind_ptr, buf + row_start, len);
+               pg_row = mdb_get_int32(buf, row_start);
+               col->cur_blob_pg = pg_row >> 8;
+               col->cur_blob_row = pg_row & 0xff;
+
+               return len;
+       }
+       return 0;
+}
+int 
+mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size)
+{
+       guint16 ole_len;
+       guint16 ole_flags;
+       char *buf;
+       int pg_row, row_start;
+       int len;
+
+       ole_len = mdb_get_int16(ole_ptr, 0);
+       ole_flags = mdb_get_int16(ole_ptr, 2);
+       mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %08x",
+               ole_len, ole_flags);
+
+       col->chunk_size = chunk_size;
+
+       if (ole_flags == 0x8000) {
+               /* inline ole field, if we can satisfy it, then do it */
+               len = col->cur_value_len - MDB_MEMO_OVERHEAD;
+               if (chunk_size >= len) {
+                       if (col->bind_ptr) 
+                               memcpy(col->bind_ptr, 
+                                       &mdb->pg_buf[col->cur_value_start + 
+                                               MDB_MEMO_OVERHEAD],
+                                       len);
+                       return len;
+               } else {
+                       return 0;
+               }
+       } else if (ole_flags == 0x4000) {
+               pg_row = mdb_get_int32(ole_ptr, 4);
+               col->cur_blob_pg = pg_row >> 8;
+               col->cur_blob_row = pg_row & 0xff;
+               mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld",
+                       col->cur_blob_row, col->cur_blob_pg);
+
+               if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) {
+                       return 0;
+               }
+               mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len);
+
+               if (col->bind_ptr) {
+                       memcpy(col->bind_ptr, buf + row_start, len);
+                       if (mdb_get_option(MDB_DEBUG_OLE))
+                               buffer_dump(col->bind_ptr, 0, 16);
+               }
+               return len;
+       } else if (ole_flags == 0x0000) {
+               pg_row = mdb_get_int32(ole_ptr, 4);
+               col->cur_blob_pg = pg_row >> 8;
+               col->cur_blob_row = pg_row & 0xff;
+
+               if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) {
+                       return 0;
+               }
+
+               if (col->bind_ptr) 
+                       memcpy(col->bind_ptr, buf + row_start, len);
+
+               pg_row = mdb_get_int32(buf, row_start);
+               col->cur_blob_pg = pg_row >> 8;
+               col->cur_blob_row = pg_row & 0xff;
+
+               return len;
+       } else {
+               fprintf(stderr,"Unhandled ole field flags = %04x\n", ole_flags);
+               return 0;
+       }
+}
+int mdb_copy_ole(MdbHandle *mdb, char *dest, int start, int size)
+{
+       guint16 ole_len;
+       guint16 ole_flags;
+       guint32 row_start, pg_row;
+       guint32 len;
+       char *buf;
+
+       if (size<MDB_MEMO_OVERHEAD) {
+               return 0;
+       } 
+
+       /* The 16 bit integer at offset 0 is the length of the memo field.
+        * The 32 bit integer at offset 4 contains page and row information.
+        */
+       ole_len = mdb_pg_get_int16(mdb, start);
+       ole_flags = mdb_pg_get_int16(mdb, start+2);
+
+       if (ole_flags == 0x8000) {
+               len = size - MDB_MEMO_OVERHEAD;
+               /* inline ole field */
+               if (dest) memcpy(dest, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD],
+                       size - MDB_MEMO_OVERHEAD);
+               return len;
+       } else if (ole_flags == 0x4000) {
+               pg_row = mdb_get_int32(mdb->pg_buf, start+4);
+               mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8);
+
+               if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) {
+                       return 0;
+               }
+               mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d",
+                       pg_row & 0xff, row_start, len);
+
+               if (dest)
+                       memcpy(dest, buf + row_start, len);
+               return len;
+       } else if (ole_flags == 0x0000) {
+               int cur = 0;
+               pg_row = mdb_get_int32(mdb->pg_buf, start+4);
+               mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8);
+               do {
+                       if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) {
+                               return 0;
+                       }
+
+                       mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d",
+                               pg_row & 0xff, row_start, len);
+
+                       if (dest) 
+                               memcpy(dest+cur, buf + row_start + 4, len - 4);
+                       cur += len - 4;
+
+                       /* find next lval page */
+                       pg_row = mdb_get_int32(buf, row_start);
+               } while ((pg_row >> 8));
+               return cur;
+       } else {
+               fprintf(stderr,"Unhandled ole field flags = %04x\n", ole_flags);
+               return 0;
+       }
+}
+static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size)
+{
+       guint16 memo_len;
+       static char text[MDB_BIND_SIZE];
+       guint16 memo_flags;
+       guint32 row_start, pg_row;
+       guint32 len;
+       char *buf;
+
+       if (size<MDB_MEMO_OVERHEAD) {
+               return "";
+       } 
+
+#if MDB_DEBUG
+       buffer_dump(mdb->pg_buf, start, start + 12);
+#endif
+
+       /* The 16 bit integer at offset 0 is the length of the memo field.
+        * The 32 bit integer at offset 4 contains page and row information.
+        */
+       memo_len = mdb_pg_get_int16(mdb, start);
+       memo_flags = mdb_pg_get_int16(mdb, start+2);
+
+       if (memo_flags & 0x8000) {
+               /* inline memo field */
+               strncpy(text, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD],
+                       size - MDB_MEMO_OVERHEAD);
+               text[size - MDB_MEMO_OVERHEAD]='\0';
+               return text;
+       } else if (memo_flags & 0x4000) {
+               pg_row = mdb_get_int32(mdb->pg_buf, start+4);
+#if MDB_DEBUG
+               printf("Reading LVAL page %06x\n", pg_row >> 8);
+#endif
+               if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) {
+                       return "";
+               }
+#if MDB_DEBUG
+               printf("row num %d start %d len %d\n",
+                       pg_row & 0xff, row_start, len);
+               buffer_dump(mdb->pg_buf, row_start, row_start + len);
+#endif
+               if (IS_JET3(mdb)) {
+                       strncpy(text, buf + row_start, len);
+                       text[len]='\0';
+               } else {
+                       mdb_unicode2ascii(mdb, buf, row_start, len, text);
+               }
+               return text;
+       } else { /* if (memo_flags == 0x0000) { */
+               pg_row = mdb_get_int32(mdb->pg_buf, start+4);
+#if MDB_DEBUG
+               printf("Reading LVAL page %06x\n", pg_row >> 8);
+#endif
+               text[0]='\0';
+               do {
+                       if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) {
+                               return "";
+                       }
+#if MDB_DEBUG
+                       printf("row num %d start %d len %d\n",
+                               pg_row & 0xff, row_start, len);
+#endif
+                       strncat(text, buf + row_start + 4, 
+                               strlen(text) + len - 4 > MDB_BIND_SIZE ?
+                               MDB_BIND_SIZE - strlen(text) : len - 4);
+
+                       /* find next lval page */
+                       pg_row = mdb_get_int32(mdb->pg_buf, row_start);
+               } while ((pg_row >> 8));
+               return text;
+/*
+       } else {
+               fprintf(stderr,"Unhandled memo field flags = %04x\n", memo_flags);
+               return "";
+*/
+       }
+}
+static char *
+mdb_num_to_string(MdbHandle *mdb, int start, int datatype, int prec, int scale)
+{
+       char *text;
+       gint32 l;
+
+       memcpy(&l, mdb->pg_buf+start+13, 4);
+
+       text = (char *) g_malloc(prec+2);
+       sprintf(text, "%0*" G_GINT32_FORMAT, prec, GINT32_FROM_LE(l));
+       if (scale) {
+               memmove(text+prec-scale, text+prec-scale+1, scale+1);
+               text[prec-scale] = '.';
+       }
+       return text;
+}
+
+static int trim_trailing_zeros(char * buff, int n)
+{
+       char * p = buff + n - 1;
+
+       while (p >= buff && *p == '0')
+               *p-- = '\0';
+
+       if (*p == '.')
+               *p = '\0';
+
+       return 0;
+}
+                               
+char *mdb_col_to_string(MdbHandle *mdb, unsigned char *buf, int start, int datatype, int size)
+{
+       /* FIX ME -- not thread safe */
+       static char text[MDB_BIND_SIZE];
+       time_t t;
+       int n;
+       float tf;
+       double td;
+
+       switch (datatype) {
+               case MDB_BOOL:
+                       /* shouldn't happen.  bools are handled specially
+                       ** by mdb_xfer_bound_bool() */
+               break;
+               case MDB_BYTE:
+                       sprintf(text,"%d",mdb_get_byte(buf, start));
+                       return text;
+               break;
+               case MDB_INT:
+                       sprintf(text,"%ld",(long)mdb_get_int16(buf, start));
+                       return text;
+               break;
+               case MDB_LONGINT:
+                       sprintf(text,"%ld",mdb_get_int32(buf, start));
+                       return text;
+               break;
+               case MDB_FLOAT:
+                       tf = mdb_get_single(mdb->pg_buf, start);
+                       n = sprintf(text,"%.*f",FLT_DIG - (int)ceil(log10(tf)), tf);
+                       trim_trailing_zeros(text, n);
+                       return text;
+               break;
+               case MDB_DOUBLE:
+                       td = mdb_get_double(mdb->pg_buf, start);
+                       n = sprintf(text,"%.*f",DBL_DIG - (int)ceil(log10(td)), td);
+                       trim_trailing_zeros(text, n);
+                       return text;
+               break;
+               case MDB_TEXT:
+                       if (size<0) {
+                               return "";
+                       }
+                       if (IS_JET4(mdb)) {
+/*
+                               int i;
+                               for (i=0;i<size;i++) {
+                                       fprintf(stdout, "%c %02x ", mdb->pg_buf[start+i], mdb->pg_buf[start+i]);
+                               } 
+                               fprintf(stdout, "\n");
+*/
+                               mdb_unicode2ascii(mdb, mdb->pg_buf, start, size, text);
+                       } else {
+                               strncpy(text, &buf[start], size);
+                               text[size]='\0';
+                       }
+                       return text;
+               break;
+               case MDB_SDATETIME:
+                       td = mdb_get_double(mdb->pg_buf, start);
+                       if (td > 1) {
+                               t = (long int)((td - 25569.0) * 86400.0);
+                       } else {
+                               t = (long int)(td * 86400.0);
+                       }
+                       strftime(text, MDB_BIND_SIZE, date_fmt, (struct tm*)gmtime(&t));
+                       return text;
+
+               break;
+               case MDB_MEMO:
+                       return mdb_memo_to_string(mdb, start, size);
+               break;
+               case MDB_MONEY:
+                       mdb_money_to_string(mdb, start, text);
+                       return text;
+               case MDB_NUMERIC:
+               break;
+               default:
+                       return "";
+               break;
+       }
+       return NULL;
+}
+int mdb_col_disp_size(MdbColumn *col)
+{
+       switch (col->col_type) {
+               case MDB_BOOL:
+                       return 1;
+               break;
+               case MDB_BYTE:
+                       return 4;
+               break;
+               case MDB_INT:
+                       return 6;
+               break;
+               case MDB_LONGINT:
+                       return 11;
+               break;
+               case MDB_FLOAT:
+                       return 10;
+               break;
+               case MDB_DOUBLE:
+                       return 10;
+               break;
+               case MDB_TEXT:
+                       return col->col_size;
+               break;
+               case MDB_SDATETIME:
+                       return 20;
+               break;
+               case MDB_MEMO:
+                       return 255; 
+               break;
+               case MDB_MONEY:
+                       return 21;
+               break;
+       }
+       return 0;
+}
+int mdb_col_fixed_size(MdbColumn *col)
+{
+       switch (col->col_type) {
+               case MDB_BOOL:
+                       return 1;
+               break;
+               case MDB_BYTE:
+                       return -1;
+               break;
+               case MDB_INT:
+                       return 2;
+               break;
+               case MDB_LONGINT:
+                       return 4;
+               break;
+               case MDB_FLOAT:
+                       return 4;
+               break;
+               case MDB_DOUBLE:
+                       return 8;
+               break;
+               case MDB_TEXT:
+                       return -1;
+               break;
+               case MDB_SDATETIME:
+                       return 4;
+               break;
+               case MDB_MEMO:
+                       return -1; 
+               break;
+               case MDB_MONEY:
+                       return 8;
+               break;
+       }
+       return 0;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/dump.c b/navit/src/data/poi_geodownload/libmdb/dump.c
new file mode 100644 (file)
index 0000000..7ee17f9
--- /dev/null
@@ -0,0 +1,39 @@
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+void buffer_dump(const unsigned char* buf, int start, int end)
+{
+       char asc[20];
+       int j, k;
+
+       memset(asc, 0, sizeof(asc));
+       k = 0;
+       for (j=start; j<=end; j++) {
+               if (k == 0) {
+                       fprintf(stdout, "%04x  ", j);
+               }
+               fprintf(stdout, "%02x ", buf[j]);
+               asc[k] = isprint(buf[j]) ? buf[j] : '.';
+               k++;
+               if (k == 8) {
+                       fprintf(stdout, " ");
+               }
+               if (k == 16) {
+                       fprintf(stdout, "  %s\n", asc);
+                       memset(asc, 0, sizeof(asc));
+                       k = 0;
+               }
+       }
+       for (j=k; j<16; j++) {
+               fprintf(stdout, "   ");
+       }
+       if (k < 8) {
+               fprintf(stdout, " ");
+       }
+       fprintf(stdout, "  %s\n", asc);
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/file.c b/navit/src/data/poi_geodownload/libmdb/file.c
new file mode 100644 (file)
index 0000000..941830c
--- /dev/null
@@ -0,0 +1,376 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/*
+typedef struct {
+       int             pg_size;
+       guint16         row_count_offset; 
+       guint16         tab_num_rows_offset;
+       guint16         tab_num_cols_offset;
+       guint16         tab_num_idxs_offset;
+       guint16         tab_num_ridxs_offset;
+       guint16         tab_usage_map_offset;
+       guint16         tab_first_dpg_offset;
+       guint16         tab_cols_start_offset;
+       guint16         tab_ridx_entry_size;
+       guint16         col_fixed_offset;
+       guint16         col_size_offset;
+       guint16         col_num_offset;
+       guint16         tab_col_entry_size;
+       guint16         tab_free_map_offset;
+       guint16         tab_col_offset_var;
+       guint16         tab_col_offset_fixed;
+       guint16         tab_row_col_num_offset;
+} MdbFormatConstants; 
+*/
+MdbFormatConstants MdbJet4Constants = {
+       4096, 0x0c, 16, 45, 47, 51, 55, 56, 63, 12, 15, 23, 5, 25, 59, 7, 21, 9
+};
+MdbFormatConstants MdbJet3Constants = {
+       2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5 /* not sure on 5, need to check */
+};
+
+static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg);
+
+/**
+ * mdb_find_file:
+ * @filename: path to MDB (database) file
+ *
+ * Finds and returns the absolute path to an MDB file.  Function will first try
+ * to fstat file as passed, then search through the $MDBPATH if not found.
+ *
+ * Return value: gchar pointer to absolute path. Caller is responsible for
+ * freeing.
+ **/
+
+static gchar *mdb_find_file(char *file_name)
+{
+       struct stat status;
+       gchar *mdbpath, **dir, *tmpfname;
+       unsigned int i = 0;
+
+       /* try the provided file name first */
+       if (!stat(file_name, &status)) {
+               return g_strdup(file_name);
+       }
+       
+       /* Now pull apart $MDBPATH and try those */
+       mdbpath = (gchar *) getenv("MDBPATH");
+       /* no path, can't find file */
+       if (!mdbpath || !strlen(mdbpath)) return NULL;
+
+       dir = g_strsplit(mdbpath, ":", 0); 
+       while (dir[i]) {
+               if (!strlen(dir[i])) continue;
+               tmpfname = g_strconcat(dir[i++], "/", file_name, NULL);
+               if (!stat(tmpfname, &status)) {
+                       g_strfreev(dir);
+                       return tmpfname;
+               }
+               g_free(tmpfname);
+       }
+       g_strfreev(dir);
+       return NULL;
+}
+/**
+ * mdb_open:
+ * @filename: path to MDB (database) file
+ * @flags: MDB_NOFLAGS for read-only, MDB_WRITABLE for read/write
+ *
+ * Opens an MDB file and returns an MdbHandle to it.  MDB File may be relative
+ * to the current directory, a full path to the file, or relative to a 
+ * component of $MDBPATH.
+ *
+ * Return value: pointer to MdbHandle structure.
+ **/
+MdbHandle *mdb_open(char *filename, MdbFileFlags flags)
+{
+       MdbHandle *mdb;
+
+       mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle));
+       mdb_set_default_backend(mdb, "access");
+       /* need something to bootstrap with, reassign after page 0 is read */
+       mdb->fmt = &MdbJet3Constants;
+       mdb->f = (MdbFile *) g_malloc0(sizeof(MdbFile));
+       mdb->f->refs = 1;
+       mdb->f->fd = -1;
+       mdb->f->filename = (char *) mdb_find_file(filename);
+       if (!mdb->f->filename) { 
+               fprintf(stderr, "Can't alloc filename\n");
+               mdb_close(mdb);
+               return NULL; 
+       }
+       if (flags & MDB_WRITABLE) {
+               mdb->f->writable = TRUE;
+               mdb->f->fd = open(mdb->f->filename,O_RDWR);
+       } else {
+               mdb->f->fd = open(mdb->f->filename,O_RDONLY);
+       }
+
+       if (mdb->f->fd==-1) {
+               fprintf(stderr,"Couldn't open file %s\n",mdb->f->filename); 
+               mdb_close(mdb);
+               return NULL;
+       }
+       if (!mdb_read_pg(mdb, 0)) {
+               fprintf(stderr,"Couldn't read first page.\n");
+               mdb_close(mdb);
+               return NULL;
+       }
+       if (mdb->pg_buf[0] != 0) {
+               mdb_close(mdb);
+               return NULL; 
+       }
+       mdb->f->jet_version = mdb_pg_get_int32(mdb, 0x14);
+       if (IS_JET4(mdb)) {
+               mdb->fmt = &MdbJet4Constants;
+       } else if (IS_JET3(mdb)) {
+               mdb->fmt = &MdbJet3Constants;
+       } else {
+               fprintf(stderr,"Unknown Jet version.\n");
+               mdb_close(mdb);
+               return NULL; 
+       }
+
+       return mdb;
+}
+
+/**
+ * mdb_close:
+ * @mdb: Handle to open MDB database file
+ *
+ * Dereferences MDB file, closes if reference count is 0, and destroys handle.
+ *
+ **/
+void 
+mdb_close(MdbHandle *mdb)
+{
+       if (!mdb) return;       
+       mdb_free_catalog(mdb);
+       g_free(mdb->stats);
+       g_free(mdb->backend_name);
+
+       if (mdb->f) {
+               if (mdb->f->refs > 1) {
+                       mdb->f->refs--;
+               } else {
+                       if (mdb->f->fd != -1) close(mdb->f->fd);
+                       g_free(mdb->f->filename);
+                       g_free(mdb->f);
+               }
+       }
+
+       g_free(mdb);
+}
+/**
+ * mdb_clone_handle:
+ * @mdb: Handle to open MDB database file
+ *
+ * Clones an existing database handle.  Cloned handle shares the file descriptor
+ * but has its own page buffer, page position, and similar internal variables.
+ *
+ * Return value: new handle to the database.
+ */
+MdbHandle *mdb_clone_handle(MdbHandle *mdb)
+{
+       MdbHandle *newmdb;
+       MdbCatalogEntry *entry, *data;
+       unsigned int i;
+
+       newmdb = (MdbHandle *) g_memdup(mdb, sizeof(MdbHandle));
+       newmdb->stats = NULL;
+       newmdb->catalog = g_ptr_array_new();
+       for (i=0;i<mdb->num_catalog;i++) {
+               entry = g_ptr_array_index(mdb->catalog,i);
+               data = g_memdup(entry,sizeof(MdbCatalogEntry));
+               g_ptr_array_add(newmdb->catalog, data);
+       }
+       mdb->backend_name = NULL;
+       if (mdb->f) {
+               mdb->f->refs++;
+       }
+       return newmdb;
+}
+
+/* 
+** mdb_read a wrapper for read that bails if anything is wrong 
+*/
+ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg)
+{
+       ssize_t len;
+
+       if (pg && mdb->cur_pg == pg) return mdb->fmt->pg_size;
+
+       len = _mdb_read_pg(mdb, mdb->pg_buf, pg);
+       //fprintf(stderr, "read page %d type %02x\n", pg, mdb->pg_buf[0]);
+       mdb->cur_pg = pg;
+       /* kan - reset the cur_pos on a new page read */
+       mdb->cur_pos = 0; /* kan */
+       return len;
+}
+ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg)
+{
+       ssize_t len;
+
+       len = _mdb_read_pg(mdb, mdb->alt_pg_buf, pg);
+       return len;
+}
+static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg)
+{
+       ssize_t len;
+       struct stat status;
+       off_t offset = pg * mdb->fmt->pg_size;
+
+        fstat(mdb->f->fd, &status);
+        if (status.st_size < offset) { 
+                fprintf(stderr,"offset %lu is beyond EOF\n",offset);
+                return 0;
+        }
+       if (mdb->stats && mdb->stats->collect) 
+               mdb->stats->pg_reads++;
+
+       lseek(mdb->f->fd, offset, SEEK_SET);
+       len = read(mdb->f->fd,pg_buf,mdb->fmt->pg_size);
+       if (len==-1) {
+               perror("read");
+               return 0;
+       }
+       else if (len<mdb->fmt->pg_size) {
+               /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */
+               return 0;
+       } 
+       return len;
+}
+void mdb_swap_pgbuf(MdbHandle *mdb)
+{
+char tmpbuf[MDB_PGSIZE];
+
+       memcpy(tmpbuf,mdb->pg_buf, MDB_PGSIZE);
+       memcpy(mdb->pg_buf,mdb->alt_pg_buf, MDB_PGSIZE);
+       memcpy(mdb->alt_pg_buf,tmpbuf,MDB_PGSIZE);
+}
+
+
+/* really stupid, just here for consistancy */
+unsigned char mdb_get_byte(unsigned char *buf, int offset)
+{
+       return buf[offset];
+}
+unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset)
+{
+       if (offset < 0 || offset+1 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos++;
+       return mdb->pg_buf[offset];
+}
+
+int mdb_get_int16(unsigned char *buf, int offset)
+{
+       return buf[offset+1]*256+buf[offset];
+}
+int mdb_pg_get_int16(MdbHandle *mdb, int offset)
+{
+       if (offset < 0 || offset+2 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=2;
+       return mdb_get_int16(mdb->pg_buf, offset);
+}
+
+gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset)
+{
+       gint32 l = 0;
+       if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=3;
+       memcpy((char *)&l+1, &(mdb->pg_buf[offset]), 3);
+#if 0
+       printf("l=0x%08x 0x%08x\n",l,GINT32_FROM_BE(l));
+#endif
+       return GINT32_FROM_BE(l);
+}
+gint32 mdb_get_int24(unsigned char *buf, int offset)
+{
+       gint32 l = 0;
+       memcpy(&l, &buf[offset], 3);
+       return GINT32_FROM_LE(l);
+}
+gint32 mdb_pg_get_int24(MdbHandle *mdb, int offset)
+{
+       if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=3;
+       return mdb_get_int24(mdb->pg_buf, offset);
+}
+
+long mdb_get_int32(unsigned char *buf, int offset)
+{
+       guint32 l;
+       memcpy(&l, &buf[offset], 4);
+       return (long)GINT32_FROM_LE(l);
+}
+long mdb_pg_get_int32(MdbHandle *mdb, int offset)
+{
+       if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=4;
+       return mdb_get_int32(mdb->pg_buf, offset);
+}
+
+float mdb_get_single(unsigned char *buf, int offset)
+{
+       union {guint32 g; float f;} f;
+       memcpy(&f, &buf[offset], 4);
+       f.g = GUINT32_FROM_LE(f.g);
+       return f.f;
+}
+float mdb_pg_get_single(MdbHandle *mdb, int offset)
+{
+       if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=4;
+       return mdb_get_single(mdb->pg_buf, offset);
+}
+
+double mdb_get_double(unsigned char *buf, int offset)
+{
+       union {guint64 g; double d;} d;
+       memcpy(&d, &buf[offset], 8);
+       d.g = GUINT64_FROM_LE(d.g);
+       return d.d;
+}
+double mdb_pg_get_double(MdbHandle *mdb, int offset)
+{
+       if (offset <0 || offset+8 > mdb->fmt->pg_size) return -1;
+       mdb->cur_pos+=8;
+       return mdb_get_double(mdb->pg_buf, offset);
+}
+
+
+int 
+mdb_set_pos(MdbHandle *mdb, int pos)
+{
+       if (pos<0 || pos >= mdb->fmt->pg_size) return 0;
+
+       mdb->cur_pos=pos;
+       return pos;
+}
+int mdb_get_pos(MdbHandle *mdb)
+{
+       return mdb->cur_pos;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/iconv.c b/navit/src/data/poi_geodownload/libmdb/iconv.c
new file mode 100644 (file)
index 0000000..9f41afe
--- /dev/null
@@ -0,0 +1,63 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+int
+mdb_unicode2ascii(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest)
+{
+       unsigned int i;
+
+       if (buf[offset]==0xff && buf[offset+1]==0xfe) {
+               strncpy(dest, &buf[offset+2], len-2);
+               dest[len-2]='\0';
+       } else {
+               /* convert unicode to ascii, rather sloppily */
+               for (i=0;i<len;i+=2)
+                       dest[i/2] = buf[offset + i];
+               dest[len/2]='\0';
+       }
+       return len;
+}
+
+int
+mdb_ascii2unicode(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest)
+{
+       unsigned int i = 0;
+
+       if (!buf) return 0;
+
+       if (IS_JET3(mdb)) {
+               strncpy(dest, &buf[offset], len);
+               dest[len]='\0';
+               return strlen(dest);
+       }
+
+       while (i<strlen(&buf[offset]) && (i*2+2)<len) {
+               dest[i*2] = buf[offset+i];
+               dest[i*2+1] = 0;
+               i++;
+       }
+
+       return (i*2);
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/include/mdbtools.h b/navit/src/data/poi_geodownload/libmdb/include/mdbtools.h
new file mode 100644 (file)
index 0000000..7be25a7
--- /dev/null
@@ -0,0 +1,536 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _mdbtools_h_
+#define _mdbtools_h_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#define MDB_DEBUG 0
+
+#define MDB_PGSIZE 4096
+#define MDB_MAX_OBJ_NAME 256
+#define MDB_MAX_COLS 256
+#define MDB_MAX_IDX_COLS 10
+#define MDB_CATALOG_PG 18
+#define MDB_MEMO_OVERHEAD 12
+#define MDB_BIND_SIZE 16384
+
+enum {
+       MDB_PAGE_DB = 0,
+       MDB_PAGE_DATA,
+       MDB_PAGE_TABLE,
+       MDB_PAGE_INDEX,
+       MDB_PAGE_LEAF,
+       MDB_PAGE_MAP
+};
+enum {
+       MDB_VER_JET3 = 0,
+       MDB_VER_JET4 = 1
+};
+enum {
+       MDB_FORM = 0,
+       MDB_TABLE,
+       MDB_MACRO,
+       MDB_SYSTEM_TABLE,
+       MDB_REPORT,
+       MDB_QUERY,
+       MDB_LINKED_TABLE,
+       MDB_MODULE,
+       MDB_RELATIONSHIP,
+       MDB_UNKNOWN_09,
+       MDB_UNKNOWN_0A,
+       MDB_DATABASE_PROPERTY,
+       MDB_ANY = -1
+};
+enum {
+       MDB_BOOL = 0x01,
+       MDB_BYTE = 0x02,
+       MDB_INT = 0x03,
+       MDB_LONGINT = 0x04,
+       MDB_MONEY = 0x05,
+       MDB_FLOAT = 0x06,
+       MDB_DOUBLE = 0x07,
+       MDB_SDATETIME = 0x08,
+       MDB_TEXT = 0x0a,
+       MDB_OLE = 0x0b,
+       MDB_MEMO = 0x0c,
+       MDB_REPID = 0x0f,
+       MDB_NUMERIC = 0x10
+};
+
+/* SARG operators */
+enum {
+       MDB_OR = 1,
+       MDB_AND,
+       MDB_NOT,
+       MDB_EQUAL,
+       MDB_GT,
+       MDB_LT,
+       MDB_GTEQ,
+       MDB_LTEQ,
+       MDB_LIKE,
+       MDB_ISNULL,
+       MDB_NOTNULL
+};
+
+typedef enum {
+       MDB_TABLE_SCAN,
+       MDB_LEAF_SCAN,
+       MDB_INDEX_SCAN
+} MdbStrategy;
+
+typedef enum {
+       MDB_NOFLAGS = 0x00,
+       MDB_WRITABLE = 0x01
+} MdbFileFlags;
+
+enum {
+       MDB_DEBUG_LIKE = 0x0001,
+       MDB_DEBUG_WRITE = 0x0002,
+       MDB_DEBUG_USAGE = 0x0004,
+       MDB_DEBUG_OLE = 0x0008,
+       MDB_DEBUG_ROW = 0x0010,
+       MDB_USE_INDEX = 0x0020
+};
+
+#define mdb_is_logical_op(x) (x == MDB_OR || \
+                               x == MDB_AND || \
+                               x == MDB_NOT )
+
+#define mdb_is_relational_op(x) (x == MDB_EQUAL || \
+                               x == MDB_GT || \
+                               x == MDB_LT || \
+                               x == MDB_GTEQ || \
+                               x == MDB_LTEQ || \
+                               x == MDB_LIKE || \
+                               x == MDB_ISNULL || \
+                               x == MDB_NOTNULL )
+
+enum {
+       MDB_ASC,
+       MDB_DESC
+};
+
+enum {
+       MDB_IDX_UNIQUE = 0x01,
+       MDB_IDX_IGNORENULLS = 0x02,
+       MDB_IDX_REQUIRED = 0x08 
+};
+
+#define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4)
+#define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3)
+
+/* hash to store registered backends */
+/* extern GHashTable   *mdb_backends; */
+
+/* forward declarations */
+typedef struct mdbindex MdbIndex;
+typedef struct mdbsargtree MdbSargNode;
+
+typedef struct {
+       char *name;
+       unsigned char needs_length; /* or precision */
+       unsigned char needs_scale;
+       unsigned char needs_quotes;
+} MdbBackendType;
+               
+typedef struct {
+        MdbBackendType *types_table;
+} MdbBackend;
+
+typedef struct {
+       gboolean collect;
+       unsigned long pg_reads;
+} MdbStatistics;
+
+typedef struct {
+       int           fd;
+       gboolean      writable;
+       char          *filename;
+       guint32         jet_version;
+       guint32         db_key;
+       char            db_passwd[14];
+       MdbBackend      *default_backend;
+       char                    *backend_name;
+       MdbStatistics   *stats;
+       /* free map */
+       int  map_sz;
+       unsigned char *free_map;
+       /* reference count */
+       int refs;
+} MdbFile; 
+
+/* offset to row count on data pages...version dependant */
+typedef struct {
+       int             pg_size;
+       guint16         row_count_offset; 
+       guint16         tab_num_rows_offset;
+       guint16         tab_num_cols_offset;
+       guint16         tab_num_idxs_offset;
+       guint16         tab_num_ridxs_offset;
+       guint16         tab_usage_map_offset;
+       guint16         tab_first_dpg_offset;
+       guint16         tab_cols_start_offset;
+       guint16         tab_ridx_entry_size;
+       guint16         col_fixed_offset;
+       guint16         col_size_offset;
+       guint16         col_num_offset;
+       guint16         tab_col_entry_size;
+       guint16         tab_free_map_offset;
+       guint16         tab_col_offset_var;
+       guint16         tab_col_offset_fixed;
+       guint16         tab_row_col_num_offset;
+} MdbFormatConstants; 
+
+typedef struct {
+       MdbFile       *f;
+       guint32       cur_pg;
+       guint16       row_num;
+       unsigned int  cur_pos;
+       unsigned char pg_buf[MDB_PGSIZE];
+       unsigned char alt_pg_buf[MDB_PGSIZE];
+       unsigned int  num_catalog;
+       GPtrArray       *catalog;
+       MdbBackend      *default_backend;
+       char            *backend_name;
+       MdbFormatConstants *fmt;
+       MdbStatistics *stats;
+#ifdef HAVE_ICONV
+       iconv_t iconv_out;
+#endif
+} MdbHandle; 
+
+typedef struct {
+       MdbHandle       *mdb;
+       char           object_name[MDB_MAX_OBJ_NAME+1];
+       int            object_type;
+       unsigned long  table_pg; /* misnomer since object may not be a table */
+       unsigned long  kkd_pg;
+       unsigned int   kkd_rowid;
+       int                     num_props;
+       GArray          *props;
+       GArray          *columns;
+       int             flags;
+} MdbCatalogEntry;
+
+typedef struct {
+       gchar *name;
+       GHashTable      *hash;
+} MdbProperties;
+
+typedef union {
+       int     i;
+       double  d;
+       char    s[256];
+} MdbAny;
+
+typedef struct {
+       char            name[MDB_MAX_OBJ_NAME+1];
+       int             col_type;
+       int             col_size;
+       void    *bind_ptr;
+       int             *len_ptr;
+       GHashTable      *properties;
+       unsigned int    num_sargs;
+       GPtrArray       *sargs;
+       GPtrArray       *idx_sarg_cache;
+       unsigned char   is_fixed;
+       int             query_order;
+       /* col_num is the current column order, 
+        * does not include deletes */
+       int             col_num;        
+       int             cur_value_start;
+       int             cur_value_len;
+       /* MEMO/OLE readers */
+       guint32         cur_blob_pg;
+       int             cur_blob_row;
+       int             chunk_size;
+       /* numerics only */
+       int             col_prec;
+       int             col_scale;
+       MdbProperties   *props;
+       /* info needed for handling deleted/added columns */
+       int             fixed_offset;
+       int             var_col_num;
+       /* row_col_num is the row column number order, 
+        * including deleted columns */
+       int             row_col_num;
+} MdbColumn;
+
+struct mdbsargtree {
+       int       op;
+       MdbColumn *col;
+       MdbAny    value;
+       void      *parent;
+       MdbSargNode *left;
+       MdbSargNode *right;
+};
+
+typedef struct {
+       guint32 pg;
+       int start_pos;
+       int offset;
+       int len;
+       guint16 idx_starts[2000];       
+       unsigned char cache_value[256];
+} MdbIndexPage;
+
+typedef int (*MdbSargTreeFunc)(MdbSargNode *, gpointer *data);
+
+#define MDB_MAX_INDEX_DEPTH 10
+
+typedef struct {
+       int cur_depth;
+       guint32 last_leaf_found;
+       int clean_up_mode;
+       MdbIndexPage pages[MDB_MAX_INDEX_DEPTH];
+} MdbIndexChain;
+
+typedef struct {
+       MdbCatalogEntry *entry;
+       char    name[MDB_MAX_OBJ_NAME+1];
+       unsigned int    num_cols;
+       GPtrArray       *columns;
+       unsigned int    num_rows;
+       int     index_start;
+       unsigned int    num_real_idxs;
+       unsigned int    num_idxs;
+       GPtrArray       *indices;
+       guint32 first_data_pg;
+       guint32 cur_pg_num;
+       guint32 cur_phys_pg;
+       unsigned int    cur_row;
+       int  noskip_del;  /* don't skip deleted rows */
+       /* object allocation map */
+       guint32  map_base_pg;
+       unsigned int  map_sz;
+       unsigned char *usage_map;
+       /* pages with free space left */
+       guint32  freemap_base_pg;
+       unsigned int  freemap_sz;
+       unsigned char *free_usage_map;
+       /* query planner */
+       MdbSargNode *sarg_tree;
+       MdbStrategy strategy;
+       MdbIndex *scan_idx;
+       MdbHandle *mdbidx;
+       MdbIndexChain *chain;
+       MdbProperties   *props;
+       unsigned int num_var_cols;  /* to know if row has variable columns */
+       /* temp table */
+       unsigned int  is_temp_table;
+       GPtrArray     *temp_table_pages;
+} MdbTableDef;
+
+struct mdbindex {
+       int             index_num;
+       char            name[MDB_MAX_OBJ_NAME+1];
+       unsigned char   index_type;
+       guint32         first_pg;
+       int             num_rows;  /* number rows in index */
+       unsigned int    num_keys;
+       short   key_col_num[MDB_MAX_IDX_COLS];
+       unsigned char   key_col_order[MDB_MAX_IDX_COLS];
+       unsigned char   flags;
+       MdbTableDef     *table;
+};
+
+typedef struct {
+       char            name[MDB_MAX_OBJ_NAME+1];
+} MdbColumnProp;
+
+typedef struct {
+       void *value;
+       int siz;
+       int start;
+       unsigned char is_null;
+       unsigned char is_fixed;
+       int colnum;
+       int offset;
+} MdbField;
+
+typedef struct {
+       int     op;
+       MdbAny  value;
+} MdbSarg;
+
+/* mem.c */
+extern void mdb_init();
+extern void mdb_exit();
+
+/* file.c */
+extern ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg);
+extern ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg);
+extern unsigned char mdb_get_byte(unsigned char *buf, int offset);
+extern int    mdb_get_int16(unsigned char *buf, int offset);
+extern gint32   mdb_get_int24(unsigned char *buf, int offset);
+extern long   mdb_get_int32(unsigned char *buf, int offset);
+extern float  mdb_get_single(unsigned char *buf, int offset);
+extern double mdb_get_double(unsigned char *buf, int offset);
+extern unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset);
+extern int    mdb_pg_get_int16(MdbHandle *mdb, int offset);
+extern gint32   mdb_pg_get_int24(MdbHandle *mdb, int offset);
+extern long   mdb_pg_get_int32(MdbHandle *mdb, int offset);
+extern float  mdb_pg_get_single(MdbHandle *mdb, int offset);
+extern double mdb_pg_get_double(MdbHandle *mdb, int offset);
+extern gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset);
+extern MdbHandle *mdb_open(char *filename, MdbFileFlags flags);
+extern void mdb_close(MdbHandle *mdb);
+extern MdbHandle *mdb_clone_handle(MdbHandle *mdb);
+extern void mdb_swap_pgbuf(MdbHandle *mdb);
+extern long _mdb_get_int32(unsigned char *buf, int offset);
+
+/* catalog.c */
+extern void mdb_free_catalog(MdbHandle *mdb);
+extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type);
+extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type);
+extern char *mdb_get_objtype_string(int obj_type);
+
+/* table.c */
+extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry);
+extern void mdb_free_tabledef(MdbTableDef *table);
+extern MdbTableDef *mdb_read_table(MdbCatalogEntry *entry);
+extern MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type);
+extern void mdb_append_column(GPtrArray *columns, MdbColumn *in_col);
+extern void mdb_free_columns(GPtrArray *columns);
+extern GPtrArray *mdb_read_columns(MdbTableDef *table);
+extern void mdb_table_dump(MdbCatalogEntry *entry);
+extern guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos);
+extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos);
+extern int read_pg_if(MdbHandle *mdb, int *cur_pos, int offset);
+extern guint16 read_pg_if_n(MdbHandle *mdb, unsigned char *buf, int *cur_pos, int len);
+extern int mdb_is_user_table(MdbCatalogEntry *entry);
+extern int mdb_is_system_table(MdbCatalogEntry *entry);
+
+/* data.c */
+extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr);
+extern void mdb_data_dump(MdbTableDef *table);
+extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr);
+extern int mdb_rewind_table(MdbTableDef *table);
+extern int mdb_fetch_row(MdbTableDef *table);
+extern int mdb_is_fixed_col(MdbColumn *col);
+extern char *mdb_col_to_string(MdbHandle *mdb, unsigned char *buf, int start, int datatype, int size);
+extern int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, int *len);
+extern int mdb_find_end_of_row(MdbHandle *mdb, int row);
+extern int mdb_col_fixed_size(MdbColumn *col);
+extern int mdb_col_disp_size(MdbColumn *col);
+extern void mdb_bind_len(MdbTableDef *table, int col_num, int *len_ptr);
+extern int mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr);
+extern int mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size);
+extern void mdb_set_date_fmt(const char *);
+extern int mdb_read_row(MdbTableDef *table, unsigned int row);
+
+/* dump.c */
+extern void buffer_dump(const unsigned char* buf, int start, int end);
+
+/* backend.c */
+extern char *mdb_get_coltype_string(MdbBackend *backend, int col_type);
+extern int  mdb_coltype_takes_length(MdbBackend *backend, int col_type);
+extern void mdb_init_backends();
+extern void mdb_register_backend(MdbBackendType *backend, char *backend_name);
+extern void mdb_remove_backends();
+extern int  mdb_set_default_backend(MdbHandle *mdb, char *backend_name);
+extern char *mdb_get_relationships(MdbHandle *mdb);
+
+/* sargs.c */
+extern int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields);
+extern int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field);
+extern void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data);
+extern int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data);
+extern int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg);
+extern int mdb_test_string(MdbSargNode *node, char *s);
+extern int mdb_test_int(MdbSargNode *node, gint32 i);
+extern int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg);
+
+
+
+/* index.c */
+extern GPtrArray *mdb_read_indices(MdbTableDef *table);
+extern void mdb_index_dump(MdbTableDef *table, MdbIndex *idx);
+extern void mdb_index_scan_free(MdbTableDef *table);
+extern int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg);
+extern int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row);
+extern void mdb_index_hash_text(guchar *text, guchar *hash);
+extern void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table);
+extern int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row);
+extern void mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest);
+extern void mdb_free_indices(GPtrArray *indices);
+void mdb_index_page_reset(MdbIndexPage *ipg);
+extern MdbIndexPage *mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain);
+extern MdbIndexPage *mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain);
+extern void mdb_index_page_init(MdbIndexPage *ipg);
+
+
+/* stats.c */
+extern void mdb_stats_on(MdbHandle *mdb);
+extern void mdb_stats_off(MdbHandle *mdb);
+extern void mdb_dump_stats(MdbHandle *mdb);
+
+/* like.c */
+extern int mdb_like_cmp(char *s, char *r);
+
+/* write.c */
+extern int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields);
+extern guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size);
+extern int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum);
+extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields);
+extern int mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size);
+extern int mdb_pg_get_freespace(MdbHandle *mdb);
+extern int mdb_update_row(MdbTableDef *table);
+extern unsigned char *mdb_new_data_pg(MdbCatalogEntry *entry);
+
+/* map.c */
+extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size);
+guint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg);
+
+/* props.c */
+extern GPtrArray *mdb_read_props_list(gchar *kkd, int len);
+extern void mdb_free_props(MdbProperties *props);
+extern MdbProperties *mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len);
+
+/* worktable.c */
+extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name);
+extern void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col);
+extern void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed);
+extern void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int column);
+extern void mdb_temp_columns_end(MdbTableDef *table);
+
+/* options.c */
+extern int mdb_get_option(unsigned long optnum);
+extern void mdb_debug(int klass, char *fmt, ...);
+
+/* iconv.c */
+extern int mdb_unicode2ascii(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest);
+extern int mdb_ascii2unicode(MdbHandle *mdb, unsigned char *buf, int offset, unsigned int len, char *dest);
+
+#endif /* _mdbtools_h_ */
diff --git a/navit/src/data/poi_geodownload/libmdb/index.c b/navit/src/data/poi_geodownload/libmdb/index.c
new file mode 100644 (file)
index 0000000..e840536
--- /dev/null
@@ -0,0 +1,905 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000-2004 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+MdbIndexPage *mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain);
+MdbIndexPage *mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg);
+
+char idx_to_text[] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0-7     0x00-0x07 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8-15    0x09-0x0f */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 16-23   0x10-0x17 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 24-31   0x19-0x1f */
+' ',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 32-39   0x20-0x27 */
+0x00, 0x00, 0x00, 0x00, 0x00, ' ',  ' ',  0x00, /* 40-47   0x29-0x2f */
+'V',  'W',  'X',  'Y',  'Z',  '[',  '\\', ']',  /* 48-55   0x30-0x37 */
+'^',  '_',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56-63   0x39-0x3f */
+0x00, '`',  'a',  'b',  'd',  'f',  'g',  'h',  /* 64-71   0x40-0x47 */
+'i',  'j',  'k',  'l',  'm',  'o',  'p',  'r',  /* 72-79   0x49-0x4f  H */
+'s',  't',  'u',  'v',  'w',  'x',  'z',  '{',  /* 80-87   0x50-0x57  P */
+'|',  '}',  '~',  '5',  '6',  '7',  '8',  '9',  /* 88-95   0x59-0x5f */
+0x00, '`',  'a',  'b',  'd',  'f',  'g',  'h',  /* 96-103  0x60-0x67 */
+'i',  'j',  'k',  'l',  'm',  'o',  'p',  'r',  /* 014-111 0x69-0x6f  h */
+'s',  't',  'u',  'v',  'w',  'x',  'z',  '{',  /* 112-119 0x70-0x77  p */
+'|',  '}',  '~',  0x00, 0x00, 0x00, 0x00, 0x00, /* 120-127 0x78-0x7f */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128-135 0x80-0x87 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+0x00, 0x00, 0x00, 0x00, 0x00, '`',  0x00, 0x00, /* 0xc0-0xc7 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+0x00, '`',  0x00, '`',  '`',  '`',  0x00, 0x00, /* 0xe0-0xe7 */
+'f',  'f',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+0x00, 0x00, 0x00, 'r',  0x00, 0x00, 'r',  0x00, /* 0xf0-0xf7 */
+0x81, 0x00, 0x00, 0x00, 'x',  0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+GPtrArray *
+mdb_read_indices(MdbTableDef *table)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       MdbIndex *pidx;
+       unsigned int i, j;
+       int idx_num, key_num, col_num;
+       int cur_pos, name_sz, idx2_sz, type_offset;
+       int index_start_pg = mdb->cur_pg;
+       gchar *tmpbuf;
+
+        table->indices = g_ptr_array_new();
+
+        if (IS_JET4(mdb)) {
+               cur_pos = table->index_start + 52 * table->num_real_idxs;
+               idx2_sz = 28;
+               type_offset = 23;
+       } else {
+               cur_pos = table->index_start + 39 * table->num_real_idxs;
+               idx2_sz = 20;
+               type_offset = 19;
+       }
+
+       tmpbuf = (gchar *) g_malloc(idx2_sz);
+       for (i=0;i<table->num_idxs;i++) {
+               read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz);
+               cur_pos += idx2_sz;
+               pidx = (MdbIndex *) g_malloc0(sizeof(MdbIndex));
+               pidx->table = table;
+               pidx->index_num = mdb_get_int16(tmpbuf, 4);
+               pidx->index_type = tmpbuf[type_offset]; 
+               g_ptr_array_add(table->indices, pidx);
+       }
+       g_free(tmpbuf);
+
+       for (i=0;i<table->num_idxs;i++) {
+               pidx = g_ptr_array_index (table->indices, i);
+               if (IS_JET4(mdb)) {
+                       name_sz=read_pg_if_16(mdb, &cur_pos);
+                       cur_pos += 2;
+                       tmpbuf = g_malloc(name_sz);
+                       read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz);
+                       cur_pos += name_sz;
+                       mdb_unicode2ascii(mdb, tmpbuf, 0, name_sz, pidx->name); 
+                       g_free(tmpbuf);
+               } else {
+                       read_pg_if(mdb, &cur_pos, 0);
+                       name_sz=mdb->pg_buf[cur_pos++];
+                       read_pg_if_n(mdb, pidx->name, &cur_pos, name_sz);
+                       cur_pos += name_sz;
+                       pidx->name[name_sz]='\0';               
+               }
+               //fprintf(stderr, "index name %s\n", pidx->name);
+       }
+
+       mdb_read_alt_pg(mdb, entry->table_pg);
+       mdb_read_pg(mdb, index_start_pg);
+       cur_pos = table->index_start;
+       idx_num=0;
+       for (i=0;i<table->num_real_idxs;i++) {
+               if (IS_JET4(mdb)) cur_pos += 4;
+               do {
+                       pidx = g_ptr_array_index (table->indices, idx_num++);
+               } while (pidx && pidx->index_type==2);
+
+               /* if there are more real indexes than index entries left after
+                  removing type 2's decrement real indexes and continue.  Happens
+                  on Northwind Orders table.
+               */
+               if (!pidx) {
+                       table->num_real_idxs--;
+                       continue;
+               }
+
+               pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf, 
+                               fmt->tab_cols_start_offset +
+                               (i*fmt->tab_ridx_entry_size));
+
+               key_num=0;
+               for (j=0;j<MDB_MAX_IDX_COLS;j++) {
+                       col_num=read_pg_if_16(mdb,&cur_pos);
+                       cur_pos += 2;
+                       read_pg_if(mdb, &cur_pos, 0);
+                       cur_pos++;
+                       if (col_num == 0xFFFF)
+                               continue;
+                       /* set column number to a 1 based column number and store */
+                       pidx->key_col_num[key_num] = col_num + 1;
+                       pidx->key_col_order[key_num] =
+                               (mdb->pg_buf[cur_pos-1]) ? MDB_ASC : MDB_DESC;
+                       key_num++;
+               }
+               pidx->num_keys = key_num;
+
+               cur_pos += 4;
+               pidx->first_pg = read_pg_if_32(mdb, &cur_pos);
+               cur_pos += 4;
+               read_pg_if(mdb, &cur_pos, 0);
+               pidx->flags = mdb->pg_buf[cur_pos++];
+               if (IS_JET4(mdb)) cur_pos += 9;
+       }
+       return NULL;
+}
+void
+mdb_index_hash_text(guchar *text, guchar *hash)
+{
+       unsigned int k;
+
+       for (k=0;k<strlen(text);k++) {
+               hash[k] = idx_to_text[text[k]];
+               if (!(hash[k])) fprintf(stderr, 
+                               "No translation available for %02x %d\n", 
+                               text[k],text[k]);
+       }
+       hash[strlen(text)]=0;
+}
+void
+mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest)
+{
+       int i, j = 0;
+
+       for (i = sz; i > 0; i--) {
+               dest[j++] = src[i];
+       }
+}
+void 
+mdb_index_cache_sarg(MdbColumn *col, MdbSarg *sarg, MdbSarg *idx_sarg)
+{
+       //guint32 cache_int;
+       unsigned char *c;
+
+       switch (col->col_type) {
+               case MDB_TEXT:
+               mdb_index_hash_text(sarg->value.s, idx_sarg->value.s);
+               break;
+
+               case MDB_LONGINT:
+               idx_sarg->value.i = GUINT32_SWAP_LE_BE(sarg->value.i);
+               //cache_int = sarg->value.i * -1;
+               c = (unsigned char *) &(idx_sarg->value.i);
+               c[0] |= 0x80;
+               //printf("int %08x %02x %02x %02x %02x\n", sarg->value.i, c[0], c[1], c[2], c[3]);
+               break;  
+
+               case MDB_INT:
+               break;  
+
+               default:
+               break;  
+       }
+}
+#if 0
+int 
+mdb_index_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSarg *sarg, int offset, int len)
+{
+char tmpbuf[256];
+int lastchar;
+
+       switch (col->col_type) {
+               case MDB_BYTE:
+                       return mdb_test_int(sarg, mdb_pg_get_byte(mdb, offset));
+                       break;
+               case MDB_INT:
+                       return mdb_test_int(sarg, mdb_pg_get_int16(mdb, offset));
+                       break;
+               case MDB_LONGINT:
+                       return mdb_test_int(sarg, mdb_pg_get_int32(mdb, offset));
+                       break;
+               case MDB_TEXT:
+                       strncpy(tmpbuf, &mdb->pg_buf[offset],255);
+                       lastchar = len > 255 ? 255 : len;
+                       tmpbuf[lastchar]='\0';
+                       return mdb_test_string(sarg, tmpbuf);
+               default:
+                       fprintf(stderr, "Calling mdb_test_sarg on unknown type.  Add code to mdb_test_sarg() for type %d\n",col->col_type);
+                       break;
+       }
+       return 1;
+}
+#endif
+int
+mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, unsigned char *buf, int len)
+{
+       unsigned int i, j;
+       MdbColumn *col;
+       MdbTableDef *table = idx->table;
+       MdbSarg *idx_sarg;
+       MdbSarg *sarg;
+       MdbField field;
+       MdbSargNode node;
+       //int c_offset = 0, 
+       int c_len;
+
+#if 0
+       fprintf(stderr,"mdb_index_test_sargs called on ");
+       for (i=0;i<len;i++)
+               fprintf(stderr,"%02x ",buf[i]); //mdb->pg_buf[offset+i]);
+       fprintf(stderr,"\n");
+#endif
+       for (i=0;i<idx->num_keys;i++) {
+               //c_offset++; /* the per column null indicator/flags */
+               col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
+               /*
+                * This will go away eventually
+                */
+               if (col->col_type==MDB_TEXT) {
+                       //c_len = strlen(&mdb->pg_buf[offset + c_offset]);
+                       c_len = strlen(buf);
+               } else {
+                       c_len = col->col_size;
+                       //fprintf(stderr,"Only text types currently supported.  How did we get here?\n");
+               }
+               /*
+                * If we have no cached index values for this column, 
+                * create them.
+                */
+               if (col->num_sargs && !col->idx_sarg_cache) {
+                       col->idx_sarg_cache = g_ptr_array_new();
+                       for (j=0;j<col->num_sargs;j++) {
+                               sarg = g_ptr_array_index (col->sargs, j);
+                               idx_sarg = g_memdup(sarg,sizeof(MdbSarg));
+                               //printf("calling mdb_index_cache_sarg\n");
+                               mdb_index_cache_sarg(col, sarg, idx_sarg);
+                               g_ptr_array_add(col->idx_sarg_cache, idx_sarg);
+                       }
+               }
+
+               for (j=0;j<col->num_sargs;j++) {
+                       sarg = g_ptr_array_index (col->idx_sarg_cache, j);
+                       /* XXX - kludge */
+                       node.op = sarg->op;
+                       node.value = sarg->value;
+                       //field.value = &mdb->pg_buf[offset + c_offset];
+                       field.value = buf;
+                       field.siz = c_len;
+                       field.is_null = FALSE;
+                       if (!mdb_test_sarg(mdb, col, &node, &field)) {
+                               /* sarg didn't match, no sense going on */
+                               return 0;
+                       }
+               }
+       }
+       return 1;
+}
+/*
+ * pack the pages bitmap
+ */
+int
+mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
+{
+       int mask_bit = 0;
+       int mask_pos = 0x16;
+       int mask_byte = 0;
+       int elem = 0;
+       int len, start, i;
+
+       start = ipg->idx_starts[elem++];
+
+       while (start) {
+               len = ipg->idx_starts[elem] - start;
+               fprintf(stdout, "len is %d\n", len);
+               for (i=0; i < len; i++) {
+                       mask_bit++;
+                       if (mask_bit==8) {
+                               mask_bit=0;
+                               mdb->pg_buf[mask_pos++] = mask_byte;
+                               mask_byte = 0;
+                       }
+                       /* upon reaching the len, set the bit */
+               }
+               mask_byte = (1 << mask_bit) | mask_byte;
+               fprintf(stdout, "mask byte is %02x at %d\n", mask_byte, mask_pos);
+               start = ipg->idx_starts[elem++];
+       }
+       /* flush the last byte if any */
+       mdb->pg_buf[mask_pos++] = mask_byte;
+       /* remember to zero the rest of the bitmap */
+       for (i = mask_pos; i < 0xf8; i++) {
+               mdb->pg_buf[mask_pos++] = 0;
+       }
+       return 0;
+}
+/*
+ * unpack the pages bitmap
+ */
+int
+mdb_index_unpack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg)
+{
+       int mask_bit = 0;
+       int mask_pos = 0x16;
+       int mask_byte;
+       int start = 0xf8;
+       int elem = 0;
+       int len = 0;
+
+       ipg->idx_starts[elem++]=start;
+
+#if 0
+       fprintf(stdout, "Unpacking index page %u\n", ipg->pg);
+#endif
+       do {
+               len = 0;
+               do {
+                       mask_bit++;
+                       if (mask_bit==8) {
+                               mask_bit=0;
+                               mask_pos++;
+                       }
+                       mask_byte = mdb->pg_buf[mask_pos];
+                       len++;
+               } while (mask_pos <= 0xf8 && !((1 << mask_bit) & mask_byte));
+               //fprintf(stdout, "%d %d %d %d\n", mask_pos, mask_bit, mask_byte, len);
+
+               start += len;
+               if (mask_pos < 0xf8) ipg->idx_starts[elem++]=start;
+
+       } while (mask_pos < 0xf8);
+
+       /* if we zero the next element, so we don't pick up the last pages starts*/
+       ipg->idx_starts[elem]=0;
+
+       return elem;
+}
+/*
+ * find the next entry on a page (either index or leaf). Uses state information
+ * stored in the MdbIndexPage across calls.
+ */
+int
+mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg)
+{
+       if (!ipg->pg) return 0;
+
+       /* if this page has not been unpacked to it */
+       if (!ipg->idx_starts[0]){
+               //fprintf(stdout, "Unpacking page %d\n", ipg->pg);
+               mdb_index_unpack_bitmap(mdb, ipg);
+       }
+
+       
+       if (ipg->idx_starts[ipg->start_pos + 1]==0) return 0; 
+       ipg->len = ipg->idx_starts[ipg->start_pos+1] - ipg->idx_starts[ipg->start_pos];
+       ipg->start_pos++;
+       //fprintf(stdout, "Start pos %d\n", ipg->start_pos);
+
+       return ipg->len;
+}
+void mdb_index_page_reset(MdbIndexPage *ipg)
+{
+       ipg->offset = 0xf8; /* start byte of the index entries */
+       ipg->start_pos=0;
+       ipg->len = 0; 
+       ipg->idx_starts[0]=0;
+}
+void mdb_index_page_init(MdbIndexPage *ipg)
+{
+       memset(ipg, 0, sizeof(MdbIndexPage));
+       mdb_index_page_reset(ipg);
+}
+/*
+ * find the next leaf page if any given a chain. Assumes any exhausted leaf 
+ * pages at the end of the chain have been peeled off before the call.
+ */
+MdbIndexPage *
+mdb_find_next_leaf(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain)
+{
+       MdbIndexPage *ipg, *newipg;
+       guint32 pg;
+       guint passed = 0;
+
+       ipg = mdb_index_read_bottom_pg(mdb, idx, chain);
+
+       /*
+        * If we are at the first page deep and it's not an index page then
+        * we are simply done. (there is no page to find
+        */
+
+       if (mdb->pg_buf[0]==MDB_PAGE_LEAF) {
+               /* Indexes can have leaves at the end that don't appear
+                * in the upper tree, stash the last index found so
+                * we can follow it at the end.  */
+               chain->last_leaf_found = ipg->pg;
+               return ipg;
+       }
+
+       /*
+        * apply sargs here, currently we don't
+        */
+       do {
+               ipg->len = 0;
+               //printf("finding next on pg %lu\n", ipg->pg);
+               if (!mdb_index_find_next_on_page(mdb, ipg)) {
+                       //printf("find_next_on_page returned 0\n");
+                       return 0;
+               }
+               pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 3);
+               //printf("Looking at pg %lu at %lu %d\n", pg, ipg->offset, ipg->len);
+               ipg->offset += ipg->len;
+
+               /*
+                * add to the chain and call this function
+                * recursively.
+                */
+               newipg = mdb_chain_add_page(mdb, chain, pg);
+               newipg = mdb_find_next_leaf(mdb, idx, chain);
+               //printf("returning pg %lu\n",newipg->pg);
+               return newipg;
+       } while (!passed);
+       /* no more pages */
+       return NULL;
+
+}
+MdbIndexPage *
+mdb_chain_add_page(MdbHandle *mdb, MdbIndexChain *chain, guint32 pg)
+{
+       MdbIndexPage *ipg;
+
+       chain->cur_depth++;
+       if (chain->cur_depth > MDB_MAX_INDEX_DEPTH) {
+               fprintf(stderr,"Error! maximum index depth of %d exceeded.  This is probably due to a programming bug, If you are confident that your indexes really are this deep, adjust MDB_MAX_INDEX_DEPTH in mdbtools.h and recompile.\n", MDB_MAX_INDEX_DEPTH);
+               exit(1);
+       }
+       ipg = &(chain->pages[chain->cur_depth - 1]);
+       mdb_index_page_init(ipg);
+       ipg->pg = pg;
+
+       return ipg;
+}
+/*
+ * returns the bottom page of the IndexChain, if IndexChain is empty it 
+ * initializes it by reading idx->first_pg (the root page)
+ */
+MdbIndexPage *
+mdb_index_read_bottom_pg(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain)
+{
+       MdbIndexPage *ipg;
+
+       /*
+        * if it's new use the root index page (idx->first_pg)
+        */
+       if (!chain->cur_depth) {
+               ipg = &(chain->pages[0]);
+               mdb_index_page_init(ipg);
+               chain->cur_depth = 1;
+               ipg->pg = idx->first_pg;
+               if (!(ipg = mdb_find_next_leaf(mdb, idx, chain)))
+                       return 0;
+       } else {
+               ipg = &(chain->pages[chain->cur_depth - 1]);
+               ipg->len = 0; 
+       }
+
+       mdb_read_pg(mdb, ipg->pg);
+
+       return ipg;
+}
+/*
+ * unwind the stack and search for new leaf node
+ */
+MdbIndexPage *
+mdb_index_unwind(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain)
+{
+       MdbIndexPage *ipg;
+
+       //printf("page %lu finished\n",ipg->pg);
+       if (chain->cur_depth==1) {
+               //printf("cur_depth == 1 we're out\n");
+               return NULL;
+       }
+       /* 
+       * unwind the stack until we find something or reach 
+       * the top.
+       */
+       ipg = NULL;
+       while (chain->cur_depth>1 && ipg==NULL) {
+               //printf("chain depth %d\n", chain->cur_depth);
+               chain->cur_depth--;
+               ipg = mdb_find_next_leaf(mdb, idx, chain);
+               if (ipg) mdb_index_find_next_on_page(mdb, ipg);
+       }
+       if (chain->cur_depth==1) {
+               //printf("last leaf %lu\n", chain->last_leaf_found);
+               return NULL;
+       }
+       return ipg;
+}
+/*
+ * the main index function.
+ * caller provides an index chain which is the current traversal of index
+ * pages from the root page to the leaf.  Initially passed as blank, 
+ * mdb_index_find_next will store it's state information here. Each invocation
+ * then picks up where the last one left off, allowing us to scroll through
+ * the index one by one.
+ *
+ * Sargs are applied here but also need to be applied on the whole row b/c
+ * text columns may return false positives due to hashing and non-index
+ * columns with sarg values can't be tested here.
+ */
+int
+mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row)
+{
+       MdbIndexPage *ipg;
+       int passed = 0;
+       int idx_sz;
+       int idx_start = 0;
+       MdbColumn *col;
+
+       ipg = mdb_index_read_bottom_pg(mdb, idx, chain);
+
+       /*
+        * loop while the sargs don't match
+        */
+       do {
+               ipg->len = 0;
+               /*
+                * if no more rows on this leaf, try to find a new leaf
+                */
+               if (!mdb_index_find_next_on_page(mdb, ipg)) {
+                       if (!chain->clean_up_mode) {
+                               if (!(ipg = mdb_index_unwind(mdb, idx, chain)))
+                                       chain->clean_up_mode = 1;
+                       }
+                       if (chain->clean_up_mode) {
+                               //fprintf(stdout,"in cleanup mode\n");
+
+                               if (!chain->last_leaf_found) return 0;
+                               mdb_read_pg(mdb, chain->last_leaf_found);
+                               chain->last_leaf_found = mdb_pg_get_int24(mdb, 0x0c);
+                               //printf("next leaf %lu\n", chain->last_leaf_found);
+                               mdb_read_pg(mdb, chain->last_leaf_found);
+                               /* reuse the chain for cleanup mode */
+                               chain->cur_depth = 1;
+                               ipg = &chain->pages[0];
+                               mdb_index_page_init(ipg);
+                               ipg->pg = chain->last_leaf_found;
+                               //printf("next on page %d\n",
+                               if (!mdb_index_find_next_on_page(mdb, ipg))
+                                       return 0;
+                       }
+               }
+               *row = mdb->pg_buf[ipg->offset + ipg->len - 1];
+#if 0
+               printf("page: ");
+               buffer_dump(mdb->pg_buf, ipg->offset+ipg->len-4, ipg->offset+ipg->len-2);
+#endif
+               *pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4);
+#if 0
+               printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, ipg->pg, ipg->offset, ipg->len);
+#endif
+               col=g_ptr_array_index(idx->table->columns,idx->key_col_num[0]-1);
+               idx_sz = mdb_col_fixed_size(col);
+               /* handle compressed indexes, single key indexes only? */
+               if (idx->num_keys==1 && idx_sz>0 && ipg->len - 4 < idx_sz) {
+#if 0
+                       printf("short index found\n");
+                       buffer_dump(ipg->cache_value, 0, idx_sz);
+#endif
+                       memcpy(&ipg->cache_value[idx_sz - (ipg->len - 4)], &mdb->pg_buf[ipg->offset], ipg->len);
+#if 0
+                       buffer_dump(ipg->cache_value, 0, idx_sz);
+#endif
+               } else {
+                       idx_start = ipg->offset + (ipg->len - 4 - idx_sz);
+                       memcpy(ipg->cache_value, &mdb->pg_buf[idx_start], idx_sz);
+               }
+
+               //idx_start = ipg->offset + (ipg->len - 4 - idx_sz);
+               passed = mdb_index_test_sargs(mdb, idx, ipg->cache_value, idx_sz);
+
+//             printf("passed=%d\n", passed);
+
+               buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1);
+               ipg->offset += ipg->len;
+
+       } while (!passed);
+
+#if 0
+       fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->len);
+       buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset+ipg->len-1);
+#endif
+
+       return ipg->len;
+}
+/*
+ * XXX - FIX ME
+ * This function is grossly inefficient.  It scans the entire index building 
+ * an IndexChain to a specific row.  We should be checking the index pages 
+ * for matches against the indexed fields to find the proper leaf page, but
+ * getting it working first and then make it fast!
+ */
+int 
+mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row)
+{
+       MdbIndexPage *ipg;
+       int passed = 0;
+       guint32 datapg;
+       guint16 datarow;
+
+       ipg = mdb_index_read_bottom_pg(mdb, idx, chain);
+
+       do {
+               ipg->len = 0;
+               /*
+                * if no more rows on this leaf, try to find a new leaf
+                */
+               if (!mdb_index_find_next_on_page(mdb, ipg)) {
+                       /* back to top? We're done */
+                       if (chain->cur_depth==1)
+                               return 0;
+
+                       /* 
+                        * unwind the stack until we find something or reach 
+                        * the top.
+                        */
+                       while (chain->cur_depth>1) {
+                               chain->cur_depth--;
+                               if (!(ipg = mdb_find_next_leaf(mdb, idx, chain)))
+                                       return 0;
+                               mdb_index_find_next_on_page(mdb, ipg);
+                       }
+                       if (chain->cur_depth==1)
+                               return 0;
+               }
+               /* test row and pg */
+               datarow = mdb->pg_buf[ipg->offset + ipg->len - 1];
+               datapg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4);
+
+               if (datapg == pg && datarow == row) {
+                       passed = 1;
+               }
+               ipg->offset += ipg->len;
+       } while (!passed);
+
+       /* index chain from root to leaf should now be in "chain" */
+       return 1;
+}
+
+void mdb_index_walk(MdbTableDef *table, MdbIndex *idx)
+{
+MdbHandle *mdb = table->entry->mdb;
+int cur_pos = 0;
+unsigned char marker;
+MdbColumn *col;
+unsigned int i;
+
+       if (idx->num_keys!=1) return;
+
+       mdb_read_pg(mdb, idx->first_pg);
+       cur_pos = 0xf8;
+       
+       for (i=0;i<idx->num_keys;i++) {
+               marker = mdb->pg_buf[cur_pos++];
+               col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
+               //printf("column %d coltype %d col_size %d (%d)\n",i,col->col_type, mdb_col_fixed_size(col), col->col_size);
+       }
+}
+void 
+mdb_index_dump(MdbTableDef *table, MdbIndex *idx)
+{
+       unsigned int i;
+       MdbColumn *col;
+
+       fprintf(stdout,"index number     %d\n", idx->index_num);
+       fprintf(stdout,"index name       %s\n", idx->name);
+       fprintf(stdout,"index first page %d\n", idx->first_pg);
+       fprintf(stdout,"index rows       %d\n", idx->num_rows);
+       if (idx->index_type==1) fprintf(stdout,"index is a primary key\n");
+       for (i=0;i<idx->num_keys;i++) {
+               col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
+               fprintf(stdout,"Column %s(%d) Sorted %s Unique: %s\n", 
+                       col->name,
+                       idx->key_col_num[i], 
+                       idx->key_col_order[i]==MDB_ASC ? "ascending" : "descending",
+                       idx->flags & MDB_IDX_UNIQUE ? "Yes" : "No"
+                       );
+       }
+       mdb_index_walk(table, idx);
+}
+/*
+ * compute_cost tries to assign a cost to a given index using the sargs 
+ * available in this query.
+ *
+ * Indexes with no matching sargs are assigned 0
+ * Unique indexes are preferred over non-uniques
+ * Operator preference is equal, like, isnull, others 
+ */
+int mdb_index_compute_cost(MdbTableDef *table, MdbIndex *idx)
+{
+       unsigned int i;
+       MdbColumn *col;
+       MdbSarg *sarg = NULL;
+       int not_all_equal = 0;
+
+       if (!idx->num_keys) return 0;
+       if (idx->num_keys > 1) {
+               for (i=0;i<idx->num_keys;i++) {
+                       col=g_ptr_array_index(table->columns,idx->key_col_num[i]-1);
+                       if (col->sargs) sarg = g_ptr_array_index (col->sargs, 0);
+                       if (!sarg || sarg->op != MDB_EQUAL) not_all_equal++;
+               }
+       }
+
+       col=g_ptr_array_index(table->columns,idx->key_col_num[0]-1);
+       /* 
+        * if this is the first key column and there are no sargs,
+        * then this index is useless.
+        */
+       if (!col->num_sargs) return 0;
+
+       sarg = g_ptr_array_index (col->sargs, 0);
+
+       /*
+        * a like with a wild card first is useless as a sarg */
+       if (sarg->op == MDB_LIKE && sarg->value.s[0]=='%')
+               return 0;
+
+       /*
+        * this needs a lot of tweaking.
+        */
+       if (idx->flags & MDB_IDX_UNIQUE) {
+               if (idx->num_keys == 1) {
+                       //printf("op is %d\n", sarg->op);
+                       switch (sarg->op) {
+                               case MDB_EQUAL:
+                                       return 1; break;
+                               case MDB_LIKE:
+                                       return 4; break;
+                               case MDB_ISNULL:
+                                       return 12; break;
+                               default:
+                                       return 8; break;
+                       }
+               } else {
+                       switch (sarg->op) {
+                               case MDB_EQUAL:
+                                       if (not_all_equal) return 2; 
+                                       else return 1;
+                                       break;
+                               case MDB_LIKE:
+                                       return 6; break;
+                               case MDB_ISNULL:
+                                       return 12; break;
+                               default:
+                                       return 9; break;
+                       }
+               }
+       } else {
+               if (idx->num_keys == 1) {
+                       switch (sarg->op) {
+                               case MDB_EQUAL:
+                                       return 2; break;
+                               case MDB_LIKE:
+                                       return 5; break;
+                               case MDB_ISNULL:
+                                       return 12; break;
+                               default:
+                                       return 10; break;
+                       }
+               } else {
+                       switch (sarg->op) {
+                               case MDB_EQUAL:
+                                       if (not_all_equal) return 3; 
+                                       else return 2;
+                                       break;
+                               case MDB_LIKE:
+                                       return 7; break;
+                               case MDB_ISNULL:
+                                       return 12; break;
+                               default:
+                                       return 11; break;
+                       }
+               }
+       }
+       return 0;
+}
+/*
+ * choose_index runs mdb_index_compute_cost for each available index and picks
+ * the best.
+ *
+ * Returns strategy to use (table scan, or index scan)
+ */
+MdbStrategy 
+mdb_choose_index(MdbTableDef *table, int *choice)
+{
+       unsigned int i;
+       MdbIndex *idx;
+       int cost = 0;
+       int least = 99;
+
+       *choice = -1;
+       for (i=0;i<table->num_idxs;i++) {
+               idx = g_ptr_array_index (table->indices, i);
+               cost = mdb_index_compute_cost(table, idx);
+               //printf("cost for %s is %d\n", idx->name, cost);
+               if (cost && cost < least) {
+                       least = cost;
+                       *choice = i;
+               }
+       }
+       /* and the winner is: *choice */
+       if (least==99) return MDB_TABLE_SCAN;
+       return MDB_INDEX_SCAN;
+}
+void
+mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table)
+{
+       int i;
+
+       if (mdb_get_option(MDB_USE_INDEX) && mdb_choose_index(table, &i) == MDB_INDEX_SCAN) {
+               table->strategy = MDB_INDEX_SCAN;
+               table->scan_idx = g_ptr_array_index (table->indices, i);
+               table->chain = g_malloc0(sizeof(MdbIndexChain));
+               table->mdbidx = mdb_clone_handle(mdb);
+               mdb_read_pg(table->mdbidx, table->scan_idx->first_pg);
+               //printf("best index is %s\n",table->scan_idx->name);
+       }
+       //printf("TABLE SCAN? %d\n", table->strategy);
+}
+void 
+mdb_index_scan_free(MdbTableDef *table)
+{
+       if (table->chain) {
+               g_free(table->chain);
+               table->chain = NULL;
+       }
+       if (table->mdbidx) {
+               mdb_close(table->mdbidx);
+               table->mdbidx = NULL;
+       }
+}
+
+void mdb_free_indices(GPtrArray *indices)
+{
+       unsigned int i;
+
+       if (!indices) return;
+       for (i=0; i<indices->len; i++)
+               g_free (g_ptr_array_index(indices, i));
+       g_ptr_array_free(indices, TRUE);
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/kkd.c b/navit/src/data/poi_geodownload/libmdb/kkd.c
new file mode 100644 (file)
index 0000000..ea72887
--- /dev/null
@@ -0,0 +1,149 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+
+/*
+** Note: This code is mostly garbage right now...just a test to parse out the
+**       KKD structures.
+*/
+
+GArray *mdb_get_column_props(MdbCatalogEntry *entry, int start)
+{
+int pos, cnt=0;
+int len, tmp, cplen;
+MdbColumnProp prop;
+MdbHandle *mdb = entry->mdb;
+
+       entry->props = g_array_new(FALSE,FALSE,sizeof(MdbColumnProp));
+       len = mdb_pg_get_int16(mdb,start);
+       pos = start + 6;
+       while (pos < start+len) {
+               tmp = mdb_pg_get_int16(mdb,pos); /* length of string */
+               pos += 2;
+               cplen = tmp > MDB_MAX_OBJ_NAME ? MDB_MAX_OBJ_NAME : tmp;
+               g_memmove(prop.name,&mdb->pg_buf[pos],cplen);
+               prop.name[cplen]='\0';
+               pos += tmp; 
+               g_array_append_val(entry->props, prop.name);
+               cnt++;
+       }
+       entry->num_props = cnt;
+       return entry->props;
+}
+
+GHashTable *mdb_get_column_def(MdbCatalogEntry *entry, int start)
+{
+GHashTable *hash = NULL;
+MdbHandle *mdb = entry->mdb;
+MdbColumnProp prop;
+int tmp, pos, col_num, val_len, i;
+int len, col_type;
+unsigned char c;
+int end;
+
+       fprintf(stdout,"\n data\n");
+       fprintf(stdout,"-------\n");
+       len = mdb_pg_get_int16(mdb,start);
+       fprintf(stdout,"length = %3d\n",len);
+       pos = start + 6;
+       end = start + len;
+       while (pos < end) {
+               fprintf(stdout,"pos = %3d\n",pos);
+               start = pos;
+               tmp = mdb_pg_get_int16(mdb,pos); /* length of field */
+               pos += 2;
+               col_type = mdb_pg_get_int16(mdb,pos); /* ??? */
+               pos += 2;
+               col_num = 0;
+               if (col_type) {
+                       col_num = mdb_pg_get_int16(mdb,pos); 
+                       pos += 2;
+               }
+               val_len = mdb_pg_get_int16(mdb,pos);
+               pos += 2;
+               fprintf(stdout,"length = %3d %04x %2d %2d ",tmp, col_type, col_num, val_len);
+               for (i=0;i<val_len;i++) {
+                       c = mdb->pg_buf[pos+i];
+                       if (isprint(c))
+                               fprintf(stdout,"  %c",c);
+                       else 
+                               fprintf(stdout," %02x",c);
+
+               }
+               pos = start + tmp; 
+               prop = g_array_index(entry->props,MdbColumnProp,col_num);
+               fprintf(stdout," Property %s",prop.name); 
+               fprintf(stdout,"\n");
+       }
+       return hash;
+}
+void mdb_kkd_dump(MdbCatalogEntry *entry)
+{
+int rows;
+int kkd_start, kkd_end;
+int i, tmp, pos, row_type, datapos=0;
+MdbColumnProp prop;
+MdbHandle *mdb = entry->mdb;
+int rowid = entry->kkd_rowid;
+
+
+       mdb_read_pg(mdb, entry->kkd_pg);
+       rows = mdb_pg_get_int16(mdb,8);
+       fprintf(stdout,"number of rows = %d\n",rows);
+       kkd_start = mdb_pg_get_int16(mdb,10+rowid*2);
+       fprintf(stdout,"kkd start = %d %04x\n",kkd_start,kkd_start);
+       kkd_end = mdb->fmt->pg_size;
+       for (i=0;i<rows;i++) {
+               tmp = mdb_pg_get_int16(mdb, 10+i*2);
+               if (tmp < mdb->fmt->pg_size &&
+                   tmp > kkd_start &&
+                   tmp < kkd_end) {
+                       kkd_end = tmp;
+               }
+       }
+       fprintf(stdout,"kkd end = %d %04x\n",kkd_end,kkd_end);
+       pos = kkd_start + 4; /* 4 = K K D \0 */
+       while (pos < kkd_end) {
+               tmp = mdb_pg_get_int16(mdb,pos);
+               row_type = mdb_pg_get_int16(mdb,pos+4);
+               fprintf(stdout,"row size = %3d type = 0x%02x\n",tmp,row_type);
+               if (row_type==0x80)  {
+                       fprintf(stdout,"\nColumn Properties\n");
+                       fprintf(stdout,"-----------------\n");
+                       mdb_get_column_props(entry,pos);
+                       for (i=0;i<entry->num_props;i++) {
+                               prop = g_array_index(entry->props,MdbColumnProp,i);
+                               fprintf(stdout,"%3d %s\n",i,prop.name); 
+                       }
+               }
+               if (row_type==0x01) datapos = pos;
+               pos += tmp;
+       }
+       
+       if (datapos) {
+               mdb_get_column_def(entry, datapos);
+       }
+}
+
diff --git a/navit/src/data/poi_geodownload/libmdb/like.c b/navit/src/data/poi_geodownload/libmdb/like.c
new file mode 100644 (file)
index 0000000..0a23d45
--- /dev/null
@@ -0,0 +1,78 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <mdbtools.h>
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/**
+ * mdb_like_cmp
+ * @s: String to search within.
+ * @r: Search pattern.
+ *
+ * Tests the string @s to see if it matches the search pattern @r.  In the
+ * search pattern, a percent sign indicates matching on any number of
+ * characters, and an underscore indicates matching any single character.
+ *
+ * Returns: 1 if the string matches, 0 if the string does not match.
+ */
+int mdb_like_cmp(char *s, char *r)
+{
+       unsigned int i;
+       int ret;
+
+       mdb_debug(MDB_DEBUG_LIKE, "comparing %s and %s", s, r);
+       switch (r[0]) {
+               case '\0':
+                       if (s[0]=='\0') {
+                               return 1;
+                       } else {
+                               return 0;
+                       }
+               case '_':
+                       /* skip one character */
+                       return mdb_like_cmp(&s[1],&r[1]);
+               case '%':
+                       /* skip any number of characters */
+                       /* the strlen(s)+1 is important so the next call can */
+                       /* if there are trailing characters */
+                       for(i=0;i<strlen(s)+1;i++) {
+                               if (mdb_like_cmp(&s[i],&r[1])) {
+                                       return 1;
+                               }
+                       }
+                       return 0;
+               default:
+                       for(i=0;i<strlen(r);i++) {
+                               if (r[i]=='_' || r[i]=='%') break;
+                       }
+                       if (strncmp(s,r,i)) {
+                               return 0;
+                       } else {
+                               mdb_debug(MDB_DEBUG_LIKE, "at pos %d comparing %s and %s", i, &s[i], &r[i]);
+                               ret = mdb_like_cmp(&s[i],&r[i]);
+                               mdb_debug(MDB_DEBUG_LIKE, "returning %d (%s and %s)", ret, &s[i], &r[i]);
+                               return ret;
+                       }
+       }
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/map.c b/navit/src/data/poi_geodownload/libmdb/map.c
new file mode 100644 (file)
index 0000000..1164b7b
--- /dev/null
@@ -0,0 +1,133 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+static guint32 
+mdb_map_find_next0(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
+{
+       guint32 pgnum, i, usage_bitlen;
+       unsigned char *usage_bitmap;
+
+       pgnum = mdb_get_int32(map, 1);
+       usage_bitmap = map + 5;
+       usage_bitlen = (map_sz - 5) * 8;
+
+       i = (start_pg >= pgnum) ? start_pg-pgnum+1 : 0;
+       for (; i<usage_bitlen; i++) {
+               if (usage_bitmap[i/8] & (1 << (i%8))) {
+                       return pgnum + i;
+               }
+       }
+       /* didn't find anything */
+       return 0;
+}
+static int 
+mdb_map_find_next1(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
+{
+       guint32 map_ind, max_map_pgs, offset, usage_bitlen;
+
+       /*
+       * start_pg will tell us where to (re)start the scan
+       * for the next data page.  each usage_map entry points to a
+       * 0x05 page which bitmaps (mdb->fmt->pg_size - 4) * 8 pages.
+       *
+       * map_ind gives us the starting usage_map entry
+       * offset gives us a page offset into the bitmap
+       */
+       usage_bitlen = (mdb->fmt->pg_size - 4) * 8;
+       max_map_pgs = (map_sz - 1) / 4;
+       map_ind = (start_pg + 1) / usage_bitlen;
+       offset = (start_pg + 1) % usage_bitlen;
+
+       for (; map_ind<max_map_pgs; map_ind++) {
+               unsigned char *usage_bitmap;
+               guint32 i, map_pg;
+
+               if (!(map_pg = mdb_get_int32(map, (map_ind*4)+1))) {
+                       continue;
+               }
+               if(mdb_read_alt_pg(mdb, map_pg) != mdb->fmt->pg_size) {
+                       fprintf(stderr, "Oops! didn't get a full page at %d\n", map_pg);
+                       exit(1);
+               } 
+
+               usage_bitmap = mdb->alt_pg_buf + 4;
+               for (i=offset; i<usage_bitlen; i++) {
+                       if (usage_bitmap[i/8] & (1 << (i%8))) {
+                               return map_ind*usage_bitlen + i;
+                       }
+               }
+               offset = 0;
+       }
+       /* didn't find anything */
+       return 0;
+}
+guint32 
+mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg)
+{
+       if (map[0] == 0) {
+               return mdb_map_find_next0(mdb, map, map_sz, start_pg);
+       } else if (map[0] == 1) {
+               return mdb_map_find_next1(mdb, map, map_sz, start_pg);
+       }
+
+       fprintf(stderr, "Warning: unrecognized usage map type: %d\n", map[0]);
+       return -1;
+}
+guint32
+mdb_alloc_page(MdbTableDef *table)
+{
+       printf("Allocating new page\n");
+       return 0;
+}
+guint32 
+mdb_map_find_next_freepage(MdbTableDef *table, int row_size)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       guint32 pgnum;
+       guint32 cur_pg = 0;
+       int free_space;
+
+       do {
+               pgnum = mdb_map_find_next(mdb, 
+                               table->free_usage_map, 
+                               table->freemap_sz, cur_pg);
+               printf("looking at page %d\n", pgnum);
+               if (!pgnum) {
+                       /* allocate new page */
+                       pgnum = mdb_alloc_page(table);
+                       return pgnum;
+               }
+               cur_pg = pgnum;
+
+               mdb_read_pg(mdb, pgnum);
+               free_space = mdb_pg_get_freespace(mdb);
+               
+       } while (free_space < row_size);
+
+       printf("page %d has %d bytes left\n", pgnum, free_space);
+
+       return pgnum;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/mem.c b/navit/src/data/poi_geodownload/libmdb/mem.c
new file mode 100644 (file)
index 0000000..9c51832
--- /dev/null
@@ -0,0 +1,50 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+#include <locale.h>
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/**
+ * mdb_init:
+ *
+ * Initializes the LibMDB library.  This function should be called exactly once
+ * by calling program and prior to any other function.
+ *
+ **/
+void mdb_init()
+{
+       mdb_init_backends();
+}
+
+/**
+ * mdb_exit:
+ *
+ * Cleans up the LibMDB library.  This function should be called exactly once
+ * by the calling program prior to exiting (or prior to final use of LibMDB 
+ * functions).
+ *
+ **/
+void mdb_exit()
+{
+       mdb_remove_backends();
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/money.c b/navit/src/data/poi_geodownload/libmdb/money.c
new file mode 100644 (file)
index 0000000..7f2cf65
--- /dev/null
@@ -0,0 +1,139 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 1998-1999  Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#define MAXPRECISION 20
+/* 
+** these routines are copied from the freetds project which does something
+** very similiar
+*/
+
+static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier);
+static int do_carry(unsigned char *product);
+static char *array_to_string(unsigned char *array, int unsigned scale, char *s);
+
+/**
+ * mdb_money_to_string
+ * @mdb: Handle to open MDB database file
+ * @start: Offset of the field within the current page
+ * @s: String that will receieve the value
+ *
+ * Returns: the string that has received the value.
+ */
+char *mdb_money_to_string(MdbHandle *mdb, int start, char *s)
+{
+       int num_bytes = 8;
+       int i;
+       int neg=0;
+       unsigned char multiplier[MAXPRECISION], temp[MAXPRECISION];
+       unsigned char product[MAXPRECISION];
+       unsigned char money[num_bytes];
+
+       memset(multiplier,0,MAXPRECISION);
+       memset(product,0,MAXPRECISION);
+       multiplier[0]=1;
+       memcpy(money, mdb->pg_buf + start, num_bytes);
+
+       /* Perform two's complement for negative numbers */
+       if (money[7] & 0x80) {
+               neg = 1;
+               for (i=0;i<num_bytes;i++) {
+                       money[i] = ~money[i];
+               }
+               for (i=0; i<num_bytes; i++) {
+                       money[i] ++;
+                       if (money[i]!=0) break;
+               }
+       }
+
+       for (i=0;i<num_bytes;i++) {
+               /* product += multiplier * current byte */
+               multiply_byte(product, money[i], multiplier);
+
+               /* multiplier = multiplier * 256 */
+               memcpy(temp, multiplier, MAXPRECISION);
+               memset(multiplier,0,MAXPRECISION);
+               multiply_byte(multiplier, 256, temp);
+       }
+       if (neg) {
+               s[0]='-';
+               array_to_string(product, 4, &s[1]);
+       } else {
+               array_to_string(product, 4, s);
+       }
+       return s;
+}
+static int multiply_byte(unsigned char *product, int num, unsigned char *multiplier)
+{
+       unsigned char number[3];
+       unsigned int i, j;
+
+       number[0]=num%10;
+       number[1]=(num/10)%10;
+       number[2]=(num/100)%10;
+
+       for (i=0;i<MAXPRECISION;i++) {
+               if (multiplier[i] == 0) continue;
+               for (j=0;j<3;j++) {
+                       if (number[j] == 0) continue;
+                       product[i+j] += multiplier[i]*number[j];
+               }
+               do_carry(product);
+       }
+       return 0;
+}
+static int do_carry(unsigned char *product)
+{
+       unsigned int j;
+
+       for (j=0;j<MAXPRECISION-1;j++) {
+               if (product[j]>9) {
+                       product[j+1]+=product[j]/10;
+                       product[j]=product[j]%10;
+               }
+       }
+       if (product[j]>9) {
+               product[j]=product[j]%10;
+       }
+       return 0;
+}
+static char *array_to_string(unsigned char *array, unsigned int scale, char *s)
+{
+       unsigned int top, i, j=0;
+       
+       for (top=MAXPRECISION;(top>0) && (top-1>scale) && !array[top-1];top--);
+
+       if (top == 0) {
+               s[j++] = '0';
+       } else {
+               for (i=top; i>0; i--) {
+                       if (j == top-scale) s[j++]='.';
+                       s[j++]=array[i-1]+'0';
+               }
+       }
+       s[j]='\0';
+
+       return s;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/options.c b/navit/src/data/poi_geodownload/libmdb/options.c
new file mode 100644 (file)
index 0000000..cdbbc66
--- /dev/null
@@ -0,0 +1,86 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2004 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <mdbtools.h>
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+#define DEBUG 1
+
+static unsigned long opts;
+static int optset;
+
+static void load_options();
+
+void
+mdb_debug(int klass, char *fmt, ...)
+{
+#ifdef DEBUG
+       va_list ap;
+
+       if (!optset) load_options();
+       if (klass & opts) {     
+       va_start(ap, fmt);
+       vfprintf (stdout,fmt, ap);
+       va_end(ap);
+       fprintf(stdout,"\n");
+       }
+#endif
+}
+
+static void
+load_options()
+{
+       char *opt;
+       char *s;
+
+    if (!optset && (s=getenv("MDBOPTS"))) {
+               opt = strtok(s, ":");
+               do {
+               if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX;
+               if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE;
+               if (!strcmp(opt, "debug_write")) opts |= MDB_DEBUG_WRITE;
+               if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE;
+               if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE;
+               if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW;
+               if (!strcmp(opt, "debug_all")) {
+                               opts |= MDB_DEBUG_LIKE;
+                               opts |= MDB_DEBUG_WRITE;
+                               opts |= MDB_DEBUG_USAGE;
+                               opts |= MDB_DEBUG_OLE;
+                               opts |= MDB_DEBUG_ROW;
+                       }
+                       opt = strtok(NULL,":");
+               } while (opt);
+    }
+       optset = 1;
+}
+int
+mdb_get_option(unsigned long optnum)
+{
+       if (!optset) load_options();
+       return ((opts & optnum) > 0);
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/props.c b/navit/src/data/poi_geodownload/libmdb/props.c
new file mode 100644 (file)
index 0000000..61db9f5
--- /dev/null
@@ -0,0 +1,127 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ *
+ * This library is free software; you can redistribute it and/or 
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+GPtrArray *
+mdb_read_props_list(gchar *kkd, int len)
+{
+       guint32 record_len;
+       int pos = 0;
+       gchar *name;
+       GPtrArray *names = NULL;
+       int i = 0;
+
+       names = g_ptr_array_new();
+#ifdef MDB_DEBUG
+       buffer_dump(kkd, 0, len - 1);
+#endif
+       pos = 0;
+       while (pos < len) {
+               record_len = mdb_get_int16(kkd, pos);
+               pos += 2;
+#ifdef MDB_DEBUG
+               printf("%02d ",i++);
+               buffer_dump(kkd, pos - 2, pos + record_len - 1);
+#endif
+               name = g_malloc(record_len + 1);
+               strncpy(name, &kkd[pos], record_len);
+               name[record_len] = '\0';
+               pos += record_len;
+               g_ptr_array_add(names, name);
+#ifdef MDB_DEBUG
+               printf("new len = %d\n", names->len);
+#endif
+       }
+       return names;
+}
+void
+mdb_free_props(MdbProperties *props)
+{
+       if (!props) return;
+
+       if (props->name) g_free(props->name);
+       g_free(props);
+}
+MdbProperties *
+mdb_alloc_props()
+{
+       MdbProperties *props;
+
+       props = g_malloc0(sizeof(MdbProperties));
+
+       return props;
+}
+MdbProperties * 
+mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
+{
+       guint32 record_len, name_len;
+       int pos = 0;
+       int elem, dtype, dsize;
+       gchar *name, *value;
+       MdbProperties *props;
+       int i = 0;
+
+#ifdef MDB_DEBUG
+       buffer_dump(kkd, 0, len - 1);
+#endif
+       pos = 0;
+
+       /* skip the name record */
+       record_len = mdb_get_int16(kkd, pos);
+       pos += 4;
+       name_len = mdb_get_int16(kkd, pos);
+       pos += 2;
+       props = mdb_alloc_props();
+       if (name_len) {
+               props->name = g_malloc(name_len + 1);
+               strncpy(props->name, &kkd[pos], name_len);
+               props->name[name_len]='\0';
+       }
+       pos += name_len;
+
+       props->hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+       while (pos < len) {
+               record_len = mdb_get_int16(kkd, pos);
+               elem = mdb_get_int16(kkd, pos + 4);
+               dtype = kkd[pos + 3];
+               dsize = mdb_get_int16(kkd, pos + 6);
+               value = g_malloc(dsize + 1);
+               strncpy(value, &kkd[pos + 8], dsize);
+               value[dsize] = '\0';
+               name = g_ptr_array_index(names,elem);
+#ifdef MDB_DEBUG
+               printf("%02d ",i++);
+               buffer_dump(kkd, pos, pos + record_len - 1);
+               printf("elem %d dsize %d dtype %d\n", elem, dsize, dtype);
+#endif
+               if (dtype == MDB_MEMO) dtype = MDB_TEXT;
+               if (dtype == MDB_BOOL) {
+                       g_hash_table_insert(props->hash, g_strdup(name), g_strdup(kkd[pos + 8] ? "yes" : "no"));
+               } else {
+                       g_hash_table_insert(props->hash, g_strdup(name), g_strdup(mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize)));
+               }
+               g_free(value);
+               pos += record_len;
+       }
+       return props;
+       
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/sargs.c b/navit/src/data/poi_geodownload/libmdb/sargs.c
new file mode 100644 (file)
index 0000000..b14aaa9
--- /dev/null
@@ -0,0 +1,273 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * code for handling searchable arguments (sargs) used primary by the sql 
+ * engine to support where clause handling.  The sargs are configured in 
+ * a tree with AND/OR operators connecting the child nodes. NOT operations
+ * have only one child on the left side.  Logical operators (=,<,>,etc..)
+ * have no children.
+ *
+ * datatype support is a bit weak at this point.  To add more types create
+ * a mdb_test_[type]() function and invoke it from mdb_test_sarg()
+ */
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+void
+mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data)
+{
+       if (func(node, data))
+               return;
+       if (node->left) mdb_sql_walk_tree(node->left, func, data);
+       if (node->right) mdb_sql_walk_tree(node->right, func, data);
+}
+int 
+mdb_test_string(MdbSargNode *node, char *s)
+{
+int rc;
+
+       if (node->op == MDB_LIKE) {
+               return mdb_like_cmp(s,node->value.s);
+       }
+       rc = strncmp(node->value.s, s, 255);
+       switch (node->op) {
+               case MDB_EQUAL:
+                       if (rc==0) return 1;
+                       break;
+               case MDB_GT:
+                       if (rc<0) return 1;
+                       break;
+               case MDB_LT:
+                       if (rc>0) return 1;
+                       break;
+               case MDB_GTEQ:
+                       if (rc<=0) return 1;
+                       break;
+               case MDB_LTEQ:
+                       if (rc>=0) return 1;
+                       break;
+               default:
+                       fprintf(stderr, "Calling mdb_test_sarg on unknown operator.  Add code to mdb_test_string() for operator %d\n",node->op);
+                       break;
+       }
+       return 0;
+}
+int mdb_test_int(MdbSargNode *node, gint32 i)
+{
+       switch (node->op) {
+               case MDB_EQUAL:
+                       printf("comparing %x and %x %d\n", i, node->value.i, node->value.i == i);
+                       if (node->value.i == i) return 1;
+                       break;
+               case MDB_GT:
+                       if (node->value.i < i) return 1;
+                       break;
+               case MDB_LT:
+                       if (node->value.i > i) return 1;
+                       break;
+               case MDB_GTEQ:
+                       if (node->value.i <= i) return 1;
+                       break;
+               case MDB_LTEQ:
+                       if (node->value.i >= i) return 1;
+                       break;
+               default:
+                       fprintf(stderr, "Calling mdb_test_sarg on unknown operator.  Add code to mdb_test_int() for operator %d\n",node->op);
+                       break;
+       }
+       return 0;
+}
+#if 0
+#endif
+int
+mdb_find_indexable_sargs(MdbSargNode *node, gpointer data)
+{
+       MdbSarg sarg;
+
+       if (node->op == MDB_OR || node->op == MDB_NOT) return 1;
+
+       /* 
+        * right now all we do is look for sargs that are anded together from
+        * the root.  Later we may put together OR ops into a range, and then 
+        * range scan the leaf pages. That is col1 = 2 or col1 = 4 becomes
+        * col1 >= 2 and col1 <= 4 for the purpose of index scans, and then
+        * extra rows are thrown out when the row is tested against the main
+        * sarg tree.  range scans are generally only a bit better than table
+        * scanning anyway.
+        *
+        * also, later we should support the NOT operator, but it's generally
+        * a pretty worthless test for indexes, ie NOT col1 = 3, we are 
+        * probably better off table scanning.
+        */
+       if (mdb_is_relational_op(node->op) && node->col) {
+               //printf("op = %d value = %s\n", node->op, node->value.s);
+               sarg.op = node->op;
+               sarg.value = node->value;
+               mdb_add_sarg(node->col, &sarg);
+       }
+       return 0;
+}
+int 
+mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field)
+{
+char tmpbuf[256];
+int lastchar;
+
+       if (node->op == MDB_ISNULL) {
+               if (field->is_null) return 0;
+               else return 1;
+       } else if (node->op == MDB_NOTNULL) {
+               if (field->is_null) return 1;
+               else return 0;
+       }
+       switch (col->col_type) {
+               case MDB_BOOL:
+                       return mdb_test_int(node, !field->is_null);
+                       break;
+               case MDB_BYTE:
+                       return mdb_test_int(node, (gint32)((char *)field->value)[0]);
+                       break;
+               case MDB_INT:
+                       return mdb_test_int(node, (gint32)mdb_get_int16(field->value, 0));
+                       break;
+               case MDB_LONGINT:
+                       return mdb_test_int(node, (gint32)mdb_get_int32(field->value, 0));
+                       break;
+               case MDB_TEXT:
+                       if (IS_JET4(mdb)) {
+                               mdb_unicode2ascii(mdb, field->value, 0, field->siz, tmpbuf);
+                       } else {
+                               strncpy(tmpbuf, field->value, 255);
+                               lastchar = field->siz > 255 ? 255 : field->siz;
+                               tmpbuf[lastchar]='\0';
+                       }
+                       return mdb_test_string(node, tmpbuf);
+               default:
+                       fprintf(stderr, "Calling mdb_test_sarg on unknown type.  Add code to mdb_test_sarg() for type %d\n",col->col_type);
+                       break;
+       }
+       return 1;
+}
+int
+mdb_find_field(int col_num, MdbField *fields, int num_fields)
+{
+       int i;
+
+       for (i=0;i<num_fields;i++) {
+               if (fields[i].colnum == col_num) return i;
+       }
+       return -1;
+}
+int
+mdb_test_sarg_node(MdbHandle *mdb, MdbSargNode *node, MdbField *fields, int num_fields)
+{
+       int elem;
+       MdbColumn *col;
+       int rc;
+
+       if (mdb_is_relational_op(node->op)) {
+               col = node->col;
+               /* for const = const expressions */
+               if (!col) {
+                       return (node->value.i);
+               }
+               elem = mdb_find_field(col->col_num, fields, num_fields);
+               if (!mdb_test_sarg(mdb, col, node, &fields[elem])) 
+                       return 0;
+       } else { /* logical op */
+               switch (node->op) {
+               case MDB_NOT:
+                       rc = mdb_test_sarg_node(mdb, node->left, fields, num_fields);
+                       return !rc;
+                       break;
+               case MDB_AND:
+                       if (!mdb_test_sarg_node(mdb, node->left, fields, num_fields))
+                               return 0;
+                       return mdb_test_sarg_node(mdb, node->right, fields, num_fields);
+                       break;
+               case MDB_OR:
+                       if (mdb_test_sarg_node(mdb, node->left, fields, num_fields))
+                               return 1;
+                       return mdb_test_sarg_node(mdb, node->right, fields, num_fields);
+                       break;
+               }
+       }
+       return 1;
+}
+int 
+mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields)
+{
+       MdbSargNode *node;
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+
+       node = table->sarg_tree;
+
+       /* there may not be a sarg tree */
+       if (!node) return 1;
+
+       return mdb_test_sarg_node(mdb, node, fields, num_fields);
+}
+#if 0
+int mdb_test_sargs(MdbHandle *mdb, MdbColumn *col, int offset, int len)
+{
+MdbSarg *sarg;
+int i;
+
+       for (i=0;i<col->num_sargs;i++) {
+               sarg = g_ptr_array_index (col->sargs, i);
+               if (!mdb_test_sarg(mdb, col, sarg, offset, len)) {
+                       /* sarg didn't match, no sense going on */
+                       return 0;       
+               }
+       }
+
+       return 1;
+}
+#endif
+int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg)
+{
+MdbSarg *sarg;
+        if (!col->sargs) {
+               col->sargs = g_ptr_array_new();
+       }
+       sarg = g_memdup(in_sarg,sizeof(MdbSarg));
+        g_ptr_array_add(col->sargs, sarg);
+       col->num_sargs++;
+
+       return 1;
+}
+int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg)
+{
+       MdbColumn *col;
+       unsigned int i;
+
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index (table->columns, i);
+               if (!strcasecmp(col->name,colname)) {
+                       return mdb_add_sarg(col, in_sarg);
+               }
+       }
+       /* else didn't find the column return 0! */
+       return 0;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/stats.c b/navit/src/data/poi_geodownload/libmdb/stats.c
new file mode 100644 (file)
index 0000000..1abf285
--- /dev/null
@@ -0,0 +1,74 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/**
+ * mdb_stats_on:
+ * @mdb: Handle to the (open) MDB file to collect stats on.
+ *
+ * Begins collection of statistics on an MDBHandle.
+ *
+ * Statistics in LibMDB will track the number of reads from the MDB file.  The
+ * collection of statistics is started and stopped with the mdb_stats_on and
+ * mdb_stats_off functions.  Collected statistics are accessed by reading the
+ * MdbStatistics structure or calling mdb_dump_stats.
+ * 
+ */
+void
+mdb_stats_on(MdbHandle *mdb)
+{
+       if (!mdb->stats) 
+               mdb->stats = g_malloc0(sizeof(MdbStatistics));
+
+       mdb->stats->collect = TRUE;
+}
+/**
+ * mdb_stats_off:
+ * @mdb: pointer to handle of MDB file with active stats collection.
+ *
+ * Turns off statistics collection.
+ *
+ * If mdb_stats_off is not called, statistics will be turned off when handle
+ * is freed using mdb_close.
+ **/
+void
+mdb_stats_off(MdbHandle *mdb)
+{
+       if (!mdb->stats) return;
+
+       mdb->stats->collect = FALSE;
+}
+/**
+ * mdb_dump_stats:
+ * @mdb: pointer to handle of MDB file with active stats collection.
+ *
+ * Dumps current statistics to stdout.
+ **/
+void
+mdb_dump_stats(MdbHandle *mdb)
+{
+       if (!mdb->stats) return;
+
+       fprintf(stdout, "Physical Page Reads: %lu\n", mdb->stats->pg_reads);
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/table.c b/navit/src/data/poi_geodownload/libmdb/table.c
new file mode 100644 (file)
index 0000000..d3afca8
--- /dev/null
@@ -0,0 +1,368 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+
+static gint mdb_col_comparer(MdbColumn **a, MdbColumn **b)
+{
+       if ((*a)->col_num > (*b)->col_num)
+               return 1;
+       else if ((*a)->col_num < (*b)->col_num)
+               return -1;
+       else
+               return 0;
+}
+
+unsigned char mdb_col_needs_size(int col_type)
+{
+       if (col_type == MDB_TEXT) {
+               return TRUE;
+       } else {
+               return FALSE;
+       }
+}
+
+MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry)
+{
+       MdbTableDef *table;
+
+       table = (MdbTableDef *) g_malloc0(sizeof(MdbTableDef));
+       table->entry=entry;
+       strcpy(table->name, entry->object_name);
+
+       return table;   
+}
+void mdb_free_tabledef(MdbTableDef *table)
+{
+       if (!table) return;
+       if (table->is_temp_table) {
+               unsigned int i;
+               for (i=0; i<table->temp_table_pages->len; i++)
+                       g_free(g_ptr_array_index(table->temp_table_pages,i));
+               g_ptr_array_free(table->temp_table_pages, TRUE);
+       }
+       mdb_free_columns(table->columns);
+       mdb_free_indices(table->indices);
+       g_free(table->usage_map);
+       g_free(table->free_usage_map);
+       g_free(table);
+}
+MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
+{
+       MdbTableDef *table;
+       MdbHandle *mdb = entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       int len, row_start, pg_row;
+       char *buf;
+
+       table = mdb_alloc_tabledef(entry);
+
+       mdb_read_pg(mdb, entry->table_pg);
+       if (mdb->pg_buf[0] != 0x02) return NULL; /* not a valid table def page */
+
+       len = mdb_pg_get_int16(mdb,8);
+
+       table->num_rows = mdb_pg_get_int32(mdb, fmt->tab_num_rows_offset);
+       table->num_var_cols = mdb_pg_get_int16(mdb, fmt->tab_num_cols_offset-2);
+       table->num_cols = mdb_pg_get_int16(mdb, fmt->tab_num_cols_offset);
+       table->num_idxs = mdb_pg_get_int32(mdb, fmt->tab_num_idxs_offset); 
+       table->num_real_idxs = mdb_pg_get_int32(mdb, fmt->tab_num_ridxs_offset); 
+       /* grab a copy of the usage map */
+       pg_row = mdb_pg_get_int32(mdb, fmt->tab_usage_map_offset);
+       mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->map_sz));
+       table->usage_map = g_memdup(buf + row_start, table->map_sz);
+       if (mdb_get_option(MDB_DEBUG_USAGE)) 
+               buffer_dump(buf, row_start, row_start+table->map_sz-1);
+       mdb_debug(MDB_DEBUG_USAGE,"usage map found on page %ld row %d start %d len %d",
+               pg_row >> 8, pg_row & 0xff, row_start, table->map_sz);
+
+       /* grab a copy of the free space page map */
+       pg_row = mdb_pg_get_int32(mdb, fmt->tab_free_map_offset);
+       mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->freemap_sz));
+       table->free_usage_map = g_memdup(buf + row_start, table->freemap_sz);
+       mdb_debug(MDB_DEBUG_USAGE,"free map found on page %ld row %d start %d len %d\n",
+               pg_row >> 8, pg_row & 0xff, row_start, table->freemap_sz);
+
+       table->first_data_pg = mdb_pg_get_int16(mdb, fmt->tab_first_dpg_offset);
+
+       return table;
+}
+MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type)
+{
+       unsigned int i;
+       MdbCatalogEntry *entry;
+
+       mdb_read_catalog(mdb, obj_type);
+
+       for (i=0; i<mdb->num_catalog; i++) {
+               entry = g_ptr_array_index(mdb->catalog, i);
+               if (!strcasecmp(entry->object_name, table_name))
+                       return mdb_read_table(entry);
+       }
+
+       return NULL;
+}
+
+/*
+** read the next page if offset is > pg_size
+** return true if page was read
+*/ 
+int 
+read_pg_if(MdbHandle *mdb, int *cur_pos, int offset)
+{
+       if (*cur_pos + offset >= mdb->fmt->pg_size) {
+               mdb_read_pg(mdb, mdb_pg_get_int32(mdb,4));
+               *cur_pos = 8 - (mdb->fmt->pg_size - (*cur_pos));
+               return 1;
+       }
+       return 0;
+}
+guint32 
+read_pg_if_32(MdbHandle *mdb, int *cur_pos)
+{
+       unsigned char c[4];
+       int i, rc = 0;
+
+       for (i=0;i<4;i++) {
+               rc += read_pg_if(mdb, cur_pos, i);
+               c[i] = mdb->pg_buf[(*cur_pos) + i];
+       }
+       return mdb_get_int32(c, 0);
+}
+guint16 
+read_pg_if_16(MdbHandle *mdb, int *cur_pos)
+{
+       unsigned char low_byte, high_byte;
+       int rc = 0;
+
+       rc += read_pg_if(mdb, cur_pos, 0);
+       low_byte = mdb->pg_buf[*cur_pos];
+       rc += read_pg_if(mdb, cur_pos, 1);
+       high_byte = mdb->pg_buf[(*cur_pos) + 1];
+
+       return (high_byte * 256 + low_byte);
+}
+guint16 
+read_pg_if_n(MdbHandle *mdb, unsigned char *buf, int *cur_pos, int len)
+{
+       if (*cur_pos + len < mdb->fmt->pg_size) {
+               memcpy(buf, &mdb->pg_buf[*cur_pos], len);
+               return 0;
+       } else {
+               int half = mdb->fmt->pg_size - *cur_pos;
+               memcpy(buf, &mdb->pg_buf[*cur_pos], half);
+               mdb_read_pg(mdb, mdb_pg_get_int32(mdb,4));
+               memcpy(buf + half, &mdb->pg_buf[8], len - half);
+               *cur_pos = 8 - half;
+               return 1;
+       }
+}
+
+void mdb_append_column(GPtrArray *columns, MdbColumn *in_col)
+{
+       g_ptr_array_add(columns, g_memdup(in_col,sizeof(MdbColumn)));
+}
+void mdb_free_columns(GPtrArray *columns)
+{
+       unsigned int i;
+
+       if (!columns) return;
+       for (i=0; i<columns->len; i++)
+               g_free (g_ptr_array_index(columns, i));
+       g_ptr_array_free(columns, TRUE);
+}
+GPtrArray *mdb_read_columns(MdbTableDef *table)
+{
+       MdbHandle *mdb = table->entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       MdbColumn *pcol;
+       unsigned char *col;
+       unsigned int i;
+       int cur_pos, name_sz;
+       
+       table->columns = g_ptr_array_new();
+
+       col = (unsigned char *) g_malloc(fmt->tab_col_entry_size);
+
+       cur_pos = fmt->tab_cols_start_offset + 
+               (table->num_real_idxs * fmt->tab_ridx_entry_size);
+
+       /* new code based on patch submitted by Tim Nelson 2000.09.27 */
+
+       /* 
+       ** column attributes 
+       */
+       for (i=0;i<table->num_cols;i++) {
+#ifdef MDB_DEBUG
+       /* printf("column %d\n", i);
+       buffer_dump(mdb->pg_buf, cur_pos ,cur_pos + 18); */
+#endif
+               read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size);
+               cur_pos += fmt->tab_col_entry_size;
+               pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn));
+
+               pcol->col_type = col[0];
+
+               // col_num_offset == 1 or 5
+               pcol->col_num = col[fmt->col_num_offset];
+
+               //fprintf(stdout,"----- column %d -----\n",pcol->col_num);
+               // col_var == 3 or 7
+               pcol->var_col_num = mdb_get_int16(col, fmt->tab_col_offset_var);
+               //fprintf(stdout,"var column pos %d\n",pcol->var_col_num);
+
+               // col_var == 5 or 9
+               pcol->row_col_num = mdb_get_int16(col, fmt->tab_row_col_num_offset);
+               //fprintf(stdout,"row column num %d\n",pcol->row_col_num);
+
+               /* FIXME: can this be right in Jet3 and Jet4? */
+               if (pcol->col_type == MDB_NUMERIC) {
+                       pcol->col_prec = col[11];
+                       pcol->col_scale = col[12];
+               }
+
+               // col_fixed_offset == 13 or 15
+               pcol->is_fixed = col[fmt->col_fixed_offset] & 0x01 ? 1 : 0;
+
+               // col_fixed_offset == 13 or 15
+               pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed);
+               //fprintf(stdout,"fixed column offset %d\n",pcol->fixed_offset);
+               //fprintf(stdout,"col type %s\n",pcol->is_fixed ? "fixed" : "variable");
+
+               if (pcol->col_type != MDB_BOOL) {
+                       // col_size_offset == 16 or 23
+                       pcol->col_size = mdb_get_int16(col, fmt->col_size_offset);
+               } else {
+                       pcol->col_size=0;
+               }
+               
+               g_ptr_array_add(table->columns, pcol);
+       }
+
+       g_free (col);
+
+       /* 
+       ** column names - ordered the same as the column attributes table
+       */
+       for (i=0;i<table->num_cols;i++) {
+               pcol = g_ptr_array_index(table->columns, i);
+
+               if (IS_JET4(mdb)) {
+                       char *tmp_buf;
+                       name_sz = read_pg_if_16(mdb, &cur_pos);
+                       cur_pos += 2;
+                       tmp_buf = (char *) g_malloc(name_sz);
+                       read_pg_if_n(mdb, tmp_buf, &cur_pos, name_sz);
+                       mdb_unicode2ascii(mdb, tmp_buf, 0, name_sz, pcol->name);
+                       g_free(tmp_buf);
+                       cur_pos += name_sz;
+               } else if (IS_JET3(mdb)) {
+                       read_pg_if(mdb, &cur_pos, 0);
+                       name_sz = mdb->pg_buf[cur_pos];
+                       cur_pos++;
+                       read_pg_if_n(mdb, pcol->name, &cur_pos, name_sz);
+                       pcol->name[name_sz]='\0';
+                       cur_pos += name_sz;
+               } else {
+                       fprintf(stderr,"Unknown MDB version\n");
+               }
+       }
+
+       /* Sort the columns by col_num */
+       g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer);
+
+       table->index_start = cur_pos;
+       return table->columns;
+}
+
+void mdb_table_dump(MdbCatalogEntry *entry)
+{
+MdbTableDef *table;
+MdbColumn *col;
+int coln;
+MdbIndex *idx;
+MdbHandle *mdb = entry->mdb;
+unsigned int i, bitn;
+guint32 pgnum;
+
+       table = mdb_read_table(entry);
+       fprintf(stdout,"definition page     = %lu\n",entry->table_pg);
+       fprintf(stdout,"number of datarows  = %d\n",table->num_rows);
+       fprintf(stdout,"number of columns   = %d\n",table->num_cols);
+       fprintf(stdout,"number of indices   = %d\n",table->num_real_idxs);
+
+       mdb_read_columns(table);
+       mdb_read_indices(table);
+
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index(table->columns,i);
+       
+               fprintf(stdout,"column %d Name: %-20s Type: %s(%d)\n",
+                       i, col->name,
+                       mdb_get_coltype_string(mdb->default_backend, col->col_type),
+                       col->col_size);
+       }
+
+       for (i=0;i<table->num_idxs;i++) {
+               idx = g_ptr_array_index (table->indices, i);
+               mdb_index_dump(table, idx);
+       }
+       if (table->usage_map) {
+               printf("pages reserved by this object\n");
+               printf("usage map pg %" G_GUINT32_FORMAT "\n",
+                       table->map_base_pg);
+               printf("free map pg %" G_GUINT32_FORMAT "\n",
+                       table->freemap_base_pg);
+               pgnum = mdb_get_int32(table->usage_map,1);
+               /* the first 5 bytes of the usage map mean something */
+               coln = 0;
+               for (i=5;i<table->map_sz;i++) {
+                       for (bitn=0;bitn<8;bitn++) {
+                               if (table->usage_map[i] & 1 << bitn) {
+                                       coln++;
+                                       printf("%6" G_GUINT32_FORMAT, pgnum);
+                                       if (coln==10) {
+                                               printf("\n");
+                                               coln = 0;
+                                       } else {
+                                               printf(" ");
+                                       }
+                               }
+                               pgnum++;
+                       }
+               }
+               printf("\n");
+       }
+}
+
+int mdb_is_user_table(MdbCatalogEntry *entry)
+{
+       return ((entry->object_type == MDB_TABLE)
+        && !(entry->flags & 0x80000002)) ? 1 : 0;
+}
+int mdb_is_system_table(MdbCatalogEntry *entry)
+{
+       return ((entry->object_type == MDB_TABLE)
+        && (entry->flags & 0x80000002)) ? 1 : 0;
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/worktable.c b/navit/src/data/poi_geodownload/libmdb/worktable.c
new file mode 100644 (file)
index 0000000..6f893dc
--- /dev/null
@@ -0,0 +1,99 @@
+/* MDB Tools - A library for reading MS Access database files
+ * Copyright (C) 2004 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+/*
+ * Temp table routines.  These are currently used to generate mock results for
+ * commands like "list tables" and "describe table"
+ */
+
+void
+mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed)
+{
+       memset(tcol,0,sizeof(MdbColumn));
+       strcpy(tcol->name, col_name);
+       tcol->col_type = col_type;
+       if ((col_type == MDB_TEXT) || (col_type == MDB_MEMO)) {
+               tcol->col_size = col_size;
+       } else {
+               tcol->col_size = mdb_col_fixed_size(tcol);
+       }
+       tcol->is_fixed = is_fixed;
+}
+void
+mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int colnum)
+{
+       field->value = value;
+       field->siz = siz;
+       field->is_fixed = is_fixed;
+       field->is_null = is_null;
+       field->start = start;
+       field->colnum = colnum;
+}
+MdbTableDef *
+mdb_create_temp_table(MdbHandle *mdb, char *name)
+{
+       MdbCatalogEntry *entry;
+       MdbTableDef *table;
+
+       /* dummy up a catalog entry */
+       entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry));
+       entry->mdb = mdb;
+       entry->object_type = MDB_TABLE;
+       entry->table_pg = 0;
+       strcpy(entry->object_name, name);
+
+       table = mdb_alloc_tabledef(entry);
+       table->columns = g_ptr_array_new();
+       table->is_temp_table = 1;
+       table->temp_table_pages = g_ptr_array_new();
+
+       return table;
+}
+void
+mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col)
+{
+       col->col_num = table->num_cols;
+       if (!col->is_fixed)
+               col->var_col_num = table->num_var_cols++;
+       g_ptr_array_add(table->columns, g_memdup(col, sizeof(MdbColumn)));
+       table->num_cols++;
+}
+/*
+ * Should be called after setting up all temp table columns
+ */
+void mdb_temp_columns_end(MdbTableDef *table)
+{
+       MdbColumn *col;
+       unsigned int i;
+       unsigned int start = 0;
+
+       for (i=0; i<table->num_cols; i++) {
+               col = g_ptr_array_index(table->columns, i);
+               if (col->is_fixed) {
+                       col->fixed_offset = start;
+                       start += col->col_size;
+               }
+       }
+}
diff --git a/navit/src/data/poi_geodownload/libmdb/write.c b/navit/src/data/poi_geodownload/libmdb/write.c
new file mode 100644 (file)
index 0000000..1cff96a
--- /dev/null
@@ -0,0 +1,878 @@
+/* MDB Tools - A library for reading MS Access database file
+ * Copyright (C) 2000 Brian Bruns
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "mdbtools.h"
+#include "time.h"
+#include "math.h"
+
+#ifdef DMALLOC
+#include "dmalloc.h"
+#endif
+
+
+//static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg);
+static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields);
+
+void
+_mdb_put_int16(unsigned char *buf, guint32 offset, guint32 value)
+{
+       buf[offset] = value % 256;
+       value /= 256;
+       buf[offset+1] = value % 256;
+}
+void
+_mdb_put_int32(unsigned char *buf, guint32 offset, guint32 value)
+{
+       buf[offset] = value % 256;
+       value /= 256;
+       buf[offset+1] = value % 256;
+       value /= 256;
+       buf[offset+2] = value % 256;
+       value /= 256;
+       buf[offset+3] = value % 256;
+}
+ssize_t
+mdb_write_pg(MdbHandle *mdb, unsigned long pg)
+{
+       ssize_t len;
+       struct stat status;
+       off_t offset = pg * mdb->fmt->pg_size;
+
+       fstat(mdb->f->fd, &status);
+       /* is page beyond current size + 1 ? */
+       if (status.st_size < offset + mdb->fmt->pg_size) {
+               fprintf(stderr,"offset %lu is beyond EOF\n",offset);
+               return 0;
+       }
+       lseek(mdb->f->fd, offset, SEEK_SET);
+       len = write(mdb->f->fd,mdb->pg_buf,mdb->fmt->pg_size);
+       if (len==-1) {
+               perror("write");
+               return 0;
+       } else if (len<mdb->fmt->pg_size) {
+       /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->pg_size); */
+               return 0;
+       }
+       mdb->cur_pos = 0;
+       return len;
+}
+
+static int 
+mdb_is_col_indexed(MdbTableDef *table, int colnum)
+{
+       unsigned int i, j;
+       MdbIndex *idx;
+
+       for (i=0;i<table->num_idxs;i++) {
+               idx = g_ptr_array_index (table->indices, i);
+               for (j=0;j<idx->num_keys;j++) {
+                       if (idx->key_col_num[j]==colnum) return 1;
+               }
+       }
+       return 0;
+}
+static int
+mdb_crack_row4(MdbTableDef *table, int row_start, int row_end, MdbField *fields)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbColumn *col;
+       unsigned char *pg_buf = mdb->pg_buf;
+       unsigned int i;
+       unsigned int row_var_cols=0, row_fixed_cols, row_cols;
+       unsigned int fixed_cols_found;
+       unsigned int col_start;
+       unsigned char *nullmask;
+       unsigned int bitmask_sz;
+       unsigned int byte_num, bit_num;
+       unsigned int *var_col_offsets = NULL;
+
+       if (mdb_get_option(MDB_DEBUG_ROW)) {
+               buffer_dump(pg_buf, row_start, row_end);
+       }
+
+       row_cols = mdb_pg_get_int16(mdb, row_start);
+
+       bitmask_sz = (row_cols + 7) / 8;
+       nullmask = &pg_buf[row_end - bitmask_sz + 1];
+
+       /* read table of variable column locations */
+       if (table->num_var_cols > 0) {
+               row_var_cols = mdb_pg_get_int16(mdb, row_end - bitmask_sz - 1);
+               var_col_offsets = (int *)g_malloc((row_var_cols+1)*sizeof(int));
+               for (i=0; i<row_var_cols+1; i++) {
+                       var_col_offsets[i] = mdb_pg_get_int16(mdb,
+                               row_end - bitmask_sz - 3 - (i*2));
+               }
+       }
+       fixed_cols_found = 0;
+       row_fixed_cols = row_cols - row_var_cols;
+
+       /* read information into fields[] */
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index(table->columns,i);
+               fields[i].colnum = i;
+               fields[i].is_fixed = (mdb_is_fixed_col(col)) ? 1 : 0;
+               byte_num = col->col_num / 8;
+               bit_num = col->col_num % 8;
+               /* logic on nulls is reverse, 1 is not null, 0 is null */
+               fields[i].is_null = nullmask[byte_num] & (1 << bit_num) ? 0 : 1;
+
+               if ((fields[i].is_fixed)
+                && (fixed_cols_found < row_fixed_cols)) {
+                       col_start = col->fixed_offset + 2;
+                       fields[i].start = row_start + col_start;
+                       fields[i].value = &pg_buf[row_start + col_start];
+                       fields[i].siz = col->col_size;
+                       fixed_cols_found++;
+               /* Use col->var_col_num because a deleted column is still
+                * present in the variable column offsets table for the row */
+               } else if ((!fields[i].is_fixed)
+                && (col->var_col_num < row_var_cols)) {
+                       col_start = var_col_offsets[col->var_col_num];
+                       fields[i].start = row_start + col_start;
+                       fields[i].value = &pg_buf[row_start + col_start];
+                       fields[i].siz = var_col_offsets[(col->var_col_num)+1] -
+                               col_start;
+               } else {
+                       fields[i].start = 0;
+                       fields[i].value = NULL;
+                       fields[i].siz = 0;
+                       fields[i].is_null = 1;
+               }
+       }
+       g_free(var_col_offsets);
+
+       return row_cols;
+}
+static int
+mdb_crack_row3(MdbTableDef *table, int row_start, int row_end, MdbField *fields)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbColumn *col;
+       unsigned char *pg_buf = mdb->pg_buf;
+       unsigned int i;
+       unsigned int row_var_cols = 0, row_fixed_cols, row_cols;
+       unsigned int fixed_cols_found, var_cols_found;
+       unsigned int col_start;
+       unsigned char *nullmask;
+       unsigned int bitmask_sz;
+       unsigned int byte_num, bit_num;
+       unsigned int *var_col_offsets = NULL;
+       unsigned int num_jumps = 0, jumps_used = 0;
+       unsigned int col_ptr, row_len;
+
+       if (mdb_get_option(MDB_DEBUG_ROW)) {
+               buffer_dump(pg_buf, row_start, row_end);
+       }
+
+       row_cols = pg_buf[row_start];
+
+       bitmask_sz = (row_cols + 7) / 8;
+       nullmask = &pg_buf[row_end - bitmask_sz + 1];
+
+       /* read table of variable column locations */
+       if (table->num_var_cols > 0) {
+               row_var_cols = pg_buf[row_end - bitmask_sz];
+               row_len = row_end - row_start + 1;
+               num_jumps = (row_len - 1) / 256;
+               col_ptr = row_end - bitmask_sz - num_jumps - 1;
+               /* If last jump is a dummy value, ignore it */
+               if ((col_ptr-row_start-row_var_cols)/256 < num_jumps)
+                       num_jumps--;
+
+               var_col_offsets = (int *)g_malloc((row_var_cols+1)*sizeof(int));
+               jumps_used = 0;
+               for (i=0; i<row_var_cols+1; i++) {
+                       if ((jumps_used < num_jumps)
+                        && (i == pg_buf[row_end-bitmask_sz-jumps_used-1])) {
+                               jumps_used++;
+                       }
+                       var_col_offsets[i] = pg_buf[col_ptr-i]+(jumps_used*256);
+               }
+       }
+       fixed_cols_found = 0;
+       var_cols_found = 0;
+       row_fixed_cols = row_cols - row_var_cols;
+
+       if (mdb_get_option(MDB_DEBUG_ROW)) {
+               fprintf(stdout,"bitmask_sz %d num_jumps %d\n",bitmask_sz, num_jumps);
+               fprintf(stdout,"row_var_cols %d\n", row_var_cols);
+               fprintf(stdout,"row_fixed_cols %d\n", row_fixed_cols);
+       }
+
+       /* read information into fields[] */
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index (table->columns, i);
+               fields[i].colnum = i;
+               fields[i].is_fixed = (mdb_is_fixed_col(col)) ? 1 : 0;
+               byte_num = col->col_num / 8;
+               bit_num = col->col_num % 8;
+               /* logic on nulls is reverse, 1 is not null, 0 is null */
+               fields[i].is_null = nullmask[byte_num] & (1 << bit_num) ? 0 : 1;
+
+               if ((fields[i].is_fixed)
+                && (fixed_cols_found < row_fixed_cols)) {
+                       col_start = col->fixed_offset + 1;
+                       fields[i].start = row_start + col_start;
+                       fields[i].value = &pg_buf[row_start + col_start];
+                       fields[i].siz = col->col_size;
+                       fixed_cols_found++;
+               } else if ((!fields[i].is_fixed)
+                  && (var_cols_found < row_var_cols)) {
+                       col_start = var_col_offsets[var_cols_found];
+                       fields[i].start = row_start + col_start;
+                       fields[i].value = &pg_buf[row_start + col_start];
+                       fields[i].siz = var_col_offsets[var_cols_found+1] -
+                               col_start;
+                       var_cols_found++;
+               } else {
+                       fields[i].start = 0;
+                       fields[i].value = NULL;
+                       fields[i].siz = 0;
+                       fields[i].is_null = 1;
+               }
+       }
+       g_free(var_col_offsets);
+
+       return row_cols;
+}
+/**
+ * mdb_crack_row:
+ * @table: Table that the row belongs to
+ * @row_start: offset to start of row on current page
+ * @row_end: offset to end of row on current page
+ * @fields: pointer to MdbField array to be popluated by mdb_crack_row
+ *
+ * Cracks a row buffer apart into its component fields.  
+ * 
+ * A row buffer is that portion of a data page which contains the values for
+ * that row.  Its beginning and end can be found in the row offset table.
+ *
+ * The resulting MdbField array contains pointers into the row for each field 
+ * present.  Be aware that by modifying field[]->value, you would be modifying 
+ * the row buffer itself, not a copy.
+ *
+ * This routine is mostly used internally by mdb_fetch_row() but may have some
+ * applicability for advanced application programs.
+ *
+ * Return value: number of fields present.
+ */
+int
+mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields)
+{
+MdbCatalogEntry *entry = table->entry;
+MdbHandle *mdb = entry->mdb;
+
+       if (IS_JET4(mdb)) {
+               return mdb_crack_row4(table, row_start, row_end, fields);
+       } else {
+               return mdb_crack_row3(table, row_start, row_end, fields);
+       }
+}
+
+static int
+mdb_pack_null_mask(unsigned char *buffer, int num_fields, MdbField *fields)
+{
+       int pos = 0, bit = 0, byte = 0;
+       int i;
+
+       /* 'Not null' bitmap */
+       for (i=0; i<num_fields; i++) {
+               /* column is null if bit is clear (0) */
+               if (!fields[i].is_null) {
+                       byte |= 1 << bit;
+                       //printf("%d %d %d %d\n", i, bit, 1 << bit, byte);
+               }
+               bit++;
+               if (bit==8) {
+                       buffer[pos++] = byte;
+                       bit = byte = 0;
+               }
+       }
+       /* if we've written any bits to the current byte, flush it */
+       if (bit)
+               buffer[pos++] = byte;
+       
+       return pos;
+}
+/* fields must be ordered with fixed columns first, then vars, subsorted by 
+ * column number */
+static int
+mdb_pack_row4(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields)
+{
+       unsigned int pos = 0;
+       unsigned int var_cols = 0;
+       unsigned int i;
+
+       row_buffer[pos++] = num_fields & 0xff;
+       row_buffer[pos++] = (num_fields >> 8) & 0xff; 
+
+       /* Fixed length columns */
+       for (i=0;i<num_fields;i++) {
+               if (fields[i].is_fixed) {
+                       fields[i].offset = pos;
+                       if (!fields[i].is_null) {
+                               memcpy(&row_buffer[pos], fields[i].value, fields[i].siz);
+                       }
+                       pos += fields[i].siz;
+               }
+       }
+       /* For tables without variable-length columns */
+       if (table->num_var_cols == 0) {
+               pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields);
+               return pos;
+       }
+       /* Variable length columns */
+       for (i=0;i<num_fields;i++) {
+               if (!fields[i].is_fixed) {
+                       var_cols++;
+                       fields[i].offset = pos;
+                       if (! fields[i].is_null) {
+                               memcpy(&row_buffer[pos], fields[i].value, fields[i].siz);
+                               pos += fields[i].siz;
+                       }
+               }
+       }
+       /* EOD */
+       row_buffer[pos] = pos & 0xff;
+       row_buffer[pos+1] = (pos >> 8) & 0xff;
+       pos += 2;
+
+       /* Offsets of the variable-length columns */
+       for (i=num_fields; i>0; i--) {
+               if (!fields[i-1].is_fixed) {
+                       row_buffer[pos++] = fields[i-1].offset & 0xff;
+                       row_buffer[pos++] = (fields[i-1].offset >> 8) & 0xff;
+               }
+       }
+       /* Number of variable-length columns */
+       row_buffer[pos++] = var_cols & 0xff;
+       row_buffer[pos++] = (var_cols >> 8) & 0xff;
+
+       pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields);
+       return pos;
+}
+
+static int
+mdb_pack_row3(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields)
+{
+       unsigned int pos = 0;
+       unsigned int var_cols = 0;
+       unsigned int i, j;
+       unsigned char *offset_high;
+
+       row_buffer[pos++] = num_fields;
+
+       /* Fixed length columns */
+       for (i=0;i<num_fields;i++) {
+               if (fields[i].is_fixed) {
+                       fields[i].offset = pos;
+                       if (!fields[i].is_null) {
+                               memcpy(&row_buffer[pos], fields[i].value, fields[i].siz);
+                       }
+                       pos += fields[i].siz;
+               }
+       }
+       /* For tables without variable-length columns */
+       if (table->num_var_cols == 0) {
+               pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields);
+               return pos;
+       }
+       /* Variable length columns */
+       for (i=0;i<num_fields;i++) {
+               if (!fields[i].is_fixed) {
+                       var_cols++;
+                       fields[i].offset = pos;
+                       if (! fields[i].is_null) {
+                               memcpy(&row_buffer[pos], fields[i].value, fields[i].siz);
+                               pos += fields[i].siz;
+                       }
+               }
+       }
+
+       offset_high = (unsigned char *) g_malloc(var_cols+1);
+       offset_high[0] = (pos << 8) & 0xff;
+       j = 1;
+       
+       /* EOD */
+       row_buffer[pos] = pos & 0xff;
+       pos++;
+
+       /* Variable length column offsets */
+       for (i=num_fields; i>0; i--) {
+               if (!fields[i-1].is_fixed) {
+                       row_buffer[pos++] = fields[i-1].offset & 0xff;
+                       offset_high[j++] = (fields[i-1].offset << 8) & 0xff;
+               }
+       }
+
+       /* Dummy jump table entry */
+       if (offset_high[0] < (pos+(num_fields+7)/8-1)/255) {
+               row_buffer[pos++] = 0xff;
+       }
+       /* Jump table */
+       for (i=0; i<var_cols; i++) {
+               if (offset_high[i] > offset_high[i+1]) {
+                       row_buffer[pos++] = var_cols-i;
+               }
+       }
+       g_free(offset_high);
+
+       row_buffer[pos++] = var_cols;
+
+       pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields);
+       return pos;
+}
+int
+mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, int unsigned num_fields, MdbField *fields)
+{
+       if (table->is_temp_table) {
+               unsigned int i;
+               for (i=0; i<num_fields; i++) {
+                       MdbColumn *c = g_ptr_array_index(table->columns, i);
+                       fields[i].is_null = (fields[i].value) ? 0 : 1;
+                       fields[i].colnum = i;
+                       fields[i].is_fixed = c->is_fixed;
+                       if ((c->col_type != MDB_TEXT)
+                        && (c->col_type != MDB_MEMO)) {
+                               fields[i].siz = c->col_size;
+                       }
+               }
+       }
+       if (IS_JET4(table->entry->mdb)) {
+               return mdb_pack_row4(table, row_buffer, num_fields, fields);
+       } else {
+               return mdb_pack_row3(table, row_buffer, num_fields, fields);
+       }
+}
+int
+mdb_pg_get_freespace(MdbHandle *mdb)
+{
+       int rows, free_start, free_end;
+       int row_count_offset = mdb->fmt->row_count_offset;
+
+       rows = mdb_pg_get_int16(mdb, row_count_offset);
+       free_start = row_count_offset + 2 + (rows * 2);
+        free_end = mdb_pg_get_int16(mdb, row_count_offset + (rows * 2));
+       mdb_debug(MDB_DEBUG_WRITE,"free space left on page = %d", free_end - free_start);
+       return (free_end - free_start);
+}
+unsigned char *
+mdb_new_leaf_pg(MdbCatalogEntry *entry)
+{
+       MdbHandle *mdb = entry->mdb;
+       unsigned char *new_pg;
+
+       new_pg = (unsigned char *) g_malloc0(mdb->fmt->pg_size);
+               
+       new_pg[0]=0x04;
+       new_pg[1]=0x01;
+       _mdb_put_int32(new_pg, 4, entry->table_pg);
+       
+       return new_pg;
+}
+unsigned char *
+mdb_new_data_pg(MdbCatalogEntry *entry)
+{
+       MdbFormatConstants *fmt = entry->mdb->fmt;
+       unsigned char *new_pg;
+
+       new_pg = (unsigned char *) g_malloc0(fmt->pg_size);
+               
+       new_pg[0]=0x01;
+       new_pg[1]=0x01;
+       _mdb_put_int16(new_pg, 2, fmt->pg_size - fmt->row_count_offset - 2);
+       _mdb_put_int32(new_pg, 4, entry->table_pg);
+       
+       return new_pg;
+}
+
+int
+mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum)
+{
+       unsigned int i;
+       MdbIndex *idx;
+       
+       for (i=0;i<table->num_idxs;i++) {
+               idx = g_ptr_array_index (table->indices, i);
+               mdb_debug(MDB_DEBUG_WRITE,"Updating %s (%d).", idx->name, idx->index_type);
+               if (idx->index_type==1) {
+                       mdb_update_index(table, idx, num_fields, fields, pgnum, rownum);
+               }
+       }
+       return 1;
+}
+
+int
+mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+
+       table->scan_idx = idx;
+       table->chain = g_malloc0(sizeof(MdbIndexChain));
+       table->mdbidx = mdb_clone_handle(mdb);
+       mdb_read_pg(table->mdbidx, table->scan_idx->first_pg);
+
+       return 1;
+}
+
+int
+mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum)
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       int idx_xref[16];
+       unsigned int i, j;
+       MdbIndexChain *chain;
+       MdbField idx_fields[10];
+
+       for (i = 0; i < idx->num_keys; i++) {
+               for (j = 0; j < num_fields; j++) {
+                       // key_col_num is 1 based, can't remember why though
+                       if (fields[j].colnum == idx->key_col_num[i]-1) {
+                               idx_xref[i] = j;
+                               idx_fields[i] = fields[j];
+                       }
+               }
+       }
+       for (i = 0; i < idx->num_keys; i++) {
+               fprintf(stdout, "key col %d (%d) is mapped to field %d (%d %d)\n",
+                       i, idx->key_col_num[i], idx_xref[i], fields[idx_xref[i]].colnum, 
+                       fields[idx_xref[i]].siz);
+       }
+       for (i = 0; i < num_fields; i++) {
+               fprintf(stdout, "%d (%d %d)\n",
+                       i, fields[i].colnum, 
+                       fields[i].siz);
+       }
+
+       chain = g_malloc0(sizeof(MdbIndexChain));
+
+       mdb_index_find_row(mdb, idx, chain, pgnum, rownum);
+       printf("chain depth = %d\n", chain->cur_depth);
+       printf("pg = %" G_GUINT32_FORMAT "\n",
+               chain->pages[chain->cur_depth-1].pg);
+       //mdb_copy_index_pg(table, idx, &chain->pages[chain->cur_depth-1]);
+       mdb_add_row_to_leaf_pg(table, idx, &chain->pages[chain->cur_depth-1], idx_fields);
+       
+       return 1;
+}
+
+int
+mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields)
+{
+       int new_row_size;
+       unsigned char row_buffer[4096];
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+       guint32 pgnum;
+       guint16 rownum;
+
+       if (!mdb->f->writable) {
+               fprintf(stderr, "File is not open for writing\n");
+               return 0;
+       }
+       new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields);
+       if (mdb_get_option(MDB_DEBUG_WRITE)) {
+               buffer_dump(row_buffer, 0, new_row_size-1);
+       }
+       pgnum = mdb_map_find_next_freepage(table, new_row_size);
+       if (!pgnum) {
+               fprintf(stderr, "Unable to allocate new page.\n");
+               return 0;
+       }
+
+       rownum = mdb_add_row_to_pg(table, row_buffer, new_row_size);
+
+       if (mdb_get_option(MDB_DEBUG_WRITE)) {
+               buffer_dump(mdb->pg_buf, 0, 39);
+               buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1);
+       }
+       mdb_debug(MDB_DEBUG_WRITE, "writing page %d", pgnum);
+       if (!mdb_write_pg(mdb, pgnum)) {
+               fprintf(stderr, "write failed! exiting...\n");
+               exit(1);
+       }
+
+       mdb_update_indexes(table, num_fields, fields, pgnum, rownum);
+       return 1;
+}
+/*
+ * Assumes caller has verfied space is available on page and adds the new 
+ * row to the current pg_buf.
+ */
+guint16
+mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size)
+{
+       unsigned char *new_pg;
+       int num_rows, i, pos, row_start, row_end, row_size;
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbFormatConstants *fmt = mdb->fmt;
+
+       if (table->is_temp_table) {
+               GPtrArray *pages = table->temp_table_pages;
+               if (pages->len == 0) {
+                       new_pg = mdb_new_data_pg(entry);
+                       g_ptr_array_add(pages, new_pg);
+               } else {
+                       new_pg = g_ptr_array_index(pages, pages->len - 1);
+                       if (mdb_get_int16(new_pg, 2) < new_row_size + 2) {
+                               new_pg = mdb_new_data_pg(entry);
+                               g_ptr_array_add(pages, new_pg);
+                       }
+               }
+
+               num_rows = mdb_get_int16(new_pg, fmt->row_count_offset);
+               pos = (num_rows == 0) ? fmt->pg_size :
+                       mdb_get_int16(new_pg, fmt->row_count_offset + (num_rows*2));
+       } else {  /* is not a temp table */
+               new_pg = mdb_new_data_pg(entry);
+
+               num_rows = mdb_pg_get_int16(mdb, fmt->row_count_offset);
+               pos = fmt->pg_size;
+
+               /* copy existing rows */
+               for (i=0;i<num_rows;i++) {
+                       row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2));
+                       row_end = mdb_find_end_of_row(mdb, i);
+                       row_size = row_end - row_start + 1;
+                       pos -= row_size;
+                       memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size);
+                       _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos);
+               }
+       }
+
+       /* add our new row */
+       pos -= new_row_size;
+       memcpy(&new_pg[pos], row_buffer, new_row_size);
+       /* add row to the row offset table */
+       _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (num_rows*2), pos);
+
+       /* update number rows on this page */
+       num_rows++;
+       _mdb_put_int16(new_pg, fmt->row_count_offset, num_rows);
+
+       /* update the freespace */
+       _mdb_put_int16(new_pg,2,pos - fmt->row_count_offset - 2 - (num_rows*2));
+
+       /* copy new page over old */
+       if (!table->is_temp_table) {
+               memcpy(mdb->pg_buf, new_pg, fmt->pg_size);
+               g_free(new_pg);
+       }
+
+       return num_rows;
+}
+int 
+mdb_update_row(MdbTableDef *table)
+{
+int row_start, row_end;
+unsigned int i;
+MdbColumn *col;
+MdbCatalogEntry *entry = table->entry;
+MdbHandle *mdb = entry->mdb;
+MdbFormatConstants *fmt = mdb->fmt;
+MdbField fields[256];
+unsigned char row_buffer[4096];
+int old_row_size, new_row_size, delta;
+unsigned int num_fields;
+
+       if (!mdb->f->writable) {
+               fprintf(stderr, "File is not open for writing\n");
+               return 0;
+       }
+       row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + ((table->cur_row-1)*2)); 
+       row_end = mdb_find_end_of_row(mdb, table->cur_row-1);
+       old_row_size = row_end - row_start;
+
+       row_start &= 0x0FFF; /* remove flags */
+
+       mdb_debug(MDB_DEBUG_WRITE,"page %lu row %d start %d end %d", (unsigned long) table->cur_phys_pg, table->cur_row-1, row_start, row_end);
+       if (mdb_get_option(MDB_DEBUG_LIKE))
+               buffer_dump(mdb->pg_buf, row_start, row_end);
+
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index(table->columns,i);
+               if (col->bind_ptr && mdb_is_col_indexed(table,i)) {
+                       fprintf(stderr, "Attempting to update column that is part of an index\n");
+                       return 0;
+               }
+       }
+       num_fields = mdb_crack_row(table, row_start, row_end, fields);
+
+       if (mdb_get_option(MDB_DEBUG_WRITE)) {
+               for (i=0;i<num_fields;i++) {
+                       printf("col %d %d start %d siz %d\n", i, fields[i].colnum, fields[i].start, fields[i].siz);
+               }
+       }
+       for (i=0;i<table->num_cols;i++) {
+               col = g_ptr_array_index(table->columns,i);
+               if (col->bind_ptr) {
+                       printf("yes\n");
+                       fields[i].value = col->bind_ptr;
+                       fields[i].siz = *(col->len_ptr);
+               }
+       }
+
+       new_row_size = mdb_pack_row(table, row_buffer, num_fields, fields);
+       if (mdb_get_option(MDB_DEBUG_WRITE)) 
+               buffer_dump(row_buffer, 0, new_row_size-1);
+       delta = new_row_size - old_row_size;
+       if ((mdb_pg_get_freespace(mdb) - delta) < 0) {
+               fprintf(stderr, "No space left on this page, update will not occur\n");
+               return 0;
+       }
+       /* do it! */
+       mdb_replace_row(table, table->cur_row-1, row_buffer, new_row_size);
+       return 0;
+}
+int 
+mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size)
+{
+MdbCatalogEntry *entry = table->entry;
+MdbHandle *mdb = entry->mdb;
+MdbFormatConstants *fmt = mdb->fmt;
+unsigned char *new_pg;
+guint16 num_rows;
+int row_start, row_end, row_size;
+int i, pos;
+
+       if (mdb_get_option(MDB_DEBUG_WRITE)) {
+               buffer_dump(mdb->pg_buf, 0, 39);
+               buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1);
+       }
+       mdb_debug(MDB_DEBUG_WRITE,"updating row %d on page %lu", row, (unsigned long) table->cur_phys_pg);
+       new_pg = mdb_new_data_pg(entry);
+
+       num_rows = mdb_pg_get_int16(mdb, fmt->row_count_offset);
+       _mdb_put_int16(new_pg, fmt->row_count_offset, num_rows);
+
+       pos = mdb->fmt->pg_size;
+
+       /* rows before */
+       for (i=0;i<row;i++) {
+               row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2));
+               row_end = mdb_find_end_of_row(mdb, i);
+               row_size = row_end - row_start + 1;
+               pos -= row_size;
+               memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size);
+               _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos);
+       }
+       
+       /* our row */
+       pos -= new_row_size;
+       memcpy(&new_pg[pos], new_row, new_row_size);
+       _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (row*2), pos);
+       
+       /* rows after */
+       for (i=row+1;i<num_rows;i++) {
+               row_start = mdb_pg_get_int16(mdb, (fmt->row_count_offset + 2) + (i*2));
+               row_end = mdb_find_end_of_row(mdb, i);
+               row_size = row_end - row_start + 1;
+               pos -= row_size;
+               memcpy(&new_pg[pos], &mdb->pg_buf[row_start], row_size);
+               _mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos);
+       }
+
+       /* almost done, copy page over current */
+       memcpy(mdb->pg_buf, new_pg, fmt->pg_size);
+
+       g_free(new_pg);
+
+       _mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb));
+       if (mdb_get_option(MDB_DEBUG_WRITE)) {
+               buffer_dump(mdb->pg_buf, 0, 39);
+               buffer_dump(mdb->pg_buf, fmt->pg_size - 160, fmt->pg_size-1);
+       }
+       /* drum roll, please */
+       if (!mdb_write_pg(mdb, table->cur_phys_pg)) {
+               fprintf(stderr, "write failed! exiting...\n");
+               exit(1);
+       }
+       return 0;
+}
+static int
+mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields) 
+/*,  guint32 pgnum, guint16 rownum) 
+static int
+mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg)
+*/
+{
+       MdbCatalogEntry *entry = table->entry;
+       MdbHandle *mdb = entry->mdb;
+       MdbColumn *col;
+       guint32 pg;
+       guint16 row;
+       unsigned char *new_pg;
+       unsigned char key_hash[256];
+       unsigned char iflag;
+       int keycol;
+
+       new_pg = mdb_new_leaf_pg(entry);
+
+       mdb_index_page_reset(ipg);
+       mdb_read_pg(mdb, ipg->pg);
+
+       /* do we support this index type yet? */
+       if (idx->num_keys > 1) {
+               fprintf(stderr,"multikey indexes not yet supported, aborting\n");
+               return 0;
+       }
+       keycol = idx->key_col_num[0];
+       col = g_ptr_array_index (table->columns, keycol - 1);
+       printf("keycol = %d (%s)\n", keycol, col->name);
+       if (!mdb_is_fixed_col(col)) {
+               fprintf(stderr,"variable length key columns not yet supported, aborting\n");
+               return 0;
+       }
+       printf("col size = %d\n", col->col_size);
+
+       while (mdb_index_find_next_on_page(mdb, ipg)) {
+
+               /* check for compressed indexes.  */
+               if (ipg->len < col->col_size + 1) {
+                       fprintf(stderr,"compressed indexes not yet supported, aborting\n");
+                       return 0;
+               }
+
+               pg = mdb_pg_get_int24_msb(mdb, ipg->offset + ipg->len - 4);
+               row = mdb->pg_buf[ipg->offset + ipg->len - 1];
+               iflag = mdb->pg_buf[ipg->offset];
+               mdb_index_swap_n(&mdb->pg_buf[ipg->offset + 1], col->col_size, key_hash);
+               key_hash[col->col_size - 1] &= 0x7f;
+               printf("length = %d\n", ipg->len);
+               printf("iflag = %d pg = %" G_GUINT32_FORMAT
+                       " row = %" G_GUINT16_FORMAT "\n", iflag, pg, row);
+               buffer_dump(mdb->pg_buf, ipg->offset, ipg->offset + ipg->len - 1);
+               buffer_dump(mdb->pg_buf, ipg->offset + 1, ipg->offset + col->col_size);
+               buffer_dump(key_hash, 0, col->col_size - 1);
+               ipg->offset += ipg->len;
+               ipg->len = 0;
+               row++;
+       }
+       g_free(new_pg);
+
+       return ipg->len;
+}
diff --git a/navit/src/data/poi_geodownload/poi_geodownload.c b/navit/src/data/poi_geodownload/poi_geodownload.c
new file mode 100644 (file)
index 0000000..8062ca5
--- /dev/null
@@ -0,0 +1,661 @@
+#include <mdbtools.h>
+#include "debug.h"
+#include "coord.h"
+#include "map.h"
+#include "item.h"
+#include "projection.h"
+#include "plugin.h"
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+struct map_priv
+{
+       char *filename;
+       MdbHandle *h;
+       MdbHandle *h_idx;
+       MdbTableDef *table;
+       GPtrArray *table_col;
+       MdbColumn **cols;
+       MdbIndex *idx;
+       int idx_size;
+       enum item_type type;
+};
+
+struct map_rect_priv
+{
+       struct item item;
+       struct map_priv *m;
+       int cidx;
+};
+
+#if 0
+struct index_data {
+       unsigned char data[15];
+};
+struct poi {
+       char filename[1024];
+       char icon[1024];
+       long pos;
+       MdbHandle *h;
+       MdbHandle *h_idx;
+       MdbTableDef *table;
+       GPtrArray *table_col;
+       MdbColumn **cols;
+       MdbIndex *idx;
+       int idx_size;
+       struct index_data index_data;
+       MdbIndexChain chain;
+       struct poi *next;
+} *poi_list;
+
+struct poi_data {
+       struct poi *poi;
+       int page;
+       int row;
+};
+
+       char poipath[256];
+       char poibmp[256];
+
+
+static void
+print_col(MdbHandle *h, MdbColumn *col, char *buffer, int hex)
+{
+       switch (col->col_type) {
+       case MDB_BOOL:
+               strcpy(buffer, mdb_pg_get_byte(h, col->cur_value_start) ? "True" : "False");
+               break;
+       case MDB_BYTE:
+               sprintf(buffer, "%d", mdb_pg_get_byte(h, col->cur_value_start));
+               break;
+       case MDB_LONGINT:
+               if (hex)
+                       sprintf(buffer, "0x%lx", mdb_pg_get_int32(h, col->cur_value_start));
+               else
+                       sprintf(buffer, "%ld", mdb_pg_get_int32(h, col->cur_value_start));
+               break;
+       case MDB_DOUBLE:
+               sprintf(buffer, "%f", mdb_pg_get_double(h, col->cur_value_start));
+               break;
+       case MDB_TEXT:
+               sprintf(buffer, "%s", mdb_col_to_string (h, h->pg_buf, col-> cur_value_start,
+                                col->col_type, col->cur_value_len));
+               break;
+       default:
+               sprintf(buffer, "unknown (%d)", col->col_type);
+       }
+}
+
+static void
+setup_idx_data(struct index_data *idx, struct coord *c, unsigned int geoflags, int size)
+{
+       /* 7f 80 1c 91 0a 7f 80 5c  f5 41 7f 80 00 00 05 */
+       idx->data[0]=0x7f;
+       idx->data[1]=(c->x >> 24) ^ 0x80;
+       idx->data[2]=c->x >> 16;
+       idx->data[3]=c->x >> 8;
+       idx->data[4]=c->x;
+       idx->data[5]=0x7f;
+       idx->data[6]=(c->y >> 24) ^ 0x80;
+       idx->data[7]=c->y >> 16;
+       idx->data[8]=c->y >> 8;
+       idx->data[9]=c->y;
+       idx->data[10]=0x7f;
+       if (size > 12) {
+               idx->data[11]=0x80 | (geoflags >> 24);
+               idx->data[12]=geoflags >> 16;
+               idx->data[13]=geoflags >> 8;
+               idx->data[14]=geoflags;
+       } else {
+               idx->data[11]=geoflags;
+       }
+}
+
+static void
+setup_idx_rect(struct coord *rect, struct index_data *idx, int size)
+{
+       struct coord r[2];
+       r[0].x=rect[0].x;
+       r[0].y=rect[1].y;
+       r[1].x=rect[1].x;
+       r[1].y=rect[0].y;
+#if 0
+       printf("low 0x%x 0%x\n", r[0].x, r[0].y);
+       printf("high 0x%x 0%x\n", r[1].x, r[1].y);
+#endif
+       setup_idx_data(idx, r, 0, size);
+       setup_idx_data(idx+1, r+1, 0xffffffff, size);
+}
+
+static int
+load_row(struct poi *poi, int pg, int row)
+{
+       int row_start, row_end, offset;
+       unsigned int num_fields, i;
+       MdbField fields[256];
+       MdbFormatConstants *fmt;
+       int debug=0;
+
+       fmt=poi->h->fmt;
+       mdb_read_pg(poi->h, pg);
+       if (debug)
+               printf("Page Type %d row_count_offset %d\n",poi->h->pg_buf[0], fmt->row_count_offset);
+       if (debug > 1) {
+               for (i = 0; i <= row; i++) {
+                       offset=(fmt->row_count_offset + 2) + i * 2;
+                       printf("row %d %d 0x%x\n", i, offset, mdb_pg_get_int16(poi->h, offset));
+               }
+       }
+       row_start = mdb_pg_get_int16(poi->h, (fmt->row_count_offset + 2) + row * 2);
+       if (row_start & 0x4000)
+               return 1;
+       row_end = mdb_find_end_of_row(poi->h, row);
+       if (debug) {
+               printf("start=0x%x end=0x%x\n", row_start, row_end);
+               buffer_dump(poi->h->pg_buf, row_start, row_end);
+       }
+
+       poi->h->cur_pos=row_start & 0x1fff;
+       poi->table->cur_row=row+1;
+       num_fields = mdb_crack_row(poi->table, row_start & 0x1fff, row_end, fields);
+       if (debug)
+               printf("num_fields=%d\n", num_fields);
+       for (i = 0; i < num_fields; i++) {
+               poi->cols[i]->cur_value_start=fields[i].start;
+               poi->cols[i]->cur_value_len=fields[i].siz;
+       }
+       return 0;
+}
+
+static MdbIndexPage *
+index_next_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain)
+{
+       MdbIndexPage *ipg;
+
+       ipg = mdb_index_read_bottom_pg(mdb, idx, chain);
+       if (!mdb_index_find_next_on_page(mdb, ipg)) {
+#if 0
+               printf("no next\n");    
+#endif
+               if (!chain->clean_up_mode) {
+#if 0
+                       printf("no cleanup\n"); 
+#endif
+                       if (!(ipg = mdb_index_unwind(mdb, idx, chain)))
+                               chain->clean_up_mode = 1;
+               }
+               if (chain->clean_up_mode) {
+#if 0
+                       printf("cleanup\n");    
+#endif
+                       //fprintf(stdout,"in cleanup mode\n");
+
+                       if (!chain->last_leaf_found) {
+                               printf("no last_leaf_found\n");
+                               return NULL;
+                       }
+                       mdb_read_pg(mdb, chain->last_leaf_found);
+                       chain->last_leaf_found =
+                           mdb_pg_get_int24(mdb, 0x0c);
+                       //printf("next leaf %lu\n", chain->last_leaf_found);
+                       mdb_read_pg(mdb, chain->last_leaf_found);
+                       /* reuse the chain for cleanup mode */
+                       chain->cur_depth = 1;
+                       ipg = &chain->pages[0];
+                       mdb_index_page_init(ipg);
+                       ipg->pg = chain->last_leaf_found;
+                       //printf("next on page %d\n",
+                       if (!mdb_index_find_next_on_page(mdb, ipg)) {
+#if 0
+                               printf("no find_next_on_page\n");
+#endif
+                               return NULL;
+                       }
+               }
+       }
+       return ipg;
+}
+
+static int
+index_next(struct poi *poi, struct index_data *idx)
+{
+       MdbIndexPage *ipg;
+       MdbIndexChain *chain = &poi->chain;
+       int row;
+       int pg;
+       int offset;
+       char *cmp, *low, *high;
+       int debug=0;
+
+
+       for(;;) {
+       for(;;) {
+       ipg=index_next_row(poi->h_idx, poi->idx, chain);
+       if (! ipg)
+               return 0;
+       row = poi->h_idx->pg_buf[ipg->offset + ipg->len - 1];
+       pg = mdb_pg_get_int24_msb(poi->h_idx, ipg->offset + ipg->len - 4);
+
+       offset=poi->idx_size+4-ipg->len;
+       memcpy(poi->index_data.data+offset, poi->h_idx->pg_buf+ipg->offset, ipg->len - 4);
+       cmp=poi->index_data.data;
+       low=idx[0].data;
+       high=idx[1].data;
+       if (debug > 1) {
+               buffer_dump(low, 0, poi->idx_size-1);
+               buffer_dump(cmp, 0, poi->idx_size-1);
+               buffer_dump(high, 0, poi->idx_size-1);
+               printf("%d %d %d\n", memcmp(cmp, low, poi->idx_size), memcmp(cmp, high, poi->idx_size), offset);
+       }
+#if 0
+       buffer_dump(poi->h_idx->pg_buf, ipg->offset, ipg->offset+ipg->len-1);
+#endif
+       ipg->offset += ipg->len;
+       if (memcmp(cmp, low, poi->idx_size) >= 0) {
+               if (memcmp(cmp, high, poi->idx_size) <=0 ) {
+                       if (debug) {
+                               printf("match\n");
+                               buffer_dump(low, 0, poi->idx_size-1);
+                               buffer_dump(cmp, 0, poi->idx_size-1);
+                               buffer_dump(high, 0, poi->idx_size-1);
+                               printf("%d %d %d\n", memcmp(cmp, low, poi->idx_size), memcmp(cmp, high, poi->idx_size), offset);
+                       }
+                       break;
+               } else {
+                       return 0;
+               }
+       }
+       if (debug > 1)
+               printf("row=0x%x pg=0x%x len=%d\n", row, pg, ipg->len);
+       }
+       if (debug)
+               printf("match: row=0x%x pg=0x%x len=%d\n", row, pg, ipg->len);
+               if (!load_row(poi, pg, row))
+                       break;
+       }
+       return 1;
+}
+
+#endif
+
+static int
+load_poi_table(struct map_priv *m, MdbCatalogEntry *entry)
+{
+       int j;
+       MdbIndex *idx;
+
+       m->h_idx=NULL;
+       m->table = mdb_read_table(entry);
+       m->table_col = mdb_read_columns(m->table);
+       mdb_read_indices(m->table);
+       m->cols = (MdbColumn **) (m->table_col->pdata);
+       if (m->table_col->len < 4 || strcasecmp(m->cols[0]->name, "X") ||
+               strcasecmp(m->cols[1]->name, "Y") || strcasecmp(m->cols[3]->name, "GEOFLAGS")) 
+                       return 1;
+       for (j = 0; j < m->table->num_idxs; j++) {
+               idx = m->table->indices->pdata[j];
+               if (idx->num_keys == 3 && idx->key_col_num[0] == 1 &&
+                   idx->key_col_num[1] == 2 && idx->key_col_num[2] == 4) {
+                       m->idx = idx;
+                       m->idx_size=3+m->cols[0]->col_size+m->cols[1]->col_size+m->cols[3]->col_size;
+                       m->h_idx=mdb_clone_handle(m->h);
+               }
+       }
+       return 0;       
+}
+
+#if 0
+
+static void
+load_poi(char *filename, char *icon, int type)
+{
+       int i;
+       MdbCatalogEntry *entry;
+       GPtrArray *catalog;
+       struct poi *new = g_new0(struct poi, 1);
+
+       FILE *fp = fopen(filename,"r");
+       if( fp ) {
+              fclose(fp);
+       } else {
+               printf("ERR : POI file %s does not exists!\n",filename);
+               exit(0);
+               return -1;
+       }
+
+
+       fp = fopen(icon,"r");
+       if( fp ) {
+              fclose(fp);
+       } else {
+               printf("ERR : WARNING INCORRECT PICTURE! %s!\n",icon);
+               exit(0);
+               return -1;
+       }
+
+       strcpy(new->filename,filename);
+       strcpy(new->icon,icon);
+       new->type = type;
+
+
+       if (type == 0) {
+               new->h = mdb_open(filename, MDB_NOFLAGS);
+               catalog = mdb_read_catalog(new->h, MDB_TABLE);
+               for (i = 0; i < catalog->len; i++) {
+                       entry = catalog->pdata[i];
+                       if (!strcasecmp(entry->object_name, "_INDEXDATA")) {
+                               if (load_poi_table(new, entry)) {
+                                       printf("%s invalid\n", filename);
+                                       g_free(new);
+                                       new=NULL;
+                               }
+                       }
+               }
+               g_ptr_array_free(catalog, 1);
+       }
+       if (new) {
+               new->next = poi_list;
+               poi_list = new;
+       }
+}
+
+static void
+get_coord(struct poi *p, struct coord *c)
+{
+       c->x=mdb_pg_get_int32(p->h, p->cols[0]->cur_value_start);
+       c->y=mdb_pg_get_int32(p->h, p->cols[1]->cur_value_start);
+}
+
+static void
+poi_info(struct display_list *list, struct popup_item **popup)
+{
+       struct poi_data *data=list->data;
+       struct poi *poi=data->poi;
+       struct popup_item *popup_last, *popup_val_last;
+       char *text,buffer[4096];
+       int j;
+       MdbColumn *col;
+       char *v;
+
+       popup_last = *popup;
+
+       popup_val_last = NULL;
+       sprintf(buffer,"File:%s", poi->filename);
+       popup_item_new_text(&popup_val_last, buffer, 1);
+       sprintf(buffer,"Icon:%s", poi->icon);
+       popup_item_new_text(&popup_val_last, buffer, 2);
+       if (poi->type == 0) {
+               printf("poi_info pg=%d row=%d\n", data->page, data->row);
+               load_row(poi, data->page, data->row);
+               sprintf(buffer,"Page:%d", data->page);
+               popup_item_new_text(&popup_val_last, buffer, 3);
+               sprintf(buffer,"Row:%d", data->row);
+               popup_item_new_text(&popup_val_last, buffer, 4);
+               for (j = 0; j < poi->table_col->len; j++) {
+                       col = poi->table_col->pdata[j];
+       #if 0
+                       printf("start: %d type:%d\n", col->cur_value_start, col->col_type);
+       #endif
+                       sprintf(buffer, "%s:", col->name);
+                       v = buffer + strlen(buffer);
+                       if (!strcasecmp(col->name,"X") || !strcasecmp(col->name,"Y")) 
+                               print_col(poi->h, col, v, 1);
+                       else
+                               print_col(poi->h, col, v, 0);
+       #if 0
+                       printf("%s\n", buffer);
+       #endif
+                       text=g_convert(buffer,-1,"utf-8","iso8859-1",NULL,NULL,NULL);
+                       popup_item_new_text(&popup_val_last, buffer, j+10);
+                       g_free(text);
+               }
+       }
+       popup_item_new_text(&popup_last, "POI", 20)->submenu = popup_val_last;
+       *popup=popup_last;
+}
+
+static void
+draw_poi(struct poi *p, struct container *co, struct point *pnt)
+{
+       struct poi_data data;
+       data.poi=p;
+       if (p->type == 0) {
+               data.page=p->h->cur_pg;
+               data.row=p->table->cur_row-1;
+       }
+       if (p->type == 1) {
+               data.row=p->pos;
+       }
+       display_add(&co->disp[display_poi], 5, 0, p->icon, 1, pnt, poi_info, &data, sizeof(data));
+}
+
+static void
+plugin_draw(struct container *co)
+{
+       struct coord c;
+       struct point pnt;
+       struct poi *p;
+       struct index_data idx[2];
+       int use_index=0;
+       int debug=1;
+
+       p = poi_list;
+
+       if (co->trans->scale > 1024)
+               return; 
+       if (debug) {
+               printf("scale=%ld\n", co->trans->scale);
+               printf("rect 0x%lx,0%lx-0x%lx,0x%lx\n", co->trans->rect[0].x, co->trans->rect[0].y, co->trans->rect[1].x, co->trans->rect[1].y);
+       }
+       while (p) {
+               if (p->type == 0) {
+                       if (use_index)
+                               setup_idx_rect(co->trans->rect, idx, p->idx_size);
+                       if (! use_index) {
+                               printf("rewind %s %p\n", p->filename, p->table);
+                               mdb_rewind_table(p->table);
+                               while (mdb_fetch_row(p->table)) {
+                                       get_coord(p, &c);
+                                       if (transform(co->trans, &c, &pnt)) {
+                                               if (debug)
+                                                       printf("coord 0x%lx,0x%lx pg %d row %d\n", c.x, c.y, p->h->cur_pg, p->table->cur_row);
+                                               draw_poi(p, co, &pnt);
+                                       }
+                               }
+                       }  else {
+                               memset(&p->chain, 0, sizeof(p->chain));
+                               while (index_next(p, idx)) {
+                                       get_coord(p, &c);
+                                       if (transform(co->trans, &c, &pnt)) {
+                                               if (debug)
+                                                       printf("coord 0x%lx,0x%lx pg %d row %d\n", c.x, c.y, p->h->cur_pg, p->table->cur_row);
+                                               draw_poi(p, co, &pnt);
+                                       }
+                               }
+                       }
+               }
+               if (p->type == 1) {
+                       FILE *f;
+                       char line[1024];
+                       struct text_poi tpoi;
+                       if(!(f=fopen(p->filename, "r"))){
+                               printf("can't open poi file for drawing!\n");
+                               exit(0);
+                       }
+#if 0
+                       printf("opened poi file %s for drawing!\n",p->filename);
+#endif
+                       p->pos=ftell(f);
+                       fgets(line, 1024, f);
+                       while (!feof(f)) {
+                               if (strlen(line)) {
+                                       line[strlen(line)-1]='\0';
+                               }
+                               if (parse_text_poi(line, &tpoi)) {
+                                       transform_mercator(&tpoi.lat,&tpoi.lng,&c);
+//                                     printf("%ld %ld\n", c.x, c.y);
+                                       if (transform(co->trans, &c, &pnt)) {
+                                               draw_poi(p, co, &pnt);
+                                       }
+                               }
+                               p->pos=ftell(f);
+                               fgets(line, 1024, f);
+                       }
+                       fclose(f);                      
+               }
+               p = p->next;
+       }
+
+}
+
+#endif
+
+static void
+map_destroy_poi_geodownload(struct map_priv *m)
+{
+        dbg(1,"enter\n");
+        g_free(m);
+}
+
+static void
+poi_geodownload_coord_rewind(void *priv_data)
+{
+       struct map_rect_priv *mr=priv_data;
+       mr->cidx=0;
+}
+
+
+static int
+poi_geodownload_coord_get(void *priv_data, struct coord *c, int count)
+{
+       struct map_rect_priv *mr=priv_data;
+       dbg(1,"enter\n");
+       if (mr->cidx || !count)
+               return 0;
+       c->x=mdb_pg_get_int32(mr->m->h, mr->m->cols[0]->cur_value_start);
+       c->y=mdb_pg_get_int32(mr->m->h, mr->m->cols[1]->cur_value_start);
+       dbg(1,"x=0x%x y=0x%x\n", c->x, c->y);
+       return 1;
+}
+
+static void
+poi_geodownload_attr_rewind(void *priv_data)
+{
+}
+
+static int
+poi_geodownload_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
+{
+       dbg(1,"enter\n");
+       return 0;
+}
+
+static struct item_methods methods_poi_geodownload = {
+       poi_geodownload_coord_rewind,
+       poi_geodownload_coord_get,
+       poi_geodownload_attr_rewind,
+       poi_geodownload_attr_get,
+};
+
+
+static struct map_rect_priv *
+map_rect_new_poi_geodownload(struct map_priv *map, struct map_selection *sel)
+{
+        struct map_rect_priv *mr;
+
+        dbg(1,"enter\n");
+        mr=g_new0(struct map_rect_priv, 1);
+       mr->item.meth=&methods_poi_geodownload;
+       mr->item.id_hi=0;
+       mr->item.id_lo=0;
+       mr->item.priv_data=mr;
+       mr->item.type=map->type;
+       mr->m=map;
+       mdb_rewind_table(map->table);
+        return mr;
+}
+
+
+static void
+map_rect_destroy_poi_geodownload(struct map_rect_priv *mr)
+{
+       g_free(mr);
+}
+
+static struct item *
+map_rect_get_item_poi_geodownload(struct map_rect_priv *mr)
+{
+       dbg(1,"enter\n");
+       if (mdb_fetch_row(mr->m->table))
+               return &mr->item;
+       return NULL;
+}
+
+static struct item *
+map_rect_get_item_byid_poi_geodownload(struct map_rect_priv *mr, int id_hi, int id_lo)
+{
+       return NULL;
+}
+
+
+static struct map_methods map_methods_poi_geodownload = {
+       map_destroy_poi_geodownload,
+       map_rect_new_poi_geodownload,
+       map_rect_destroy_poi_geodownload,
+       map_rect_get_item_poi_geodownload,
+       map_rect_get_item_byid_poi_geodownload,
+};
+
+static struct map_priv *
+map_new_poi_geodownload(struct map_methods *meth, char *filename, struct attr **attrs, char **charset, enum projection *pro)
+{
+        struct map_priv *m;
+        dbg(1,"filename %s\n",filename);
+       MdbCatalogEntry *entry;
+       GPtrArray *catalog;
+       int i;
+       struct attr *attr;
+
+        *meth=map_methods_poi_geodownload;
+        *charset="iso8859-1";
+        *pro=projection_mg;
+
+        m=g_new(struct map_priv, 1);
+        m->filename=g_strdup(filename);
+       m->h = mdb_open(m->filename, MDB_NOFLAGS);
+       m->type=type_none;
+       dbg(1,"attr_search\n");
+       attr=attr_search(attrs, NULL, attr_item_type);
+       dbg(1,"attr_search result %p\n", attr);
+       if (attr) {
+               m->type=attr->u.item_type;
+               printf("type '%s'\n", item_to_name(m->type));
+       }
+               
+       
+       catalog = mdb_read_catalog(m->h, MDB_TABLE);
+       for (i = 0; i < catalog->len; i++) {
+               entry = catalog->pdata[i];
+               dbg(1,"object name '%s'\n", entry->object_name);
+               if (!strcasecmp(entry->object_name, "_INDEXDATA")) {
+                       if (load_poi_table(m, entry)) {
+                               printf("%s invalid\n", filename);
+                               g_free(m);
+                               m=NULL;
+                       }
+               }
+       }
+       g_ptr_array_free(catalog, 1);
+        return m;
+}
+
+void
+plugin_init(void)
+{
+       dbg(1,"plugin_init\n");
+       plugin_register_map_type("poi_geodownload", map_new_poi_geodownload);
+}
+
index 908be5b..17e62f8 100644 (file)
@@ -291,7 +291,7 @@ static struct map_methods map_methods_textfile = {
 };
 
 static struct map_priv *
-map_new_textfile(struct map_methods *meth, char *filename, char **charset, enum projection *pro)
+map_new_textfile(struct map_methods *meth, char *filename, struct attr **attrs, char **charset, enum projection *pro)
 {
        struct map_priv *m;
        dbg(1,"map_new_textfile %s\n",filename);        
index 593d7f3..7a2f205 100644 (file)
@@ -466,8 +466,10 @@ do_draw(struct displaylist *displaylist, struct transformation *t, GList *mapset
                while ((item=map_rect_get_item(mr))) {
                        if (item->type < type_line) {
                                item_coord_get(item, &c, 1);
-                               if (!transform(t, pro, &c, &pnt[0]))
+                               if (!transform(t, pro, &c, &pnt[0])) {
+                                       dbg(1,"not visible\n");
                                        continue;
+                               }
                                count=1;
                        } else {
                                count=0;
index 286da7a..6af8b34 100644 (file)
@@ -7,9 +7,8 @@
 #include "debug.h"
 #include "destination.h"
 #include "navit.h"
-#include "attr.h"
-#include "coord.h"
 #include "item.h"
+#include "coord.h"
 #include "search.h"
 
 #define COL_COUNT 8
index 89c5a2e..81ec9b2 100644 (file)
@@ -1,6 +1,5 @@
 #include <string.h>
 #include <glib.h>
-#include "attr.h"
 #include "coord.h"
 #include "debug.h"
 #include "item.h"
index 473d8f9..d497f15 100644 (file)
@@ -1,4 +1,3 @@
-#include "attr.h"
 
 
 enum item_type {
@@ -9,6 +8,8 @@ enum item_type {
 #undef ITEM
 };
 
+#include "attr.h"
+
 #define item_is_equal_id(a,b) ((a).id_hi == (b).id_hi && (a).id_lo == (b).id_lo)
 #define item_is_equal(a,b) (item_is_equal_id(a,b) && (a).map == (b).map)
 
index 0f771d2..71d3311 100644 (file)
@@ -89,6 +89,10 @@ ITEM(poi_picnic)
 ITEM(poi_hospital)
 ITEM(poi_camping)
 ITEM(poi_public_utilities)
+ITEM(poi_burgerking)
+ITEM(poi_kfc)
+ITEM(poi_mcdonalds)
+ITEM(poi_wienerwald)
 ITEM2(0x80000000,line)
 ITEM2(0x80000001,line_unspecified)
 /* Line */
index a209c14..36bf329 100644 (file)
@@ -26,10 +26,10 @@ struct map_rect {
 };
 
 struct map *
-map_new(const char *type, const char *filename)
+map_new(const char *type, const char *filename, struct attr **attrs)
 {
        struct map *m;
-       struct map_priv *(*maptype_new)(struct map_methods *meth, const char *name, char **charset, enum projection *pro);
+       struct map_priv *(*maptype_new)(struct map_methods *meth, const char *name, struct attr *attrs, char **charset, enum projection *pro);
 
        maptype_new=plugin_get_map_type(type);
        if (! maptype_new)
@@ -39,7 +39,7 @@ map_new(const char *type, const char *filename)
        m->active=1;
        m->filename=g_strdup(filename);
        m->type=g_strdup(type);
-       m->priv=maptype_new(&m->meth, filename, &m->charset, &m->projection);
+       m->priv=maptype_new(&m->meth, filename, attrs, &m->charset, &m->projection);
        return m;
 }
 
index c0b9361..9127494 100644 (file)
@@ -28,7 +28,7 @@ struct map;
 struct map_rect;
 struct map_search;
 struct map_selection;
-struct map *map_new(const char *type, const char *filename);
+struct map *map_new(const char *type, const char *filename, struct attr **attrs);
 char * map_convert_string(struct map *this, char *str);
 void map_convert_free(char *str);
 char *map_get_filename(struct map *this);
index 17fbecf..39cb0d5 100644 (file)
@@ -1,7 +1,7 @@
 #include <glib.h>
 #include <glib/gprintf.h>
 #include "debug.h"
-#include "attr.h"
+#include "item.h"
 #include "mapset.h"
 #include "map.h"
 
index 9bb1dd2..652563d 100644 (file)
@@ -694,7 +694,7 @@ navit_window_items_open(struct menu *men, struct navit *this_, struct navit_wind
                        if (item_coord_get(item, &c, 1)) {
                                if (coord_rect_contains(&sel.rect, &c) && g_hash_table_lookup(nwi->hash, &item->type)) {
                                        if (! item_attr_get(item, attr_label, &attr)) 
-                                               attr.u.str=NULL;
+                                               attr.u.str="";
                                        idist=transform_distance(center, &c);
                                        if (idist < dist) {
                                                get_direction(dirbuf, transform_get_angle_delta(center, &c, 0), 1);
index 075709b..701598d 100644 (file)
@@ -1,10 +1,11 @@
 enum projection;
+struct attr;
 PLUGIN_FUNC1(draw, struct container *, co)
 PLUGIN_FUNC3(popup, struct container *, map, struct popup *, p, struct popup_item **, list)
 struct navit;
 PLUGIN_TYPE(graphics, (struct graphics_methods *meth)) 
 PLUGIN_TYPE(gui, (struct navit *nav, struct gui_methods *meth, int w, int h)) 
-PLUGIN_TYPE(map, (struct map_methods *meth, char *data, char **charset, enum projection *pro)) 
+PLUGIN_TYPE(map, (struct map_methods *meth, char *data, struct attr **attr, char **charset, enum projection *pro)) 
 PLUGIN_TYPE(osd, (struct osd_methods *meth)) 
 PLUGIN_TYPE(speech, (char *data, struct speech_methods *meth)) 
 PLUGIN_TYPE(vehicle, (struct vehicle_methods *meth)) 
index 8ac9518..3d7e3e0 100644 (file)
@@ -2,7 +2,6 @@
 #include "debug.h"
 #include "map.h"
 #include "mapset.h"
-#include "attr.h"
 #include "coord.h"
 #include "item.h"
 #include "search.h"
index 0eff60b..a2ff462 100644 (file)
@@ -28,6 +28,33 @@ struct xmlstate {
 } *xmlstate_root;
 
 
+static struct attr ** convert_to_attr(struct xmlstate *state)
+{
+       const gchar **attribute_name=state->attribute_names;
+       const gchar **attribute_value=state->attribute_values;
+       int count=0;
+       struct attr **ret;
+
+       while (*attribute_name) {
+               count++;
+               attribute_name++;
+       }
+       ret=g_new(struct attr, count+1);
+       attribute_name=state->attribute_names;
+       count=0;
+       while (*attribute_name) {
+               ret[count]=attr_new_from_text(*attribute_name,*attribute_value);
+               if (ret[count])
+                       count++;
+               attribute_name++;
+               attribute_value++;
+       }       
+       ret[count]=NULL;
+       dbg(0,"ret=%p\n", ret);
+       return ret;
+}
+
+
 static const char * find_attribute(struct xmlstate *state, const char *attribute, int required)
 {
        const gchar **attribute_name=state->attribute_names;
@@ -342,11 +369,13 @@ xmlconfig_mapset(struct xmlstate *state)
 static int
 xmlconfig_map(struct xmlstate *state)
 {
+       struct attr **attr;
        const char *type=find_attribute(state, "type", 1);
        const char *data=find_attribute(state, "data", 1);
        if (! type || ! data)
                return 0;
-       state->element_object = map_new(type, data);
+       attr=convert_to_attr(state);
+       state->element_object = map_new(type, data, attr);
        if (! state->element_object)
                return 0;
        if (!find_boolean(state, "active", 1, 0))