[rfc] Ole

Nirgal Vourgère <[email protected]> Wed, 9 Feb 2011 00:02:03 +0000
Newsgroups gmane.comp.db.mdb-tools.devel
Message-ID <[email protected]>
I spend quite some time today, trying to make ole fields work.

We use them in 2 places:
- mdb-export (but we only printed the first chunk of data).
- mdb-prop (but it did not work when the props are in more than a chunk)

In both cases, we need a loop like
- Read the first chunk
- While there are other chunks, get them.

Attached is a patch I'm working on:
A new function
void *mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size)
reads all the chunks and return a plain buffer.

Other major changes:
- mdb_old_read_next now stops when col->cur_blob_pg_row becomes 0, as it should.
- mdb_ole_read_first returns the real size read. It means -4 for type 2 chunks. It's more consistent with the other returned value. Having the extra 4 bytes was why mdb-prop was crashing.
- Changed mdb-prop and mdb-export to use that new function.


I played with catalog.c to automatically loads the LvProp, in yet another path, but it's crashing from time to time. So the included patch is for your information only, I'll fix it soon I hope.

Comments are welcome of course!

------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb

_______________________________________________
mdbtools-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mdbtools-dev
ole.WIP.diff (text/x-patch, 6.2 KB)
Index: mdbtools-0.6pre1+git20110208/src/util/mdb-export.c
===================================================================
--- mdbtools-0.6pre1+git20110208.orig/src/util/mdb-export.c
+++ mdbtools-0.6pre1+git20110208/src/util/mdb-export.c
@@ -82,6 +82,8 @@
 	char sanitize = 0;
 	char *namespace = "";
 	int  opt;
+	char *value;
+	size_t length;
 
 	while ((opt=getopt(argc, argv, "HQq:X:d:D:R:I:N:S"))!=-1) {
 		switch (opt) {
@@ -168,6 +170,7 @@
 	if (insert_dialect)
 		if (!mdb_set_default_backend(mdb, insert_dialect)) {
 			fprintf(stderr, "Invalid backend type\n");
+			if (escape_char) g_free (escape_char);
 			mdb_exit();
 			exit(1);
 		}
@@ -227,22 +230,26 @@
 		}
 
 		for (j=0;j<table->num_cols;j++) {
+			if (j>0)
+				fputs(delimiter, stdout);
 			col=g_ptr_array_index(table->columns,j);
-			if ((col->col_type == MDB_OLE)
-			 && ((j==0) || (col->cur_value_len))) {
-				mdb_ole_read(mdb, col, bound_values[j], MDB_BIND_SIZE);
-			}
-			if (j>0) {
-				fprintf(stdout,delimiter);
-			}
 			if (!bound_lens[j]) {
-				print_col(insert_dialect?"NULL":"",0,col->col_type, 0, quote_char, escape_char);
+				if (insert_dialect)
+					fputs("NULL", stdout);
 			} else {
-				print_col(bound_values[j], quote_text, col->col_type, bound_lens[j], quote_char, escape_char);
+				if (col->col_type == MDB_OLE) {
+					value = mdb_ole_read_full(mdb, col, &length);
+				} else {
+					value = bound_values[j];
+					length = bound_lens[j];
+				}
+				print_col(value, quote_text, col->col_type, length, quote_char, escape_char);
+				if (col->col_type == MDB_OLE)
+					free(value);
 			}
 		}
-		if (insert_dialect) fprintf(stdout,");");
-		fprintf(stdout, row_delimiter);
+		if (insert_dialect) fputs(");", stdout);
+		fputs(row_delimiter, stdout);
 	}
 	for (j=0;j<table->num_cols;j++) {
 		g_free(bound_values[j]);
@@ -258,7 +265,7 @@
 	mdb_close(mdb);
 	mdb_exit();
 
-	exit(0);
+	return 0;
 }
 
 static char *escapes(char *s)
Index: mdbtools-0.6pre1+git20110208/src/libmdb/data.c
===================================================================
--- mdbtools-0.6pre1+git20110208.orig/src/libmdb/data.c
+++ mdbtools-0.6pre1+git20110208/src/libmdb/data.c
@@ -19,6 +19,7 @@
 
 #include "mdbtools.h"
 #include "time.h"
+#include "math.h"
 
 #ifdef DMALLOC
 #include "dmalloc.h"
@@ -346,8 +347,8 @@
 		/* On rare occasion, mdb_map_find_next will return a wrong page */
 		/* Found in a big file, over 4,000,000 records */
 		fprintf(stderr,
-			"warning: page %d from map doesn't match: Type=%d, buf[4..7]=%d Expected table_pg=%d\n",
-			next_pg, mdb_get_int32(mdb->pg_buf, 4), entry->table_pg);
+			"warning: page %d from map doesn't match: Type=%d, buf[4..7]=%ld Expected table_pg=%ld\n",
+			next_pg, mdb->pg_buf[0], mdb_get_int32(mdb->pg_buf, 4), entry->table_pg);
 	}
 	fprintf(stderr, "Warning: defaulting to brute force read\n");
 #endif 
@@ -481,6 +482,8 @@
 		/* inline or single-page fields don't have a next */
 		return 0;
 	} else {
+		if (!col->cur_blob_pg_row)
+			return 0; /* we are done */
 		if (mdb_find_pg_row(mdb, col->cur_blob_pg_row,
 			&buf, &row_start, &len)) {
 			return 0;
@@ -489,7 +492,7 @@
 			memcpy(col->bind_ptr, buf + row_start + 4, len - 4);
 		col->cur_blob_pg_row = mdb_get_int32(buf, row_start);
 
-		return len;
+		return len - 4;
 	}
 	return 0;
 }
@@ -549,12 +552,43 @@
 			memcpy(col->bind_ptr, buf + row_start + 4, len - 4);
 		col->cur_blob_pg_row = mdb_get_int32(buf, row_start);
 
-		return len;
+		return len - 4;
 	} else {
 		fprintf(stderr,"Unhandled ole field flags = %02x\n", ole_len >> 24);
 		return 0;
 	}
 }
+/*
+ * mdb_ole_read_full calls mdb_ole_read then loop over mdb_ole_read_next as much as necessary.
+ * returns the result in a big buffer.
+ * The call must free it.
+ * Note that this function is not indempotent: It may be called only once per column after each bind.
+ */
+void*
+mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size)
+{
+	char ole_ptr[MDB_MEMO_OVERHEAD];
+	char *result = malloc(MDB_BIND_SIZE);
+	size_t result_buffer_size = MDB_BIND_SIZE;
+	size_t len, pos;
+
+	memcpy(ole_ptr, col->bind_ptr, MDB_MEMO_OVERHEAD);
+
+	len = mdb_ole_read(mdb, col, ole_ptr, MDB_BIND_SIZE);
+	memcpy(result, col->bind_ptr, len);
+	pos = len;
+	while ((len = mdb_ole_read_next(mdb, col, ole_ptr))) {
+		if (pos+len >= MDB_BIND_SIZE) {
+			result_buffer_size += MDB_BIND_SIZE;
+			result = realloc(result, result_buffer_size);
+		}
+		memcpy(result + pos, col->bind_ptr, len);
+		pos += len;
+	}
+	*size = pos;
+	return result;
+}
+
 #ifdef MDB_COPY_OLE
 static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size)
 {
Index: mdbtools-0.6pre1+git20110208/src/util/mdb-prop.c
===================================================================
--- mdbtools-0.6pre1+git20110208.orig/src/util/mdb-prop.c
+++ mdbtools-0.6pre1+git20110208/src/util/mdb-prop.c
@@ -80,21 +80,11 @@
 	}
 
 	if (found) {
-		MdbColumn *col;
-		gchar kkd_ptr[MDB_MEMO_OVERHEAD];
-		void *kkd_pg = g_malloc(200000);
-		size_t len, pos;
-		memcpy(kkd_ptr, buf, MDB_MEMO_OVERHEAD);
-		col = g_ptr_array_index(table->columns, col_num - 1);
-		len = mdb_ole_read(mdb, col, kkd_ptr, MDB_BIND_SIZE);
-		memcpy(kkd_pg, buf, len);
-		pos = len;
-		while ((len = mdb_ole_read_next(mdb, col, kkd_ptr))) {
-			memcpy(kkd_pg + pos, buf, len);
-			pos += len;
-		}
-		dump_kkd(mdb, kkd_pg, pos);
-		g_free(kkd_pg);
+		MdbColumn *col = g_ptr_array_index(table->columns, col_num - 1);
+		size_t size;
+		void *kkd = mdb_ole_read_full(mdb, col, &size);
+		dump_kkd(mdb, kkd, size);
+		free(kkd);
 	}
 
 	g_free(buf);
@@ -121,6 +111,7 @@
 #endif
 	if (strcmp("KKD", kkd)) {
 		fprintf(stderr, "Unrecognized format.\n");
+		buffer_dump(kkd, 0, len);
 		return;
 	}
 	
Index: mdbtools-0.6pre1+git20110208/include/mdbtools.h
===================================================================
--- mdbtools-0.6pre1+git20110208.orig/include/mdbtools.h
+++ mdbtools-0.6pre1+git20110208/include/mdbtools.h
@@ -448,6 +448,7 @@
 extern int mdb_col_disp_size(MdbColumn *col);
 extern size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr);
 extern size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size);
+extern void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size);
 extern void mdb_set_date_fmt(const char *);
 extern int mdb_read_row(MdbTableDef *table, unsigned int row);