diff --git a/HACKERS b/HACKERS index 487db23..85711a2 100644 --- a/HACKERS +++ b/HACKERS @@ -89,11 +89,11 @@ course of action has been to stop at the first non-printable character After the name there is sometimes have (not yet determined why only sometimes) a page pointer and offset to the KKD records (see below). There is also pointer to other catalog pages, but I'm not really sure how to parse those. -Column Definition +Table Definition ----------------- The second and third bytes of each catalog entry store a 16 bit page pointer to -a column definition, including name, type, size, number of datarows, a pointer +a table definition, including name, type, size, number of datarows, a pointer to the first data page, and possibly more. I haven't fully figured this out so what follows is rough. The header to table definition pages start look something like this: @@ -144,6 +144,41 @@ Column Type may be one of the following (not complete). Following the 18 byte column records begins the column names, listed in order with a 1 byte size prefix preceding each name. +Data Rows +--------- + +The header of a data page looks like this: + ++------+---------+--------------------------------------------------------+ +| 0x01 | 1 byte | Page type | +| 0x01 | 1 byte | Unknown | +| ???? | 2 bytes | Unknown | +| ???? | 2 bytes | Page pointer to table definition | +| 0x00 | 2 bytes | Unknown | +| ???? | 4 bytes | number of rows of data in this table | ++------+---------+--------------------------------------------------------+ +| Iterate for the number of records | ++-------------------------------------------------------------------------+ +| ???? | 2 bytes | offset to the records location on this page | ++-------------------------------------------------------------------------+ + +Each data row looks like this: + ++------+---------+--------------------------------------------------------+ +| ???? | 1 byte | Number of columns stored in this row | +| ???? | n bytes | Fixed length columns | +| ???? | n bytes | Variable length columns | +| ???? | 1 byte | length of data from beginning of record | +| ???? | n bytes | offset from start of row for each variable length col | +| ???? | 1 byte | number of variable length columns | +| ???? | 1 byte | Unknown | ++------+---------+--------------------------------------------------------+ + +Note: it is possible for the offset to the beginning of a variable length +column to require more than one byte (if the sum of the lengths of columns is +greater than 255). I have no idea how this is represented in the data as I +have not looked at tables large enough for this to occur yet. + KKD Records ----------- diff --git a/README b/README index f5053d8..7639a6d 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ -This is mdbtools version 0.001 +This is mdbtools version 0.002 -This software is very, very pre-pre-pre-pre-alpha (did I make my point?), so +This software is very, very pre-pre-pre-alpha (did I make my point?), so unless you know C and probably a little something about databases and reverse engineering file formats, you're welcome to try it out but don't expect much if anything to work. @@ -19,7 +19,8 @@ mdb-dump -- a simple hex dump utility that I've been using to look at mdb files prcat -- print the catalog table from an mdb file (try offset 9000). prkkd -- prints some info about a KKD record given the offset to it. -If you're interested in digging into the project let me know, and I'll try to get a mailing list together. + +Check out http://mdbtools.sourceforge.net for CVS, mailing list and similar. Brian Bruns camber@ais.org diff --git a/src/include/mdbtools.h b/src/include/mdbtools.h index e3ff108..3d065f6 100644 --- a/src/include/mdbtools.h +++ b/src/include/mdbtools.h @@ -77,6 +77,15 @@ typedef struct { GArray *columns; } MdbCatalogEntry; +typedef struct { + char name[MDB_MAX_OBJ_NAME+1]; + int num_cols; + int num_rows; + int num_pgs; + int first_data_pg; + GArray *columns; +} MdbTableDef; + typedef struct { char name[MDB_MAX_OBJ_NAME+1]; } MdbColumnProp; @@ -90,6 +99,7 @@ typedef struct { extern MdbHandle *mdb_alloc_handle(); extern void mdb_free_handle(MdbHandle *mdb); extern void mdb_free_catalog(MdbHandle *mdb); +extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry); extern size_t mdb_read_pg(MdbHandle *mdb, unsigned long pg); extern int mdb_get_int16(MdbHandle *mdb, int offset); diff --git a/src/libmdb/catalog.c b/src/libmdb/catalog.c index 9f0416d..3c6e0ef 100644 --- a/src/libmdb/catalog.c +++ b/src/libmdb/catalog.c @@ -42,7 +42,7 @@ static char *type_name[] = {"Form", } } -MdbCatalogEntry *mdb_catalog_entry(MdbHandle *mdb, int rowid, MdbCatalogEntry *entry) +MdbCatalogEntry *mdb_read_catalog_entry(MdbHandle *mdb, int rowid, MdbCatalogEntry *entry) { int offset; int rows; @@ -118,7 +118,7 @@ int next_pg, next_pg_off; fprintf(stdout,"YES! next pg = %04x %d\n",next_pg, next_pg); continue; } - if (mdb_catalog_entry(mdb, i, &entry)) { + if (mdb_read_catalog_entry(mdb, i, &entry)) { data = g_memdup(&entry,sizeof(MdbCatalogEntry)); mdb->catalog = g_list_append(mdb->catalog, data); } @@ -134,7 +134,7 @@ int next_pg, next_pg_off; rows = mdb_catalog_rows(mdb); for (i=0;ipg_buf[11 + 2 * i] & 0x40) continue; - if (mdb_catalog_entry(mdb, i, &entry)) { + if (mdb_read_catalog_entry(mdb, i, &entry)) { data = g_memdup(&entry,sizeof(MdbCatalogEntry)); mdb->catalog = g_list_append(mdb->catalog, data); } diff --git a/src/libmdb/mem.c b/src/libmdb/mem.c index dbf8088..c15027d 100644 --- a/src/libmdb/mem.c +++ b/src/libmdb/mem.c @@ -46,3 +46,17 @@ MdbCatalogEntry *entryp; g_free(entryp); } } +MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry) +{ +MdbTableDef *table; + + table = (MdbTableDef *) malloc(sizeof(MdbTableDef)); + memset(table, '\0', sizeof(MdbTableDef)); + strcpy(table->name, entry->object_name); + + return table; +} +void mdb_free_tabledef(MdbTableDef *table) +{ + if (table) free(table); +} diff --git a/src/libmdb/table.c b/src/libmdb/table.c index cae5c63..6ba5df9 100644 --- a/src/libmdb/table.c +++ b/src/libmdb/table.c @@ -58,39 +58,53 @@ unsigned char mdb_col_needs_size(int col_type) } } -/* -** -*/ +MdbTableDef *mdb_read_table(MdbCatalogEntry *entry) +{ +MdbTableDef *table; +MdbHandle *mdb = entry->mdb; +int len, i; + + table = mdb_alloc_tabledef(entry); + + mdb_read_pg(mdb, entry->table_pg); + len = mdb_get_int16(mdb,8); + + table->num_rows = mdb_get_int32(mdb,12); + table->num_cols = mdb_get_int16(mdb,25); + table->num_pgs = mdb_get_int32(mdb,27); + table->first_data_pg = mdb_get_int16(mdb,36); + + return table; +} + +MdbColumn *mdb_read_column(MdbTableDef *table) +{ +} void mdb_table_dump(MdbCatalogEntry *entry) { -int num_cols, num_rows, data_pgs, first_dpg; int len, i; int cur_col, cur_name; int col_type, col_size; int col_start, name_start; char name[MDB_MAX_OBJ_NAME+1]; int name_sz; +MdbTableDef *table; MdbHandle *mdb = entry->mdb; - mdb_read_pg(mdb, entry->table_pg); - len = mdb_get_int16(mdb,8); - num_rows = mdb_get_int32(mdb,12); - num_cols = mdb_get_int16(mdb,25); - data_pgs = mdb_get_int32(mdb,27); - first_dpg = mdb_get_int16(mdb,36); - fprintf(stdout,"number of datarows = %d\n",num_rows); - fprintf(stdout,"number of columns = %d\n",num_cols); - fprintf(stdout,"number of datapages = %d\n",data_pgs); - fprintf(stdout,"first data page = %d\n",first_dpg); + table = mdb_read_table(entry); + fprintf(stdout,"number of datarows = %d\n",table->num_rows); + fprintf(stdout,"number of columns = %d\n",table->num_cols); + fprintf(stdout,"number of datapages = %d\n",table->num_pgs); + fprintf(stdout,"first data page = %d\n",table->first_data_pg); - col_start = 43 + (data_pgs * 8); - name_start = col_start + (num_cols * 18); + col_start = 43 + (table->num_pgs * 8); + name_start = col_start + (table->num_cols * 18); cur_col = col_start; cur_name = name_start; - for (i=0;inum_cols;i++) { col_type = mdb->pg_buf[cur_col]; col_size = mdb_get_int16(mdb,cur_col+16); @@ -106,4 +120,3 @@ MdbHandle *mdb = entry->mdb; cur_name += name_sz + 1; } } - diff --git a/src/util/prcat.c b/src/util/prcat.c index fcdf6d3..9bd625e 100644 --- a/src/util/prcat.c +++ b/src/util/prcat.c @@ -1,20 +1,19 @@ /* 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 program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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, + * This program 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "mdbtools.h" diff --git a/src/util/prtable.c b/src/util/prtable.c index 826e921..883f7b4 100644 --- a/src/util/prtable.c +++ b/src/util/prtable.c @@ -1,7 +1,8 @@ /* 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 + * + * 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. @@ -25,7 +26,8 @@ int rows; int i; unsigned char buf[2048]; MdbHandle *mdb; -MdbCatalogEntry entry; +MdbCatalogEntry *entry; +GList *l; if (argc<2) { @@ -35,14 +37,12 @@ MdbCatalogEntry entry; mdb = mdb_open(argv[1]); - mdb_read_pg(mdb, MDB_CATALOG_PG); - rows = mdb_catalog_rows(mdb); + mdb_read_catalog(mdb, MDB_TABLE); - for (i=0;icatalog);l;l=g_list_next(l)) { + entry = l->data; + if (!strcmp(entry->object_name,argv[2])) { + mdb_table_dump(entry); } }