mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-06-28 15:39:02 +08:00
add -M option to mdb-ver
make gmdb2 version match mainline code new dissector for jet4 tdef pages in gmdb2 gmdb2 right mouse click behaviour bugfix pre-compute index page bitmap in mdb_index_unpack_page() in preparation for index writes.
This commit is contained in:
parent
a62f26df50
commit
3a9aa2ceb7
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
Fri Feb 13 12:51:50 EST 2004 Brian Bruns <brian@bruns.com>
|
||||
|
||||
* src/extras/.cvsignore: change mdb-dump to mdb-hexdump
|
||||
* include/Makefile.am:
|
||||
* include/mdbver.h.in: new file
|
||||
* configure.in: add mdbver.h to AC_OUTPUT
|
||||
* src/util/mdb-ver.c: add -M flag to show MDB Tools version to help support
|
||||
* src/gmdb2/main2.c: change version number to mdbtools version number
|
||||
* src/gmdb2/sql.c: added some (commented) code to change cursor on execute.
|
||||
* src/gmdb2/table.c: right mouse click selects before calling popup.
|
||||
* src/gmdb2/debug.c: add separate dissector for jet4 tdef pages
|
||||
* src/gmdb2/gladefiles/gmdb2-prefs.glade: add help button
|
||||
* src/libmdb/index.c: pre-compute index page bitmap in mdb_index_unpack_page() in preparation for index writes.
|
||||
* include/mdbtools.h: change IndexPage structure for new algorithm
|
||||
|
||||
Wed Feb 11 15:30:42 EST 2004 Brian Bruns <brian@bruns.com>
|
||||
|
||||
* HACKING: rewritten to better reflect Jet4
|
||||
|
64
HACKING
64
HACKING
@ -123,7 +123,7 @@ unknown.
|
||||
Notes for offset_row:
|
||||
- Offsets that have 0x40 in the high order byte point to a location within
|
||||
the page where a Data Pointer (4 bytes) to another data page is stored. Also
|
||||
know as an overflow page.
|
||||
known as an overflow page.
|
||||
- Offsets that have 0x80 in the high order byte are deleted rows.
|
||||
(These flags are delflag and lookupflag in source code)
|
||||
|
||||
@ -165,11 +165,13 @@ Notes:
|
||||
. The var_len field indicates the size of the var_table[].
|
||||
. The eod field points at the last byte of the var_cols field. It is used to
|
||||
determine where the last var_col ends.
|
||||
. For boolean fixed columns, the values are in null_table[]: 0 indicates a false value, 1 indicates a true value
|
||||
. For boolean fixed columns, the values are in null_table[]: 0 indicates a false
|
||||
value, 1 indicates a true value
|
||||
. An 0xFF stored in the var_table indicates that this column has been deleted.
|
||||
|
||||
In Jet3 offsets are stored as 1 byte fields yielding a maximum of 256 bytes. To
|
||||
get around this offsets are computed using a jump table. The jump table stores the number of the first column in this jump segment. If the size of the data is
|
||||
get around this offsets are computed using a jump table. The jump table stores
|
||||
the number of the first column in this jump segment. If the size of the data is
|
||||
less than 256 then no jump table will be present.
|
||||
|
||||
For example if the row contains 45 columns and the offset of the 14th column is
|
||||
@ -271,7 +273,8 @@ or 4096 - (12+2+4) = 4078(jet4) bytes max in a page.
|
||||
TDEF Pages (Table Definition)
|
||||
-----------------------------
|
||||
|
||||
Every table in the database has a TDEF page. It contains a definition of the columns, types, sizes, indexes, and similar information.
|
||||
Every table in the database has a TDEF page. It contains a definition of
|
||||
the columns, types, sizes, indexes, and similar information.
|
||||
|
||||
+-------------------------------------------------------------------------+
|
||||
| Jet3/Jet4 TDEF Header
|
||||
@ -381,7 +384,7 @@ next_pg field.
|
||||
| ???? | 4 bytes | free_pages | Points to a similar record as above, |
|
||||
| | | | listing pages which contain free space. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Iterate for the number of num_real_idx (12 bytes per idxs) |
|
||||
| Iterate for the number of num_real_idx (12 bytes per idxs) |
|
||||
+-------------------------------------------------------------------------+
|
||||
| 0x00 | 4 bytes | ??? | |
|
||||
| ???? | 4 bytes | num_idx_rows| (not sure) |
|
||||
@ -410,7 +413,7 @@ next_pg field.
|
||||
+-------------------------------------------------------------------------+
|
||||
| ???? | 4 bytes | ??? | |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Iterate 10 times for 10 possible columns (10*3 = 30 bytes) |
|
||||
| Iterate 10 times for 10 possible columns (10*3 = 30 bytes) |
|
||||
+-------------------------------------------------------------------------+
|
||||
| ???? | 2 bytes | col_num | number of a column (0xFFFF= none) |
|
||||
| ???? | 1 byte | col_order | 0x01 = ascendency order |
|
||||
@ -515,7 +518,8 @@ follows:
|
||||
| ???? | 4 bytes | map_page | pointer to page type 0x05 containing map |
|
||||
+--------------------------------------------------------------------------+
|
||||
|
||||
Note that the intial start page is gone and is reused for the first page indirection. The 0x05 type page header looks like:
|
||||
Note that the intial start page is gone and is reused for the first page
|
||||
indirection. The 0x05 type page header looks like:
|
||||
|
||||
+--------------------------------------------------------------------------+
|
||||
| Usage Map Page (type 0x05) |
|
||||
@ -572,7 +576,8 @@ the count starts from the low order bit. For example take the data:
|
||||
|
||||
00 20 00 04 80 00 ...
|
||||
|
||||
This first entry starts at 0xf8 (always). Convert the bytes to binary starting with the low order bit and stopping at the first "on" bit:
|
||||
This first entry starts at 0xf8 (always). Convert the bytes to binary starting
|
||||
with the low order bit and stopping at the first "on" bit:
|
||||
|
||||
0000 0000 0000 01
|
||||
-- 00 --- -- 20 -->
|
||||
@ -587,9 +592,13 @@ starts 13 (0xd) bytes further in at 0x112. The final entry starts at
|
||||
0 0000 0000 0001
|
||||
<-- 04 -- -- 80 ---
|
||||
|
||||
or 13 (0xd) bytes more at 0x120. In this example the rest of the mask (up to offset 0xf8) would be zero filled and thus this last entry at 0x120 isn't an actual entry but the stopping point of the data.
|
||||
or 13 (0xd) bytes more at 0x120. In this example the rest of the mask (up
|
||||
to offset 0xf8) would be zero filled and thus this last entry at 0x120 isn't
|
||||
an actual entry but the stopping point of the data.
|
||||
|
||||
Since 0xf8 = 248 and 0x16 = 22, (248 - 22) * 8 = 1808 and 2048 - 1808 = 240 leaving just enough space for the bit mask to encode the remainder of the page. One wonders why MS didn't use a row offset table like they did on data pages,
|
||||
Since 0xf8 = 248 and 0x16 = 22, (248 - 22) * 8 = 1808 and 2048 - 1808 = 240
|
||||
leaving just enough space for the bit mask to encode the remainder of the page.
|
||||
One wonders why MS didn't use a row offset table like they did on data pages,
|
||||
seems like it would have been easier and more flexible.
|
||||
|
||||
So now we come to the index entries for type 0x03 pages which look like this:
|
||||
@ -613,13 +622,16 @@ The flag field is generally either 0x00, 0x7f, 0x80. 0x80 is the one's
|
||||
complement of 0x7f and all text data in the index would then need to be negated.
|
||||
The reason for this negation is unknown, although I suspect it has to do with
|
||||
descending order. The 0x00 flag indicates that the key column is null, and no
|
||||
data will follow, only the page pointer. In multicolumn indexes the flag field plus data is repeated for the number of columns participating in the key.
|
||||
data will follow, only the page pointer. In multicolumn indexes the flag field
|
||||
plus data is repeated for the number of columns participating in the key.
|
||||
|
||||
Update: There is a compression scheme utilized on leaf pages as follows:
|
||||
Normally an index entry with an integer primary key would be 9 bytes (1 for the flags field, 4 for the integer, 3 for page, and 1 for row). The entry can be shorter than 9, containing only 5 bytes, the first byte is the last octet of the
|
||||
encoded primary key field (integer) and the last four are the page/row pointer.
|
||||
Thus if the first key value on the page is 1 and it points to page 261 (00 01 05
|
||||
) row 3, it becomes
|
||||
Normally an index entry with an integer primary key would be 9 bytes (1
|
||||
for the flags field, 4 for the integer, 3 for page, and 1 for row). The
|
||||
entry can be shorter than 9, containing only 5 bytes, the first byte is the last
|
||||
octet of the encoded primary key field (integer) and the last four are the page/row
|
||||
pointer. Thus if the first key value on the page is 1 and it points to page 261
|
||||
(00 01 05) row 3, it becomes
|
||||
7f 00 00 00 01 00 01 05 03
|
||||
|
||||
the next index entry can be:
|
||||
@ -627,9 +639,11 @@ the next index entry can be:
|
||||
|
||||
that is, the key value is 2 (the last octet changes to 02) page 261 row 4.
|
||||
|
||||
Access stores an 'alphabetic sort order' version of the text key columns in the index. Basically this means that upper and lower case characters A-Z are merged and start at 0x60. Digits are 0x56 through 0x5f. Once converted into this
|
||||
(non-ascii) character set, the text value is able to be sorted in 'alphabetic'
|
||||
order. A text column will end with a NULL (0x00 or 0xff if negated).
|
||||
Access stores an 'alphabetic sort order' version of the text key columns in the index.
|
||||
Basically this means that upper and lower case characters A-Z are merged and start at
|
||||
0x60. Digits are 0x56 through 0x5f. Once converted into this (non-ascii) character set,
|
||||
the text value is able to be sorted in 'alphabetic' order. A text column will end with
|
||||
a NULL (0x00 or 0xff if negated).
|
||||
|
||||
The leaf page entries store the key column and the 3 byte page and 1 byte row
|
||||
number.
|
||||
@ -644,10 +658,13 @@ character set, compare against each index entry, and on successful comparison
|
||||
follow the page and row number to the data. Because text data is managled
|
||||
during this conversion there is no 'covered querys' possible on text columns.
|
||||
|
||||
To conserve on frequent index updates, Jet also does something special when creating new leaf pages at the end of a primary key
|
||||
(maybe others as well) index. The next leaf page pointer of the last leaf node points to the new leaf page but the index tree
|
||||
is not otherwise updated. In src/libmdb/index.c, the last leaf 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.
|
||||
To conserve on frequent index updates, Jet also does something special when
|
||||
creating new leaf pages at the end of a primary key (maybe others as well) index.
|
||||
The next leaf page pointer of the last leaf node points to the new leaf page but
|
||||
the index tree is not otherwise updated. In src/libmdb/index.c, the last leaf
|
||||
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
|
||||
-----------
|
||||
@ -656,7 +673,8 @@ 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.
|
||||
|
||||
Update: The KKD records are stored in LvProp column of MSysObjects so they are stored as other OLE/Memo fields are.
|
||||
Update: The KKD records are stored in LvProp column of MSysObjects so they are
|
||||
stored as other OLE/Memo fields are.
|
||||
|
||||
They look a little like this: (this needs work...see the kkd.c)
|
||||
|
||||
|
@ -127,4 +127,4 @@ AC_SUBST(READLINE_LIBS)
|
||||
localedir=${datadir}/locale
|
||||
AC_SUBST(localedir)
|
||||
|
||||
AC_OUTPUT(src/util/Makefile src/extras/Makefile Makefile include/Makefile src/libmdb/Makefile src/sql/Makefile src/odbc/Makefile doc/Makefile src/gmdb2/Makefile src/gmdb2/gladefiles/Makefile src/gmdb2/pixmaps/Makefile src/gmdb2/help/Makefile src/gmdb2/help/C/Makefile mdbtools.spec)
|
||||
AC_OUTPUT(src/util/Makefile src/extras/Makefile Makefile include/Makefile src/libmdb/Makefile src/sql/Makefile src/odbc/Makefile doc/Makefile src/gmdb2/Makefile src/gmdb2/gladefiles/Makefile src/gmdb2/pixmaps/Makefile src/gmdb2/help/Makefile src/gmdb2/help/C/Makefile mdbtools.spec include/mdbver.h)
|
||||
|
@ -1 +1 @@
|
||||
include_HEADERS = mdbtools.h mdbsql.h mdbodbc.h mdbprivate.h
|
||||
include_HEADERS = mdbtools.h mdbsql.h mdbodbc.h mdbprivate.h mdbver.h
|
||||
|
@ -266,8 +266,10 @@ typedef struct {
|
||||
int mask_pos;
|
||||
unsigned char mask_byte;
|
||||
int mask_bit;
|
||||
int start_pos;
|
||||
int offset;
|
||||
int len;
|
||||
guint16 idx_starts[2000];
|
||||
unsigned char cache_value[256];
|
||||
} MdbIndexPage;
|
||||
|
||||
|
@ -2,4 +2,4 @@ Makefile
|
||||
Makefile.in
|
||||
.deps
|
||||
.libs
|
||||
mdb-dump
|
||||
mdb-hexdump
|
||||
|
@ -650,7 +650,47 @@ GtkTreeIter *container;
|
||||
}
|
||||
}
|
||||
void
|
||||
gmdb_debug_dissect_tabledef_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
|
||||
gmdb_debug_dissect_tabledef_pg4(GtkTreeStore *store, char *fbuf, int offset, int len)
|
||||
{
|
||||
gchar str[100];
|
||||
guint32 i, num_idx, num_cols, idx_entries;
|
||||
int newbase;
|
||||
GtkTreeIter *node, *container;
|
||||
|
||||
snprintf(str, 100, "Next TDEF Page: 0x%06x (%lu)",
|
||||
get_uint32(&fbuf[offset+4]), get_uint32(&fbuf[offset+4]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+4, offset+7);
|
||||
snprintf(str, 100, "Length of Data: %lu", get_uint32(&fbuf[offset+8]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+8, offset+11);
|
||||
snprintf(str, 100, "# of Records: %lu", get_uint32(&fbuf[offset+16]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+16, offset+19);
|
||||
snprintf(str, 100, "Autonumber Value: %lu", get_uint32(&fbuf[offset+20]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+20, offset+23);
|
||||
snprintf(str, 100, "Table Type: 0x%02x (%s)", fbuf[offset+40],
|
||||
gmdb_val_to_str(table_types, fbuf[offset+40]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+40, offset+40);
|
||||
num_cols = get_uint16(&fbuf[offset+41]);
|
||||
snprintf(str, 100, "Max # of Columns: %u", num_cols);
|
||||
gmdb_debug_add_item(store, NULL, str, offset+41, offset+42);
|
||||
snprintf(str, 100, "# of VarCols: %u",
|
||||
get_uint16(&fbuf[offset+43]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+43, offset+44);
|
||||
snprintf(str, 100, "# of Columns: %u",
|
||||
get_uint16(&fbuf[offset+45]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+45, offset+46);
|
||||
idx_entries = get_uint32(&fbuf[offset+47]);
|
||||
snprintf(str, 100, "# of Index Entries: %lu", idx_entries);
|
||||
gmdb_debug_add_item(store, NULL, str, offset+47, offset+50);
|
||||
|
||||
num_idx = get_uint32(&fbuf[offset+51]);
|
||||
snprintf(str, 100, "# of Real Indices: %lu", num_idx);
|
||||
gmdb_debug_add_item(store, NULL, str, offset+51, offset+54);
|
||||
|
||||
gmdb_debug_add_page_ptr(store, NULL, fbuf, "Used Pages Pointer", offset+55);
|
||||
gmdb_debug_add_page_ptr(store, NULL, fbuf, "Pages Freespace Pointer", offset+59);
|
||||
}
|
||||
void
|
||||
gmdb_debug_dissect_tabledef_pg3(GtkTreeStore *store, char *fbuf, int offset, int len)
|
||||
{
|
||||
gchar str[100];
|
||||
guint32 i, num_idx, num_cols, idx_entries;
|
||||
@ -670,7 +710,7 @@ GtkTreeIter *node, *container;
|
||||
gmdb_val_to_str(table_types, fbuf[offset+20]));
|
||||
gmdb_debug_add_item(store, NULL, str, offset+20, offset+20);
|
||||
num_cols = get_uint16(&fbuf[offset+21]);
|
||||
snprintf(str, 100, "# of Columns: %u", num_cols);
|
||||
snprintf(str, 100, "Max # of Columns: %u", num_cols);
|
||||
gmdb_debug_add_item(store, NULL, str, offset+21, offset+22);
|
||||
snprintf(str, 100, "# of VarCols: %u",
|
||||
get_uint16(&fbuf[offset+23]));
|
||||
@ -687,6 +727,7 @@ GtkTreeIter *node, *container;
|
||||
|
||||
gmdb_debug_add_item(store, NULL, str, offset+31, offset+34);
|
||||
gmdb_debug_add_page_ptr(store, NULL, fbuf, "Used Pages Pointer", offset+35);
|
||||
gmdb_debug_add_page_ptr(store, NULL, fbuf, "Pages Freespace Pointer", offset+39);
|
||||
|
||||
container = gmdb_debug_add_item(store, NULL, "Index Entries", -1, -1);
|
||||
for (i=0;i<num_idx;i++) {
|
||||
@ -748,6 +789,14 @@ GtkTreeIter *node, *container;
|
||||
}
|
||||
}
|
||||
void
|
||||
gmdb_debug_dissect_tabledef_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
|
||||
{
|
||||
if (IS_JET3(mdb))
|
||||
gmdb_debug_dissect_tabledef_pg3(store, fbuf, offset, len);
|
||||
else
|
||||
gmdb_debug_dissect_tabledef_pg4(store, fbuf, offset, len);
|
||||
}
|
||||
void
|
||||
gmdb_debug_dissect(GtkTreeStore *store, char *fbuf, int offset, int len)
|
||||
{
|
||||
gchar str[100];
|
||||
|
@ -11,6 +11,8 @@
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="default_height">200</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="enable_layout_config">True</property>
|
||||
|
@ -24,6 +24,18 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="help_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="response_id">-11</property>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel_button">
|
||||
<property name="visible">True</property>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* MDB Tools - A library for reading MS Access database file
|
||||
* Copyright (C) 2000 Brian Bruns
|
||||
* Copyright (C) 2000-2004 Brian Bruns
|
||||
*
|
||||
* 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
|
||||
@ -19,6 +19,7 @@
|
||||
#include <libgnome/gnome-help.h>
|
||||
#include <glade/glade.h>
|
||||
#include <mdbtools.h>
|
||||
#include <mdbver.h>
|
||||
#include <mdbsql.h>
|
||||
#include "gmdb.h"
|
||||
|
||||
@ -52,8 +53,8 @@ GdkPixbuf *pixbuf;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (GMDB_ICONDIR "logo.xpm", NULL);
|
||||
|
||||
gtk_widget_show (gnome_about_new ("Gnome MDB Viewer", "0.2",
|
||||
"Copyright 2002-2003 Brian Bruns",
|
||||
gtk_widget_show (gnome_about_new ("Gnome MDB Viewer", MDB_VERSION_NO,
|
||||
"Copyright 2002-2004 Brian Bruns",
|
||||
_("The Gnome-MDB Viewer is the grapical interface to "
|
||||
"MDB Tools. It lets you view and export data and schema"
|
||||
"from MDB files produced by MS Access 97/2000/XP."),
|
||||
|
@ -362,20 +362,29 @@ gmdb_sql_select_hist_cb(GtkList *list, GladeXML *xml)
|
||||
void
|
||||
gmdb_sql_execute_cb(GtkWidget *w, GladeXML *xml)
|
||||
{
|
||||
guint len;
|
||||
gchar *buf;
|
||||
gchar *bound_data[256];
|
||||
int i;
|
||||
MdbSQLColumn *sqlcol;
|
||||
gchar *titles[256];
|
||||
GtkTextBuffer *txtbuffer;
|
||||
GtkTextIter start, end;
|
||||
GtkWidget *textview, *combo, *treeview, *store;
|
||||
GList *history;
|
||||
GType *gtypes;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeViewColumn *column;
|
||||
long row, maxrow;
|
||||
guint len;
|
||||
gchar *buf;
|
||||
gchar *bound_data[256];
|
||||
int i;
|
||||
MdbSQLColumn *sqlcol;
|
||||
gchar *titles[256];
|
||||
GtkTextBuffer *txtbuffer;
|
||||
GtkTextIter start, end;
|
||||
GtkWidget *textview, *combo, *treeview, *store;
|
||||
GtkWidget *window;
|
||||
GList *history;
|
||||
GType *gtypes;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeViewColumn *column;
|
||||
long row, maxrow;
|
||||
/* GdkCursor *watch, *pointer; */
|
||||
|
||||
/* need to figure out how to clock during the treeview recalc/redraw
|
||||
window = glade_xml_get_widget(xml, "sql_window");
|
||||
watch = gdk_cursor_new(GDK_WATCH);
|
||||
gdk_window_set_cursor(GTK_WIDGET(window)->window, watch);
|
||||
gdk_cursor_unref(watch);
|
||||
*/
|
||||
|
||||
/* stuff this query on the history */
|
||||
textview = glade_xml_get_widget(xml, "sql_textview");
|
||||
@ -455,6 +464,13 @@ long row, maxrow;
|
||||
|
||||
mdb_sql_reset(sql);
|
||||
g_free(buf);
|
||||
|
||||
/*
|
||||
pointer = gdk_cursor_new(GDK_LEFT_PTR);
|
||||
gdk_window_set_cursor(GTK_WIDGET(window)->window, pointer);
|
||||
gdk_cursor_unref(pointer);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -41,7 +41,7 @@ MdbCatalogEntry *entry;
|
||||
}
|
||||
|
||||
entry = g_ptr_array_index(mdb->catalog,selected_table);
|
||||
gmdb_debug_new_cb(w, &entry->table_pg);
|
||||
gmdb_debug_new_cb(w, (gpointer *) &entry->table_pg);
|
||||
}
|
||||
void
|
||||
gmdb_table_def_cb(GtkList *list, GtkWidget *w, gpointer data)
|
||||
@ -94,9 +94,9 @@ gmdb_table_unselect_cb(GnomeIconList *gil, int num, GdkEvent *ev, gpointer data)
|
||||
void
|
||||
gmdb_table_select_cb(GnomeIconList *gil, int num, GdkEvent *ev, gpointer data)
|
||||
{
|
||||
int i;
|
||||
MdbCatalogEntry *entry;
|
||||
gchar *text;
|
||||
int i;
|
||||
MdbCatalogEntry *entry;
|
||||
gchar *text;
|
||||
|
||||
text = (gchar *) gnome_icon_list_get_icon_data(gil, num);
|
||||
|
||||
@ -116,13 +116,25 @@ gchar *text;
|
||||
}
|
||||
|
||||
}
|
||||
gboolean
|
||||
gmdb_table_popup_cb(GtkWidget *menu, GdkEvent *event)
|
||||
{
|
||||
GdkEventButton *event_button;
|
||||
//GtkWidget *menu;
|
||||
GdkEventButton *event_button;
|
||||
GnomeIconList *gil;
|
||||
gdouble x,y;
|
||||
int num;
|
||||
|
||||
gil = (GnomeIconList *) glade_xml_get_widget (mainwin_xml, "table_iconlist");
|
||||
|
||||
if (selected_table == -1) return FALSE;
|
||||
if (event->type == GDK_BUTTON_PRESS) {
|
||||
event_button = (GdkEventButton *) event;
|
||||
x = event_button->x;
|
||||
y = event_button->y;
|
||||
num = gnome_icon_list_get_icon_at(gil, x, y);
|
||||
if (num != -1) {
|
||||
gnome_icon_list_select_icon(gil, num);
|
||||
}
|
||||
if (event_button->button == 3) {
|
||||
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
|
||||
event_button->button, event_button->time);
|
||||
|
@ -312,6 +312,42 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, unsigned char *buf, int len)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* unpack the pages bitmap
|
||||
*/
|
||||
int
|
||||
mdb_index_unpack_page(MdbHandle *mdb, MdbIndexPage *ipg)
|
||||
{
|
||||
int mask_bit = 0;
|
||||
int mask_pos = 0x16;
|
||||
int mask_byte;
|
||||
int start = 0xf8;
|
||||
int elem = 0;
|
||||
int len = 0;
|
||||
|
||||
ipg->idx_starts[elem++]=start;
|
||||
|
||||
//fprintf(stdout, "Unpacking index page %lu\n", ipg->pg);
|
||||
do {
|
||||
len = 0;
|
||||
do {
|
||||
mask_bit++;
|
||||
if (mask_bit==8) {
|
||||
mask_bit=0;
|
||||
mask_pos++;
|
||||
}
|
||||
mask_byte = mdb->pg_buf[mask_pos];
|
||||
len++;
|
||||
} while (mask_pos <= 0xf8 && !((1 << mask_bit) & mask_byte));
|
||||
//fprintf(stdout, "%d %d %d %d\n", mask_pos, mask_bit, mask_byte, len);
|
||||
|
||||
start += len;
|
||||
if (mask_pos < 0xf8) ipg->idx_starts[elem++]=start;
|
||||
|
||||
} while (mask_pos < 0xf8);
|
||||
|
||||
return elem;
|
||||
}
|
||||
/*
|
||||
* find the next entry on a page (either index or leaf). Uses state information
|
||||
* stored in the MdbIndexPage across calls.
|
||||
@ -319,6 +355,22 @@ mdb_index_test_sargs(MdbHandle *mdb, MdbIndex *idx, unsigned char *buf, int len)
|
||||
int
|
||||
mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg)
|
||||
{
|
||||
int offset, len;
|
||||
int ret = 0;
|
||||
|
||||
if (!ipg->pg) return 0;
|
||||
|
||||
/* if this page has not been unpacked to it */
|
||||
if (!ipg->idx_starts[0])
|
||||
mdb_index_unpack_page(mdb, ipg);
|
||||
|
||||
|
||||
if (ipg->idx_starts[ipg->start_pos + 1]==0) return 0;
|
||||
ipg->len = ipg->idx_starts[ipg->start_pos+1] - ipg->idx_starts[ipg->start_pos];
|
||||
ipg->start_pos++;
|
||||
|
||||
|
||||
/*
|
||||
do {
|
||||
//fprintf(stdout, "%d %d\n", ipg->mask_bit, ipg->mask_byte);
|
||||
ipg->mask_bit++;
|
||||
@ -333,7 +385,7 @@ mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg)
|
||||
|
||||
if (ipg->mask_pos>=0xf8)
|
||||
return 0;
|
||||
|
||||
*/
|
||||
return ipg->len;
|
||||
}
|
||||
void mdb_index_page_reset(MdbIndexPage *ipg)
|
||||
@ -341,6 +393,7 @@ void mdb_index_page_reset(MdbIndexPage *ipg)
|
||||
ipg->offset = 0xf8; /* start byte of the index entries */
|
||||
ipg->mask_pos = 0x16;
|
||||
ipg->mask_bit=0;
|
||||
ipg->start_pos=0;
|
||||
ipg->len = 0;
|
||||
}
|
||||
void mdb_index_page_init(MdbIndexPage *ipg)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* MDB Tools - A library for reading MS Access database file
|
||||
* Copyright (C) 2000 Brian Bruns
|
||||
* Copyright (C) 2000-2004 Brian Bruns
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
@ -18,6 +18,7 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "mdbtools.h"
|
||||
#include "mdbver.h"
|
||||
#include "mdbprivate.h"
|
||||
#include <locale.h>
|
||||
|
||||
@ -28,24 +29,41 @@
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
MdbHandle *mdb;
|
||||
/* doesn't handle tables > 256 columns. Can that happen? */
|
||||
MdbHandle *mdb;
|
||||
int print_mdbver = 0;
|
||||
int opt;
|
||||
|
||||
/* setlocale (LC_ALL, ""); */
|
||||
bindtextdomain (PACKAGE, LOCALEDIR);
|
||||
textdomain (PACKAGE);
|
||||
while ((opt=getopt(argc, argv, "M"))!=-1) {
|
||||
switch (opt) {
|
||||
case 'M':
|
||||
print_mdbver = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (print_mdbver) {
|
||||
fprintf(stdout,"%s\n", MDB_FULL_VERSION);
|
||||
if (argc-optind < 1) exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
** optind is now the position of the first non-option arg,
|
||||
** see getopt(3)
|
||||
*/
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,_("Usage: %s <file>\n"),argv[0]);
|
||||
if (argc-optind < 1) {
|
||||
fprintf(stderr,_("Usage: %s [-M] <file>\n"),argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mdb_init();
|
||||
|
||||
if (!(mdb = mdb_open(argv[optind]))) {
|
||||
fprintf(stderr,_("Error: unable to open file %s\n"),argv[optind]);
|
||||
exit(1);
|
||||
}
|
||||
if (IS_JET3(mdb)) {
|
||||
|
Loading…
Reference in New Issue
Block a user