1 /* MDB Tools - A library for reading MS Access database file
2  * Copyright (C) 2000 Brian Bruns
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 /* Objects attached to debug_window:
20  *   GList *nav_list: list of pages viewed, entries are guint32 *'s
21  *   guint *nav_elem: index to current page in nav_list
22  *   GtkBuilder *debugwin_xml: the associated builder object
23  *   gboolean *dissect: whether dissecting is turned on
24  */
25 
26 #include "gmdb.h"
27 
28 extern MdbHandle *mdb;
29 
30 GList *debug_list = NULL;
31 
32 #define LINESZ 77
33 
34 /* prototypes */
35 static void gmdb_debug_init(MdbHandle *mdb, GtkBuilder *xml);
36 static void gmdb_debug_text_on(GtkWidget *textbox, int start_byte, int end_byte);
37 static void gmdb_debug_text_off(GtkWidget *textbox);
38 static GtkTreeIter *gmdb_debug_add_item(GtkTreeStore *store, GtkTreeIter *iter, gchar *text, int start, int len);
39 static void gmdb_debug_clear(GtkBuilder *xml);
40 static void gmdb_debug_dissect(GtkTreeStore *store, char *fbuf, int offset, int len);
41 static guint16 get_uint16(void *c);
42 static guint32 get_uint32(void *c);
43 static long gmdb_get_max_page(MdbHandle *mdb);
44 static void gmdb_debug_display(GtkBuilder *xml, guint32 page);
45 static void gmdb_debug_jump(GtkBuilder *xml, int msb);
46 
47 /* value to string stuff */
48 typedef struct GMdbValStr {
49 	gint value;
50 	gchar *string;
51 } GMdbValStr;
52 
53 GMdbValStr table_types[] = {
54 	{ 0x4e, "User" },
55 	{ 0x53, "System" },
56 	{ 0, NULL }
57 };
58 GMdbValStr column_types[] = {
59 	{ 0x01, "boolean" },
60 	{ 0x02, "byte" },
61 	{ 0x03, "int" },
62 	{ 0x04, "longint" },
63 	{ 0x05, "money" },
64 	{ 0x06, "float" },
65 	{ 0x07, "double" },
66 	{ 0x08, "short datetime" },
67 	{ 0x09, "binary" },
68 	{ 0x0a, "text" },
69 	{ 0x0b, "OLE" },
70 	{ 0x0c, "memo/hyperlink" },
71 	{ 0x0d, "Unknown" },
72 	{ 0x0f, "GUID" },
73 	{ 0, NULL }
74 };
75 GMdbValStr object_types[] = {
76 	{ 0x00, "Database Definition" },
77 	{ 0x01, "Data" },
78 	{ 0x02, "Table Definition" },
79 	{ 0x03, "Index" },
80 	{ 0x04, "Leaf Index" },
81 	{ 0, NULL }
82 };
83 
84 /* callbacks */
85 static void
gmdb_debug_select_cb(GtkTreeSelection * select,GtkBuilder * xml)86 gmdb_debug_select_cb(GtkTreeSelection *select, GtkBuilder *xml)
87 {
88 	int start_row, end_row;
89 	int start_col, end_col;
90 	GtkTreeIter iter;
91 	GtkTreeModel *model;
92 	gint32 start, end, len;
93 	GtkWidget *textview;
94 	gchar *fieldname;
95 
96 	fprintf(stderr, "select_cb fired\n");
97 
98 	textview = GTK_WIDGET(gtk_builder_get_object(xml, "debug_textview"));
99 	gmdb_debug_text_off(textview);
100 
101 	if (!select)
102 		return;
103 	if (!gtk_tree_selection_get_selected (select, &model, &iter))
104 		return;
105 
106 	gtk_tree_model_get (model, &iter, 0, &fieldname,
107 		1, &start,
108 		2, &len, -1);
109 	g_free (fieldname);
110 	if ((start == -1) || (len < 1))
111 		return;
112 
113 	end = start + len - 1;
114 	start_row = LINESZ * (start / 16);
115 	end_row = LINESZ * (end / 16);
116 	start_col = 8 + (start % 16) * 3;
117 	end_col = 8 + (end % 16) * 3;
118 
119 	if (start_row == end_row) {
120 		gmdb_debug_text_on(textview,
121 			start_row + start_col,
122 			start_row + end_col + 2);
123 		gmdb_debug_text_on(textview,
124 			start_row + 59 + (start % 16),
125 			start_row + 59 + (end % 16) + 1);
126 	} else {
127 		int i;
128 		gmdb_debug_text_on(textview,
129 			start_row + start_col,
130 			/* 55 = 8 (addr) + 15 (bytes) * 3 (%02x " ") + 2 (last byte) */
131 			start_row + 55);
132 		gmdb_debug_text_on(textview,
133 			start_row + 59 + (start % 16),
134 			start_row + 75);
135 		for (i=start_row + LINESZ; i < end_row; i+=LINESZ) {
136 			gmdb_debug_text_on(textview, i + 8, i + 55);
137 			gmdb_debug_text_on(textview, i + 59, i + 75);
138 		}
139 		gmdb_debug_text_on(textview,
140 			end_row + 8,
141 			end_row + end_col + 2);
142 		gmdb_debug_text_on(textview,
143 			end_row + 59,
144 			end_row + 59 + (end % 16) + 1);
145 	}
146 }
147 void
gmdb_debug_forward_cb(GtkWidget * w,gpointer data)148 gmdb_debug_forward_cb(GtkWidget *w, gpointer data)
149 {
150 	guint *nav_elem;
151 	guint32 *page;
152 	GtkBuilder *xml;
153     GtkWidget *win;
154 	GList *nav_list;
155 	guint num_items;
156 
157 	win = gtk_widget_get_toplevel(w);
158 	nav_list = g_object_get_data(G_OBJECT(win),"nav_list");
159 	nav_elem = g_object_get_data(G_OBJECT(win),"nav_elem");
160 	num_items = g_list_length(nav_list);
161 	if (!nav_elem || *nav_elem == num_items)
162 		return;
163 	(*nav_elem)++;
164 	g_object_set_data(G_OBJECT(win), "nav_elem", nav_elem);
165 	page = g_list_nth_data(nav_list,(*nav_elem) - 1);
166 
167 	xml = g_object_get_data(G_OBJECT(win), "debugwin_xml");
168 	gmdb_debug_display(xml, *page);
169 }
170 void
gmdb_debug_back_cb(GtkWidget * w,gpointer data)171 gmdb_debug_back_cb(GtkWidget *w, gpointer data)
172 {
173 	guint *nav_elem;
174 	guint32 *page;
175 	GtkBuilder *xml;
176     GtkWidget *win;
177 	GList *nav_list;
178 
179 	win = gtk_widget_get_toplevel(w);
180 	nav_list = g_object_get_data(G_OBJECT(win),"nav_list");
181 	nav_elem = g_object_get_data(G_OBJECT(win),"nav_elem");
182 	if (!nav_elem || *nav_elem==1)
183 		return; /* at top of list already */
184 	(*nav_elem)--;
185 	g_object_set_data(G_OBJECT(win), "nav_elem", nav_elem);
186 	page = g_list_nth_data(nav_list,(*nav_elem) - 1);
187 
188 	xml = g_object_get_data(G_OBJECT(win), "debugwin_xml");
189 	gmdb_debug_display(xml, *page);
190 }
191 static void
gmdb_nav_add_page(GtkWidget * win,guint32 page_num)192 gmdb_nav_add_page(GtkWidget *win, guint32 page_num)
193 {
194 	GList *nav_list = NULL;
195 	GList *link = NULL;
196 	guint *nav_elem;
197 	guint num_items;
198 	int i;
199 
200 	nav_list = g_object_get_data(G_OBJECT(win),"nav_list");
201 	nav_elem = g_object_get_data(G_OBJECT(win),"nav_elem");
202 	if (!nav_elem) {
203 		nav_elem = g_malloc0(sizeof(guint));
204 	}
205 
206 	/*
207 	 * If we are positioned in the middle of the list and jumping from here
208 	 * clear the end of the list first.
209 	 */
210 	num_items = g_list_length(nav_list);
211 	if (num_items > *nav_elem) {
212 		for (i=num_items - 1; i >= *nav_elem; i--) {
213 			link = g_list_nth(nav_list,i);
214 			nav_list = g_list_remove_link(nav_list, link);
215 			g_free(link->data);
216 			g_list_free_1(link);
217 		}
218 	}
219 
220 	nav_list = g_list_append(nav_list, g_memdup2(&page_num, 4));
221 	*nav_elem = g_list_length(nav_list);
222 
223 	g_object_set_data(G_OBJECT(win), "nav_list", nav_list);
224 	g_object_set_data(G_OBJECT(win), "nav_elem", nav_elem);
225 }
226 
227 void
gmdb_debug_jump_cb(GtkWidget * w,gpointer data)228 gmdb_debug_jump_cb(GtkWidget *w, gpointer data)
229 {
230 	GtkWidget *win = gtk_widget_get_toplevel(w);
231 	gmdb_debug_jump(g_object_get_data(G_OBJECT(win), "debugwin_xml"), 0);
232 }
233 void
gmdb_debug_jump_msb_cb(GtkWidget * w,gpointer data)234 gmdb_debug_jump_msb_cb(GtkWidget *w, gpointer data)
235 {
236 	GtkWidget *win = gtk_widget_get_toplevel(w);
237 	gmdb_debug_jump(g_object_get_data(G_OBJECT(win), "debugwin_xml"), 1);
238 }
239 static void
gmdb_debug_jump(GtkBuilder * xml,int msb)240 gmdb_debug_jump(GtkBuilder *xml, int msb)
241 {
242 	GtkTextView *textview;
243 	GtkTextBuffer *txtbuffer;
244 	GtkTextIter start, end;
245 	GtkWidget *entry;
246 	gchar *text;
247 	gchar page[12];
248 	gchar digits[4][3];
249 	gchar *hex_digit;
250 	int i, num_digits = 0;
251 
252 	textview = GTK_TEXT_VIEW(gtk_builder_get_object(xml, "debug_textview"));
253 	txtbuffer = gtk_text_view_get_buffer(textview);
254 	if (!gtk_text_buffer_get_selection_bounds(txtbuffer, &start, &end)) {
255         GtkStatusbar *statusbar = GTK_STATUSBAR(gtk_builder_get_object(xml, "statusbar1"));
256         gtk_statusbar_push(statusbar,
257                 gtk_statusbar_get_context_id(statusbar, "Debug messages"),
258                 "Nothing selected");
259 		return;
260 	}
261 	text = g_strdup(gtk_text_buffer_get_text(txtbuffer, &start, &end, FALSE));
262 	//fprintf(stderr, "selected text = %s\n",text);
263 	hex_digit = strtok(text, " ");
264 	strcpy(page, "0x");
265 	do {
266 		if (strlen(hex_digit)>2) {
267 			fprintf(stderr, "Not a hex value\n");
268 			return;
269 		}
270 		strcpy(digits[num_digits++],hex_digit);
271 	} while (num_digits < 4 && (hex_digit = strtok(NULL," ")));
272 	if (msb) {
273 		for (i=0;i<num_digits;i++) {
274 			strcat(page, digits[i]);
275 		}
276 	} else {
277 		for (i=num_digits-1;i>=0;i--) {
278 			strcat(page, digits[i]);
279 		}
280 	}
281 	g_free(text);
282 	//fprintf(stderr, "going to page %s\n",page);
283 	entry = GTK_WIDGET(gtk_builder_get_object(xml, "debug_entry"));
284 	gtk_entry_set_text(GTK_ENTRY(entry),page);
285 	gmdb_debug_display_cb(entry, NULL);
286 }
287 
288 /*
289  * w: pointer to GtkEntry 'debug_entry'
290  */
291 void
gmdb_debug_display_cb(GtkWidget * w,gpointer data)292 gmdb_debug_display_cb(GtkWidget *w, gpointer data)
293 {
294 	int page;
295 	GtkWidget *win;
296     GtkEntry *entry;
297 	gchar *s;
298 	GtkBuilder *xml;
299 
300 	fprintf(stderr, "display fired\n");
301 
302 	if (!mdb) return;
303 
304 	win = gtk_widget_get_toplevel(w);
305 	xml = g_object_get_data(G_OBJECT(win), "debugwin_xml");
306     entry = GTK_ENTRY(gtk_builder_get_object(xml, "debug_entry"));
307 
308 	s = g_strdup(gtk_entry_get_text(entry));
309 	if (!strncmp(s,"0x",2)) {
310 		page = strtol(s+2, NULL, 16);
311 	} else {
312 		page = strtol(s, NULL, 10);
313 	}
314 	g_free(s);
315 
316 	if (page>gmdb_get_max_page(mdb) || page<0) {
317 		GtkWidget* dlg = gtk_message_dialog_new (GTK_WINDOW(win),
318 		    GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
319 		    GTK_BUTTONS_CLOSE,
320 		    _("Page entered is outside valid page range."));
321 		gtk_dialog_run (GTK_DIALOG (dlg));
322 		gtk_widget_destroy (dlg);
323 	}
324 
325 	/* add to the navigation list */
326 	gmdb_nav_add_page(win, page);
327 	/* gmdb_debug_display handles the mechanics of getting the page up */
328 	gmdb_debug_display(xml, page);
329 }
330 static void
gmdb_debug_display(GtkBuilder * xml,guint32 page)331 gmdb_debug_display(GtkBuilder *xml, guint32 page)
332 {
333 	char *fbuf;
334 	char *tbuf;
335 	int i, j;
336 	char line[80];
337 	char field[10];
338 	GtkTextBuffer *buffer;
339 	GtkTextIter iter;
340 	GtkTextView *textview;
341 	GtkWidget *entry, *window;
342 	char *pagestr;
343 	gboolean *dissect;
344 	GtkTreeView *tree;
345 	GtkTreeStore *store;
346 
347 	textview = GTK_TEXT_VIEW(gtk_builder_get_object(xml, "debug_textview"));
348 	gmdb_debug_clear(xml);
349 
350 	pagestr = g_strdup_printf("%lu", (unsigned long)page);
351 	entry = GTK_WIDGET(gtk_builder_get_object(xml, "debug_entry"));
352 	gtk_entry_set_text(GTK_ENTRY(entry),pagestr);
353 	g_free(pagestr);
354 
355 	mdb_read_pg(mdb, page);
356 	fbuf = g_malloc(mdb->fmt->pg_size);
357 	memcpy(fbuf, mdb->pg_buf, mdb->fmt->pg_size);
358 
359 	tbuf = g_malloc0( (mdb->fmt->pg_size / 16) * sizeof(line));
360 	i = 0;
361 	while (i<mdb->fmt->pg_size) {
362 		snprintf(line, sizeof(line), "%06x  ", i);
363 
364 		for(j=0; j<16; j++) {
365 			snprintf(field, sizeof(field), "%02x ", ((unsigned char*)fbuf)[i+j]);
366 			strcat(line,field);
367 		}
368 
369 		strcat(line, "  |");
370 
371 		for(j=0; j<16; j++) {
372 			snprintf(field, sizeof(field), "%c", (isprint(fbuf[i+j])) ? fbuf[i+j] : '.');
373 			strcat(line,field);
374 		}
375 		strcat(line, "|\n");
376 		i += 16;
377 		strcat(tbuf, line);
378 	}
379 	buffer = gtk_text_view_get_buffer(textview);
380 	gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
381 	gtk_text_buffer_insert(buffer,&iter,tbuf,strlen(tbuf));
382 
383 	tree = GTK_TREE_VIEW(gtk_builder_get_object(xml, "debug_treeview"));
384 	store = GTK_TREE_STORE(gtk_tree_view_get_model(tree));
385 
386 	window = GTK_WIDGET(gtk_builder_get_object(xml, "debug_window"));
387 	dissect = g_object_get_data(G_OBJECT(window),"dissect");
388 	if (!dissect || *dissect)
389 		gmdb_debug_dissect(store, fbuf, 0, mdb->fmt->pg_size);
390 
391 	g_free(fbuf);
392 	g_free(tbuf);
393 }
394 /* functions */
395 static long
gmdb_get_max_page(MdbHandle * mdb)396 gmdb_get_max_page(MdbHandle *mdb)
397 {
398 struct stat st;
399 
400 	assert( fstat(fileno(mdb->f->stream), &st)!=-1 );
401 	return (st.st_size/mdb->fmt->pg_size)-1;
402 }
403 static gchar *
gmdb_val_to_str(GMdbValStr * valstr,gint val)404 gmdb_val_to_str(GMdbValStr *valstr, gint val)
405 {
406 gchar *strptr;
407 int i = 0;
408 
409 	do {
410 		strptr = valstr[i].string;
411 		if (val == valstr[i].value) {
412 			return strptr;
413 		}
414 		i++;
415 	} while (strptr);
416 	return "unknown";
417 }
418 static guint16
get_uint16(void * c)419 get_uint16(void *c)
420 {
421 	guint16 i;
422 	memcpy(&i, c, 2);
423 	return GINT16_FROM_LE(i);
424 }
425 static guint32
get_uint32(void * c)426 get_uint32(void *c)
427 {
428 	guint32 l;
429 	memcpy(&l, c, 4);
430 	return GINT32_FROM_LE(l);
431 }
432 static void
gmdb_debug_dissect_column(GtkTreeStore * store,GtkTreeIter * parent,char * fbuf,int offset)433 gmdb_debug_dissect_column(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset)
434 {
435 	gchar *str;
436 	unsigned char *foff = (unsigned char*)fbuf + offset;
437 
438 	str = g_strdup_printf("Column Type: 0x%02x (%s)", foff[0],
439 		gmdb_val_to_str(column_types, foff[0]));
440 	gmdb_debug_add_item(store, parent, str, offset, 1);
441 	str = g_strdup_printf("Column #: %d", get_uint16(foff+1));
442 	gmdb_debug_add_item(store, parent, str, offset+1, 2);
443 	str = g_strdup_printf("VarCol Offset: %d", get_uint16(foff+3));
444 	gmdb_debug_add_item(store, parent, str, offset+3, 2);
445 	str = g_strdup_printf("Unknown");
446 	gmdb_debug_add_item(store, parent, str, offset+5, 4);
447 	str = g_strdup_printf("Unknown");
448 	gmdb_debug_add_item(store, parent, str, offset+9, 4);
449 	str = g_strdup_printf("Variable Column: %s",
450 		(foff[13] & 0x01) ? "No" : "Yes");
451 	gmdb_debug_add_item(store, parent, str, offset+13, 1);
452 	str = g_strdup_printf("Fixed Col Offset: %d", get_uint16(foff+14));
453 	gmdb_debug_add_item(store, parent, str, offset+14, 2);
454 	str = g_strdup_printf("Column Length: %d", get_uint16(foff+16));
455 	gmdb_debug_add_item(store, parent, str, offset+16, 2);
456 }
457 static void
gmdb_debug_dissect_index1(GtkTreeStore * store,GtkTreeIter * parent,char * fbuf,int offset)458 gmdb_debug_dissect_index1(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset)
459 {
460 	gchar *str;
461 
462 	gmdb_debug_add_item(store, parent, g_strdup("Unknown"), offset, 4);
463 	str = g_strdup_printf("Rows in Index: %lu",
464 		(unsigned long)get_uint32(fbuf+offset+4));
465 	gmdb_debug_add_item(store, parent, str, offset+4, 4);
466 }
467 static void
gmdb_debug_dissect_index2(GtkTreeStore * store,GtkTreeIter * parent,char * fbuf,int offset)468 gmdb_debug_dissect_index2(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset)
469 {
470 	gchar *str;
471 	unsigned char flags;
472 
473 	str = g_strdup("Column mask");
474 	gmdb_debug_add_item(store, parent, str, offset, 30);
475 	str = g_strdup("Unknown");
476 	gmdb_debug_add_item(store, parent, str, offset+30, 4);
477 	str = g_strdup("Root index page");
478 	gmdb_debug_add_item(store, parent, str, offset+34, 4);
479 
480 	flags = fbuf[offset+38];
481 	str = g_strconcat("Index Flags:",
482 		(flags & MDB_IDX_UNIQUE) ? " Unique" : "",
483 		(flags & MDB_IDX_IGNORENULLS) ? " IgnoreNulls" : "",
484 		(flags & MDB_IDX_REQUIRED) ? " Required" : "",
485 		NULL);
486 	if (strcmp(str, "Index Flags:") == 0) {
487 		gchar *str2 = g_strconcat(str, " None", NULL);
488 		g_free(str);
489 		str = str2;
490 	}
491 	gmdb_debug_add_item(store, parent, str, offset+38, 1);
492 }
493 static void
gmdb_debug_add_page_ptr(GtkTreeStore * store,GtkTreeIter * parent,char * fbuf,const char * label,int offset)494 gmdb_debug_add_page_ptr(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, const char *label, int offset)
495 {
496 	gchar *str;
497 	GtkTreeIter *node;
498 	guint32 pg_row = get_uint32(fbuf+offset);
499 
500 	str = g_strdup(label);
501 	node = gmdb_debug_add_item(store, parent, str, offset, 4);
502 
503 	str = g_strdup_printf("Row Number: %u", pg_row & 0xff);
504 	gmdb_debug_add_item(store, node, str, offset, 1);
505 	str = g_strdup_printf("Page Number: %u", pg_row >> 8);
506 	gmdb_debug_add_item(store, node, str, offset+1, 3);
507 }
508 static void
gmdb_debug_dissect_row(GtkTreeStore * store,GtkTreeIter * parent,char * fbuf,int offset,int len)509 gmdb_debug_dissect_row(GtkTreeStore *store, GtkTreeIter *parent, char *fbuf, int offset, int len)
510 {
511 	gchar *str;
512 	int bitmask_sz;
513 	int num_cols, var_cols, var_cols_loc, fixed_end, eod_ptr;
514 	int i;
515 
516 	num_cols = fbuf[offset];
517 	str = g_strdup_printf("Num columns: %u", num_cols);
518 	gmdb_debug_add_item(store, parent, str, offset, 1);
519 	bitmask_sz = (num_cols+7) / 8;
520 	var_cols_loc = offset + len - bitmask_sz - 1;
521 	var_cols = fbuf[var_cols_loc];
522 	fixed_end = offset + fbuf[var_cols_loc - 1] - 1; /* work even if 0 b/c of EOD */
523 	str = g_strdup("Fixed columns");
524 	gmdb_debug_add_item(store, parent, str, offset + 1, fixed_end - offset);
525 	for (i=0;i<var_cols;i++) {
526 	}
527 	eod_ptr = var_cols_loc - var_cols - 1;
528 	for (i=0;i<var_cols;i++) {
529 		int loc1 = fbuf[var_cols_loc - i - 1],
530 		    loc2 = fbuf[var_cols_loc - i - 2];
531 		str = g_strdup_printf("Var col %d", var_cols-i);
532 		gmdb_debug_add_item(store, parent, str,
533 			offset + loc1, loc2 - loc1);
534 	}
535 	str = g_strdup_printf("End of data (EOD): 0x%02x (%u)",
536 		((unsigned char*)fbuf)[eod_ptr], ((unsigned char*)fbuf)[eod_ptr]);
537 	gmdb_debug_add_item(store, parent, str, eod_ptr, 1);
538 	for (i=0;i<var_cols;i++) {
539 		str = g_strdup_printf("Var col %d offset: 0x%02x (%u)", var_cols-i,
540 			((unsigned char*)fbuf)[eod_ptr+i+1], ((unsigned char*)fbuf)[eod_ptr+i+1]);
541 		gmdb_debug_add_item(store, parent, str, eod_ptr + i + 1, 1);
542 	}
543 	str = g_strdup_printf("Num var cols: %u", var_cols);
544 	gmdb_debug_add_item(store, parent, str, var_cols_loc, 1);
545 	str = g_strdup("Null mask");
546 	gmdb_debug_add_item(store, parent, str, var_cols_loc + 1,
547 		offset + len - (var_cols_loc + 1));
548 }
549 static void
gmdb_debug_dissect_index_pg(GtkTreeStore * store,char * fbuf,int offset,int len)550 gmdb_debug_dissect_index_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
551 {
552 	gchar *str;
553 	guint32 tdef;
554 
555 	str = g_strdup_printf("Page free space: %u", get_uint16(fbuf+offset+2));
556 	gmdb_debug_add_item(store, NULL, str, offset+2, 2);
557 
558 	tdef = get_uint32(fbuf+offset+4);
559 	str = g_strdup_printf("Parents TDEF page: 0x%06x (%lu)", tdef,
560 		(unsigned long)tdef);
561 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
562 }
563 
564 static void
gmdb_debug_dissect_leaf_pg(GtkTreeStore * store,char * fbuf,int offset,int len)565 gmdb_debug_dissect_leaf_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
566 {
567 	gchar *str;
568 	guint32 temp;
569 
570 	temp = get_uint32(fbuf+offset+4);
571 	str = g_strdup_printf("Parent's TDEF page: 0x%06x (%lu)", temp,
572 		(unsigned long)temp);
573 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
574 
575 	temp = get_uint32(fbuf+offset+8);
576 	str = g_strdup_printf("Previous leaf page: 0x%06x (%lu)", temp,
577 		(unsigned long)temp);
578 	gmdb_debug_add_item(store, NULL, str, offset+8, 4);
579 
580 	temp = get_uint32(fbuf+offset+12);
581 	str = g_strdup_printf("Next leaf page: 0x%06x (%lu)", temp,
582 		(unsigned long)temp);
583 	gmdb_debug_add_item(store, NULL, str, offset+12, 4);
584 }
585 static void
gmdb_debug_dissect_data_pg4(GtkTreeStore * store,char * fbuf,int offset,int len)586 gmdb_debug_dissect_data_pg4(GtkTreeStore *store, char *fbuf, int offset, int len)
587 {
588 	gchar *str;
589 	int num_rows, i, row_start, row_len;
590 	guint32 tdef;
591 	//GtkTreeIter *container;
592 
593 	str = g_strdup_printf("Page free space: %u", get_uint16(fbuf+offset+2));
594 	gmdb_debug_add_item(store, NULL, str, offset+2, 2);
595 
596 	tdef = get_uint32(fbuf+offset+4);
597 	str = g_strdup_printf("Parent's TDEF page: 0x%06x (%lu)", tdef,
598 		(unsigned long)tdef);
599 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
600 
601 	num_rows = get_uint16(fbuf+offset+12);
602 	str = g_strdup_printf("Num rows: %u", num_rows);
603 	gmdb_debug_add_item(store, NULL, str, offset+12, 2);
604 	for (i=0;i<num_rows;i++) {
605 		row_start = get_uint16(fbuf+offset+14+(2*i));
606 		str = g_strdup_printf("Row %d offset: 0x%02x (%u)",
607 			i+1, row_start, row_start) ;
608 		gmdb_debug_add_item(store, NULL, str, offset+14+(2*i), 2);
609 	}
610 	for (i=0;i<num_rows;i++) {
611 		row_start = get_uint16(fbuf+offset+14+(2*i));
612 		if (i==0)
613 			row_len = mdb->fmt->pg_size - row_start;
614 		else
615 			row_len = (get_uint16(fbuf+offset+14+(i-1)*2)
616 				& 0x0FFF) - row_start;
617 		str = g_strdup_printf("Row %d", i+1);
618 		/*container = */gmdb_debug_add_item(store, NULL, str,
619 			row_start, row_len);
620 
621 		/* usage pages have parent id of 0 (database) and do not
622 		 * follow normal row format */
623 		/* if (tdef)
624 			gmdb_debug_dissect_row(store, container, fbuf, row_start, row_len);
625 		*/
626 	}
627 }
628 static void
gmdb_debug_dissect_data_pg3(GtkTreeStore * store,char * fbuf,int offset,int len)629 gmdb_debug_dissect_data_pg3(GtkTreeStore *store, char *fbuf, int offset, int len)
630 {
631 	gchar *str;
632 	int num_rows, i, row_start, row_len;
633 	guint32 tdef;
634 	GtkTreeIter *container;
635 
636 	str = g_strdup_printf("Page free space: %u", get_uint16(fbuf+offset+2));
637 	gmdb_debug_add_item(store, NULL, str, offset+2, 2);
638 
639 	tdef = get_uint32(fbuf+offset+4);
640 	str = g_strdup_printf("Parent's TDEF page: 0x%06x (%lu)", tdef,
641 		(unsigned long)tdef);
642 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
643 
644 	num_rows = get_uint16(fbuf+offset+8);
645 	str = g_strdup_printf("Num rows: %u", num_rows);
646 	gmdb_debug_add_item(store, NULL, str, offset+8, 2);
647 	for (i=0;i<num_rows;i++) {
648 		row_start = get_uint16(fbuf+offset+10+(2*i));
649 		str = g_strdup_printf("Row %d offset: 0x%02x (%u)",
650 			i+1, row_start, row_start) ;
651 		gmdb_debug_add_item(store, NULL, str, offset+10+(2*i), 2);
652 	}
653 	for (i=0;i<num_rows;i++) {
654 		row_start = get_uint16(fbuf+offset+10+(2*i));
655 		if (i==0)
656 			row_len = mdb->fmt->pg_size - row_start;
657 		else
658 			row_len = (get_uint16(fbuf+offset+10+(i-1)*2)
659 				& 0x0FFF) - row_start;
660 		str = g_strdup_printf("Row %d", i+1);
661 		container = gmdb_debug_add_item(store, NULL, str,
662 			row_start, row_len);
663 
664 		/* usage pages have parent id of 0 (database) and do not
665 		 * follow normal row format */
666 		if (tdef)
667 			gmdb_debug_dissect_row(store, container, fbuf,
668 				row_start, row_len);
669 	}
670 }
671 static void
gmdb_debug_dissect_data_pg(GtkTreeStore * store,char * fbuf,int offset,int len)672 gmdb_debug_dissect_data_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
673 {
674 	if (IS_JET3(mdb))
675 		gmdb_debug_dissect_data_pg3(store, fbuf, offset, len);
676 	else
677 		gmdb_debug_dissect_data_pg4(store, fbuf, offset, len);
678 }
679 static void
gmdb_debug_dissect_tabledef_pg4(GtkTreeStore * store,char * fbuf,int offset,int len)680 gmdb_debug_dissect_tabledef_pg4(GtkTreeStore *store, char *fbuf, int offset, int len)
681 {
682 	gchar *str;
683 	guint32 i, num_idx, num_cols, idx_entries;
684 	int newbase, infobase;
685 	GtkTreeIter *container = NULL;
686 	char *foff = fbuf + offset;
687 
688 	str = g_strdup_printf("Next TDEF Page: 0x%06x (%lu)",
689 		get_uint32(foff+4), (unsigned long)get_uint32(foff+4));
690 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
691 	str = g_strdup_printf("Length of Data: %lu",
692 		(unsigned long)get_uint32(foff+8));
693 	gmdb_debug_add_item(store, NULL, str, offset+8, 4);
694 	str = g_strdup_printf("Records: %lu",
695 		(unsigned long)get_uint32(foff+16));
696 	gmdb_debug_add_item(store, NULL, str, offset+16, 4);
697 	str = g_strdup_printf("Autonumber Value: %lu",
698 		(unsigned long)get_uint32(foff+20));
699 	gmdb_debug_add_item(store, NULL, str, offset+20, 4);
700 	str = g_strdup_printf("Table Type: 0x%02x (%s)", foff[40],
701 		gmdb_val_to_str(table_types, foff[40]));
702 	gmdb_debug_add_item(store, NULL, str, offset+40, 1);
703 	str = g_strdup_printf("Max Columns: %u", get_uint16(foff+41));
704 	gmdb_debug_add_item(store, NULL, str, offset+41, 2);
705 	str = g_strdup_printf("Var Columns: %u", get_uint16(foff+43));
706 	gmdb_debug_add_item(store, NULL, str, offset+43, 2);
707 	num_cols = get_uint16(foff+45);
708 	str = g_strdup_printf("Columns: %u", num_cols);
709 	gmdb_debug_add_item(store, NULL, str, offset+45, 2);
710 	idx_entries = get_uint32(foff+47);
711 	str = g_strdup_printf("Index Entries: %lu",
712 		(unsigned long)idx_entries);
713 	gmdb_debug_add_item(store, NULL, str, offset+47, 4);
714 	num_idx = get_uint32(foff+51);
715 	str = g_strdup_printf("Real Indices: %lu",
716 		(unsigned long)num_idx);
717 	gmdb_debug_add_item(store, NULL, str, offset+51, 4);
718 
719 	gmdb_debug_add_page_ptr(store, NULL, fbuf, "Used Pages Pointer", offset+55);
720 	gmdb_debug_add_page_ptr(store, NULL, fbuf, "Pages Freespace Pointer", offset+59);
721 	newbase = offset+63;
722 
723 	if (num_idx > 0) {
724 		str = g_strdup("Index Entries");
725 		container = gmdb_debug_add_item(store, NULL, str, -1, 0);
726 	}
727 	for (i=0;i<num_idx;i++) {
728 		/*GtkTreeIter *node;*/
729 		str = g_strdup_printf("Index %d", i+1);
730 		/*node = */gmdb_debug_add_item(store, container, str, newbase, 12);
731 		//gmdb_debug_dissect_index1(store, node, fbuf, offset+63);
732 		newbase += 12;
733 	}
734 
735 	infobase = newbase;
736 	newbase += 25 * num_cols;
737 	str = g_strdup("Column Info");
738 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
739 	for (i=0;i<num_cols;i++) {
740 		GtkTreeIter *node/*, *subnode*/;
741 //		char *tmpstr;
742 		int namelen;
743 
744 		str = g_strdup_printf("Column %d", i+1);
745 		node = gmdb_debug_add_item(store, container, str, -1, 0);
746 
747 		str = g_strdup("Data");
748 		/*subnode = */gmdb_debug_add_item(store, node, str, infobase, 25);
749 		//gmdb_debug_dissect_column(store, subnode, fbuf, infobase);
750 		infobase += 25;
751 
752 		str = g_strdup("Name");
753 		namelen = get_uint16(fbuf+newbase);
754 //		tmpstr = g_malloc(namelen + 1);
755 //		strncpy(tmpstr, &fbuf[newbase+1], namelen);
756 //		tmpstr[namelen]=0;
757 //		str = g_strdup_printf("Column %d: %s", i+1, tmpstr);
758 //		g_free(tmpstr);
759 		gmdb_debug_add_item(store, node, str, newbase+2, namelen);
760 		newbase += namelen+2;
761 	}
762 }
763 static void
gmdb_debug_dissect_tabledef_pg3(GtkTreeStore * store,char * fbuf,int offset,int len)764 gmdb_debug_dissect_tabledef_pg3(GtkTreeStore *store, char *fbuf, int offset, int len)
765 {
766 	gchar *str;
767 	guint32 i, num_idx, num_cols, idx_entries;
768 	int newbase;
769 	GtkTreeIter *node, *container;
770 	char *foff = fbuf + offset;
771 
772 	str = g_strdup_printf("Next TDEF Page: 0x%06x (%lu)",
773 		get_uint32(foff+4), (unsigned long)get_uint32(foff+4));
774 	gmdb_debug_add_item(store, NULL, str, offset+4, 4);
775 	str = g_strdup_printf("Length of Data: %lu",
776 		(unsigned long)get_uint32(foff+8));
777 	gmdb_debug_add_item(store, NULL, str, offset+8, 4);
778 	str = g_strdup_printf("# of Records: %lu",
779 		(unsigned long)get_uint32(foff+12));
780 	gmdb_debug_add_item(store, NULL, str, offset+12, 4);
781 	str = g_strdup_printf("Autonumber Value: %lu",
782 		(unsigned long)get_uint32(foff+16));
783 	gmdb_debug_add_item(store, NULL, str, offset+16, 4);
784 	str = g_strdup_printf("Table Type: 0x%02x (%s)", foff[20],
785 		gmdb_val_to_str(table_types, foff[20]));
786 	gmdb_debug_add_item(store, NULL, str, offset+20, 1);
787 	str = g_strdup_printf("Max # of Columns: %u", get_uint16(foff+21));
788 	gmdb_debug_add_item(store, NULL, str, offset+21, 2);
789 	str = g_strdup_printf("# of VarCols: %u", get_uint16(foff+23));
790 	gmdb_debug_add_item(store, NULL, str, offset+23, 2);
791 	num_cols = get_uint16(foff+25);
792 	str = g_strdup_printf("# of Columns: %u", num_cols);
793 	gmdb_debug_add_item(store, NULL, str, offset+25, 2);
794 	idx_entries = get_uint32(foff+27);
795 	str = g_strdup_printf("# of Index Entries: %lu",
796 		(unsigned long)idx_entries);
797 	gmdb_debug_add_item(store, NULL, str, offset+27, 4);
798 	num_idx = get_uint32(foff+31);
799 	str = g_strdup_printf("# of Real Indices: %lu",
800 		(unsigned long)num_idx);
801 
802 	gmdb_debug_add_item(store, NULL, str, offset+31, 4);
803 	gmdb_debug_add_page_ptr(store, NULL, fbuf, "Used Pages Pointer", offset+35);
804 	gmdb_debug_add_page_ptr(store, NULL, fbuf, "Pages Freespace Pointer", offset+39);
805 	newbase = offset + 43;
806 
807 	str = g_strdup("Index Entries");
808 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
809 	for (i=0;i<num_idx;i++) {
810 		str = g_strdup_printf("Index %d", i+1);
811 		node = gmdb_debug_add_item(store, container, str, newbase, 8);
812 		gmdb_debug_dissect_index1(store, node, fbuf, offset+43);
813 		newbase += 8;
814 	}
815 
816 	str = g_strdup("Column Data");
817 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
818 	for (i=0;i<num_cols;i++) {
819 		str = g_strdup_printf("Column %d", i+1);
820 		node = gmdb_debug_add_item(store, container, str, newbase, 18);
821 		gmdb_debug_dissect_column(store, node, fbuf, newbase);
822 		newbase += 18;
823 	}
824 
825 	str = g_strdup("Column Names");
826 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
827 	for (i=0;i<num_cols;i++) {
828 		char *tmpstr;
829 		int namelen;
830 
831 		namelen = fbuf[newbase];
832 		tmpstr = g_malloc(namelen + 1);
833 		strncpy(tmpstr, &fbuf[newbase+1], namelen);
834 		tmpstr[namelen]=0;
835 		str = g_strdup_printf("Column %d: %s", i+1, tmpstr);
836 		g_free(tmpstr);
837 		node = gmdb_debug_add_item(store, container, str,
838 			newbase + 1, namelen);
839 		newbase += namelen + 1;
840 	}
841 	str = g_strdup("Index definition 1");
842 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
843 	for (i=0;i<num_idx;i++) {
844 		str = g_strdup_printf("Index %d", i+1);
845 		node = gmdb_debug_add_item(store, container, str, newbase, 39);
846 		gmdb_debug_dissect_index2(store, node, fbuf, newbase);
847 		newbase += 39;
848 	}
849 	str = g_strdup("Index definition 2");
850 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
851 	for (i=0;i<idx_entries;i++) {
852 		str = g_strdup_printf("Index %d", i+1);
853 		node = gmdb_debug_add_item(store, container, str, newbase, 20);
854 		newbase += 20;
855 	}
856 
857 	str = g_strdup("Index Names");
858 	container = gmdb_debug_add_item(store, NULL, str, -1, 0);
859 	for (i=0;i<idx_entries;i++) {
860 		char *tmpstr;
861 		int namelen;
862 
863 		namelen = fbuf[newbase];
864 		tmpstr = g_malloc(namelen + 1);
865 		strncpy(tmpstr, &fbuf[newbase+1], namelen);
866 		tmpstr[namelen]=0;
867 		str = g_strdup_printf("Index %d: %s", i+1, tmpstr);
868 		node = gmdb_debug_add_item(store, container, str,
869 			newbase+1, namelen);
870 		g_free(tmpstr);
871 		newbase += namelen + 1;
872 	}
873 }
874 static void
gmdb_debug_dissect_tabledef_pg(GtkTreeStore * store,char * fbuf,int offset,int len)875 gmdb_debug_dissect_tabledef_pg(GtkTreeStore *store, char *fbuf, int offset, int len)
876 {
877 	if (IS_JET3(mdb))
878 		gmdb_debug_dissect_tabledef_pg3(store, fbuf, offset, len);
879 	else
880 		gmdb_debug_dissect_tabledef_pg4(store, fbuf, offset, len);
881 }
882 static void
gmdb_debug_dissect(GtkTreeStore * store,char * fbuf,int offset,int len)883 gmdb_debug_dissect(GtkTreeStore *store, char *fbuf, int offset, int len)
884 {
885 	gchar *str;
886 
887 	str = g_strdup_printf("Page Type: 0x%02x (%s)", ((unsigned char*)fbuf)[offset],
888 		gmdb_val_to_str(object_types, fbuf[offset]));
889 	gmdb_debug_add_item(store, NULL, str, 0, 1);
890 	switch (fbuf[offset]) {
891 		case 0x00:
892 			//gmdb_debug_dissect_dbpage(store, fbuf, 1, len);
893 			break;
894 		case 0x01:
895 			gmdb_debug_dissect_data_pg(store, fbuf, 0, len);
896 			break;
897 		case 0x02:
898 			gmdb_debug_dissect_tabledef_pg(store, fbuf, 0, len);
899 			break;
900 		case 0x03:
901 			gmdb_debug_dissect_index_pg(store, fbuf, 0, len);
902 			break;
903 		case 0x04:
904 			gmdb_debug_dissect_leaf_pg(store, fbuf, 0, len);
905 			break;
906 	}
907 }
908 
909 static void
gmdb_debug_clear(GtkBuilder * xml)910 gmdb_debug_clear(GtkBuilder *xml)
911 {
912 GtkTextBuffer *buffer;
913 GtkTreeStore *store;
914 GtkTreeView *treeview;
915 GtkWidget *textview;
916 
917 	textview = GTK_WIDGET(gtk_builder_get_object(xml, "debug_textview"));
918 	treeview = GTK_TREE_VIEW(gtk_builder_get_object(xml, "debug_treeview"));
919 	store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
920 
921 	/* clear the tree */
922 	gtk_tree_store_clear(store);
923 
924 	/* call delete text last because remove_node fires unselect signal */
925 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
926 	gtk_text_buffer_set_text(buffer, "", 0);
927 
928 }
929 
930 static GtkTreeIter *
gmdb_debug_add_item(GtkTreeStore * store,GtkTreeIter * iter1,gchar * text,int start,int len)931 gmdb_debug_add_item(GtkTreeStore *store, GtkTreeIter *iter1, gchar *text, int start, int len)
932 {
933 	GtkTreeIter *iter2;
934 
935 	iter2 = g_malloc(sizeof(GtkTreeIter));
936 	gtk_tree_store_append(store, iter2, iter1);
937 	gtk_tree_store_set(store, iter2, 0, text, 1, start, 2, len, -1);
938 	g_free(text);
939 
940 	return iter2;
941 }
942 
943 static void
gmdb_debug_text_on(GtkWidget * textbox,int start_byte,int end_byte)944 gmdb_debug_text_on(GtkWidget *textbox,
945 	int start_byte, int end_byte)
946 {
947 	GtkTextBuffer *buffer;
948 	GtkTextIter start, end;
949 
950 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textbox));
951 	gtk_text_buffer_get_iter_at_offset (buffer, &start, start_byte);
952 	gtk_text_buffer_get_iter_at_offset (buffer, &end, end_byte);
953 	gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(textbox),
954 		&start, 0.0, FALSE, 0.0, 0.0);
955 	gtk_text_buffer_apply_tag_by_name (buffer, "debug_on", &start, &end);
956 }
957 
958 static void
gmdb_debug_text_off(GtkWidget * textbox)959 gmdb_debug_text_off(GtkWidget *textbox)
960 {
961 	GtkTextBuffer *buffer;
962 	int end_byte;
963 	GtkTextIter start, end;
964 
965 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textbox));
966 	end_byte = gtk_text_buffer_get_char_count(buffer);
967 	gtk_text_buffer_get_iter_at_offset (buffer, &start, 0);
968 	gtk_text_buffer_get_iter_at_offset (buffer, &end, end_byte);
969 	gtk_text_buffer_remove_all_tags (buffer, &start, &end);
970 }
971 
972 static gint
gmdb_debug_delete_cb(GtkWidget * w,GtkBuilder * xml)973 gmdb_debug_delete_cb(GtkWidget *w, GtkBuilder *xml)
974 {
975 	return FALSE;
976 }
977 void
gmdb_debug_close_cb(GtkWidget * w,gpointer data)978 gmdb_debug_close_cb(GtkWidget *w, gpointer data)
979 {
980 	GtkBuilder *xml;
981 
982 	fprintf(stderr, "close fired\n");
983 	xml = g_object_get_data(G_OBJECT(w), "debugwin_xml");
984 	debug_list = g_list_remove(debug_list, xml);
985 	gtk_widget_destroy(w);
986 }
987 void
gmdb_debug_close_all()988 gmdb_debug_close_all()
989 {
990 	GtkBuilder *xml;
991 	GtkWidget *win;
992 
993 	fprintf(stderr, "close_all fired\n");
994 	while ((xml = g_list_nth_data(debug_list, 0))) {
995 		win = GTK_WIDGET(gtk_builder_get_object(xml, "debug_window"));
996 		debug_list = g_list_remove(debug_list, xml);
997 		if (win) gtk_widget_destroy(win);
998 	}
999 }
1000 
1001 void
gmdb_debug_new_cb(GtkWidget * w,gpointer data)1002 gmdb_debug_new_cb(GtkWidget *w, gpointer data)
1003 {
1004 	GtkTextView *textview;
1005 	GtkWidget *entry, *debugwin;
1006 	GtkBuilder *debugwin_xml;
1007 	GtkWidget *tree;
1008 	GtkTreeStore *store;
1009 	GtkCellRenderer *renderer;
1010 	GtkTreeViewColumn *column;
1011 	GtkTreeSelection *select;
1012     GError *error = NULL;
1013 
1014 	/* load the interface */
1015 	debugwin_xml = gtk_builder_new();
1016     if (!gtk_builder_add_from_file(debugwin_xml, GMDB_UIDIR "gmdb-debug.ui", &error)) {
1017         g_warning("Error adding " GMDB_UIDIR "gmdb-debug.ui: %s", error->message);
1018         g_error_free(error);
1019     }
1020 	/* connect the signals in the interface */
1021 	gtk_builder_connect_signals(debugwin_xml, NULL);
1022 
1023 	debug_list = g_list_append(debug_list, debugwin_xml);
1024 
1025 	/* set signals with user data, anyone know how to do this in glade? */
1026 	entry = GTK_WIDGET(gtk_builder_get_object(debugwin_xml, "debug_entry"));
1027 
1028 	debugwin = GTK_WIDGET(gtk_builder_get_object(debugwin_xml, "debug_window"));
1029 	g_signal_connect (G_OBJECT (debugwin), "delete_event",
1030 		G_CALLBACK (gmdb_debug_delete_cb), debugwin_xml);
1031 	g_object_set_data (G_OBJECT (debugwin), "debugwin_xml", debugwin_xml);
1032 
1033 	/* this should be a preference, needs to be fixed width */
1034 	textview = GTK_TEXT_VIEW(gtk_builder_get_object(debugwin_xml, "debug_textview"));
1035     gtk_text_view_set_monospace(textview, TRUE);
1036 
1037 	/* set up treeview, libglade only gives us the empty widget */
1038 	tree = GTK_WIDGET(gtk_builder_get_object(debugwin_xml, "debug_treeview"));
1039 	store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
1040 	gtk_tree_view_set_model(GTK_TREE_VIEW(tree), GTK_TREE_MODEL(store));
1041 
1042 	renderer = gtk_cell_renderer_text_new();
1043 	column = gtk_tree_view_column_new_with_attributes("Field",
1044 		renderer, "text", 0, NULL);
1045 	gtk_tree_view_append_column(GTK_TREE_VIEW (tree), column);
1046 
1047 	select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
1048 	gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
1049 	g_signal_connect (G_OBJECT (select), "changed",
1050 		G_CALLBACK (gmdb_debug_select_cb), debugwin_xml);
1051 
1052 	/* check if initial page was passed */
1053 	if (mdb) {
1054 		gmdb_debug_init(mdb, debugwin_xml);
1055 		if (data) {
1056 			gchar *text;
1057 			guint32 page = *((guint32 *)data);
1058 
1059 			text = g_strdup_printf("%lu", (unsigned long)page);
1060 			gtk_entry_set_text(GTK_ENTRY(entry), text);
1061 			g_free(text);
1062 			gmdb_debug_display_cb(entry, NULL);
1063 		}
1064 	}
1065 }
1066 void
gmdb_debug_set_dissect_cb(GtkWidget * w,gpointer data)1067 gmdb_debug_set_dissect_cb(GtkWidget *w, gpointer data)
1068 {
1069 	gboolean *dissect;
1070 
1071 	dissect = g_object_get_data(G_OBJECT(w),"dissect");
1072 	if (!dissect) return;
1073 	//printf("here %d\n", *dissect);
1074 	*dissect = !(*dissect);
1075 	g_object_set_data(G_OBJECT(w), "dissect", dissect);
1076 }
gmdb_debug_init(MdbHandle * mdb,GtkBuilder * xml)1077 static void gmdb_debug_init(MdbHandle *mdb, GtkBuilder *xml)
1078 {
1079 	gchar *str;
1080 	GtkWidget *pglabel, *entry, *window, *textview;
1081 	GtkTextBuffer *buffer;
1082 	gboolean *dissect;
1083 
1084 	pglabel = GTK_WIDGET(gtk_builder_get_object(xml, "debug_num_label"));
1085 	str = g_strdup_printf("(0-%ld):", gmdb_get_max_page(mdb));
1086 	gtk_label_set_text(GTK_LABEL(pglabel), str);
1087 	g_free(str);
1088 
1089 	entry = GTK_WIDGET(gtk_builder_get_object(xml, "debug_entry"));
1090 	gtk_widget_grab_focus(GTK_WIDGET(entry));
1091 
1092 	window = GTK_WIDGET(gtk_builder_get_object(xml, "debug_window"));
1093 	dissect = g_malloc0(sizeof(guint));
1094 	*dissect = TRUE;
1095 	g_object_set_data(G_OBJECT(window), "dissect", dissect);
1096 
1097 	textview = GTK_WIDGET(gtk_builder_get_object(xml, "debug_textview"));
1098 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textview));
1099 	gtk_text_buffer_create_tag (buffer, "debug_on",
1100 		"foreground", "white", "background", "blue", NULL);
1101 }
1102