mirror of
https://github.com/mdbtools/mdbtools.git
synced 2026-03-10 00:20:54 +08:00
patch 'props' from Nirgal Vourgère
This commit is contained in:
39
HACKING
39
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
|
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)
|
16 bit length field (non-inclusive)
|
||||||
4 bytes of unknown purpose
|
value (07.53 for the AccessVersion example above)
|
||||||
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
|
Text Data Type
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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@
|
||||||
|
|||||||
@@ -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,14 +139,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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 (!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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -77,23 +83,22 @@ mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
|
|||||||
int elem, dtype, dsize;
|
int elem, dtype, dsize;
|
||||||
gchar *name, *value;
|
gchar *name, *value;
|
||||||
MdbProperties *props;
|
MdbProperties *props;
|
||||||
int i = 0;
|
int i=0;
|
||||||
|
|
||||||
#if MDB_DEBUG
|
#if MDB_DEBUG
|
||||||
buffer_dump(kkd, 0, len);
|
buffer_dump(kkd, 0, 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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -80,7 +80,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
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;
|
size_t size;
|
||||||
void *kkd = mdb_ole_read_full(mdb, col, &size);
|
void *kkd = mdb_ole_read_full(mdb, col, &size);
|
||||||
dump_kkd(mdb, kkd, size);
|
dump_kkd(mdb, kkd, size);
|
||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user