diff --git a/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h b/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h index 91e97740c..31f48c171 100644 --- a/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h +++ b/src/migration/mdb/3rdparty/mdbtools/include/mdbtools.h @@ -1,621 +1,658 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _mdbtools_h_ #define _mdbtools_h_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include +#ifndef _WIN32 #include +#endif #include #include #include #ifdef HAVE_ICONV #include #endif #ifdef _WIN32 #include #endif #define MDB_DEBUG 0 #define MDB_PGSIZE 4096 //#define MDB_MAX_OBJ_NAME (256*3) /* unicode 16 -> utf-8 worst case */ #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 #define MDB_NO_BACKENDS 1 #define MDB_NO_STATS 1 -#ifdef _MSC_VER -#define MDB_DEPRECATED(type, funcname) type funcname +#ifdef _WIN32 +#if BUILDING_LIBMDB +#define LIBMDB_DLL __declspec(dllexport) +#else +#define LIBMDB_DLL __declspec(dllimport) +#endif +#else +#define LIBMDB_DLL +#endif + +#ifndef _WIN32 +#define MDB_DEPRECATED(type, func) type __attribute__((deprecated)) func #else -// Theses 2 atrbutes are not supported by all compilers: -// M$VC see http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc -#define MDB_DEPRECATED(type, funcname) type __attribute__((deprecated)) funcname +#define MDB_DEPRECATED(type, func) __declspec(deprecated) type func #endif -#define MDB_CONSTRUCTOR(funcname) void __attribute__((constructor)) funcname() 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, MDB_VER_ACCDB_2007 = 0x02, MDB_VER_ACCDB_2010 = 0x0103 }; 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, /* User access */ 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_DATETIME = 0x08, MDB_BINARY = 0x09, MDB_TEXT = 0x0a, MDB_OLE = 0x0b, MDB_MEMO = 0x0c, MDB_REPID = 0x0f, MDB_NUMERIC = 0x10, MDB_COMPLEX = 0x12 }; /* 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_DEBUG_PROPS = 0x0020, MDB_USE_INDEX = 0x0040, MDB_NO_MEMO = 0x0080, /* don't follow memo fields */ }; #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 }; /* export schema options */ enum { MDB_SHEXP_DROPTABLE = 1<<0, /* issue drop table during export */ MDB_SHEXP_CST_NOTNULL = 1<<1, /* generate NOT NULL constraints */ MDB_SHEXP_CST_NOTEMPTY = 1<<2, /* <>'' constraints */ MDB_SHEXP_COMMENTS = 1<<3, /* export comments on columns & tables */ MDB_SHEXP_DEFVALUES = 1<<4, /* export default values */ MDB_SHEXP_INDEXES = 1<<5, /* export indices */ MDB_SHEXP_RELATIONS = 1<<6 /* export relation (foreign keys) */ }; #define MDB_SHEXP_DEFAULT (MDB_SHEXP_CST_NOTNULL | MDB_SHEXP_COMMENTS | MDB_SHEXP_INDEXES | MDB_SHEXP_RELATIONS) /* csv export binary options */ enum { MDB_BINEXPORT_STRIP, MDB_BINEXPORT_RAW, MDB_BINEXPORT_OCTAL }; #define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4) /* obsolete */ #define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3) /* forward declarations */ typedef struct mdbindex MdbIndex; typedef struct mdbsargtree MdbSargNode; #if !MDB_NO_BACKENDS typedef struct { char *name; unsigned char needs_length; /* or precision */ unsigned char needs_scale; unsigned char needs_quotes; } MdbBackendType; +enum { + MDB_BACKEND_ACCESS = 1, + MDB_BACKEND_ORACLE, + MDB_BACKEND_SYBASE, + MDB_BACKEND_POSTGRES, + MDB_BACKEND_MYSQL, + MDB_BACKEND_SQLITE, +}; + +enum { + MDB_BACKEND_ACCESS = 1, + MDB_BACKEND_ORACLE, + MDB_BACKEND_SYBASE, + MDB_BACKEND_POSTGRES, + MDB_BACKEND_MYSQL, + MDB_BACKEND_SQLITE, +}; + typedef struct { guint32 capabilities; /* see MDB_SHEXP_* */ MdbBackendType *types_table; MdbBackendType *type_shortdate; MdbBackendType *type_autonum; const char *short_now; const char *long_now; const char *charset_statement; const char *drop_statement; const char *constaint_not_empty_statement; const char *column_comment_statement; const char *table_comment_statement; gchar* (*quote_schema_name)(const gchar*, const gchar*); } MdbBackend; #endif #if !MDB_NO_STATS typedef struct { gboolean collect; unsigned long pg_reads; } MdbStatistics; #endif typedef struct { int fd; gboolean writable; char *filename; guint32 jet_version; guint32 db_key; char db_passwd[14]; #if !MDB_NO_BACKENDS MdbBackend *default_backend; char *backend_name; #endif #if !MDB_NO_STATS MdbStatistics *stats; #endif /* free map */ int map_sz; unsigned char *free_map; /* reference count */ int refs; } MdbFile; /* offset to row count on data pages...version dependant */ +#ifdef _WIN64 +typedef __int64 ssize_t; +#elif defined _WIN32 +typedef _W64 int ssize_t; +#endif typedef struct { ssize_t 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_flags_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; #if !MDB_NO_BACKENDS MdbBackend *default_backend; char *backend_name; #endif MdbFormatConstants *fmt; #if !MDB_NO_STATS MdbStatistics *stats; #endif #ifdef HAVE_ICONV char* jet3_iconv_code; iconv_t iconv_in; 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 */ //int num_props; please use props->len GArray *props; /* GArray of MdbProperties */ GArray *columns; int flags; } MdbCatalogEntry; typedef struct { gchar *name; GHashTable *hash; } MdbProperties; typedef union { int i; double d; char s[256]; } MdbAny; struct S_MdbTableDef; /* forward definition */ typedef struct { struct S_MdbTableDef *table; 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_row; int chunk_size; /* numerics only */ int col_prec; int col_scale; unsigned char is_long_auto; unsigned char is_uuid_auto; MdbProperties *props; /* info needed for handling deleted/added columns */ int fixed_offset; unsigned 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 S_MdbTableDef { 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; size_t map_sz; unsigned char *usage_map; /* pages with free space left */ guint32 freemap_base_pg; size_t 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 MDB_DEPRECATED(void, mdb_init()); -extern MDB_DEPRECATED(void, mdb_exit()); +extern LIBMDB_DLL MDB_DEPRECATED(void, mdb_init()); +extern LIBMDB_DLL MDB_DEPRECATED(void, mdb_exit()); +/* glib - to allow static linking of glib in mdbtools */ +extern LIBMDB_DLL void mdb_g_free (gpointer mem); +extern LIBMDB_DLL gpointer mdb_g_malloc (gsize n_bytes); +extern LIBMDB_DLL gpointer mdb_g_malloc0 (gsize n_bytes); /* 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(void *buf, int offset); -extern int mdb_get_int16(void *buf, int offset); -extern long mdb_get_int32(void *buf, int offset); -extern long mdb_get_int32_msb(void *buf, int offset); -extern float mdb_get_single(void *buf, int offset); -extern double mdb_get_double(void *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 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 void mdb_set_encoding(MdbHandle *mdb, const char *encoding_name); -extern MdbHandle *mdb_open(const 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 LIBMDB_DLL ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg); +extern LIBMDB_DLL ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg); +extern LIBMDB_DLL unsigned char mdb_get_byte(void *buf, int offset); +extern LIBMDB_DLL int mdb_get_int16(char *buf, int offset); +extern LIBMDB_DLL long mdb_get_int32(char *buf, int offset); +extern LIBMDB_DLL long mdb_get_int32_msb(char *buf, int offset); +extern LIBMDB_DLL float mdb_get_single(char *buf, int offset); +extern LIBMDB_DLL double mdb_get_double(char *buf, int offset); +extern LIBMDB_DLL unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset); +extern LIBMDB_DLL int mdb_pg_get_int16(MdbHandle *mdb, int offset); +extern LIBMDB_DLL long mdb_pg_get_int32(MdbHandle *mdb, int offset); +extern LIBMDB_DLL float mdb_pg_get_single(MdbHandle *mdb, int offset); +extern LIBMDB_DLL double mdb_pg_get_double(MdbHandle *mdb, int offset); +extern LIBMDB_DLL void mdb_set_encoding(MdbHandle *mdb, const char *encoding_name); +extern LIBMDB_DLL MdbHandle *mdb_open(const char *filename, MdbFileFlags flags); +extern LIBMDB_DLL void mdb_close(MdbHandle *mdb); +extern LIBMDB_DLL MdbHandle *mdb_clone_handle(MdbHandle *mdb); +extern LIBMDB_DLL void mdb_swap_pgbuf(MdbHandle *mdb); /* catalog.c */ -extern void mdb_free_catalog(MdbHandle *mdb); -extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type); +extern LIBMDB_DLL void mdb_free_catalog(MdbHandle *mdb); +extern LIBMDB_DLL GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type); MdbCatalogEntry *mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name); -extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type); -extern const char *mdb_get_objtype_string(int obj_type); +extern LIBMDB_DLL void mdb_dump_catalog(MdbHandle *mdb, int obj_type); +extern LIBMDB_DLL const 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 guint8 read_pg_if_8(MdbHandle *mdb, int *cur_pos); -extern guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos); -extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos); -extern void *read_pg_if_n(MdbHandle *mdb, void *buf, int *cur_pos, size_t len); -extern int mdb_is_user_table(MdbCatalogEntry *entry); -extern int mdb_is_system_table(MdbCatalogEntry *entry); -extern const char *mdb_table_get_prop(const MdbTableDef *table, const gchar *key); -extern const char *mdb_col_get_prop(const MdbColumn *col, const gchar *key); +extern LIBMDB_DLL MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry); +extern LIBMDB_DLL void mdb_free_tabledef(MdbTableDef *table); +extern LIBMDB_DLL MdbTableDef *mdb_read_table(MdbCatalogEntry *entry); +extern LIBMDB_DLL MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type); +extern LIBMDB_DLL void mdb_append_column(GPtrArray *columns, MdbColumn *in_col); +extern LIBMDB_DLL void mdb_free_columns(GPtrArray *columns); +extern LIBMDB_DLL GPtrArray *mdb_read_columns(MdbTableDef *table); +extern LIBMDB_DLL void mdb_table_dump(MdbCatalogEntry *entry); +extern LIBMDB_DLL guint8 read_pg_if_8(MdbHandle *mdb, int *cur_pos); +extern LIBMDB_DLL guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos); +extern LIBMDB_DLL guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos); +extern LIBMDB_DLL void *read_pg_if_n(MdbHandle *mdb, char *buf, int *cur_pos, size_t len); +extern LIBMDB_DLL int mdb_is_user_table(MdbCatalogEntry *entry); +extern LIBMDB_DLL int mdb_is_system_table(MdbCatalogEntry *entry); +extern LIBMDB_DLL const char *mdb_table_get_prop(const MdbTableDef *table, const gchar *key); +extern LIBMDB_DLL const char *mdb_col_get_prop(const MdbColumn *col, const gchar *key); /* data.c */ -extern int mdb_bind_column_by_name(MdbTableDef *table, const gchar *col_name, void *bind_ptr, int *len_ptr); -extern void mdb_data_dump(MdbTableDef *table); -extern void mdb_date_to_tm(double td, struct tm *t); -extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_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, void *buf, int start, int datatype, int size); -extern int mdb_find_pg_row(MdbHandle *mdb, int pg_row, void **buf, int *off, size_t *len); -extern int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *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 size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr); -extern size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size); -extern void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size); -extern void mdb_set_date_fmt(const char *); -extern int mdb_read_row(MdbTableDef *table, unsigned int row); +extern LIBMDB_DLL int mdb_bind_column_by_name(MdbTableDef *table, const gchar *col_name, void *bind_ptr, int *len_ptr); +extern LIBMDB_DLL void mdb_data_dump(MdbTableDef *table); +extern LIBMDB_DLL void mdb_date_to_tm(double td, struct tm *t); +extern LIBMDB_DLL void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr); +extern LIBMDB_DLL int mdb_rewind_table(MdbTableDef *table); +extern LIBMDB_DLL int mdb_fetch_row(MdbTableDef *table); +extern LIBMDB_DLL int mdb_is_fixed_col(MdbColumn *col); +extern LIBMDB_DLL char *mdb_col_to_string(MdbHandle *mdb, char *buf, int start, int datatype, int size); +extern LIBMDB_DLL int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, size_t *len); +extern LIBMDB_DLL int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len); +extern LIBMDB_DLL int mdb_find_end_of_row(MdbHandle *mdb, int row); +extern LIBMDB_DLL int mdb_col_fixed_size(MdbColumn *col); +extern LIBMDB_DLL int mdb_col_disp_size(MdbColumn *col); +extern LIBMDB_DLL size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr); +extern LIBMDB_DLL size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size); +extern LIBMDB_DLL void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size); +extern LIBMDB_DLL void mdb_set_date_fmt(const char *); +extern LIBMDB_DLL void mdb_set_boolean_fmt_words(); +extern LIBMDB_DLL int mdb_read_row(MdbTableDef *table, unsigned int row); /* dump.c */ -extern void mdb_buffer_dump(const void *buf, int start, size_t len); +extern LIBMDB_DLL void mdb_buffer_dump(const void *buf, int start, size_t len); #if !MDB_NO_BACKENDS /* backend.c */ extern MDB_DEPRECATED(char*, mdb_get_coltype_string(MdbBackend *backend, int col_type)); extern MDB_DEPRECATED(int, mdb_coltype_takes_length(MdbBackend *backend, int col_type)); extern const MdbBackendType* mdb_get_colbacktype(const MdbColumn *col); extern const char* mdb_get_colbacktype_string(const MdbColumn *col); extern int mdb_colbacktype_takes_length(const MdbColumn *col); extern MDB_DEPRECATED(void, mdb_init_backends()); extern void mdb_register_backend(char *backend_name, guint32 capabilities, MdbBackendType *backend_type, MdbBackendType *type_shortdate, MdbBackendType *type_autonum, const char *short_now, const char *long_now, const char *charset_statement, const char *drop_statement, const char *constaint_not_empty_statement, const char *column_comment_statement, const char *table_comment_statement, gchar* (*quote_schema_name)(const gchar*, const gchar*)); extern MDB_DEPRECATED(void, mdb_remove_backends()); extern int mdb_set_default_backend(MdbHandle *mdb, const char *backend_name); extern void mdb_print_schema(MdbHandle *mdb, FILE *outfile, char *tabname, char *dbnamespace, guint32 export_options); #endif /* 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); +extern LIBMDB_DLL int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields); +extern LIBMDB_DLL int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field); +extern LIBMDB_DLL void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data); +extern LIBMDB_DLL int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data); +extern LIBMDB_DLL int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg); +extern LIBMDB_DLL int mdb_test_string(MdbSargNode *node, char *s); +extern LIBMDB_DLL int mdb_test_int(MdbSargNode *node, gint32 i); +extern LIBMDB_DLL 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(char *text, char *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); +extern LIBMDB_DLL GPtrArray *mdb_read_indices(MdbTableDef *table); +extern LIBMDB_DLL void mdb_index_dump(MdbTableDef *table, MdbIndex *idx); +extern LIBMDB_DLL void mdb_index_scan_free(MdbTableDef *table); +extern LIBMDB_DLL int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg); +extern LIBMDB_DLL int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row); +extern LIBMDB_DLL void mdb_index_hash_text(char *text, char *hash); +extern LIBMDB_DLL void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table); +extern LIBMDB_DLL int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row); +extern LIBMDB_DLL void mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest); +extern LIBMDB_DLL void mdb_free_indices(GPtrArray *indices); void mdb_index_page_reset(MdbIndexPage *ipg); -extern int mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg); +extern LIBMDB_DLL int mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg); #if !MDB_NO_STATS /* stats.c */ -extern void mdb_stats_on(MdbHandle *mdb); -extern void mdb_stats_off(MdbHandle *mdb); -extern void mdb_dump_stats(MdbHandle *mdb); +extern LIBMDB_DLL void mdb_stats_on(MdbHandle *mdb); +extern LIBMDB_DLL void mdb_stats_off(MdbHandle *mdb); +extern LIBMDB_DLL void mdb_dump_stats(MdbHandle *mdb); #endif /* like.c */ -extern int mdb_like_cmp(char *s, char *r); +extern LIBMDB_DLL int mdb_like_cmp(char *s, char *r); /* write.c */ -extern void mdb_put_int16(void *buf, guint32 offset, guint32 value); -extern void mdb_put_int32(void *buf, guint32 offset, guint32 value); -extern void mdb_put_int32_msb(void *buf, guint32 offset, guint32 value); -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_insert_row(MdbTableDef *table, int num_fields, MdbField *fields); -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, void *new_row, int new_row_size); -extern int mdb_pg_get_freespace(MdbHandle *mdb); -extern int mdb_update_row(MdbTableDef *table); -extern void *mdb_new_data_pg(MdbCatalogEntry *entry); +extern LIBMDB_DLL void mdb_put_int16(char *buf, guint32 offset, guint32 value); +extern LIBMDB_DLL void mdb_put_int32(char *buf, guint32 offset, guint32 value); +extern LIBMDB_DLL void mdb_put_int32_msb(char *buf, guint32 offset, guint32 value); +extern LIBMDB_DLL int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields); +extern LIBMDB_DLL guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size); +extern LIBMDB_DLL int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum); +extern LIBMDB_DLL int mdb_insert_row(MdbTableDef *table, int num_fields, MdbField *fields); +extern LIBMDB_DLL int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields); +extern LIBMDB_DLL int mdb_replace_row(MdbTableDef *table, int row, void *new_row, int new_row_size); +extern LIBMDB_DLL int mdb_pg_get_freespace(MdbHandle *mdb); +extern LIBMDB_DLL int mdb_update_row(MdbTableDef *table); +extern LIBMDB_DLL void *mdb_new_data_pg(MdbCatalogEntry *entry); /* map.c */ -extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size); -extern gint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg); +extern LIBMDB_DLL guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size); +extern LIBMDB_DLL gint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg); /* props.c */ -extern void mdb_free_props(MdbProperties *props); -extern void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name); -extern GArray* mdb_kkd_to_props(MdbHandle *mdb, void *kkd, size_t len); +extern LIBMDB_DLL void mdb_free_props(MdbProperties *props); +extern LIBMDB_DLL void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name); +extern LIBMDB_DLL GArray* mdb_kkd_to_props(MdbHandle *mdb, char *kkd, size_t 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); +extern LIBMDB_DLL MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name); +extern LIBMDB_DLL void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col); +extern LIBMDB_DLL void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed); +extern LIBMDB_DLL void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int column); +extern LIBMDB_DLL void mdb_temp_columns_end(MdbTableDef *table); /* options.c */ -extern int mdb_get_option(unsigned long optnum); -extern void mdb_debug(int klass, const char *fmt, ...); +extern LIBMDB_DLL int mdb_get_option(unsigned long optnum); +extern LIBMDB_DLL void mdb_debug(int klass, const char *fmt, ...); /* iconv.c */ -extern int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); -extern int mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); -extern void mdb_iconv_init(MdbHandle *mdb); -extern void mdb_iconv_close(MdbHandle *mdb); -extern const char* mdb_target_charset(MdbHandle *mdb); +extern LIBMDB_DLL int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); +extern LIBMDB_DLL int mdb_ascii2unicode(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen); +extern LIBMDB_DLL void mdb_iconv_init(MdbHandle *mdb); +extern LIBMDB_DLL void mdb_iconv_close(MdbHandle *mdb); +extern LIBMDB_DLL const char* mdb_target_charset(MdbHandle *mdb); #ifdef __cplusplus } #endif #endif /* _mdbtools_h_ */ diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c index 47366527c..190dab0b0 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/catalog.c @@ -1,174 +1,174 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif const char * mdb_get_objtype_string(int obj_type) { static const char *type_name[] = {"Form", "Table", "Macro", "System Table", "Report", "Query", "Linked Table", "Module", "Relationship", "Unknown 0x09", "User Info", "Database" }; if (obj_type > 11) { return NULL; } else { return type_name[obj_type]; } } void mdb_free_catalog(MdbHandle *mdb) { unsigned int i, j; MdbCatalogEntry *entry; if ((!mdb) || (!mdb->catalog)) return; for (i=0; icatalog->len; i++) { entry = (MdbCatalogEntry *)g_ptr_array_index(mdb->catalog, i); if (entry) { if (entry->props) { for (j=0; jprops->len; j++) mdb_free_props(g_array_index(entry->props, MdbProperties*, j)); g_array_free(entry->props, TRUE); } g_free(entry); } } 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[MDB_MAX_OBJ_NAME]; char obj_type[256]; char obj_flags[256]; char obj_props[MDB_BIND_SIZE]; int type; unsigned int i; MdbColumn *col_props; int kkd_size_ole; if (!mdb) return NULL; 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, NULL); mdb_bind_column_by_name(table, "Name", obj_name, NULL); mdb_bind_column_by_name(table, "Type", obj_type, NULL); mdb_bind_column_by_name(table, "Flags", obj_flags, NULL); i = mdb_bind_column_by_name(table, "LvProp", obj_props, &kkd_size_ole); col_props = g_ptr_array_index(table->columns, i-1); mdb_rewind_table(table); while (mdb_fetch_row(table)) { type = atoi(obj_type); if (objtype==MDB_ANY || type == objtype) { //fprintf(stderr, "obj_id: %10ld objtype: %-3d (0x%04x) obj_name: %s\n", // (atol(obj_id) & 0x00FFFFFF), type, 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); if (kkd_size_ole) { size_t kkd_len; void *kkd = mdb_ole_read_full(mdb, col_props, &kkd_len); //mdb_buffer_dump(kkd, 0, kkd_len); entry->props = mdb_kkd_to_props(mdb, kkd, kkd_len); free(kkd); } } } //mdb_dump_catalog(mdb, MDB_TABLE); mdb_free_tabledef(table); return mdb->catalog; } MdbCatalogEntry * mdb_get_catalogentry_by_name(MdbHandle *mdb, const gchar* name) { unsigned int i; MdbCatalogEntry *entry; for (i=0; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); - if (!strcasecmp(entry->object_name, name)) + if (!g_ascii_strcasecmp(entry->object_name, name)) return entry; } return NULL; } void mdb_dump_catalog(MdbHandle *mdb, int obj_type) { unsigned int i; MdbCatalogEntry *entry; mdb_read_catalog(mdb, obj_type); for (i=0;inum_catalog;i++) { entry = g_ptr_array_index(mdb->catalog,i); if (obj_type==MDB_ANY || entry->object_type==obj_type) { printf("Type: %-12s Name: %-48s Page: %06lx\n", mdb_get_objtype_string(entry->object_type), entry->object_name, entry->table_pg); } } return; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c index 756aefb53..40e3c76d3 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/data.c @@ -1,1038 +1,1062 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define OFFSET_MASK 0x1fff char *mdb_money_to_string(MdbHandle *mdb, int start); char *mdb_numeric_to_string(MdbHandle *mdb, int start, int prec, int scale); static int _mdb_attempt_bind(MdbHandle *mdb, MdbColumn *col, unsigned char isnull, int offset, int len); -static char *mdb_date_to_string(MdbHandle *mdb, int start); +static char *mdb_date_to_string(void *buf, int start); #ifdef MDB_COPY_OLE static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size); #endif static char date_fmt[64] = "%x %X"; void mdb_set_date_fmt(const char *fmt) { date_fmt[63] = 0; strncpy(date_fmt, fmt, 63); } +/* Some databases (eg PostgreSQL) do not understand integer 0/1 values + * as TRUE/FALSE, so provide a means to override the values used to be + * the SQL Standard TRUE/FALSE values. + */ +static char boolean_false_number[] = "0"; +static char boolean_true_number[] = "1"; + +static char boolean_false_word[] = "FALSE"; +static char boolean_true_word[] = "TRUE"; + +static char *boolean_false_value = boolean_false_number; +static char *boolean_true_value = boolean_true_number; + +void mdb_set_boolean_fmt_words() +{ + boolean_false_value = boolean_false_word; + boolean_true_value = boolean_true_word; +} + void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_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); if (bind_ptr) col->bind_ptr = bind_ptr; if (len_ptr) col->len_ptr = len_ptr; } int mdb_bind_column_by_name(MdbTableDef *table, const gchar *col_name, void *bind_ptr, int *len_ptr) { unsigned int i; int col_num = -1; MdbColumn *col; for (i=0;inum_cols;i++) { col=g_ptr_array_index(table->columns,i); - if (!strcasecmp(col->name,col_name)) { + if (!g_ascii_strcasecmp(col->name,col_name)) { col_num = i + 1; if (bind_ptr) col->bind_ptr = bind_ptr; if (len_ptr) col->len_ptr = len_ptr; break; } } return col_num; } /** * 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, void **buf, int *off, size_t *len) +int mdb_find_pg_row(MdbHandle *mdb, int pg_row, char **buf, int *off, size_t *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); mdb_find_row(mdb, row, off, len); mdb_swap_pgbuf(mdb); - *buf = mdb->alt_pg_buf; + *buf =(char *)mdb->alt_pg_buf; return 0; } int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len) { int rco = mdb->fmt->row_count_offset; int next_start; if (row > 1000) return -1; - *start = mdb_get_int16(mdb->pg_buf, rco + 2 + row*2); + *start = mdb_get_int16((char *)mdb->pg_buf, rco + 2 + row*2); next_start = (row == 0) ? mdb->fmt->pg_size : - mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; + mdb_get_int16((char *)mdb->pg_buf, rco + row*2) & OFFSET_MASK; *len = next_start - (*start & OFFSET_MASK); return 0; } int mdb_find_end_of_row(MdbHandle *mdb, int row) { int rco = mdb->fmt->row_count_offset; int row_end; #if 1 if (row > 1000) return -1; row_end = (row == 0) ? mdb->fmt->pg_size : - mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; + mdb_get_int16((char *)mdb->pg_buf, rco + row*2) & OFFSET_MASK; #else /* 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. */ int i, row_start; if (row > 1000) return -1; /* if lookupflag is not set, it's good (deleteflag is ok) */ for (i = row; i > 0; i--) { row_start = mdb_get_int16(mdb->pg_buf, (rco + i*2)); if (!(row_start & 0x8000)) { break; } } row_end = (i == 0) ? mdb->fmt->pg_size : row_start & OFFSET_MASK; #endif return row_end - 1; } 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 size_t 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"); + strcpy(col->bind_ptr, + value ? boolean_false_value : boolean_true_value); } if (col->len_ptr) { - *col->len_ptr = 1; + *col->len_ptr = strlen(col->bind_ptr); } return 1; } static size_t mdb_xfer_bound_ole(MdbHandle *mdb, int start, MdbColumn *col, int len) { size_t 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; } #ifdef MDB_COPY_OLE if (col->bind_ptr || col->len_ptr) { ret = mdb_copy_ole(mdb, col->bind_ptr, start, len); } #else if (col->bind_ptr) { memcpy(col->bind_ptr, mdb->pg_buf + start, MDB_MEMO_OVERHEAD); } ret = MDB_MEMO_OVERHEAD; #endif if (col->len_ptr) { *col->len_ptr = ret; } return ret; } static size_t 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 { //fprintf(stdout,"len %d size %d\n",len, col->col_size); char *str; if (col->col_type == MDB_NUMERIC) { str = mdb_numeric_to_string(mdb, start, col->col_prec, col->col_scale); } else { - str = mdb_col_to_string(mdb, mdb->pg_buf, start, col->col_type, len); + str = mdb_col_to_string(mdb, (char *)mdb->pg_buf, start, col->col_type, len); } strcpy(col->bind_ptr, str); g_free(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; MdbColumn *col; unsigned int i; int row_start; size_t row_size; int delflag, lookupflag; MdbField fields[256]; int num_fields; if (table->num_rows == 0) return 0; if (mdb_find_row(mdb, row, &row_start, &row_size)) { fprintf(stderr, "warning: mdb_find_row failed."); return 0; } 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_start + row_size - 1, lookupflag ? "[lookup]" : "", delflag ? "[delflag]" : ""); #endif if (!table->noskip_del && delflag) { return 0; } num_fields = mdb_crack_row(table, row_start, row_start + row_size - 1, 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 mdb_buffer_dump(mdb->pg_buf, row_start, row_size); #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); _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; } /* Read next data page into mdb->pg_buf */ int mdb_read_next_dpg(MdbTableDef *table) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; int next_pg; #ifndef SLOW_READ while (1) { next_pg = mdb_map_find_next(mdb, table->usage_map, table->map_sz, table->cur_phys_pg); if (next_pg < 0) break; /* unknow map type: goto fallback */ if (!next_pg) return 0; if (!mdb_read_pg(mdb, next_pg)) { fprintf(stderr, "error: reading page %d failed.\n", next_pg); return 0; } table->cur_phys_pg = next_pg; - if (mdb->pg_buf[0]==MDB_PAGE_DATA && mdb_get_int32(mdb->pg_buf, 4)==entry->table_pg) + if (mdb->pg_buf[0]==MDB_PAGE_DATA && mdb_get_int32((char *)mdb->pg_buf, 4)==entry->table_pg) return table->cur_phys_pg; /* On rare occasion, mdb_map_find_next will return a wrong page */ /* Found in a big file, over 4,000,000 records */ fprintf(stderr, "warning: page %d from map doesn't match: Type=%d, buf[4..7]=%ld Expected table_pg=%ld\n", - next_pg, mdb->pg_buf[0], mdb_get_int32(mdb->pg_buf, 4), entry->table_pg); + next_pg, mdb->pg_buf[0], mdb_get_int32((char *)mdb->pg_buf, 4), entry->table_pg); } 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]!=MDB_PAGE_DATA || mdb_get_int32(mdb->pg_buf, 4)!=entry->table_pg); + } while (mdb->pg_buf[0]!=MDB_PAGE_DATA || mdb_get_int32((char *)mdb->pg_buf, 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_get_int16(mdb->pg_buf,fmt->row_count_offset); + rows = mdb_get_int16((char *)mdb->pg_buf, fmt->row_count_offset); /* if at end of page, find a new data 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;inum_cols;i++) { bound_values[i] = (char *) g_malloc(256); mdb_bind_column(table, i+1, bound_values[i], NULL); } mdb_rewind_table(table); while (mdb_fetch_row(table)) { for (i=0;inum_cols;i++) { fprintf(stdout, "column %d is %s\n", i+1, bound_values[i]); } } for (i=0;inum_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; ipg_buf[i]); } text[(i-start)*2]='\0'; return text; } #endif /* * ole_ptr should point to the original blob value of the field. * If omited, there will be no multi-page check to that the caller is * responsible for not calling this function. Then, it doesn't have to * preserve the original value. */ size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr) { guint32 ole_len; - void *buf; + char *buf; int row_start; size_t len; if (ole_ptr) { ole_len = mdb_get_int32(ole_ptr, 0); mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", ole_len & 0x00ffffff, ole_len >> 24); if ((ole_len & 0x80000000) || (ole_len & 0x40000000)) /* inline or single-page fields don't have a next */ return 0; } mdb_debug(MDB_DEBUG_OLE, "pg_row %d", col->cur_blob_pg_row); if (!col->cur_blob_pg_row) return 0; /* we are done */ if (mdb_find_pg_row(mdb, col->cur_blob_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, (char*)buf + row_start + 4, len - 4); + memcpy(col->bind_ptr, buf + row_start + 4, len - 4); col->cur_blob_pg_row = mdb_get_int32(buf, row_start); return len - 4; } size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size) { guint32 ole_len; - void *buf; + char *buf; int row_start; size_t len; ole_len = mdb_get_int32(ole_ptr, 0); mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", ole_len & 0x00ffffff, ole_len >> 24); col->chunk_size = chunk_size; if (ole_len & 0x80000000) { /* inline ole field, if we can satisfy it, then do it */ len = col->cur_value_len - MDB_MEMO_OVERHEAD; if ((size_t)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_len & 0x40000000) { col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", col->cur_blob_pg_row & 0xff, col->cur_blob_pg_row >> 8); if (mdb_find_pg_row(mdb, col->cur_blob_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, (char*)buf + row_start, len); + memcpy(col->bind_ptr, buf + row_start, len); if (mdb_get_option(MDB_DEBUG_OLE)) mdb_buffer_dump(col->bind_ptr, 0, 16); } return len; - } else if ((ole_len & 0xff000000) == 0) { + } else if ((ole_len & 0xf0000000) == 0) { col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", col->cur_blob_pg_row & 0xff, col->cur_blob_pg_row >> 8); if (mdb_find_pg_row(mdb, col->cur_blob_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, (char*)buf + row_start + 4, len - 4); + memcpy(col->bind_ptr, buf + row_start + 4, len - 4); col->cur_blob_pg_row = mdb_get_int32(buf, row_start); mdb_debug(MDB_DEBUG_OLE, "next pg_row %d", col->cur_blob_pg_row); return len - 4; } else { fprintf(stderr,"Unhandled ole field flags = %02x\n", ole_len >> 24); return 0; } } /* * mdb_ole_read_full calls mdb_ole_read then loop over mdb_ole_read_next as much as necessary. * returns the result in a big buffer. * The call must free it. * Note that this function is not indempotent: It may be called only once per column after each bind. */ void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size) { char ole_ptr[MDB_MEMO_OVERHEAD]; char *result = malloc(MDB_BIND_SIZE); size_t result_buffer_size = MDB_BIND_SIZE; size_t len, pos; memcpy(ole_ptr, col->bind_ptr, MDB_MEMO_OVERHEAD); len = mdb_ole_read(mdb, col, ole_ptr, MDB_BIND_SIZE); memcpy(result, col->bind_ptr, len); pos = len; while ((len = mdb_ole_read_next(mdb, col, ole_ptr))) { if (pos+len >= result_buffer_size) { result_buffer_size += MDB_BIND_SIZE; result = realloc(result, result_buffer_size); } memcpy(result + pos, col->bind_ptr, len); pos += len; } if (size) *size = pos; return result; } #ifdef MDB_COPY_OLE static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size) { guint32 ole_len; gint32 row_start, pg_row; size_t len; - void *buf, *pg_buf = mdb->pg_buf; + char *buf, *pg_buf = mdb->pg_buf; if (size> 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, (char*)buf + row_start, len); return len; } else if ((ole_len & 0xff000000) == 0) { // assume all flags in MSB /* multi-page */ int cur = 0; pg_row = mdb_get_int32(pg_buf, start+4); do { 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+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 = %02x\n", ole_len >> 24); return 0; } } #endif static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) { guint32 memo_len; gint32 row_start, pg_row; size_t len; - void *buf, *pg_buf = mdb->pg_buf; + char *buf, *pg_buf = (char *)mdb->pg_buf; char *text = (char *) g_malloc(MDB_BIND_SIZE); if (size> 8); #endif if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { strcpy(text, ""); return text; } #if MDB_DEBUG printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); mdb_buffer_dump(buf, row_start, len); #endif - mdb_unicode2ascii(mdb, (char*)buf + row_start, len, text, MDB_BIND_SIZE); + mdb_unicode2ascii(mdb, buf + row_start, len, text, MDB_BIND_SIZE); return text; } else if ((memo_len & 0xff000000) == 0) { // assume all flags in MSB /* multi-page memo field */ guint32 tmpoff = 0; char *tmp; - tmp = (char *) g_malloc(memo_len); + tmp = (char *)g_malloc(memo_len); pg_row = mdb_get_int32(pg_buf, start+4); do { #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)) { g_free(tmp); strcpy(text, ""); return text; } #if MDB_DEBUG printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); #endif - if (tmpoff + len - 4 > memo_len) { + if (tmpoff + len - 4 > memo_len) break; - } - memcpy(tmp + tmpoff, (char*)buf + row_start + 4, len - 4); + + /* Stop processing on zero length multiple page memo fields */ + if (!len) + break; + + memcpy(tmp + tmpoff, buf + row_start + 4, len - 4); tmpoff += len - 4; } while (( pg_row = mdb_get_int32(buf, row_start) )); if (tmpoff < memo_len) { fprintf(stderr, "Warning: incorrect memo length\n"); } mdb_unicode2ascii(mdb, tmp, tmpoff, text, MDB_BIND_SIZE); g_free(tmp); return text; } else { fprintf(stderr, "Unhandled memo field flags = %02x\n", memo_len >> 24); strcpy(text, ""); return text; } } #if 0 static int trim_trailing_zeros(char * buff) { char *p; int n = strlen(buff); /* Don't need to trim strings with no decimal portion */ if(!strchr(buff,'.')) return 0; /* Trim the zeros */ p = buff + n - 1; while (p >= buff && *p == '0') *p-- = '\0'; /* If a decimal sign is left at the end, remove it too */ if (*p == '.') *p = '\0'; return 0; } #endif /* Date/Time is stored as a double, where the whole part is the days from 12/30/1899 and the fractional part is the fractional part of one day. */ void mdb_date_to_tm(double td, struct tm *t) { long int day, time; int yr, q; int *cal; int noleap_cal[] = {0,31,59,90,120,151,181,212,243,273,304,334,365}; int leap_cal[] = {0,31,60,91,121,152,182,213,244,274,305,335,366}; day = (long int)(td); time = (long int)(fabs(td - day) * 86400.0 + 0.5); t->tm_hour = time / 3600; t->tm_min = (time / 60) % 60; t->tm_sec = time % 60; t->tm_year = 1 - 1900; day += 693593; /* Days from 1/1/1 to 12/31/1899 */ t->tm_wday = (day+1) % 7; q = day / 146097; /* 146097 days in 400 years */ t->tm_year += 400 * q; day -= q * 146097; q = day / 36524; /* 36524 days in 100 years */ if (q > 3) q = 3; t->tm_year += 100 * q; day -= q * 36524; q = day / 1461; /* 1461 days in 4 years */ t->tm_year += 4 * q; day -= q * 1461; q = day / 365; /* 365 days in 1 year */ if (q > 3) q = 3; t->tm_year += q; day -= q * 365; yr = t->tm_year + 1900; cal = ((yr)%4==0 && ((yr)%100!=0 || (yr)%400==0)) ? leap_cal : noleap_cal; for (t->tm_mon=0; t->tm_mon<12; t->tm_mon++) { if (day < cal[t->tm_mon+1]) break; } t->tm_mday = day - cal[t->tm_mon] + 1; t->tm_yday = day; t->tm_isdst = -1; } static char * -mdb_date_to_string(MdbHandle *mdb, int start) +mdb_date_to_string(void *buf, int start) { struct tm t; char *text = (char *) g_malloc(MDB_BIND_SIZE); - double td = mdb_get_double(mdb->pg_buf, start); + double td = mdb_get_double(buf, start); mdb_date_to_tm(td, &t); strftime(text, MDB_BIND_SIZE, date_fmt, &t); return text; } static char * mdb_uuid_to_string(MdbHandle *mdb, int start) { char *text = NULL; unsigned short uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8; - uuid1 = mdb_get_int16(mdb->pg_buf, start); - uuid2 = mdb_get_int16(mdb->pg_buf, start + 2); - uuid3 = mdb_get_int16(mdb->pg_buf, start + 4); - uuid4 = mdb_get_int16(mdb->pg_buf, start + 6); - uuid5 = mdb_get_int16(mdb->pg_buf, start + 8); - uuid6 = mdb_get_int16(mdb->pg_buf, start + 10); - uuid7 = mdb_get_int16(mdb->pg_buf, start + 12); - uuid8 = mdb_get_int16(mdb->pg_buf, start + 14); + uuid1 = mdb_get_int16((char *)mdb->pg_buf, start); + uuid2 = mdb_get_int16((char *)mdb->pg_buf, start + 2); + uuid3 = mdb_get_int16((char *)mdb->pg_buf, start + 4); + uuid4 = mdb_get_int16((char *)mdb->pg_buf, start + 6); + uuid5 = mdb_get_int16((char *)mdb->pg_buf, start + 8); + uuid6 = mdb_get_int16((char *)mdb->pg_buf, start + 10); + uuid7 = mdb_get_int16((char *)mdb->pg_buf, start + 12); + uuid8 = mdb_get_int16((char *)mdb->pg_buf, start + 14); text = g_strdup_printf("{%04x%04x-%04x-%04x-%04x-%04x%04x%04x}", uuid1, uuid2, uuid3, uuid4, uuid5, uuid6, uuid7, uuid8); return text; } #if 0 int floor_log10(double f, int is_single) { unsigned int i; double y = 10.0; if (f < 0.0) f = -f; if ((f == 0.0) || (f == 1.0) || isinf(f)) { return 0; } else if (f < 1.0) { if (is_single) { /* The intermediate value p is necessary to prevent * promotion of the comparison to type double */ float p; for (i=1; (p = f * y) < 1.0; i++) y *= 10.0; } else { for (i=1; f * y < 1.0; i++) y *= 10.0; } return -(int)i; } else { /* (x > 1.0) */ for (i=0; f >= y; i++) y *= 10.0; return (int)i; } } #endif -char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int size) +char *mdb_col_to_string(MdbHandle *mdb, char *buf, int start, int datatype, int size) { char *text = NULL; 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: text = g_strdup_printf("%d", mdb_get_byte(buf, start)); break; case MDB_INT: text = g_strdup_printf("%hd", (short)mdb_get_int16(buf, start)); break; case MDB_LONGINT: case MDB_COMPLEX: text = g_strdup_printf("%ld", mdb_get_int32(buf, start)); break; case MDB_FLOAT: tf = mdb_get_single(buf, start); text = g_strdup_printf("%.8e", tf); break; case MDB_DOUBLE: td = mdb_get_double(buf, start); text = g_strdup_printf("%.16e", td); break; case MDB_BINARY: if (size<0) { text = g_strdup(""); } else { text = g_malloc(size); - memcpy((char*)buf+start, text, size); + memcpy(text, buf+start, size); } break; case MDB_TEXT: if (size<0) { text = g_strdup(""); } else { text = (char *) g_malloc(MDB_BIND_SIZE); - mdb_unicode2ascii(mdb, (char*)buf + start, + mdb_unicode2ascii(mdb, buf + start, size, text, MDB_BIND_SIZE); } break; case MDB_DATETIME: - text = mdb_date_to_string(mdb, start); + text = mdb_date_to_string(buf, start); break; case MDB_MEMO: text = mdb_memo_to_string(mdb, start, size); break; case MDB_MONEY: text = mdb_money_to_string(mdb, start); case MDB_NUMERIC: break; case MDB_REPID: text = mdb_uuid_to_string(mdb, start); break; default: text = g_strdup(""); break; } return text; } 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: case MDB_COMPLEX: 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_DATETIME: return 20; break; case MDB_MEMO: return 64000; 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: case MDB_COMPLEX: return 4; break; case MDB_FLOAT: return 4; break; case MDB_DOUBLE: return 8; break; case MDB_TEXT: return -1; break; case MDB_DATETIME: return 4; break; case MDB_BINARY: return -1; break; case MDB_MEMO: return -1; break; case MDB_MONEY: return 8; break; } return 0; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c index 905dd0d6b..74f0c9f2c 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/file.c @@ -1,544 +1,543 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #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_flags_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 }; typedef struct _RC4_KEY { unsigned char state[256]; unsigned char x; unsigned char y; } RC4_KEY; #define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg); static void RC4_set_key(RC4_KEY *key, int key_data_len, unsigned char *key_data_ptr) { unsigned char t; unsigned char index1; unsigned char index2; unsigned char* state; short counter; state = &key->state[0]; for(counter = 0; counter < 256; counter++) state[counter] = counter; key->x = 0; key->y = 0; index1 = 0; index2 = 0; for(counter = 0; counter < 256; counter++) { index2 = (key_data_ptr[index1] + state[counter] + index2) % 256; swap_byte(&state[counter], &state[index2]); index1 = (index1 + 1) % key_data_len; } } /* * this algorithm does 'encrypt in place' instead of inbuff/outbuff * note also: encryption and decryption use same routine * implementation supplied by (Adam Back) at */ static void RC4(RC4_KEY *key, int buffer_len, unsigned char * buff) { unsigned char t; unsigned char x; unsigned char y; unsigned char* state; unsigned char xorIndex; short counter; x = key->x; y = key->y; state = &key->state[0]; for(counter = 0; counter < buffer_len; counter++) { x = (x + 1) % 256; y = (state[x] + y) % 256; swap_byte(&state[x], &state[y]); xorIndex = (state[x] + state[y]) % 256; buff[counter] ^= state[xorIndex]; } key->x = x; key->y = y; } /** * 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)) { char *result; result = g_strdup(file_name); if (!result) fprintf(stderr, "Can't alloc filename\n"); return result; } /* 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 key[] = {0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, 0xe6, 0x13, 0xb6}; int j, pos; 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, "File not found\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); + mdb->f->jet_version = mdb_get_int32((char *)mdb->pg_buf, 0x14); switch(mdb->f->jet_version) { case MDB_VER_JET3: mdb->fmt = &MdbJet3Constants; break; case MDB_VER_JET4: case MDB_VER_ACCDB_2007: case MDB_VER_ACCDB_2010: mdb->fmt = &MdbJet4Constants; break; default: fprintf(stderr,"Unknown Jet version.\n"); mdb_close(mdb); return NULL; } - mdb->f->db_key = mdb_get_int32(mdb->pg_buf, 0x3e); + mdb->f->db_key = mdb_get_int32((char *)mdb->pg_buf, 0x3e); /* I don't know if this value is valid for some versions? * it doesn't seem to be valid for the databases I have * * f->db_key ^= 0xe15e01b9; */ mdb->f->db_key ^= 0x4ebc8afb; /* fprintf(stderr, "Encrypted file, RC4 key seed= %d\n", mdb->f->db_key); */ if (mdb->f->db_key) { /* write is not supported for encrypted files yet */ mdb->f->writable = FALSE; - /* that should be enought, but reopen the file read only just to be + /* that should be enough, but reopen the file read only just to be * sure we don't write invalid data */ close(mdb->f->fd); 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 ropen file %s in read only\n", mdb->f->filename); mdb_close(mdb); return NULL; } } /* get the db password located at 0x42 bytes into the file */ for (pos=0;pos<14;pos++) { - j = mdb_get_int32(mdb->pg_buf, 0x42+pos); + j = mdb_get_int32((char *)mdb->pg_buf, 0x42+pos); j ^= key[pos]; if ( j != 0) mdb->f->db_passwd[pos] = j; else mdb->f->db_passwd[pos] = '\0'; } 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;inum_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); //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, void *pg_buf, unsigned long pg) { ssize_t len; struct stat status; off_t offset = pg * mdb->fmt->pg_size; if (fstat(mdb->f->fd, &status) != 0) { perror("fstat"); return 0; } if (status.st_size < offset) { - fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset); + fprintf(stderr,"offset %jd is beyond EOF\n",offset); return 0; } #if !MDB_NO_STATS if (mdb->stats && mdb->stats->collect) mdb->stats->pg_reads++; #endif if (lseek(mdb->f->fd, offset, SEEK_SET) == -1) { perror("lseek"); return 0; } len = read(mdb->f->fd,pg_buf,mdb->fmt->pg_size); if (len==-1) { perror("read"); return 0; } else if (lenfmt->pg_size) { /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */ return 0; } /* * unencrypt the page if necessary. * it might make sense to cache the unencrypted data blocks? */ if (pg != 0 && mdb->f->db_key != 0) { RC4_KEY rc4_key; unsigned int tmp_key = mdb->f->db_key ^ pg; RC4_set_key(&rc4_key, 4, (unsigned char *)&tmp_key); RC4(&rc4_key, mdb->fmt->pg_size, pg_buf); } 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) +int mdb_get_int16(char *buf, int offset) { guint16 l; - memcpy(&l, (char*)buf + offset, 2); + memcpy(&l, 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); + return mdb_get_int16((char *)mdb->pg_buf, offset); } -long mdb_get_int32_msb(void *buf, int offset) +long mdb_get_int32_msb(char *buf, int offset) { gint32 l; - memcpy(&l, (char*)buf + offset, 4); + memcpy(&l, buf + offset, 4); return (long)GINT32_FROM_BE(l); } -long mdb_get_int32(void *buf, int offset) +long mdb_get_int32(char *buf, int offset) { gint32 l; - memcpy(&l, (char*)buf + offset, 4); + 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) > (int)mdb->fmt->pg_size) return -1; mdb->cur_pos+=4; - return mdb_get_int32(mdb->pg_buf, offset); + return mdb_get_int32((char *)mdb->pg_buf, offset); } -float mdb_get_single(void *buf, int offset) +float mdb_get_single(char *buf, int offset) { union {guint32 g; float f;} f; - memcpy(&f, (char*)buf + offset, 4); + 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) > (int)mdb->fmt->pg_size) return -1; mdb->cur_pos+=4; - return mdb_get_single(mdb->pg_buf, offset); + return mdb_get_single((char *)mdb->pg_buf, offset); } -double mdb_get_double(void *buf, int offset) +double mdb_get_double(char *buf, int offset) { union {guint64 g; double d;} d; - memcpy(&d, (char*)buf + offset, 8); + 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) > (int)mdb->fmt->pg_size) return -1; mdb->cur_pos+=8; - return mdb_get_double(mdb->pg_buf, offset); + return mdb_get_double((char *)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; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c index 7f19cc08f..a62d6161d 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/iconv.c @@ -1,249 +1,256 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #ifdef _WIN32 #include #endif /* * This function is used in reading text data from an MDB table. */ int mdb_unicode2ascii(MdbHandle *mdb, char *src, size_t slen, char *dest, size_t dlen) { char *tmp = NULL; size_t tlen = 0; size_t len_in, len_out; char *in_ptr, *out_ptr; if ((!src) || (!dest) || (!dlen)) return 0; /* Uncompress 'Unicode Compressed' string into tmp */ if (!IS_JET3(mdb) && (slen>=2) && ((src[0]&0xff)==0xff) && ((src[1]&0xff)==0xfe)) { unsigned int compress=1; src += 2; slen -= 2; - tmp = (char *)g_malloc(slen*2); + tmp = g_malloc(slen*2); while (slen) { if (*src == 0) { compress = (compress) ? 0 : 1; src++; slen--; } else if (compress) { tmp[tlen++] = *src++; tmp[tlen++] = 0; slen--; } else if (slen >= 2){ tmp[tlen++] = *src++; tmp[tlen++] = *src++; slen-=2; } } } in_ptr = (tmp) ? tmp : src; out_ptr = dest; len_in = (tmp) ? tlen : slen; len_out = dlen; #if HAVE_ICONV //printf("1 len_in %d len_out %d\n",len_in, len_out); while (1) { iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out); + /* + * Have seen database with odd number of bytes in UCS-2, shouldn't happen but protect against it + */ + if (!IS_JET3(mdb) && len_in<=1) { + //fprintf(stderr, "Detected invalid number of UCS-2 bytes\n"); + break; + } if ((!len_in) || (errno == E2BIG)) break; /* Don't bail if impossible conversion is encountered */ in_ptr += (IS_JET3(mdb)) ? 1 : 2; len_in -= (IS_JET3(mdb)) ? 1 : 2; *out_ptr++ = '?'; len_out--; } //printf("2 len_in %d len_out %d\n",len_in, len_out); dlen -= len_out; #else if (IS_JET3(mdb)) { size_t copy_len = len_in; if (copy_len > dlen) copy_len = dlen; strncpy(out_ptr, in_ptr, copy_len); dlen = copy_len; } else { /* rough UCS-2LE to ISO-8859-1 conversion */ unsigned int i; for (i=0; iiconv_out, &in_ptr, &len_in, &out_ptr, &len_out); //printf("len_in %d len_out %d\n", len_in, len_out); dlen -= len_out; #else if (IS_JET3(mdb)) { dlen = MIN(len_in, len_out); strncpy(out_ptr, in_ptr, dlen); } else { unsigned int i; slen = MIN(len_in, len_out/2); dlen = slen*2; for (i=0; i4)) { unsigned char *tmp = g_malloc(dlen); unsigned int tptr = 0, dptr = 0; int comp = 1; tmp[tptr++] = 0xff; tmp[tptr++] = 0xfe; while((dptr < dlen) && (tptr < dlen)) { if (((dest[dptr+1]==0) && (comp==0)) || ((dest[dptr+1]!=0) && (comp==1))) { /* switch encoding mode */ tmp[tptr++] = 0; comp = (comp) ? 0 : 1; } else if (dest[dptr]==0) { /* this string cannot be compressed */ tptr = dlen; } else if (comp==1) { /* encode compressed character */ tmp[tptr++] = dest[dptr]; dptr += 2; } else if (tptr+1 < dlen) { /* encode uncompressed character */ tmp[tptr++] = dest[dptr]; tmp[tptr++] = dest[dptr+1]; dptr += 2; } else { /* could not encode uncompressed character * into single byte */ tptr = dlen; } } if (tptr < dlen) { memcpy(dest, tmp, tptr); dlen = tptr; } g_free(tmp); } return dlen; } const char* mdb_target_charset(MdbHandle *mdb) { #ifdef HAVE_ICONV const char *iconv_code = getenv("MDBICONV"); if (!iconv_code) iconv_code = "UTF-8"; return iconv_code; #else if (!IS_JET3(mdb)) return "ISO-8859-1"; return NULL; // same as input: unknown #endif } void mdb_iconv_init(MdbHandle *mdb) { const char *iconv_code; /* check environment variable */ if (!(iconv_code=getenv("MDBICONV"))) { iconv_code="UTF-8"; } #ifdef HAVE_ICONV if (!IS_JET3(mdb)) { mdb->iconv_out = iconv_open("UCS-2LE", iconv_code); mdb->iconv_in = iconv_open(iconv_code, "UCS-2LE"); } else { /* According to Microsoft Knowledge Base pages 289525 and */ /* 202427, code page info is not contained in the database */ /* check environment variable */ const char *jet3_iconv_code_from_env = getenv("MDB_JET3_CHARSET"); if (jet3_iconv_code_from_env) mdb_set_encoding(mdb, jet3_iconv_code_from_env); else if (!mdb->jet3_iconv_code) { #ifdef _WIN32 // get the default from OS char default_encoding[] = "CP "; if (GetLocaleInfoA( MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, default_encoding+2, sizeof(default_encoding)-2-1 )) { mdb->jet3_iconv_code = g_strdup(default_encoding); } else #endif mdb->jet3_iconv_code = g_strdup("CP1252"); } mdb->iconv_out = iconv_open(mdb->jet3_iconv_code, iconv_code); mdb->iconv_in = iconv_open(iconv_code, mdb->jet3_iconv_code); } #endif } void mdb_iconv_close(MdbHandle *mdb) { #ifdef HAVE_ICONV if (mdb->iconv_out != (iconv_t)-1) iconv_close(mdb->iconv_out); if (mdb->iconv_in != (iconv_t)-1) iconv_close(mdb->iconv_in); #endif } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c index 865d5a4bf..661ebb138 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/index.c @@ -1,924 +1,1062 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 */ }; +/* JET Red (v4) Index definition byte layouts + * + * Based on: + * + * http://jabakobob.net/mdb/table-page.html + * https://github.com/jahlborn/jackcess + * + * plus inspection of JET (Red) 4 databases. (JET 3 format has fewer + * fields -- some of the ones below omitted, and others narrower.) + * + * See also JET Blue (Extensible Storage Engine) format information: + * + * https://github.com/libyal/libesedb/blob/master/documentation/Extensible%20Storage%20Engine%20%28ESE%29%20Database%20File%20%28EDB%29%20format.asciidoc + * + * which is a later Microsoft embedded database format with the same + * early base format. + * + * ---------------------------------------------------------------------- + * Index Column Definitions: + * - for each "non foreign key" index (ie pidx->index_type!=2), a list + * of columns indexed + * + * Repeated table->num_real_idxs times: + * + * Offset Bytes Meaning + * 0x0000 4 UNKNOWN; seems to be type marker, usually 1923 or 0 + * + * 0x0004 2 Column 1 ID + * 0x0006 1 Column 1 Flags + * 0x0007 2 Column 2 ID + * 0x0009 1 Column 2 Flags + * 0x000A 2 Column 3 ID + * 0x000C 1 Column 3 Flags + * 0x000D 2 Column 4 ID + * 0x000F 1 Column 4 Flags + * 0x0010 2 Column 5 ID + * 0x0012 1 Column 5 Flags + * 0x0013 2 Column 6 ID + * 0x0015 1 Column 6 Flags + * 0x0016 2 Column 7 ID + * 0x0018 1 Column 7 Flags + * 0x0019 2 Column 8 ID + * 0x001B 1 Column 8 Flags + * 0x001C 2 Column 9 ID + * 0x001E 1 Column 9 Flags + * 0x001F 2 Column 10 ID + * 0x0021 1 Column 10 Flags + * + * 0x0022 1 Usage Map row + * 0x0023 3 Usage Map page (24-bit) + * 0x0026 4 First index page + * 0x002A 4 UNKNOWN + * 0x002E 2 Index Flags + * 0x0030 4 UNKNOWN; seems to always be 0 + * 0x0034 + * + * Column ID of 0xFFFF (-1) means "not used" or "end of used columns". + * Column Flags: + * - 0x01 = Ascending + * + * Index Flags: + * - 0x0001 = Unique index + * - 0x0002 = Ignore NULLs + * - 0x0008 = Required Index + * + * ---------------------------------------------------------------------- + * Index Definitions + * - for each index (normal, primary key, foreign key), details on the + * index. + * + * - this appears to be the union of information required for normal/ + * primary key indexes, and the information required for foreign key + * indexes. + * + * Repeated table->num_idxs times: + * + * Offset Bytes Meaning + * 0x0000 4 UNKNOWN; apparently a type marker, usually 1625 or 0 + * 0x0004 4 Logical Index Number + * 0x0008 4 Index Column Definition Entry + * 0x000C 1 FK Index Type + * 0x000D 4 FK Index Number + * 0x0011 4 FK Index Table Page Number + * 0x0015 1 Flags: Update Action + * 0x0016 1 Flags: Delete Action + * 0x0017 1 Index Type + * 0x0018 4 UNKNNOWN; seems to always be 0 + * 0x001B + * + * Where Index Type is: + * 0x01 = normal + * 0x01 = primary key + * 0x02 = foreign key index reference + */ + +/* Debugging helper to dump out raw hex values of index definition */ +/* +static void hexdump(unsigned char *tmpbuf, int size) { + int i; + for (i = 0; i < size; ++i) { + fprintf(stderr, "%02x ", tmpbuf[i]); + } + fprintf(stderr, "\n"); +} +*/ + GPtrArray * mdb_read_indices(MdbTableDef *table) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; MdbFormatConstants *fmt = mdb->fmt; MdbIndex *pidx; unsigned int i, j, k; int key_num, col_num, cleaned_col_num; int cur_pos, name_sz, idx2_sz, type_offset; int index_start_pg = mdb->cur_pg; - gchar *tmpbuf; + char *tmpbuf; table->indices = g_ptr_array_new(); if (IS_JET3(mdb)) { cur_pos = table->index_start + 39 * table->num_real_idxs; idx2_sz = 20; type_offset = 19; } else { cur_pos = table->index_start + 52 * table->num_real_idxs; idx2_sz = 28; type_offset = 23; } - //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); - /* num_real_idxs should be the number of indexes of type 2. + /* Read in the definitions of table indexes, into table->indices */ + + /* num_real_idxs should be the number of indexes other than type 2. * It's not always the case. Happens on Northwind Orders table. */ + //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); + table->num_real_idxs = 0; - tmpbuf = (gchar *) g_malloc(idx2_sz); + tmpbuf = g_malloc(idx2_sz); for (i=0;inum_idxs;i++) { read_pg_if_n(mdb, tmpbuf, &cur_pos, idx2_sz); + //fprintf(stderr, "Index defn: "); + //hexdump((unsigned char *)tmpbuf, 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); /* { - gint32 dumy0 = mdb_get_int32(tmpbuf, 0); - gint8 dumy1 = tmpbuf[8]; - gint32 dumy2 = mdb_get_int32(tmpbuf, 9); - gint32 dumy3 = mdb_get_int32(tmpbuf, 13); - gint16 dumy4 = mdb_get_int16(tmpbuf, 17); - fprintf(stderr, "idx #%d: num2:%d type:%d\n", i, pidx->index_num, pidx->index_type); - fprintf(stderr, "idx #%d: %d %d %d %d %d\n", i, dumy0, dumy1, dumy2, dumy3, dumy4); + gint32 idx_marker = mdb_get_int32(tmpbuf, 0); + gint32 index_col_def_num = mdb_get_int16(tmpbuf, 8); + gint8 rel_idx_type = tmpbuf[0x0c]; + gint32 rel_idx_number = mdb_get_int32(tmpbuf, 0x0d); + gint32 rel_idx_page = mdb_get_int32(tmpbuf, 0x11); + gint8 update_action_flags = tmpbuf[0x15]; + gint8 delete_action_flags = tmpbuf[0x16]; + fprintf(stderr, "idx #%d: num2:%d num3:%d type:%d\n", i, pidx->index_num, index_col_def_num, pidx->index_type); + fprintf(stderr, "idx #%d: %d %d %d %d %d/%d\n", i, idx_marker, rel_idx_type, rel_idx_number, rel_idx_page, update_action_flags, delete_action_flags); }*/ if (pidx->index_type!=2) table->num_real_idxs++; } //fprintf(stderr, "num_idxs:%d num_real_idxs:%d\n", table->num_idxs, table->num_real_idxs); g_free(tmpbuf); + /* Pick up the names of each index */ for (i=0;inum_idxs;i++) { pidx = g_ptr_array_index (table->indices, i); if (IS_JET3(mdb)) { name_sz=read_pg_if_8(mdb, &cur_pos); } else { name_sz=read_pg_if_16(mdb, &cur_pos); } tmpbuf = g_malloc(name_sz); - read_pg_if_n(mdb, tmpbuf, &cur_pos, name_sz); - mdb_unicode2ascii(mdb, tmpbuf, name_sz, pidx->name, MDB_MAX_OBJ_NAME); + read_pg_if_n(mdb, (char *)tmpbuf, &cur_pos, name_sz); + mdb_unicode2ascii(mdb, (char *)tmpbuf, name_sz, pidx->name, MDB_MAX_OBJ_NAME); g_free(tmpbuf); //fprintf(stderr, "index %d type %d name %s\n", pidx->index_num, pidx->index_type, pidx->name); } + /* Pick up the column definitions for normal/primary key indexes */ + /* NOTE: Match should possibly be by index_col_def_num, rather + * than index_num; but in files encountered both seem to be the + * same (so left with index_num until a counter example is found). + */ mdb_read_alt_pg(mdb, entry->table_pg); mdb_read_pg(mdb, index_start_pg); cur_pos = table->index_start; for (i=0;inum_real_idxs;i++) { + /* Debugging print out, commented out + { + gchar *tmpbuf = (gchar *) g_malloc(0x34); + int now_pos = cur_pos; + read_pg_if_n(mdb, tmpbuf, &now_pos, 0x34); + fprintf(stderr, "Index defn: "); + hexdump((unsigned char *)tmpbuf, 0x34); + g_free(tmpbuf); + }*/ + if (!IS_JET3(mdb)) cur_pos += 4; /* look for index number i */ for (j=0; jnum_idxs; ++j) { pidx = g_ptr_array_index (table->indices, j); if (pidx->index_type!=2 && pidx->index_num==i) break; } if (j==table->num_idxs) { fprintf(stderr, "ERROR: can't find index #%d.\n", i); continue; } //fprintf(stderr, "index %d #%d (%s) index_type:%d\n", i, pidx->index_num, pidx->name, pidx->index_type); - pidx->num_rows = mdb_get_int32(mdb->alt_pg_buf, + pidx->num_rows = mdb_get_int32((char *)mdb->alt_pg_buf, fmt->tab_cols_start_offset + (pidx->index_num*fmt->tab_ridx_entry_size)); /* fprintf(stderr, "ridx block1 i:%d data1:0x%08x data2:0x%08x\n", i, - mdb_get_int32(mdb->pg_buf, + (unsigned int)mdb_get_int32(mdb->pg_buf, fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size), - mdb_get_int32(mdb->pg_buf, + (unsigned int)mdb_get_int32(mdb->pg_buf, fmt->tab_cols_start_offset + pidx->index_num * fmt->tab_ridx_entry_size +4)); fprintf(stderr, "pidx->num_rows:%d\n", pidx->num_rows);*/ + /* Read columns in each index */ key_num=0; for (j=0;jnum_cols; k++) { MdbColumn *col = g_ptr_array_index(table->columns,k); if (col->col_num == col_num) { cleaned_col_num = k; break; } } if (cleaned_col_num==-1) { fprintf(stderr, "CRITICAL: can't find column with internal id %d in index %s\n", col_num, pidx->name); cur_pos++; continue; } /* set column number to a 1 based column number and store */ pidx->key_col_num[key_num] = cleaned_col_num + 1; pidx->key_col_order[key_num] = (read_pg_if_8(mdb, &cur_pos)) ? MDB_ASC : MDB_DESC; //fprintf(stderr, "component %d using column #%d (internally %d)\n", j, cleaned_col_num, col_num); key_num++; } pidx->num_keys = key_num; - cur_pos += 4; - //fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", read_pg_if_32(mdb, &cur_pos)); + if (0) // DEBUGGING ONLY + { + gint32 usage_map = read_pg_if_32(mdb, &cur_pos); + fprintf(stderr, "pidx->unknown_pre_first_pg:0x%08x\n", usage_map); + } else { + cur_pos += 4; // Skip Usage map information + } pidx->first_pg = read_pg_if_32(mdb, &cur_pos); + + if (!IS_JET3(mdb)) cur_pos += 4; + pidx->flags = read_pg_if_8(mdb, &cur_pos); //fprintf(stderr, "pidx->first_pg:%d pidx->flags:0x%02x\n", pidx->first_pg, pidx->flags); - if (!IS_JET3(mdb)) cur_pos += 9; + if (!IS_JET3(mdb)) cur_pos += 5; } return NULL; } void mdb_index_hash_text(char *text, char *hash) { unsigned int k; for (k=0;k= 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, 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; //fprintf(stderr,"mdb_index_test_sargs called on "); //for (i=0;ipg_buf[offset+i]); //fprintf(stderr,"\n"); for (i=0;inum_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;jnum_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;jnum_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) { //fprintf(stdout, "elem %d is %d\n", elem, ipg->idx_starts[elem]); 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; //fprintf(stdout, "Unpacking index page %lu\n", ipg->pg); 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_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 3) >> 8; + pg = mdb_get_int32_msb((char *)mdb->pg_buf, ipg->offset + ipg->len - 3) >> 8; //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; guint32 pg_row; 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_get_int32( - mdb->pg_buf, 0x0c); + (char *)mdb->pg_buf, 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; } } - pg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); + pg_row = mdb_get_int32_msb((char *)mdb->pg_buf, ipg->offset + ipg->len - 4); *row = pg_row & 0xff; *pg = pg_row >> 8; //printf("row = %d pg = %lu ipg->pg = %lu offset = %lu len = %d\n", *row, *pg, ipg->pg, ipg->offset, ipg->len); 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) { //printf("short index found\n"); //mdb_buffer_dump(ipg->cache_value, 0, idx_sz); memcpy(&ipg->cache_value[idx_sz - (ipg->len - 4)], &mdb->pg_buf[ipg->offset], ipg->len); //mdb_buffer_dump(ipg->cache_value, 0, idx_sz); } 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, (char *)(ipg->cache_value), idx_sz); ipg->offset += ipg->len; } while (!passed); //fprintf(stdout,"len = %d pos %d\n", ipg->len, ipg->mask_pos); //mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len); 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 pg_row = (pg << 8) | (row & 0xff); guint32 datapg_row; 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 */ - datapg_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); + datapg_row = mdb_get_int32_msb((char *)mdb->pg_buf, ipg->offset + ipg->len - 4); if (pg_row == datapg_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;inum_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;inum_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;inum_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;inum_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; ilen; i++) g_free (g_ptr_array_index(indices, i)); g_ptr_array_free(indices, TRUE); } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c index 25660745d..d177a0321 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/map.c @@ -1,138 +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif static gint32 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); + pgnum = mdb_get_int32((char *)map, 1); usage_bitmap = map + 5; usage_bitlen = (map_sz - 5) * 8; i = (start_pg >= pgnum) ? start_pg-pgnum+1 : 0; for (; ifmt->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_indfmt->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; ientry; 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; } else if (pgnum==-1) { fprintf(stderr, "Error: mdb_map_find_next_freepage error while reading maps.\n"); exit(1); } 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/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c index 6f871cd14..67e29e427 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/mem.c @@ -1,31 +1,36 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" MDB_DEPRECATED(void, mdb_init()) { fprintf(stderr, "mdb_init() is DEPRECATED and does nothing. Stop calling it.\n"); } MDB_DEPRECATED(void, mdb_exit()) { fprintf(stderr, "mdb_exit() is DEPRECATED and does nothing. Stop calling it.\n"); } + +/* glib - to allow static linking of glib in mdbtools */ +void mdb_g_free (gpointer mem) { g_free(mem); } +gpointer mdb_g_malloc (gsize n_bytes) { return g_malloc(n_bytes); } +gpointer mdb_g_malloc0 (gsize n_bytes) { return g_malloc0(n_bytes); } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c index 0c8c91d61..eaea04ae3 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/money.c @@ -1,170 +1,166 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "mdbtools.h" #ifdef DMALLOC #include "dmalloc.h" #endif #define MAX_NUMERIC_PRECISION 28 /* ** 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, int neg); /** * mdb_money_to_string * @mdb: Handle to open MDB database file * @start: Offset of the field within the current page * * Returns: the allocated string that has received the value. */ char *mdb_money_to_string(MdbHandle *mdb, int start) { -#define num_bytes 8 - int scale=4; + const int num_bytes=8, scale=4; int i; int neg=0; unsigned char multiplier[MAX_NUMERIC_PRECISION], temp[MAX_NUMERIC_PRECISION]; unsigned char product[MAX_NUMERIC_PRECISION]; unsigned char bytes[num_bytes]; memset(multiplier,0,MAX_NUMERIC_PRECISION); memset(product,0,MAX_NUMERIC_PRECISION); multiplier[0]=1; memcpy(bytes, mdb->pg_buf + start, num_bytes); /* Perform two's complement for negative numbers */ if (bytes[num_bytes-1] & 0x80) { neg = 1; for (i=0;ipg_buf + start + 1, num_bytes); /* Perform two's complement for negative numbers */ if (mdb->pg_buf[start] & 0x80) neg = 1; for (i=0;i9) { 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, int neg) { char *s; unsigned int top, i, j=0; for (top=MAX_NUMERIC_PRECISION;(top>0) && (top-1>scale) && !array[top-1];top--); /* allocate enough space for all digits + minus sign + decimal point + trailing NULL byte */ s = (char *) g_malloc(MAX_NUMERIC_PRECISION+3); if (neg) s[j++] = '-'; if (top == 0) { s[j++] = '0'; } else { for (i=top; i>0; i--) { if (i == scale) s[j++]='.'; s[j++]=array[i-1]+'0'; } } s[j]='\0'; return s; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c index 670d2269a..7889a7029 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/props.c @@ -1,215 +1,215 @@ /* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000-2011 Brian Bruns and others * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mdbtools.h" static GPtrArray * mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len) { guint32 record_len; int pos = 0; gchar *name; GPtrArray *names = NULL; int i=0; names = g_ptr_array_new(); #if MDB_DEBUG mdb_buffer_dump(kkd, 0, len); #endif pos = 0; while (pos < len) { record_len = mdb_get_int16(kkd, pos); pos += 2; if (mdb_get_option(MDB_DEBUG_PROPS)) { fprintf(stderr, "%02d ",i++); mdb_buffer_dump(kkd, pos - 2, record_len + 2); } name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte in */ mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len); pos += record_len; g_ptr_array_add(names, name); #if MDB_DEBUG printf("new len = %d\n", names->len); #endif } return names; } static gboolean free_hash_entry(gpointer key, gpointer value, gpointer user_data) { g_free(key); g_free(value); return TRUE; } void mdb_free_props(MdbProperties *props) { if (!props) return; if (props->name) g_free(props->name); if (props->hash) { g_hash_table_foreach(props->hash, (GHFunc)free_hash_entry, 0); g_hash_table_destroy(props->hash); } g_free(props); } static void free_names(GPtrArray *names) { g_ptr_array_foreach(names, (GFunc)g_free, NULL); g_ptr_array_free(names, TRUE); } MdbProperties * mdb_alloc_props() { MdbProperties *props; props = g_malloc0(sizeof(MdbProperties)); return props; } static 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; #if MDB_DEBUG mdb_buffer_dump(kkd, 0, len); #endif pos = 0; 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(3*name_len + 1); mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len); mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name); } 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); dtype = kkd[pos + 3]; elem = mdb_get_int16(kkd, pos + 4); 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); if (mdb_get_option(MDB_DEBUG_PROPS)) { fprintf(stderr, "%02d ",i++); mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, dtype); mdb_buffer_dump(value, 0, dsize); } 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), mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize)); } g_free(value); pos += record_len; } return props; } static void print_keyvalue(gpointer key, gpointer value, gpointer outfile) { fprintf((FILE*)outfile,"\t%s: %s\n", (gchar *)key, (gchar *)value); } void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) { if (show_name) fprintf(outfile,"name: %s\n", props->name ? props->name : "(none)"); g_hash_table_foreach(props->hash, print_keyvalue, outfile); if (show_name) fputc('\n', outfile); } /* * That function takes a raw KKD/MR2 binary buffer, * typically read from LvProp in table MSysbjects * and returns a GArray of MdbProps* */ GArray* -mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { +mdb_kkd_to_props(MdbHandle *mdb, char *buffer, size_t len) { guint32 record_len; guint16 record_type; size_t pos; GPtrArray *names = NULL; MdbProperties *props; GArray *result; #if MDB_DEBUG mdb_buffer_dump(buffer, 0, len); #endif mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", buffer); if (strcmp("KKD", buffer) && strcmp("MR2", buffer)) { fprintf(stderr, "Unrecognized format.\n"); mdb_buffer_dump(buffer, 0, len); return NULL; } result = g_array_new(0, 0, sizeof(MdbProperties*)); pos = 4; while (pos < len) { record_len = mdb_get_int32(buffer, (int)pos); record_type = mdb_get_int16(buffer, (int)pos + 4); mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, record_len); //mdb_buffer_dump(buffer, pos+4, record_len); switch (record_type) { case 0x80: if (names) free_names(names); - names = mdb_read_props_list(mdb, (gchar *)buffer+pos+6, record_len - 6); + names = mdb_read_props_list(mdb, (char*)buffer+pos+6, record_len - 6); break; case 0x00: case 0x01: if (!names) { fprintf(stderr,"sequence error!\n"); break; } - props = mdb_read_props(mdb, names, (gchar *)buffer+pos+6, record_len - 6); + props = mdb_read_props(mdb, names, (char*)buffer+pos+6, record_len - 6); g_array_append_val(result, props); //mdb_dump_props(props, stderr, 1); break; default: fprintf(stderr,"Unknown record type %d\n", record_type); break; } pos += record_len; } if (names) free_names(names); return result; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c index cee28c062..33694083c 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/sargs.c @@ -1,311 +1,308 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #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: //fprintf(stderr, "comparing %ld and %ld\n", i, node->value.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; } int mdb_test_date(MdbSargNode *node, double td) { struct tm found; /* TODO: you should figure out a way to pull mdb_date_to_string in here * char date_tmp[MDB_BIND_SIZE]; */ time_t found_t; time_t asked_t; double diff; mdb_date_to_tm(td, &found); asked_t = node->value.i; found_t = mktime(&found); diff = difftime(asked_t, found_t); switch (node->op) { case MDB_EQUAL: if (diff==0) return 1; break; case MDB_GT: if (diff<0) return 1; break; case MDB_LT: if (diff>0) return 1; break; case MDB_GTEQ: if (diff<=0) return 1; break; case MDB_LTEQ: if (diff>=0) return 1; break; default: fprintf(stderr, "Calling mdb_test_sarg on unknown operator. Add code to mdb_test_date() for operator %d\n", node->op); break; } return 0; } 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]; - 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; - } + if (node->op == MDB_ISNULL) + return field->is_null?1:0; + else if (node->op == MDB_NOTNULL) + return field->is_null?0:1; 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: mdb_unicode2ascii(mdb, field->value, field->siz, tmpbuf, 256); return mdb_test_string(node, tmpbuf); case MDB_DATETIME: return mdb_test_date(node, mdb_get_double(field->value, 0)); 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;iop)) { 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;inum_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;inum_cols;i++) { col = g_ptr_array_index (table->columns, i); - if (!strcasecmp(col->name,colname)) { + if (!g_ascii_strcasecmp(col->name,colname)) { return mdb_add_sarg(col, in_sarg); } } /* else didn't find the column return 0! */ return 0; } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c index 896e8fa1a..a154e0f8e 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/table.c @@ -1,421 +1,421 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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; /* Temp table pages are being stored in memory */ for (i=0; itemp_table_pages->len; i++) g_free(g_ptr_array_index(table->temp_table_pages,i)); g_ptr_array_free(table->temp_table_pages, TRUE); /* Temp tables use dummy entries */ g_free(table->entry); } 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 row_start, pg_row; - void *buf, *pg_buf = mdb->pg_buf; + char *buf, *pg_buf = (char *)mdb->pg_buf; guint i; mdb_read_pg(mdb, entry->table_pg); if (mdb_get_byte(pg_buf, 0) != 0x02) /* not a valid table def page */ return NULL; table = mdb_alloc_tabledef(entry); mdb_get_int16(pg_buf, 8); /* len */ table->num_rows = mdb_get_int32(pg_buf, fmt->tab_num_rows_offset); table->num_var_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset-2); table->num_cols = mdb_get_int16(pg_buf, fmt->tab_num_cols_offset); table->num_idxs = mdb_get_int32(pg_buf, fmt->tab_num_idxs_offset); table->num_real_idxs = mdb_get_int32(pg_buf, fmt->tab_num_ridxs_offset); /* grab a copy of the usage map */ pg_row = mdb_get_int32(pg_buf, fmt->tab_usage_map_offset); mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->map_sz)); table->usage_map = g_memdup((char*)buf + row_start, (int)table->map_sz); if (mdb_get_option(MDB_DEBUG_USAGE)) mdb_buffer_dump(buf, row_start, table->map_sz); 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_get_int32(pg_buf, fmt->tab_free_map_offset); mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &(table->freemap_sz)); table->free_usage_map = g_memdup((char*)buf + row_start, (int)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_get_int16(pg_buf, fmt->tab_first_dpg_offset); if (entry->props) for (i=0; iprops->len; ++i) { MdbProperties *props = g_array_index(entry->props, MdbProperties*, i); if (!props->name) table->props = props; } 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; inum_catalog; i++) { entry = g_ptr_array_index(mdb->catalog, i); - if (!strcasecmp(entry->object_name, table_name)) + if (!g_ascii_strcasecmp(entry->object_name, table_name)) return mdb_read_table(entry); } return NULL; } guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos) { char c[4]; read_pg_if_n(mdb, c, cur_pos, 4); return mdb_get_int32(c, 0); } guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos) { char c[2]; read_pg_if_n(mdb, c, cur_pos, 2); return mdb_get_int16(c, 0); } guint8 read_pg_if_8(MdbHandle *mdb, int *cur_pos) { guint8 c; - read_pg_if_n(mdb, &c, cur_pos, 1); + read_pg_if_n(mdb, (char *)&c, cur_pos, 1); return c; } /* * Read data into a buffer, advancing pages and setting the * page cursor as needed. In the case that buf in NULL, pages * are still advanced and the page cursor is still updated. */ void * -read_pg_if_n(MdbHandle *mdb, void *void_buf, int *cur_pos, size_t len) +read_pg_if_n(MdbHandle *mdb, char *buf, int *cur_pos, size_t len) { - gchar *buf = void_buf; + char* _buf = buf; /* Advance to page which contains the first byte */ while (*cur_pos >= mdb->fmt->pg_size) { - mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4)); + mdb_read_pg(mdb, mdb_get_int32((char *)mdb->pg_buf,4)); *cur_pos -= (int)(mdb->fmt->pg_size - 8); } /* Copy pages into buffer */ while ((ssize_t)(*cur_pos + len) >= mdb->fmt->pg_size) { int piece_len = mdb->fmt->pg_size - *cur_pos; - if (buf) { - memcpy(buf, mdb->pg_buf + *cur_pos, piece_len); - buf += piece_len; + if (_buf) { + memcpy(_buf, mdb->pg_buf + *cur_pos, piece_len); + _buf += piece_len; } len -= piece_len; - mdb_read_pg(mdb, mdb_get_int32(mdb->pg_buf,4)); + mdb_read_pg(mdb, mdb_get_int32((char *)mdb->pg_buf,4)); *cur_pos = 8; } /* Copy into buffer from final page */ - if (len && buf) { - memcpy(buf, mdb->pg_buf + *cur_pos, len); + if (len && _buf) { + memcpy(_buf, mdb->pg_buf + *cur_pos, len); } *cur_pos += len; - return buf; + return _buf; } 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, j; MdbColumn *col; if (!columns) return; for (i=0; ilen; i++) { col = (MdbColumn *) g_ptr_array_index(columns, i); if (col->sargs) { for (j=0; jsargs->len; j++) { g_free( g_ptr_array_index(col->sargs, j)); } g_ptr_array_free(col->sargs, TRUE); } g_free(col); } 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, j; int cur_pos; size_t name_sz; GArray *allprops; 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;inum_cols;i++) { #ifdef MDB_DEBUG /* printf("column %d\n", i); mdb_buffer_dump(mdb->pg_buf, cur_pos, fmt->tab_col_entry_size); */ #endif - read_pg_if_n(mdb, col, &cur_pos, fmt->tab_col_entry_size); + read_pg_if_n(mdb, (char *)col, &cur_pos, fmt->tab_col_entry_size); pcol = (MdbColumn *) g_malloc0(sizeof(MdbColumn)); pcol->table = table; 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); + pcol->var_col_num = mdb_get_int16((char *)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); + pcol->row_col_num = mdb_get_int16((char *)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_flags_offset == 13 or 15 pcol->is_fixed = col[fmt->col_flags_offset] & 0x01 ? 1 : 0; pcol->is_long_auto = col[fmt->col_flags_offset] & 0x04 ? 1 : 0; pcol->is_uuid_auto = col[fmt->col_flags_offset] & 0x40 ? 1 : 0; // tab_col_offset_fixed == 14 or 21 - pcol->fixed_offset = mdb_get_int16(col, fmt->tab_col_offset_fixed); + pcol->fixed_offset = mdb_get_int16((char *)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); + pcol->col_size = mdb_get_int16((char *)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;inum_cols;i++) { char *tmp_buf; pcol = g_ptr_array_index(table->columns, i); if (IS_JET3(mdb)) name_sz = read_pg_if_8(mdb, &cur_pos); else name_sz = read_pg_if_16(mdb, &cur_pos); tmp_buf = (char *) g_malloc(name_sz); read_pg_if_n(mdb, tmp_buf, &cur_pos, name_sz); mdb_unicode2ascii(mdb, tmp_buf, name_sz, pcol->name, MDB_MAX_OBJ_NAME); g_free(tmp_buf); } /* Sort the columns by col_num */ g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer); allprops = table->entry->props; if (allprops) for (i=0;inum_cols;i++) { pcol = g_ptr_array_index(table->columns, i); for (j=0; jlen; ++j) { MdbProperties *props = g_array_index(allprops, MdbProperties*, j); if (props->name && !strcmp(props->name, pcol->name)) { pcol->props = props; break; } } } table->index_start = cur_pos; return table->columns; } #if !MDB_NO_BACKENDS void mdb_table_dump(MdbCatalogEntry *entry) { MdbTableDef *table; MdbColumn *col; int coln; MdbIndex *idx; 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); if (table->props) mdb_dump_props(table->props, stdout, 0); mdb_read_columns(table); mdb_read_indices(table); for (i=0;inum_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_colbacktype_string(col), col->col_size); if (col->props) mdb_dump_props(col->props, stdout, 0); } for (i=0;inum_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;imap_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"); } } #endif 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; } const char * mdb_table_get_prop(const MdbTableDef *table, const gchar *key) { if (!table->props) return NULL; return g_hash_table_lookup(table->props->hash, key); } const char * mdb_col_get_prop(const MdbColumn *col, const gchar *key) { if (!col->props) return NULL; return g_hash_table_lookup(col->props->hash, key); } diff --git a/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c b/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c index 004513fea..f1daaa74e 100644 --- a/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c +++ b/src/migration/mdb/3rdparty/mdbtools/libmdb/write.c @@ -1,888 +1,887 @@ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include -#include #include "mdbtools.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, guint32 pgnum, guint16 rownum); void -mdb_put_int16(void *buf, guint32 offset, guint32 value) +mdb_put_int16(char *buf, guint32 offset, guint32 value) { value = GINT32_TO_LE(value); - memcpy((char*)buf + offset, &value, 2); + memcpy(buf + offset, &value, 2); } void _mdb_put_int16(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int16"))); #else { mdb_put_int16((char*)buf, offset, value); } #endif void -mdb_put_int32(void *buf, guint32 offset, guint32 value) +mdb_put_int32(char *buf, guint32 offset, guint32 value) { value = GINT32_TO_LE(value); - memcpy((char*)buf + offset, &value, 4); + memcpy(buf + offset, &value, 4); } void _mdb_put_int32(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int32"))); #else { mdb_put_int32((char*)buf, offset, value); } #endif void -mdb_put_int32_msb(void *buf, guint32 offset, guint32 value) +mdb_put_int32_msb(char *buf, guint32 offset, guint32 value) { value = GINT32_TO_BE(value); - memcpy((char*)buf + offset, &value, 4); + memcpy(buf + offset, &value, 4); } void _mdb_put_int32_mdb(void *buf, guint32 offset, guint32 value) #ifdef HAVE_ATTRIBUTE_ALIAS __attribute__((alias("mdb_put_int32_msb"))); #else { mdb_put_int32_msb((char*)buf, offset, value); } #endif ssize_t mdb_write_pg(MdbHandle *mdb, unsigned long pg) { ssize_t len; struct stat status; off_t offset = pg * mdb->fmt->pg_size; if (fstat(mdb->f->fd, &status) != 0) { perror("fstat"); return 0; } /* is page beyond current size + 1 ? */ if ((size_t)status.st_size < (offset + mdb->fmt->pg_size)) { - fprintf(stderr,"offset %jd is beyond EOF\n",(intmax_t)offset); + fprintf(stderr,"offset %jd is beyond EOF\n",offset); return 0; } if (lseek(mdb->f->fd, offset, SEEK_SET) == -1) { perror("lseek"); return 0; } len = write(mdb->f->fd,mdb->pg_buf,mdb->fmt->pg_size); if (len==-1) { perror("write"); return 0; } else if (lenfmt->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;inum_idxs;i++) { idx = g_ptr_array_index (table->indices, i); for (j=0;jnum_keys;j++) { if (idx->key_col_num[j]==colnum) return 1; } } return 0; } static void mdb_crack_row4(MdbHandle *mdb, int row_start, int row_end, unsigned int bitmask_sz, unsigned int row_var_cols, unsigned int *var_col_offsets) { unsigned int i; for (i=0; ipg_buf, + var_col_offsets[i] = mdb_get_int16((char *)mdb->pg_buf, row_end - bitmask_sz - 3 - (i*2)); } } static void mdb_crack_row3(MdbHandle *mdb, int row_start, int row_end, unsigned int bitmask_sz, unsigned int row_var_cols, unsigned int *var_col_offsets) { unsigned int i; unsigned int num_jumps = 0, jumps_used = 0; unsigned int col_ptr, row_len; 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--; jumps_used = 0; for (i=0; ipg_buf[row_end-bitmask_sz-jumps_used-1])) { jumps_used++; } var_col_offsets[i] = mdb->pg_buf[col_ptr-i]+(jumps_used*256); } } /** * 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 + * @fields: pointer to MdbField array to be populated 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) { MdbColumn *col; MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; - void *pg_buf = mdb->pg_buf; + unsigned char *pg_buf = mdb->pg_buf; unsigned int row_var_cols=0, row_cols; unsigned char *nullmask; unsigned int bitmask_sz; unsigned int *var_col_offsets = NULL; unsigned int fixed_cols_found, row_fixed_cols; unsigned int col_count_size; unsigned int i; if (mdb_get_option(MDB_DEBUG_ROW)) { mdb_buffer_dump(pg_buf, row_start, row_end - row_start + 1); } if (IS_JET3(mdb)) { row_cols = mdb_get_byte(pg_buf, row_start); col_count_size = 1; } else { - row_cols = mdb_get_int16(pg_buf, row_start); + row_cols = mdb_get_int16((char *)pg_buf, row_start); col_count_size = 2; } bitmask_sz = (row_cols + 7) / 8; - nullmask = (unsigned char *)pg_buf + row_end - bitmask_sz + 1; + nullmask = (unsigned char*)pg_buf + row_end - bitmask_sz + 1; /* read table of variable column locations */ if (table->num_var_cols > 0) { row_var_cols = IS_JET3(mdb) ? mdb_get_byte(pg_buf, row_end - bitmask_sz) : - mdb_get_int16(pg_buf, row_end - bitmask_sz - 1); + mdb_get_int16((char *)pg_buf, row_end - bitmask_sz - 1); var_col_offsets = (unsigned int *)g_malloc((row_var_cols+1)*sizeof(int)); if (IS_JET3(mdb)) { mdb_crack_row3(mdb, row_start, row_end, bitmask_sz, row_var_cols, var_col_offsets); } else { mdb_crack_row4(mdb, row_start, row_end, bitmask_sz, row_var_cols, var_col_offsets); } } fixed_cols_found = 0; row_fixed_cols = row_cols - row_var_cols; if (mdb_get_option(MDB_DEBUG_ROW)) { fprintf(stdout,"bitmask_sz %d\n", bitmask_sz); fprintf(stdout,"row_var_cols %d\n", row_var_cols); fprintf(stdout,"row_fixed_cols %d\n", row_fixed_cols); } for (i=0;inum_cols;i++) { unsigned int byte_num, bit_num; unsigned int col_start; col = g_ptr_array_index(table->columns,i); fields[i].colnum = i; fields[i].is_fixed = col->is_fixed; 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 + col_count_size; fields[i].start = row_start + col_start; fields[i].value = (char*)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 = (char*)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_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> 8) & 0xff; /* Fixed length columns */ for (i=0;inum_var_cols == 0) { pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } /* Variable length columns */ for (i=0;i> 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;inum_var_cols == 0) { pos += mdb_pack_null_mask(&row_buffer[pos], num_fields, fields); return pos; } /* Variable length columns */ for (i=0;i> 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 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; icolumns, 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_JET3(table->entry->mdb)) { return mdb_pack_row3(table, row_buffer, num_fields, fields); } else { return mdb_pack_row4(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_get_int16(mdb->pg_buf, row_count_offset); + rows = mdb_get_int16((char *)mdb->pg_buf, row_count_offset); free_start = row_count_offset + 2 + (rows * 2); - free_end = mdb_get_int16(mdb->pg_buf, row_count_offset + (rows * 2)); + free_end = mdb_get_int16((char *)mdb->pg_buf, 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); } void * mdb_new_leaf_pg(MdbCatalogEntry *entry) { MdbHandle *mdb = entry->mdb; void *new_pg = g_malloc0(mdb->fmt->pg_size); mdb_put_int16(new_pg, 0, 0x0104); mdb_put_int32(new_pg, 4, entry->table_pg); return new_pg; } void * mdb_new_data_pg(MdbCatalogEntry *entry) { MdbFormatConstants *fmt = entry->mdb->fmt; void *new_pg = g_malloc0(fmt->pg_size); mdb_put_int16(new_pg, 0, 0x0101); 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; } /* could be static */ int mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum) { unsigned int i; MdbIndex *idx; for (i=0;inum_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; } /* could be static */ 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, pgnum, rownum); 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)) { mdb_buffer_dump(row_buffer, 0, new_row_size); } 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)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, fmt->pg_size - 160, 160); } mdb_debug(MDB_DEBUG_WRITE, "writing page %d", pgnum); if (!mdb_write_pg(mdb, pgnum)) { fprintf(stderr, "write failed!\n"); return 0; } 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) { - void *new_pg; + unsigned char *new_pg; int num_rows, i, pos, row_start; size_t 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) { + if (mdb_get_int16((char *)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); + num_rows = mdb_get_int16((char *)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)); + mdb_get_int16((char *)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_get_int16(mdb->pg_buf, fmt->row_count_offset); + num_rows = mdb_get_int16((char *)mdb->pg_buf, fmt->row_count_offset); pos = fmt->pg_size; /* copy existing rows */ for (i=0;ipg_buf + row_start, row_size); - mdb_put_int16(new_pg, (fmt->row_count_offset + 2) + (i*2), pos); + mdb_put_int16((char *)new_pg, (fmt->row_count_offset + 2) + (i*2), pos); } } /* add our new row */ pos -= new_row_size; memcpy((char*)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); + mdb_put_int16((char *)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); + mdb_put_int16((char *)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)); + mdb_put_int16((char *)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; MdbField fields[256]; unsigned char row_buffer[4096]; size_t old_row_size, new_row_size; unsigned int num_fields; if (!mdb->f->writable) { fprintf(stderr, "File is not open for writing\n"); return 0; } mdb_find_row(mdb, table->cur_row-1, &row_start, &old_row_size); row_end = row_start + old_row_size - 1; 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)) mdb_buffer_dump(mdb->pg_buf, row_start, old_row_size); for (i=0;inum_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;inum_cols;i++) { col = g_ptr_array_index(table->columns,i); if (col->bind_ptr) { 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)) mdb_buffer_dump(row_buffer, 0, new_row_size); if (new_row_size > (old_row_size + mdb_pg_get_freespace(mdb))) { 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; /* FIXME */ } /* WARNING the return code is opposite to convention used elsewhere: * returns 0 on success * returns 1 on failure * This might change on next ABI break. */ int mdb_replace_row(MdbTableDef *table, int row, void *new_row, int new_row_size) { MdbCatalogEntry *entry = table->entry; MdbHandle *mdb = entry->mdb; int pg_size = mdb->fmt->pg_size; int rco = mdb->fmt->row_count_offset; - void *new_pg; + unsigned char *new_pg; guint16 num_rows; int row_start; size_t row_size; int i, pos; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160); } 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_get_int16(mdb->pg_buf, rco); - mdb_put_int16(new_pg, rco, num_rows); + num_rows = mdb_get_int16((char *)mdb->pg_buf, rco); + mdb_put_int16((char *)new_pg, rco, num_rows); pos = pg_size; /* rows before */ for (i=0;ipg_buf + row_start, row_size); - mdb_put_int16(new_pg, rco + 2 + i*2, pos); + mdb_put_int16((char *)new_pg, rco + 2 + i*2, pos); } /* our row */ pos -= new_row_size; memcpy((char*)new_pg + pos, new_row, new_row_size); - mdb_put_int16(new_pg, rco + 2 + row*2, pos); + mdb_put_int16((char *)new_pg, rco + 2 + row*2, pos); /* rows after */ for (i=row+1;ipg_buf + row_start, row_size); - mdb_put_int16(new_pg, rco + 2 + i*2, pos); + mdb_put_int16((char *)new_pg, rco + 2 + i*2, pos); } /* almost done, copy page over current */ memcpy(mdb->pg_buf, new_pg, pg_size); g_free(new_pg); - mdb_put_int16(mdb->pg_buf, 2, mdb_pg_get_freespace(mdb)); + mdb_put_int16((char *)mdb->pg_buf, 2, mdb_pg_get_freespace(mdb)); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, 40); mdb_buffer_dump(mdb->pg_buf, pg_size - 160, 160); } /* drum roll, please */ if (!mdb_write_pg(mdb, table->cur_phys_pg)) { fprintf(stderr, "write failed!\n"); return 1; } return 0; } static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields, guint32 pgnum, guint16 rownum) /*, 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_row; guint16 row = 0; - void *new_pg; + unsigned char *new_pg; unsigned char key_hash[256]; int keycol; new_pg = mdb_new_leaf_pg(entry); /* reinitial ipg pointers to start of page */ 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); if (!col->is_fixed) { fprintf(stderr,"variable length key columns not yet supported, aborting\n"); return 0; } 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_row = mdb_get_int32_msb(mdb->pg_buf, ipg->offset + ipg->len - 4); + pg_row = mdb_get_int32_msb((char *)mdb->pg_buf, ipg->offset + ipg->len - 4); /* guint32 pg = pg_row >> 8; */ row = pg_row & 0xff; /* unsigned char iflag = mdb->pg_buf[ipg->offset]; */ /* turn the key hash back into a value */ mdb_index_swap_n(&mdb->pg_buf[ipg->offset + 1], col->col_size, key_hash); key_hash[col->col_size - 1] &= 0x7f; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, ipg->offset, ipg->len); mdb_buffer_dump(mdb->pg_buf, ipg->offset + 1, col->col_size); mdb_buffer_dump(key_hash, 0, col->col_size); } memcpy((char*)new_pg + ipg->offset, mdb->pg_buf + ipg->offset, ipg->len); ipg->offset += ipg->len; ipg->len = 0; row++; } if (!row) { fprintf(stderr,"missing indexes not yet supported, aborting\n"); return 0; } //mdb_put_int16(new_pg, mdb->fmt->row_count_offset, row); /* free space left */ - mdb_put_int16(new_pg, 2, mdb->fmt->pg_size - ipg->offset); + mdb_put_int16((char *)new_pg, 2, mdb->fmt->pg_size - ipg->offset); //printf("offset = %d\n", ipg->offset); mdb_index_swap_n(idx_fields[0].value, col->col_size, key_hash); key_hash[0] |= 0x080; if (mdb_get_option(MDB_DEBUG_WRITE)) { printf("key_hash\n"); mdb_buffer_dump(idx_fields[0].value, 0, col->col_size); mdb_buffer_dump(key_hash, 0, col->col_size); printf("--------\n"); } ((char *)new_pg)[ipg->offset] = 0x7f; memcpy((char*)new_pg + ipg->offset + 1, key_hash, col->col_size); pg_row = (pgnum << 8) | ((rownum-1) & 0xff); - mdb_put_int32_msb(new_pg, ipg->offset + 5, pg_row); + mdb_put_int32_msb((char *)new_pg, ipg->offset + 5, pg_row); ipg->idx_starts[row++] = ipg->offset + ipg->len; //ipg->idx_starts[row] = ipg->offset + ipg->len; if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size); } memcpy(mdb->pg_buf, new_pg, mdb->fmt->pg_size); mdb_index_pack_bitmap(mdb, ipg); if (mdb_get_option(MDB_DEBUG_WRITE)) { mdb_buffer_dump(mdb->pg_buf, 0, mdb->fmt->pg_size); } g_free(new_pg); return ipg->len; } diff --git a/src/migration/mdb/README b/src/migration/mdb/README index abc1617b3..f388bd707 100644 --- a/src/migration/mdb/README +++ b/src/migration/mdb/README @@ -1,17 +1,23 @@ -This is keximdb, the MDB file migration driver for Kexi. - -MDB files are the native database format of MS Access (and -also some other MS applications). This driver can be used -by Kexi's migration framework to convert simple Access +This is MDB file migration driver for KEXI. It can be used to convert simple MS Access databases into native Kexi databases. -If you have any problems, improvement proposals or you wish -to support this development, feel free to contact the authors: -* using the e-mail address below -* or using the Calligra forum http://forum.kde.org/viewforum.php?f=203 -* or ask on the #kexi IRC channel at irc.freenode.net. +MDB files are the native database format of MS Access (and also some other MS applications). + +Features: +- only import +- only tables are currently imported (no queries, forms, reports, etc.) +- imports all data types, including binary and memo +- imports primary keys +- imports data (records) + +mdbtools library is used internally (https://github.com/brianb/mdbtools). To facilitate access to +the newest possible mdbtools version regardless of operating system KEXI runs on, mdbtools' code has +been imported to src/migration/mdb/3rdparty/mdbtools directory of KEXI. Only needed source files +have been copied, that is command line tools and GUI code is not included. This is not meant to be +a fork though, improvements are contributed back to the main project. + +Home page of the MDB file migration driver: https://community.kde.org/Kexi/Migration/MDB -For more information visit: -http://www.kexi-project.org/wiki/wikiview/index.php@MDBDriver.html +Problems, proposals for improvement and support requests can be reported here: -Contact: calligra-devel at kde.org +https://community.kde.org/Kexi/Contact