diff --git a/HACKING b/HACKING index 00ee53c..58f635d 100644 --- a/HACKING +++ b/HACKING @@ -669,36 +669,33 @@ read is stored, once the index search has been exhausted by the normal search routine, it enters a "clean up mode" and reads the next leaf page pointer until it's null. -KKD Records ------------ +Properties +---------- -Design View table definitions appear to be stored in 'KKD' records (my name for -them...they always start with 'KKD\0'). Again these reside on pages, packed to -the end of the page. +Design View table definitions are stored in LvProp column of MSysObjects as OLE +fields. They contain default values, description, format, required ... -Update: The KKD records are stored in LvProp column of MSysObjects so they are -stored as other OLE/Memo fields are. +They start with a 32 bits header: 'KKD\0' in Jet3 and 'MR2\0' in Jet 4. -They look a little like this: (this needs work...see the kkd.c) +Next come chunks. Each chunk starts with: +32 bits length value (this includes the length) +16 bits chunk type (0x00 0x80 contains the names, 0x00 0x00 and 0x00 0x01 contain + the values) -'K' 'K' 'D' 0x00 -16 bit length value (this includes the length) -0x00 0x00 -0x80 0x00 (0x80 seems to indicate a header) -Then one or more of: 16 bit length field and a value of that size. +Name chunks (0x00 0x80) simply contains occurences of: +16 bit name length +name For instance: 0x0d 0x00 and 'AccessVersion' (AccessVersion is 13 bytes, 0x0d 0x00 intel order) -Next comes one of more rows of data. (column names, descriptions, etc...) +Next comes one of more chunk of data: 16 bit length value (this includes the length) -0x00 0x00 -0x00 0x00 - 16bit length field (this include the length itself) - 4 bytes of unknown purpose - 16 bit length field (non-inclusive) - value (07.53 for the AccessVersion example above) +8 bit type +16 bit name (index in the name array of above chunk 0x00 0x80) +16 bit length field (non-inclusive) +value (07.53 for the AccessVersion example above) -See kkd.c for an example, although it needs cleanup. +See props.c for an example. Text Data Type diff --git a/include/mdbtools.h b/include/mdbtools.h index 3d6f7d4..0d3ed1f 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -40,6 +40,7 @@ #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 @@ -123,8 +124,9 @@ enum { MDB_DEBUG_USAGE = 0x0004, MDB_DEBUG_OLE = 0x0008, MDB_DEBUG_ROW = 0x0010, - MDB_USE_INDEX = 0x0020, - MDB_NO_MEMO = 0x0040 /* don't follow memo fields */ + 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 || \ @@ -247,10 +249,8 @@ typedef struct { char object_name[MDB_MAX_OBJ_NAME+1]; int object_type; unsigned long table_pg; /* misnomer since object may not be a table */ - unsigned long kkd_pg; - unsigned int kkd_rowid; - int num_props; - GArray *props; + //int num_props; please use props->len + GArray *props; /* GArray of MdbProperties */ GArray *columns; int flags; } MdbCatalogEntry; @@ -441,6 +441,8 @@ 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); /* data.c */ extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr); @@ -523,9 +525,10 @@ 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); /* props.c */ -extern GPtrArray *mdb_read_props_list(gchar *kkd, int len); extern void mdb_free_props(MdbProperties *props); -extern MdbProperties *mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len); +extern void mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name); +extern GArray* kkd_to_props(MdbHandle *mdb, void *kkd, size_t len); + /* worktable.c */ extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name); diff --git a/src/libmdb/Makefile.am b/src/libmdb/Makefile.am index c1bd022..199852d 100644 --- a/src/libmdb/Makefile.am +++ b/src/libmdb/Makefile.am @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libmdb.la -libmdb_la_SOURCES= catalog.c mem.c file.c kkd.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c +libmdb_la_SOURCES= catalog.c mem.c file.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c libmdb_la_LDFLAGS = -version-info 1:0:0 AM_CPPFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) LIBS = $(GLIB_LIBS) @LIBS@ diff --git a/src/libmdb/catalog.c b/src/libmdb/catalog.c index 8179c56..8d5d52b 100644 --- a/src/libmdb/catalog.c +++ b/src/libmdb/catalog.c @@ -63,10 +63,14 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype) MdbCatalogEntry *entry, msysobj; MdbTableDef *table; char obj_id[256]; - char obj_name[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); @@ -91,14 +95,16 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype) 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(stdout, "obj_id: %10ld objtype: %-3d obj_name: %s\n", - // (atol(obj_id) & 0x00FFFFFF), type, obj_name); + //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); @@ -106,7 +112,14 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype) entry->table_pg = atol(obj_id) & 0x00FFFFFF; entry->flags = atol(obj_flags); mdb->num_catalog++; - g_ptr_array_add(mdb->catalog, entry); + 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); + //buffer_dump(kkd, 0, kkd_len); + entry->props = kkd_to_props(mdb, kkd, kkd_len); + free(kkd); + } } } //mdb_dump_catalog(mdb, MDB_TABLE); @@ -126,14 +139,12 @@ mdb_dump_catalog(MdbHandle *mdb, int 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) { - fprintf(stdout,"Type: %-10s Name: %-18s T pg: %04x KKD pg: %04x row: %2d\n", + fprintf(stdout,"Type: %-10s Name: %-18s T pg: %04x", mdb_get_objtype_string(entry->object_type), entry->object_name, - (unsigned int) entry->table_pg, - (unsigned int) entry->kkd_pg, - entry->kkd_rowid); + (unsigned int) entry->table_pg); } - } + } return; } diff --git a/src/libmdb/kkd.c b/src/libmdb/kkd.c deleted file mode 100644 index f5301b3..0000000 --- a/src/libmdb/kkd.c +++ /dev/null @@ -1,151 +0,0 @@ -/* MDB Tools - A library for reading MS Access database file - * Copyright (C) 2000 Brian Bruns - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "mdbtools.h" - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - - -/* -** Note: This code is mostly garbage right now...just a test to parse out the -** KKD structures. -*/ - -static GArray *mdb_get_column_props(MdbCatalogEntry *entry, int start) -{ -int pos, cnt=0; -int len, tmp, cplen; -MdbColumnProp prop; -MdbHandle *mdb = entry->mdb; - - entry->props = g_array_new(FALSE,FALSE,sizeof(MdbColumnProp)); - len = mdb_pg_get_int16(mdb,start); - pos = start + 6; - while (pos < start+len) { - tmp = mdb_pg_get_int16(mdb,pos); /* length of string */ - pos += 2; - cplen = tmp > MDB_MAX_OBJ_NAME ? MDB_MAX_OBJ_NAME : tmp; - g_memmove(prop.name,&mdb->pg_buf[pos],cplen); - prop.name[cplen]='\0'; - pos += tmp; - g_array_append_val(entry->props, prop.name); - cnt++; - } - entry->num_props = cnt; - return entry->props; -} - -static GHashTable *mdb_get_column_def(MdbCatalogEntry *entry, int start) -{ -GHashTable *hash = NULL; -MdbHandle *mdb = entry->mdb; -MdbColumnProp prop; -int tmp, pos, col_num, val_len, i; -int len, col_type; -unsigned char c; -int end; - - fprintf(stdout,"\n data\n"); - fprintf(stdout,"-------\n"); - len = mdb_pg_get_int16(mdb,start); - fprintf(stdout,"length = %3d\n",len); - pos = start + 6; - end = start + len; - while (pos < end) { - fprintf(stdout,"pos = %3d\n",pos); - start = pos; - tmp = mdb_pg_get_int16(mdb,pos); /* length of field */ - pos += 2; - col_type = mdb_pg_get_int16(mdb,pos); /* ??? */ - pos += 2; - col_num = 0; - if (col_type) { - col_num = mdb_pg_get_int16(mdb,pos); - pos += 2; - } - val_len = mdb_pg_get_int16(mdb,pos); - pos += 2; - fprintf(stdout,"length = %3d %04x %2d %2d ",tmp, col_type, col_num, val_len); - for (i=0;ipg_buf[pos+i]; - if (isprint(c)) - fprintf(stdout," %c",c); - else - fprintf(stdout," %02x",c); - - } - pos = start + tmp; - prop = g_array_index(entry->props,MdbColumnProp,col_num); - fprintf(stdout," Property %s",prop.name); - fprintf(stdout,"\n"); - } - return hash; -} -void mdb_kkd_dump(MdbCatalogEntry *entry) -{ -int rows; -int kkd_start, kkd_end; -int i, tmp, pos, row_type, datapos=0; -MdbColumnProp prop; -MdbHandle *mdb = entry->mdb; -int rowid = entry->kkd_rowid; - - - fprintf(stdout, "kkd_pg=%d kkd_rowid=%d\n", entry->kkd_pg, rowid); - - mdb_read_pg(mdb, entry->kkd_pg); - rows = mdb_get_int16(mdb->pg_buf, 8); - fprintf(stdout,"number of rows = %d\n",rows); - kkd_start = mdb_get_int16(mdb->pg_buf, 10+rowid*2); - fprintf(stdout,"kkd start = %d 0x%04x\n",kkd_start,kkd_start); - kkd_end = mdb->fmt->pg_size; - for (i=0;ipg_buf, 10+i*2); - if (tmp < mdb->fmt->pg_size && - tmp > kkd_start && - tmp < kkd_end) { - kkd_end = tmp; - } - } - fprintf(stdout,"kkd end = %d 0x%04x\n",kkd_end,kkd_end); - pos = kkd_start + 4; /* 4 = K K D \0 */ - while (pos < kkd_end) { - tmp = mdb_pg_get_int16(mdb,pos); - row_type = mdb_pg_get_int16(mdb,pos+4); - fprintf(stdout,"row size = %3d type = 0x%02x\n",tmp,row_type); - if (row_type==0x80) { - fprintf(stdout,"\nColumn Properties\n"); - fprintf(stdout,"-----------------\n"); - mdb_get_column_props(entry,pos); - for (i=0;inum_props;i++) { - prop = g_array_index(entry->props,MdbColumnProp,i); - fprintf(stdout,"%3d %s\n",i,prop.name); - } - } - if (row_type==0x01) datapos = pos; - pos += tmp; - } - - if (datapos) { - mdb_get_column_def(entry, datapos); - } -} - diff --git a/src/libmdb/options.c b/src/libmdb/options.c index 2c16526..3e19233 100644 --- a/src/libmdb/options.c +++ b/src/libmdb/options.c @@ -44,9 +44,9 @@ mdb_debug(int klass, char *fmt, ...) if (!optset) load_options(); if (klass & opts) { va_start(ap, fmt); - vfprintf (stdout,fmt, ap); + vfprintf (stderr,fmt, ap); va_end(ap); - fprintf(stdout,"\n"); + fprintf(stderr,"\n"); } #endif } @@ -59,7 +59,7 @@ load_options() if (!optset && (s=getenv("MDBOPTS"))) { opt = strtok(s, ":"); - do { + while (opt) { if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX; if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO; if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE; @@ -67,15 +67,17 @@ load_options() if (!strcmp(opt, "debug_usage")) opts |= MDB_DEBUG_USAGE; if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE; if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW; + if (!strcmp(opt, "debug_props")) opts |= MDB_DEBUG_PROPS; if (!strcmp(opt, "debug_all")) { opts |= MDB_DEBUG_LIKE; opts |= MDB_DEBUG_WRITE; opts |= MDB_DEBUG_USAGE; opts |= MDB_DEBUG_OLE; opts |= MDB_DEBUG_ROW; + opts |= MDB_DEBUG_PROPS; } opt = strtok(NULL,":"); - } while (opt); + } } optset = 1; } diff --git a/src/libmdb/props.c b/src/libmdb/props.c index b8c1eb8..63b5bbd 100644 --- a/src/libmdb/props.c +++ b/src/libmdb/props.c @@ -1,5 +1,5 @@ /* MDB Tools - A library for reading MS Access database file - * Copyright (C) 2000 Brian Bruns + * Copyright (C) 2000-2011 Brian Bruns and others * * * This library is free software; you can redistribute it and/or @@ -20,16 +20,16 @@ #include "mdbtools.h" -GPtrArray * -mdb_read_props_list(gchar *kkd, int len) +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(); + int i=0; #if MDB_DEBUG buffer_dump(kkd, 0, len); #endif @@ -37,13 +37,13 @@ mdb_read_props_list(gchar *kkd, int len) while (pos < len) { record_len = mdb_get_int16(kkd, pos); pos += 2; -#if MDB_DEBUG - printf("%02d ",i++); - buffer_dump(kkd, pos - 2, record_len + 2); -#endif - name = g_malloc(record_len + 1); - strncpy(name, &kkd[pos], record_len); - name[record_len] = '\0'; + if (mdb_get_option(MDB_DEBUG_PROPS)) { + fprintf(stderr, "%02d ",i++); + 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 @@ -60,6 +60,12 @@ mdb_free_props(MdbProperties *props) if (props->name) g_free(props->name); 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() { @@ -69,7 +75,7 @@ mdb_alloc_props() return props; } -MdbProperties * +static MdbProperties * mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) { guint32 record_len, name_len; @@ -77,23 +83,22 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) int elem, dtype, dsize; gchar *name, *value; MdbProperties *props; - int i = 0; + int i=0; #if MDB_DEBUG buffer_dump(kkd, 0, len); #endif pos = 0; - /* skip the name record */ record_len = mdb_get_int16(kkd, pos); pos += 4; name_len = mdb_get_int16(kkd, pos); pos += 2; props = mdb_alloc_props(); if (name_len) { - props->name = g_malloc(name_len + 1); - strncpy(props->name, &kkd[pos], name_len); - props->name[name_len]='\0'; + 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; @@ -101,18 +106,18 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) while (pos < len) { record_len = mdb_get_int16(kkd, pos); - elem = mdb_get_int16(kkd, pos + 4); 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_DEBUG - printf("%02d ",i++); - buffer_dump(kkd, pos, record_len); - printf("elem %d dsize %d dtype %d\n", elem, dsize, dtype); -#endif + 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); + 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), @@ -127,3 +132,68 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int 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); +} + +GArray* +kkd_to_props(MdbHandle *mdb, void *kkd, size_t len) { + guint32 record_len; + guint16 record_type; + size_t pos; + GPtrArray *names = NULL; + MdbProperties *props; + +#if MDB_DEBUG + buffer_dump(kkd, 0, len); +#endif + mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", kkd); + if (strcmp("KKD", kkd) && strcmp("MR2", kkd)) { + fprintf(stderr, "Unrecognized format.\n"); + buffer_dump(kkd, 0, len); + return NULL; + } + + GArray *result = g_array_new(0, 0, sizeof(MdbProperties*)); + + pos = 4; + while (pos < len) { + record_len = mdb_get_int32(kkd, pos); + record_type = mdb_get_int16(kkd, pos + 4); + mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, record_len); + //buffer_dump(kkd, pos+4, record_len); + switch (record_type) { + case 0x80: + if (names) free_names(names); + names = mdb_read_props_list(mdb, kkd+pos+6, record_len - 6); + break; + case 0x00: + case 0x01: + if (!names) { + fprintf(stderr,"sequence error!\n"); + break; + } + props = mdb_read_props(mdb, names, kkd+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/libmdb/table.c b/src/libmdb/table.c index be311b3..715e1bb 100644 --- a/src/libmdb/table.c +++ b/src/libmdb/table.c @@ -78,6 +78,7 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) MdbFormatConstants *fmt = mdb->fmt; int len, row_start, pg_row; void *buf, *pg_buf = 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 */ @@ -110,6 +111,13 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) 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) @@ -205,7 +213,7 @@ GPtrArray *mdb_read_columns(MdbTableDef *table) MdbFormatConstants *fmt = mdb->fmt; MdbColumn *pcol; unsigned char *col; - unsigned int i; + unsigned int i, j; int cur_pos; size_t name_sz; @@ -291,11 +299,25 @@ GPtrArray *mdb_read_columns(MdbTableDef *table) 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); + GArray *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 && pcol->name && !strcmp(props->name, pcol->name)) { + pcol->props = props; + break; + } + + } + } table->index_start = cur_pos; return table->columns; } @@ -316,6 +338,8 @@ guint32 pgnum; 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); @@ -326,6 +350,8 @@ guint32 pgnum; i, col->name, mdb_get_coltype_string(mdb->default_backend, col->col_type), col->col_size); + if (col->props) + mdb_dump_props(col->props, stdout, 0); } for (i=0;inum_idxs;i++) { @@ -370,3 +396,17 @@ 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/odbc/Makefile.am b/src/odbc/Makefile.am index c829f4a..02a6d9a 100644 --- a/src/odbc/Makefile.am +++ b/src/odbc/Makefile.am @@ -2,7 +2,7 @@ include_HEADERS = connectparams.h SQLDIR = ../sql SQLSOURCES = mdbsql.c parser.c lexer.c MDBDIR = ../libmdb -MDBSOURCES = backend.c index.c money.c catalog.c kkd.c sargs.c \ +MDBSOURCES = backend.c index.c money.c catalog.c sargs.c \ data.c like.c table.c dump.c file.c mem.c \ map.c props.c worktable.c options.c \ write.c stats.c iconv.c diff --git a/src/util/mdb-prop.c b/src/util/mdb-prop.c index e1fad15..0061546 100644 --- a/src/util/mdb-prop.c +++ b/src/util/mdb-prop.c @@ -1,5 +1,5 @@ /* MDB Tools - A library for reading MS Access database file - * Copyright (C) 2000 Brian Bruns + * Copyright (C) 2000-2011 Brian Bruns and others * * * This library is free software; you can redistribute it and/or @@ -80,7 +80,7 @@ main(int argc, char **argv) } if (found) { - MdbColumn *col = g_ptr_array_index(table->columns, col_num - 1); + MdbColumn *col = g_ptr_array_index(table->columns, col_num-1); size_t size; void *kkd = mdb_ole_read_full(mdb, col, &size); dump_kkd(mdb, kkd, size); @@ -94,64 +94,12 @@ main(int argc, char **argv) return 0; } -void print_keyvalue(gpointer key, gpointer value, gpointer user_data) -{ - printf("%s = %s\n", (gchar *)key, (gchar *)value); -} void dump_kkd(MdbHandle *mdb, void *kkd, size_t len) { - guint32 record_len; - guint16 record_type; - size_t pos; - GPtrArray *names = NULL; - MdbProperties *props; - -#if MDB_DEBUG - buffer_dump(kkd, 0, len); -#endif - if (strcmp("KKD", kkd)) { - fprintf(stderr, "Unrecognized format.\n"); - buffer_dump(kkd, 0, len); - return; - } - - - pos = 4; - while (pos < len) { - record_len = mdb_get_int32(kkd, pos); - record_type = mdb_get_int16(kkd, pos + 4); - //printf("len = %d type = %d\n", record_len, record_type); - switch (record_type) { - case 0x80: - names = mdb_read_props_list(kkd+pos+6, record_len - 6); - break; - case 0x00: - if (!names) { - printf("sequence error!\n"); - break; - } - props = mdb_read_props(mdb, names, kkd+pos+6, record_len - 6); - printf("type 0x00 name %s\n", props->name ? props->name : "(none)"); - g_hash_table_foreach(props->hash, print_keyvalue, NULL); - putchar('\n'); - mdb_free_props(props); - break; - case 0x01: - if (!names) { - printf("sequence error!\n"); - break; - } - props = mdb_read_props(mdb, names, kkd+pos+6, record_len - 6); - printf("type 0x01 name %s\n", props->name ? props->name : "(none)"); - g_hash_table_foreach(props->hash, print_keyvalue, NULL); - putchar('\n'); - mdb_free_props(props); - break; - default: - fprintf(stderr,"Unknown record type %d\n", record_type); - return; - } - pos += record_len; + GArray *aprops = kkd_to_props(mdb, kkd, len); + int i; + for (i=0; ilen; ++i) { + MdbProperties *props = g_array_index(aprops, MdbProperties*, i); + mdb_dump_props(props, stdout, 1); } } -