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
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
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

View File

@@ -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);

View File

@@ -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@

View File

@@ -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);
@@ -107,6 +113,13 @@ GPtrArray *mdb_read_catalog (MdbHandle *mdb, int objtype)
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);
//buffer_dump(kkd, 0, kkd_len);
entry->props = kkd_to_props(mdb, kkd, kkd_len);
free(kkd);
}
}
}
//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++) {
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;

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 (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;
}

View File

@@ -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++);
if (mdb_get_option(MDB_DEBUG_PROPS)) {
fprintf(stderr, "%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';
}
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;
@@ -84,16 +90,15 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int 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;
}

View File

@@ -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; i<entry->props->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;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;
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;i<table->num_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);
}

View File

@@ -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

View File

@@ -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
@@ -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; i<aprops->len; ++i) {
MdbProperties *props = g_array_index(aprops, MdbProperties*, i);
mdb_dump_props(props, stdout, 1);
}
}