mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-09-19 02:27:55 +08:00
patch 'props' from Nirgal Vourgère
This commit is contained in:
35
HACKING
35
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
|
||||
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
|
||||
|
@@ -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);
|
||||
|
@@ -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@
|
||||
|
@@ -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;
|
||||
|
151
src/libmdb/kkd.c
151
src/libmdb/kkd.c
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user