summaryrefslogtreecommitdiffstats
path: root/keximdb/src/mdbtools/libmdb/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'keximdb/src/mdbtools/libmdb/file.c')
-rw-r--r--keximdb/src/mdbtools/libmdb/file.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/keximdb/src/mdbtools/libmdb/file.c b/keximdb/src/mdbtools/libmdb/file.c
new file mode 100644
index 0000000..cf4a978
--- /dev/null
+++ b/keximdb/src/mdbtools/libmdb/file.c
@@ -0,0 +1,418 @@
+/* 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
+};
+
+static ssize_t _mdb_read_pg(MdbHandle *mdb, void *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 char *mdb_find_file(const 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_set_encoding:
+ * @mdb: Handle to MDB database file
+ * @encoding_name: encoding name for MDB (database) file in JET3 version.
+ * A copy of the string will be created.
+ *
+ * Sets encoding name for MDB (database) file in JET3 version.
+ * JET3 databases have no usincode support but only ANSI code page (e.g. CP1252)
+ * (not ISO), so you need to decide what code page strings in the MDB file are encoded in.
+ *
+ * Use this function after mdb_open()) but BEFORE any operation which reads text strings
+ * from the MDB file.
+ * "MDB_JET3_CHARSET" environment variable has priority over this setting.
+ *
+ **/
+void mdb_set_encoding(MdbHandle *mdb, const char *encoding_name)
+{
+#ifdef HAVE_ICONV
+ mdb_iconv_close(mdb);
+ g_free(mdb->jet3_iconv_code);
+ mdb->jet3_iconv_code = g_strdup(encoding_name);
+ mdb_iconv_init(mdb);
+#endif
+}
+
+/**
+ * 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(const char *filename, MdbFileFlags flags)
+{
+ MdbHandle *mdb;
+ int open_flags;
+
+ mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle));
+#if !MDB_NO_BACKENDS
+ mdb_set_default_backend(mdb, "access");
+#endif
+#ifdef HAVE_ICONV
+ mdb->jet3_iconv_code = 0;
+ mdb->iconv_in = (iconv_t)-1;
+ mdb->iconv_out = (iconv_t)-1;
+#endif
+ /* 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 = 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;
+ open_flags = O_RDWR;
+ } else {
+ open_flags = O_RDONLY;
+ }
+
+#ifdef _WIN32
+ open_flags |= O_BINARY;
+#endif
+
+ mdb->f->fd = open(mdb->f->filename, open_flags);
+
+ 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_get_int32(mdb->pg_buf, 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;
+ }
+ mdb_iconv_init(mdb);
+
+ 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);
+#if !MDB_NO_STATS
+ g_free(mdb->stats);
+#endif
+#if !MDB_NO_BACKENDS
+ g_free(mdb->backend_name);
+#endif
+ 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);
+ }
+ }
+
+ mdb_iconv_close(mdb);
+
+#ifdef HAVE_ICONV
+ g_free(mdb->jet3_iconv_code);
+#endif
+ 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));
+#if !MDB_NO_STATS
+ newmdb->stats = NULL;
+#endif
+ 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);
+ }
+#if !MDB_NO_BACKENDS
+ newmdb->backend_name = NULL;
+#endif
+ if (mdb->f) {
+ mdb->f->refs++;
+ }
+#ifdef HAVE_ICONV
+ newmdb->jet3_iconv_code = g_strdup(mdb->jet3_iconv_code);
+#endif
+ mdb_iconv_init(newmdb);
+
+ 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);
+
+ 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, void *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_NO_STATS
+ if (mdb->stats && mdb->stats->collect)
+ mdb->stats->pg_reads++;
+#endif
+ 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);
+}
+
+
+unsigned char mdb_get_byte(void *buf, int offset)
+{
+ return ((unsigned char *)(buf))[offset];
+}
+unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset)
+{
+ if (offset < 0 || (offset+1) > (int)mdb->fmt->pg_size) return -1;
+ mdb->cur_pos++;
+ return mdb->pg_buf[offset];
+}
+
+int mdb_get_int16(void *buf, int offset)
+{
+ guint16 l;
+ memcpy(&l, (char*)buf + offset, 2);
+ return (int)GUINT16_FROM_LE(l);
+}
+int mdb_pg_get_int16(MdbHandle *mdb, int offset)
+{
+ if (offset < 0 || (offset+2) > (int)mdb->fmt->pg_size) return -1;
+ mdb->cur_pos+=2;
+ return mdb_get_int16(mdb->pg_buf, offset);
+}
+
+long mdb_get_int32_msb(void *buf, int offset)
+{
+ gint32 l;
+ memcpy(&l, (char*)buf + offset, 4);
+ return (long)GINT32_FROM_BE(l);
+}
+long mdb_get_int32(void *buf, int offset)
+{
+ gint32 l;
+ memcpy(&l, (char*)buf + offset, 4);
+ return (long)GINT32_FROM_LE(l);
+}
+long mdb_pg_get_int32(MdbHandle *mdb, int offset)
+{
+ if (offset <0 || (offset+4) > (int)mdb->fmt->pg_size) return -1;
+ mdb->cur_pos+=4;
+ return mdb_get_int32(mdb->pg_buf, offset);
+}
+
+float mdb_get_single(void *buf, int offset)
+{
+ union {guint32 g; float f;} f;
+ memcpy(&f, (char*)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) > (int)mdb->fmt->pg_size) return -1;
+ mdb->cur_pos+=4;
+ return mdb_get_single(mdb->pg_buf, offset);
+}
+
+double mdb_get_double(void *buf, int offset)
+{
+ union {guint64 g; double d;} d;
+ memcpy(&d, (char*)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) > (int)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 >= (int)mdb->fmt->pg_size) return 0;
+
+ mdb->cur_pos=pos;
+ return pos;
+}
+int mdb_get_pos(MdbHandle *mdb)
+{
+ return mdb->cur_pos;
+}