2000-03-01 03:34:33 +00:00
/* 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"
2003-01-28 23:51:06 +00:00
# ifdef DMALLOC
# include "dmalloc.h"
# endif
2002-12-27 15:09:02 +00:00
2002-02-03 02:49:08 +00:00
static gint mdb_col_comparer ( MdbColumn * a , MdbColumn * b )
{
if ( a - > col_num > b - > col_num )
return 1 ;
else if ( a - > col_num < b - > col_num )
return - 1 ;
else
return 0 ;
}
2000-03-01 03:34:33 +00:00
unsigned char mdb_col_needs_size ( int col_type )
{
if ( col_type = = MDB_TEXT ) {
return TRUE ;
} else {
return FALSE ;
}
}
2004-02-11 22:05:13 +00:00
MdbTableDef *
mdb_read_table ( MdbCatalogEntry * entry )
2000-03-04 17:31:07 +00:00
{
2004-02-11 22:05:13 +00:00
MdbTableDef * table ;
MdbHandle * mdb = entry - > mdb ;
MdbFormatConstants * fmt = mdb - > fmt ;
int len ;
int rownum , row_start , row_end ;
guint32 pg ;
2000-03-04 17:31:07 +00:00
table = mdb_alloc_tabledef ( entry ) ;
mdb_read_pg ( mdb , entry - > table_pg ) ;
2004-01-10 21:46:14 +00:00
if ( mdb - > pg_buf [ 0 ] ! = 0x02 ) return NULL ; /* not a valid table def page */
2003-04-29 17:55:09 +00:00
len = mdb_pg_get_int16 ( mdb , 8 ) ;
2000-03-04 17:31:07 +00:00
2003-04-29 17:55:09 +00:00
table - > num_rows = mdb_pg_get_int32 ( mdb , fmt - > tab_num_rows_offset ) ;
table - > num_cols = mdb_pg_get_int16 ( mdb , fmt - > tab_num_cols_offset ) ;
table - > num_idxs = mdb_pg_get_int32 ( mdb , fmt - > tab_num_idxs_offset ) ;
table - > num_real_idxs = mdb_pg_get_int32 ( mdb , fmt - > tab_num_ridxs_offset ) ;
2002-12-20 06:17:41 +00:00
/* grab a copy of the usage map */
2003-01-01 22:29:39 +00:00
rownum = mdb - > pg_buf [ fmt - > tab_usage_map_offset ] ;
2004-02-11 22:05:13 +00:00
pg = mdb_pg_get_int24 ( mdb , fmt - > tab_usage_map_offset + 1 ) ;
mdb_read_alt_pg ( mdb , pg ) ;
2002-12-20 06:17:41 +00:00
mdb_swap_pgbuf ( mdb ) ;
2003-04-29 17:55:09 +00:00
row_start = mdb_pg_get_int16 ( mdb , ( fmt - > row_count_offset + 2 ) + ( rownum * 2 ) ) ;
2003-02-09 23:19:21 +00:00
row_end = mdb_find_end_of_row ( mdb , rownum ) ;
2002-12-27 15:09:02 +00:00
table - > map_sz = row_end - row_start + 1 ;
2004-05-30 05:06:26 +00:00
table - > usage_map = g_memdup ( & mdb - > pg_buf [ row_start ] , table - > map_sz ) ;
2004-02-16 02:00:45 +00:00
if ( mdb_get_option ( MDB_DEBUG_USAGE ) )
buffer_dump ( mdb - > pg_buf , row_start , row_end ) ;
2002-12-20 06:17:41 +00:00
/* swap back */
mdb_swap_pgbuf ( mdb ) ;
2004-02-16 02:00:45 +00:00
mdb_debug ( MDB_DEBUG_USAGE , " usage map found on page %ld rownum %d start %d end %d " , mdb_pg_get_int24 ( mdb , fmt - > tab_usage_map_offset + 1 ) , rownum , row_start , row_end ) ;
2002-12-20 06:17:41 +00:00
2003-02-09 23:19:21 +00:00
/* now grab the free space page map */
2004-01-09 21:05:56 +00:00
# if 1
//mdb_swap_pgbuf(mdb);
2003-02-09 23:19:21 +00:00
rownum = mdb - > pg_buf [ fmt - > tab_free_map_offset ] ;
2003-04-29 17:55:09 +00:00
mdb_read_alt_pg ( mdb , mdb_pg_get_int24 ( mdb , fmt - > tab_free_map_offset + 1 ) ) ;
2003-02-09 23:19:21 +00:00
mdb_swap_pgbuf ( mdb ) ;
2003-04-29 17:55:09 +00:00
row_start = mdb_pg_get_int16 ( mdb , ( fmt - > row_count_offset + 2 ) + ( rownum * 2 ) ) ;
2003-02-09 23:19:21 +00:00
row_end = mdb_find_end_of_row ( mdb , rownum ) ;
table - > freemap_sz = row_end - row_start + 1 ;
2004-05-30 05:06:26 +00:00
table - > free_usage_map = g_memdup ( & mdb - > pg_buf [ row_start ] , table - > freemap_sz ) ;
2004-01-09 21:05:56 +00:00
mdb_swap_pgbuf ( mdb ) ;
2003-04-29 17:55:09 +00:00
# endif
2004-02-16 02:00:45 +00:00
mdb_debug ( MDB_DEBUG_USAGE , " free map found on page %ld rownum %d start %d end %d \n " , mdb_pg_get_int24 ( mdb , fmt - > tab_free_map_offset + 1 ) , rownum , row_start , row_end ) ;
2003-02-09 23:19:21 +00:00
2003-04-29 17:55:09 +00:00
table - > first_data_pg = mdb_pg_get_int16 ( mdb , fmt - > tab_first_dpg_offset ) ;
2000-03-04 17:31:07 +00:00
return table ;
}
2000-10-13 21:33:04 +00:00
/*
* * read the next page if offset is > pg_size
* * return true if page was read
*/
2003-01-28 23:51:06 +00:00
int
read_pg_if ( MdbHandle * mdb , int * cur_pos , int offset )
2000-10-13 21:33:04 +00:00
{
2003-01-01 22:29:39 +00:00
if ( * cur_pos + offset > = mdb - > fmt - > pg_size ) {
2003-04-29 17:55:09 +00:00
mdb_read_pg ( mdb , mdb_pg_get_int32 ( mdb , 4 ) ) ;
2003-01-01 22:29:39 +00:00
* cur_pos = 8 - ( mdb - > fmt - > pg_size - ( * cur_pos ) ) ;
2000-10-13 21:33:04 +00:00
return 1 ;
}
return 0 ;
}
2003-01-28 23:51:06 +00:00
guint32
read_pg_if_32 ( MdbHandle * mdb , int * cur_pos )
{
unsigned char c [ 4 ] ;
int i , rc = 0 ;
for ( i = 0 ; i < 4 ; i + + ) {
rc + = read_pg_if ( mdb , cur_pos , i ) ;
c [ i ] = mdb - > pg_buf [ ( * cur_pos ) + i ] ;
}
2003-04-29 17:55:09 +00:00
return mdb_get_int32 ( c , 0 ) ;
2003-01-28 23:51:06 +00:00
}
guint16
read_pg_if_16 ( MdbHandle * mdb , int * cur_pos )
{
unsigned char low_byte , high_byte ;
int rc = 0 ;
rc + = read_pg_if ( mdb , cur_pos , 0 ) ;
low_byte = mdb - > pg_buf [ * cur_pos ] ;
rc + = read_pg_if ( mdb , cur_pos , 1 ) ;
high_byte = mdb - > pg_buf [ ( * cur_pos ) + 1 ] ;
return ( high_byte * 256 + low_byte ) ;
}
guint16
read_pg_if_n ( MdbHandle * mdb , unsigned char * buf , int * cur_pos , int len )
{
if ( * cur_pos + len < mdb - > fmt - > pg_size ) {
memcpy ( buf , & mdb - > pg_buf [ * cur_pos ] , len ) ;
return 0 ;
2004-06-11 21:57:19 +00:00
} else {
int half = mdb - > fmt - > pg_size - * cur_pos ;
memcpy ( buf , & mdb - > pg_buf [ * cur_pos ] , half ) ;
mdb_read_pg ( mdb , mdb_pg_get_int32 ( mdb , 4 ) ) ;
memcpy ( buf + half , & mdb - > pg_buf [ 8 ] , len - half ) ;
* cur_pos = 8 - half ;
return 1 ;
2003-01-28 23:51:06 +00:00
}
}
2000-10-13 21:33:04 +00:00
2000-03-12 14:08:53 +00:00
GPtrArray * mdb_read_columns ( MdbTableDef * table )
2000-03-01 03:34:33 +00:00
{
2004-01-06 00:42:07 +00:00
MdbHandle * mdb = table - > entry - > mdb ;
MdbFormatConstants * fmt = mdb - > fmt ;
2004-06-14 12:13:25 +00:00
MdbColumn * pcol ;
unsigned char * col ;
int i , cur_pos , name_sz ;
2004-01-06 00:42:07 +00:00
GSList * slist = NULL ;
2000-03-05 13:10:42 +00:00
2000-03-12 14:08:53 +00:00
table - > columns = g_ptr_array_new ( ) ;
2000-03-04 17:31:07 +00:00
2004-06-14 12:13:25 +00:00
col = ( unsigned char * ) g_malloc ( fmt - > tab_col_entry_size ) ;
cur_pos = fmt - > tab_cols_start_offset +
2003-01-01 22:29:39 +00:00
( table - > num_real_idxs * fmt - > tab_ridx_entry_size ) ;
2000-03-01 03:34:33 +00:00
2000-10-13 21:33:04 +00:00
/* new code based on patch submitted by Tim Nelson 2000.09.27 */
2000-03-01 03:34:33 +00:00
2000-10-13 21:33:04 +00:00
/*
* * column attributes
*/
2002-02-03 02:49:08 +00:00
for ( i = 0 ; i < table - > num_cols ; i + + ) {
2002-12-10 23:35:24 +00:00
# ifdef MDB_DEBUG
/* printf("column %d\n", i);
2004-06-14 12:13:25 +00:00
buffer_dump ( mdb - > pg_buf , cur_pos , cur_pos + 18 ) ; */
2002-12-10 23:35:24 +00:00
# endif
2004-06-14 12:13:25 +00:00
read_pg_if_n ( mdb , col , & cur_pos , fmt - > tab_col_entry_size ) ;
cur_pos + = fmt - > tab_col_entry_size ;
pcol = ( MdbColumn * ) g_malloc0 ( sizeof ( MdbColumn ) ) ;
2000-03-05 13:10:42 +00:00
2004-06-14 12:13:25 +00:00
pcol - > col_type = col [ 0 ] ;
2000-10-13 21:33:04 +00:00
2004-06-14 12:13:25 +00:00
// col_num_offset == 1 or 5
pcol - > col_num = col [ fmt - > col_num_offset ] ;
2004-01-06 00:42:07 +00:00
2004-06-14 12:13:25 +00:00
//fprintf(stdout,"----- column %d -----\n",pcol->col_num);
// col_var == 3 or 7
pcol - > var_col_num = mdb_get_int16 ( col , fmt - > tab_col_offset_var ) ;
//fprintf(stdout,"var column pos %d\n",pcol->var_col_num);
2004-03-04 21:25:09 +00:00
2004-06-14 12:13:25 +00:00
// col_var == 5 or 9
pcol - > row_col_num = mdb_get_int16 ( col , fmt - > tab_row_col_num_offset ) ;
//fprintf(stdout,"row column num %d\n",pcol->row_col_num);
2004-03-04 21:25:09 +00:00
2004-01-06 00:42:07 +00:00
/* FIXME: can this be right in Jet3 and Jet4? */
2004-06-14 12:13:25 +00:00
if ( pcol - > col_type = = MDB_NUMERIC ) {
pcol - > col_prec = col [ 11 ] ;
pcol - > col_scale = col [ 12 ] ;
2002-12-10 23:35:24 +00:00
}
2000-03-01 03:34:33 +00:00
2004-06-14 12:13:25 +00:00
// col_fixed_offset == 13 or 15
pcol - > is_fixed = col [ fmt - > col_fixed_offset ] & 0x01 ? 1 : 0 ;
// col_fixed_offset == 13 or 15
pcol - > fixed_offset = mdb_get_int16 ( col , fmt - > tab_col_offset_fixed ) ;
//fprintf(stdout,"fixed column offset %d\n",pcol->fixed_offset);
//fprintf(stdout,"col type %s\n",pcol->is_fixed ? "fixed" : "variable");
if ( pcol - > col_type ! = MDB_BOOL ) {
// col_size_offset == 16 or 23
pcol - > col_size = mdb_get_int16 ( col , fmt - > col_size_offset ) ;
} else {
pcol - > col_size = 0 ;
}
2002-02-03 02:49:08 +00:00
slist = g_slist_insert_sorted ( slist , pcol , ( GCompareFunc ) mdb_col_comparer ) ;
2000-03-05 13:10:42 +00:00
}
2004-06-14 12:13:25 +00:00
g_free ( col ) ;
2000-10-13 21:33:04 +00:00
/*
* * column names
*/
for ( i = 0 ; i < table - > num_cols ; i + + ) {
/* fetch the column */
2002-02-03 02:49:08 +00:00
pcol = g_slist_nth_data ( slist , i ) ;
2000-10-13 21:33:04 +00:00
2003-01-01 22:29:39 +00:00
if ( IS_JET4 ( mdb ) ) {
2004-06-14 12:13:25 +00:00
char * tmp_buf ;
name_sz = read_pg_if_16 ( mdb , & cur_pos ) ;
cur_pos + = 2 ;
tmp_buf = ( char * ) g_malloc ( name_sz ) ;
read_pg_if_n ( mdb , tmp_buf , & cur_pos , name_sz ) ;
mdb_unicode2ascii ( mdb , tmp_buf , 0 , name_sz , pcol - > name ) ;
g_free ( tmp_buf ) ;
cur_pos + = name_sz ;
2003-01-01 22:29:39 +00:00
} else if ( IS_JET3 ( mdb ) ) {
2004-06-14 12:13:25 +00:00
read_pg_if ( mdb , & cur_pos , 0 ) ;
name_sz = mdb - > pg_buf [ cur_pos ] ;
cur_pos + + ;
read_pg_if_n ( mdb , pcol - > name , & cur_pos , name_sz ) ;
2002-02-03 02:49:08 +00:00
pcol - > name [ name_sz ] = ' \0 ' ;
2004-06-14 12:13:25 +00:00
cur_pos + = name_sz ;
2002-02-03 02:49:08 +00:00
} else {
fprintf ( stderr , " Unknown MDB version \n " ) ;
2000-10-13 21:33:04 +00:00
}
}
2002-02-03 02:49:08 +00:00
/* turn this list into an array */
for ( i = 0 ; i < table - > num_cols ; i + + ) {
pcol = g_slist_nth_data ( slist , i ) ;
g_ptr_array_add ( table - > columns , pcol ) ;
}
g_slist_free ( slist ) ;
2004-06-14 12:13:25 +00:00
table - > index_start = cur_pos ;
2000-03-05 13:10:42 +00:00
return table - > columns ;
}
void mdb_table_dump ( MdbCatalogEntry * entry )
{
MdbTableDef * table ;
2000-03-12 14:08:53 +00:00
MdbColumn * col ;
2003-01-01 22:29:39 +00:00
int coln ;
2001-04-01 22:10:15 +00:00
MdbIndex * idx ;
2000-03-05 13:10:42 +00:00
MdbHandle * mdb = entry - > mdb ;
2002-12-20 06:17:41 +00:00
int i , bitn ;
2003-01-20 16:04:24 +00:00
guint32 pgnum ;
2000-03-05 13:10:42 +00:00
table = mdb_read_table ( entry ) ;
2003-01-12 22:59:41 +00:00
fprintf ( stdout , " definition page = %lu \n " , entry - > table_pg ) ;
2000-03-05 13:10:42 +00:00
fprintf ( stdout , " number of datarows = %d \n " , table - > num_rows ) ;
fprintf ( stdout , " number of columns = %d \n " , table - > num_cols ) ;
2001-04-01 22:10:15 +00:00
fprintf ( stdout , " number of indices = %d \n " , table - > num_real_idxs ) ;
2000-03-05 13:10:42 +00:00
2000-03-09 04:48:59 +00:00
mdb_read_columns ( table ) ;
2001-04-01 22:10:15 +00:00
mdb_read_indices ( table ) ;
2000-03-05 13:10:42 +00:00
for ( i = 0 ; i < table - > num_cols ; i + + ) {
2000-03-12 14:08:53 +00:00
col = g_ptr_array_index ( table - > columns , i ) ;
2000-03-05 13:10:42 +00:00
2000-03-09 04:48:59 +00:00
fprintf ( stdout , " column %d Name: %-20s Type: %s(%d) \n " ,
2000-03-12 14:08:53 +00:00
i , col - > name ,
2000-04-02 17:08:30 +00:00
mdb_get_coltype_string ( mdb - > default_backend , col - > col_type ) ,
2000-03-12 14:08:53 +00:00
col - > col_size ) ;
2000-03-01 03:34:33 +00:00
}
2001-04-01 22:10:15 +00:00
for ( i = 0 ; i < table - > num_idxs ; i + + ) {
idx = g_ptr_array_index ( table - > indices , i ) ;
2001-05-23 01:42:46 +00:00
mdb_index_dump ( table , idx ) ;
2001-04-01 22:10:15 +00:00
}
2002-12-20 06:17:41 +00:00
if ( table - > usage_map ) {
2003-01-20 16:04:24 +00:00
printf ( " pages reserved by this object \n " ) ;
2004-02-11 22:05:13 +00:00
printf ( " usage map pg %lu \n " , table - > map_base_pg ) ;
printf ( " free map pg %lu \n " , table - > freemap_base_pg ) ;
2003-04-29 17:55:09 +00:00
pgnum = mdb_get_int32 ( table - > usage_map , 1 ) ;
2002-12-20 06:17:41 +00:00
/* the first 5 bytes of the usage map mean something */
2003-01-01 22:29:39 +00:00
coln = 0 ;
2002-12-20 06:17:41 +00:00
for ( i = 5 ; i < table - > map_sz ; i + + ) {
for ( bitn = 0 ; bitn < 8 ; bitn + + ) {
2003-01-01 22:29:39 +00:00
if ( table - > usage_map [ i ] & 1 < < bitn ) {
coln + + ;
2003-01-20 16:04:24 +00:00
printf ( " %6lu " , ( long unsigned ) pgnum ) ;
2003-01-01 22:29:39 +00:00
if ( coln = = 10 ) {
printf ( " \n " ) ;
coln = 0 ;
}
}
2002-12-20 06:17:41 +00:00
pgnum + + ;
}
}
2004-02-11 22:05:13 +00:00
printf ( " \n " ) ;
2002-12-20 06:17:41 +00:00
}
2000-03-01 03:34:33 +00:00
}