patch 'props' from Nirgal Vourgère

This commit is contained in:
Brian Bruns
2011-02-16 18:58:02 -05:00
parent fa83ed0af0
commit 6696edf1f8
10 changed files with 198 additions and 278 deletions

35
HACKING
View File

@@ -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 routine, it enters a "clean up mode" and reads the next leaf page pointer until
it's null. it's null.
KKD Records Properties
----------- ----------
Design View table definitions appear to be stored in 'KKD' records (my name for Design View table definitions are stored in LvProp column of MSysObjects as OLE
them...they always start with 'KKD\0'). Again these reside on pages, packed to fields. They contain default values, description, format, required ...
the end of the page.
Update: The KKD records are stored in LvProp column of MSysObjects so they are They start with a 32 bits header: 'KKD\0' in Jet3 and 'MR2\0' in Jet 4.
stored as other OLE/Memo fields are.
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 Name chunks (0x00 0x80) simply contains occurences of:
16 bit length value (this includes the length) 16 bit name length
0x00 0x00 name
0x80 0x00 (0x80 seems to indicate a header)
Then one or more of: 16 bit length field and a value of that size.
For instance: For instance:
0x0d 0x00 and 'AccessVersion' (AccessVersion is 13 bytes, 0x0d 0x00 intel order) 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) 16 bit length value (this includes the length)
0x00 0x00 8 bit type
0x00 0x00 16 bit name (index in the name array of above chunk 0x00 0x80)
16bit length field (this include the length itself)
4 bytes of unknown purpose
16 bit length field (non-inclusive) 16 bit length field (non-inclusive)
value (07.53 for the AccessVersion example above) 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 Text Data Type

View File

@@ -40,6 +40,7 @@
#define MDB_DEBUG 0 #define MDB_DEBUG 0
#define MDB_PGSIZE 4096 #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_OBJ_NAME 256
#define MDB_MAX_COLS 256 #define MDB_MAX_COLS 256
#define MDB_MAX_IDX_COLS 10 #define MDB_MAX_IDX_COLS 10
@@ -123,8 +124,9 @@ enum {
MDB_DEBUG_USAGE = 0x0004, MDB_DEBUG_USAGE = 0x0004,
MDB_DEBUG_OLE = 0x0008, MDB_DEBUG_OLE = 0x0008,
MDB_DEBUG_ROW = 0x0010, MDB_DEBUG_ROW = 0x0010,
MDB_USE_INDEX = 0x0020, MDB_DEBUG_PROPS = 0x0020,
MDB_NO_MEMO = 0x0040 /* don't follow memo fields */ MDB_USE_INDEX = 0x0040,
MDB_NO_MEMO = 0x0080, /* don't follow memo fields */
}; };
#define mdb_is_logical_op(x) (x == MDB_OR || \ #define mdb_is_logical_op(x) (x == MDB_OR || \
@@ -247,10 +249,8 @@ typedef struct {
char object_name[MDB_MAX_OBJ_NAME+1]; char object_name[MDB_MAX_OBJ_NAME+1];
int object_type; int object_type;
unsigned long table_pg; /* misnomer since object may not be a table */ unsigned long table_pg; /* misnomer since object may not be a table */
unsigned long kkd_pg; //int num_props; please use props->len
unsigned int kkd_rowid; GArray *props; /* GArray of MdbProperties */
int num_props;
GArray *props;
GArray *columns; GArray *columns;
int flags; int flags;
} MdbCatalogEntry; } 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 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_user_table(MdbCatalogEntry *entry);
extern int mdb_is_system_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 */ /* data.c */
extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr); 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); extern gint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg);
/* props.c */ /* props.c */
extern GPtrArray *mdb_read_props_list(gchar *kkd, int len);
extern void mdb_free_props(MdbProperties *props); 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 */ /* worktable.c */
extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name); extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name);

View File

@@ -1,5 +1,5 @@
lib_LTLIBRARIES = libmdb.la 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 libmdb_la_LDFLAGS = -version-info 1:0:0
AM_CPPFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS) AM_CPPFLAGS = -I$(top_srcdir)/include $(GLIB_CFLAGS)
LIBS = $(GLIB_LIBS) @LIBS@ LIBS = $(GLIB_LIBS) @LIBS@

View File

@@ -63,10 +63,14 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
MdbCatalogEntry *entry, msysobj; MdbCatalogEntry *entry, msysobj;
MdbTableDef *table; MdbTableDef *table;
char obj_id[256]; char obj_id[256];
char obj_name[256]; char obj_name[MDB_MAX_OBJ_NAME];
char obj_type[256]; char obj_type[256];
char obj_flags[256]; char obj_flags[256];
char obj_props[MDB_BIND_SIZE];
int type; int type;
unsigned int i;
MdbColumn *col_props;
int kkd_size_ole;
if (!mdb) return NULL; if (!mdb) return NULL;
if (mdb->catalog) mdb_free_catalog(mdb); 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, "Name", obj_name, NULL);
mdb_bind_column_by_name(table, "Type", obj_type, NULL); mdb_bind_column_by_name(table, "Type", obj_type, NULL);
mdb_bind_column_by_name(table, "Flags", obj_flags, 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); mdb_rewind_table(table);
while (mdb_fetch_row(table)) { while (mdb_fetch_row(table)) {
type = atoi(obj_type); type = atoi(obj_type);
if (objtype==MDB_ANY || type == objtype) { if (objtype==MDB_ANY || type == objtype) {
// fprintf(stdout, "obj_id: %10ld objtype: %-3d obj_name: %s\n", //fprintf(stderr, "obj_id: %10ld objtype: %-3d (0x%04x) obj_name: %s\n",
// (atol(obj_id) & 0x00FFFFFF), type, obj_name); // (atol(obj_id) & 0x00FFFFFF), type, type, obj_name);
entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry)); entry = (MdbCatalogEntry *) g_malloc0(sizeof(MdbCatalogEntry));
entry->mdb = mdb; entry->mdb = mdb;
strcpy(entry->object_name, obj_name); strcpy(entry->object_name, obj_name);
@@ -107,6 +113,13 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
entry->flags = atol(obj_flags); entry->flags = atol(obj_flags);
mdb->num_catalog++; 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); //mdb_dump_catalog(mdb, MDB_TABLE);
@@ -126,12 +139,10 @@ mdb_dump_catalog(MdbHandle *mdb, int obj_type)
for (i=0;i<mdb->num_catalog;i++) { for (i=0;i<mdb->num_catalog;i++) {
entry = g_ptr_array_index(mdb->catalog,i); entry = g_ptr_array_index(mdb->catalog,i);
if (obj_type==MDB_ANY || entry->object_type==obj_type) { 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), mdb_get_objtype_string(entry->object_type),
entry->object_name, entry->object_name,
(unsigned int) entry->table_pg, (unsigned int) entry->table_pg);
(unsigned int) entry->kkd_pg,
entry->kkd_rowid);
} }
} }
return; return;

View File

@@ -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;i<val_len;i++) {
c = mdb->pg_buf[pos+i];
if (isprint(c))
fprintf(stdout," %c",c);
else
fprintf(stdout," %02x",c);
}
pos = start + tmp;
prop = g_array_index(entry->props,MdbColumnProp,col_num);
fprintf(stdout," Property %s",prop.name);
fprintf(stdout,"\n");
}
return hash;
}
void mdb_kkd_dump(MdbCatalogEntry *entry)
{
int rows;
int kkd_start, kkd_end;
int i, tmp, pos, row_type, datapos=0;
MdbColumnProp prop;
MdbHandle *mdb = entry->mdb;
int rowid = entry->kkd_rowid;
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;i<rows;i++) {
tmp = mdb_get_int16(mdb->pg_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;i<entry->num_props;i++) {
prop = g_array_index(entry->props,MdbColumnProp,i);
fprintf(stdout,"%3d %s\n",i,prop.name);
}
}
if (row_type==0x01) datapos = pos;
pos += tmp;
}
if (datapos) {
mdb_get_column_def(entry, datapos);
}
}

View File

@@ -44,9 +44,9 @@ mdb_debug(int klass, char *fmt, ...)
if (!optset) load_options(); if (!optset) load_options();
if (klass & opts) { if (klass & opts) {
va_start(ap, fmt); va_start(ap, fmt);
vfprintf (stdout,fmt, ap); vfprintf (stderr,fmt, ap);
va_end(ap); va_end(ap);
fprintf(stdout,"\n"); fprintf(stderr,"\n");
} }
#endif #endif
} }
@@ -59,7 +59,7 @@ load_options()
if (!optset && (s=getenv("MDBOPTS"))) { if (!optset && (s=getenv("MDBOPTS"))) {
opt = strtok(s, ":"); opt = strtok(s, ":");
do { while (opt) {
if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX; if (!strcmp(opt, "use_index")) opts |= MDB_USE_INDEX;
if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO; if (!strcmp(opt, "no_memo")) opts |= MDB_NO_MEMO;
if (!strcmp(opt, "debug_like")) opts |= MDB_DEBUG_LIKE; 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_usage")) opts |= MDB_DEBUG_USAGE;
if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE; if (!strcmp(opt, "debug_ole")) opts |= MDB_DEBUG_OLE;
if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW; if (!strcmp(opt, "debug_row")) opts |= MDB_DEBUG_ROW;
if (!strcmp(opt, "debug_props")) opts |= MDB_DEBUG_PROPS;
if (!strcmp(opt, "debug_all")) { if (!strcmp(opt, "debug_all")) {
opts |= MDB_DEBUG_LIKE; opts |= MDB_DEBUG_LIKE;
opts |= MDB_DEBUG_WRITE; opts |= MDB_DEBUG_WRITE;
opts |= MDB_DEBUG_USAGE; opts |= MDB_DEBUG_USAGE;
opts |= MDB_DEBUG_OLE; opts |= MDB_DEBUG_OLE;
opts |= MDB_DEBUG_ROW; opts |= MDB_DEBUG_ROW;
opts |= MDB_DEBUG_PROPS;
} }
opt = strtok(NULL,":"); opt = strtok(NULL,":");
} while (opt); }
} }
optset = 1; optset = 1;
} }

View File

@@ -1,5 +1,5 @@
/* MDB Tools - A library for reading MS Access database file /* 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 * This library is free software; you can redistribute it and/or
@@ -20,16 +20,16 @@
#include "mdbtools.h" #include "mdbtools.h"
GPtrArray * static GPtrArray *
mdb_read_props_list(gchar *kkd, int len) mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len)
{ {
guint32 record_len; guint32 record_len;
int pos = 0; int pos = 0;
gchar *name; gchar *name;
GPtrArray *names = NULL; GPtrArray *names = NULL;
int i = 0;
names = g_ptr_array_new(); names = g_ptr_array_new();
int i=0;
#if MDB_DEBUG #if MDB_DEBUG
buffer_dump(kkd, 0, len); buffer_dump(kkd, 0, len);
#endif #endif
@@ -37,13 +37,13 @@ mdb_read_props_list(gchar *kkd, int len)
while (pos < len) { while (pos < len) {
record_len = mdb_get_int16(kkd, pos); record_len = mdb_get_int16(kkd, pos);
pos += 2; pos += 2;
#if MDB_DEBUG if (mdb_get_option(MDB_DEBUG_PROPS)) {
printf("%02d ",i++); fprintf(stderr, "%02d ",i++);
buffer_dump(kkd, pos - 2, record_len + 2); buffer_dump(kkd, pos - 2, record_len + 2);
#endif }
name = g_malloc(record_len + 1); name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte in */
strncpy(name, &kkd[pos], record_len); mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len);
name[record_len] = '\0';
pos += record_len; pos += record_len;
g_ptr_array_add(names, name); g_ptr_array_add(names, name);
#if MDB_DEBUG #if MDB_DEBUG
@@ -60,6 +60,12 @@ mdb_free_props(MdbProperties *props)
if (props->name) g_free(props->name); if (props->name) g_free(props->name);
g_free(props); 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 * MdbProperties *
mdb_alloc_props() mdb_alloc_props()
{ {
@@ -69,7 +75,7 @@ mdb_alloc_props()
return props; return props;
} }
MdbProperties * static MdbProperties *
mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
{ {
guint32 record_len, name_len; guint32 record_len, name_len;
@@ -84,16 +90,15 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
#endif #endif
pos = 0; pos = 0;
/* skip the name record */
record_len = mdb_get_int16(kkd, pos); record_len = mdb_get_int16(kkd, pos);
pos += 4; pos += 4;
name_len = mdb_get_int16(kkd, pos); name_len = mdb_get_int16(kkd, pos);
pos += 2; pos += 2;
props = mdb_alloc_props(); props = mdb_alloc_props();
if (name_len) { if (name_len) {
props->name = g_malloc(name_len + 1); props->name = g_malloc(3*name_len + 1);
strncpy(props->name, &kkd[pos], name_len); mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len);
props->name[name_len]='\0'; mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name);
} }
pos += name_len; pos += name_len;
@@ -101,18 +106,18 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
while (pos < len) { while (pos < len) {
record_len = mdb_get_int16(kkd, pos); record_len = mdb_get_int16(kkd, pos);
elem = mdb_get_int16(kkd, pos + 4);
dtype = kkd[pos + 3]; dtype = kkd[pos + 3];
elem = mdb_get_int16(kkd, pos + 4);
dsize = mdb_get_int16(kkd, pos + 6); dsize = mdb_get_int16(kkd, pos + 6);
value = g_malloc(dsize + 1); value = g_malloc(dsize + 1);
strncpy(value, &kkd[pos + 8], dsize); strncpy(value, &kkd[pos + 8], dsize);
value[dsize] = '\0'; value[dsize] = '\0';
name = g_ptr_array_index(names,elem); name = g_ptr_array_index(names,elem);
#if MDB_DEBUG if (mdb_get_option(MDB_DEBUG_PROPS)) {
printf("%02d ",i++); fprintf(stderr, "%02d ",i++);
buffer_dump(kkd, pos, record_len); mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, dtype);
printf("elem %d dsize %d dtype %d\n", elem, dsize, dtype); buffer_dump(value, 0, dsize);
#endif }
if (dtype == MDB_MEMO) dtype = MDB_TEXT; if (dtype == MDB_MEMO) dtype = MDB_TEXT;
if (dtype == MDB_BOOL) { if (dtype == MDB_BOOL) {
g_hash_table_insert(props->hash, g_strdup(name), 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; 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;
}

View File

@@ -78,6 +78,7 @@ MdbTableDef *mdb_read_table(MdbCatalogEntry *entry)
MdbFormatConstants *fmt = mdb->fmt; MdbFormatConstants *fmt = mdb->fmt;
int len, row_start, pg_row; int len, row_start, pg_row;
void *buf, *pg_buf = mdb->pg_buf; void *buf, *pg_buf = mdb->pg_buf;
guint i;
mdb_read_pg(mdb, entry->table_pg); mdb_read_pg(mdb, entry->table_pg);
if (mdb_get_byte(pg_buf, 0) != 0x02) /* not a valid table def page */ 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); table->first_data_pg = mdb_get_int16(pg_buf, fmt->tab_first_dpg_offset);
if (entry->props)
for (i=0; i<entry->props->len; ++i) {
MdbProperties *props = g_array_index(entry->props, MdbProperties*, i);
if (!props->name)
table->props = props;
}
return table; return table;
} }
MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type) 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; MdbFormatConstants *fmt = mdb->fmt;
MdbColumn *pcol; MdbColumn *pcol;
unsigned char *col; unsigned char *col;
unsigned int i; unsigned int i, j;
int cur_pos; int cur_pos;
size_t name_sz; 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); mdb_unicode2ascii(mdb, tmp_buf, name_sz, pcol->name, MDB_MAX_OBJ_NAME);
g_free(tmp_buf); g_free(tmp_buf);
} }
/* Sort the columns by col_num */ /* Sort the columns by col_num */
g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer); g_ptr_array_sort(table->columns, (GCompareFunc)mdb_col_comparer);
GArray *allprops = table->entry->props;
if (allprops)
for (i=0;i<table->num_cols;i++) {
pcol = g_ptr_array_index(table->columns, i);
for (j=0; j<allprops->len; ++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; table->index_start = cur_pos;
return table->columns; return table->columns;
} }
@@ -316,6 +338,8 @@ guint32 pgnum;
fprintf(stdout,"number of columns = %d\n",table->num_cols); fprintf(stdout,"number of columns = %d\n",table->num_cols);
fprintf(stdout,"number of indices = %d\n",table->num_real_idxs); 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_columns(table);
mdb_read_indices(table); mdb_read_indices(table);
@@ -326,6 +350,8 @@ guint32 pgnum;
i, col->name, i, col->name,
mdb_get_coltype_string(mdb->default_backend, col->col_type), mdb_get_coltype_string(mdb->default_backend, col->col_type),
col->col_size); col->col_size);
if (col->props)
mdb_dump_props(col->props, stdout, 0);
} }
for (i=0;i<table->num_idxs;i++) { for (i=0;i<table->num_idxs;i++) {
@@ -370,3 +396,17 @@ int mdb_is_system_table(MdbCatalogEntry *entry)
return ((entry->object_type == MDB_TABLE) return ((entry->object_type == MDB_TABLE)
&& (entry->flags & 0x80000002)) ? 1 : 0; && (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);
}

View File

@@ -2,7 +2,7 @@ include_HEADERS = connectparams.h
SQLDIR = ../sql SQLDIR = ../sql
SQLSOURCES = mdbsql.c parser.c lexer.c SQLSOURCES = mdbsql.c parser.c lexer.c
MDBDIR = ../libmdb 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 \ data.c like.c table.c dump.c file.c mem.c \
map.c props.c worktable.c options.c \ map.c props.c worktable.c options.c \
write.c stats.c iconv.c write.c stats.c iconv.c

View File

@@ -1,5 +1,5 @@
/* MDB Tools - A library for reading MS Access database file /* 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 * This library is free software; you can redistribute it and/or
@@ -94,64 +94,12 @@ main(int argc, char **argv)
return 0; 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) void dump_kkd(MdbHandle *mdb, void *kkd, size_t len)
{ {
guint32 record_len; GArray *aprops = kkd_to_props(mdb, kkd, len);
guint16 record_type; int i;
size_t pos; for (i=0; i<aprops->len; ++i) {
GPtrArray *names = NULL; MdbProperties *props = g_array_index(aprops, MdbProperties*, i);
MdbProperties *props; mdb_dump_props(props, stdout, 1);
#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;
} }
} }