diff --git a/ChangeLog b/ChangeLog index 85a29cc..f074662 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Mar 11 21:32:19 CST 2005 Jeff Smith + * HACKING: + * src/libmdb/data.c: + * src/libmdb/iconv.c: Fix some issues with mdb_memo_to_string + Sun Mar 6 22:09:09 CST 2005 Jeff Smith * src/libmdb/table.c: Fix memory leak * include/mdbtools.h: diff --git a/HACKING b/HACKING index 1604482..914cf42 100644 --- a/HACKING +++ b/HACKING @@ -199,16 +199,16 @@ Each memo column (or other long binary data) in a row +------+---------+-------------+------------------------------------------+ | data | length | name | description | +------+---------+-------------+------------------------------------------+ -| ???? | 2 bytes | memo_len | Total length of the memo | -| ???? | 2 bytes | bitmask | See values | +| ???? | 3 bytes | memo_len | Total length of the memo | +| ???? | 1 bytes | bitmask | See values | | ???? | 4 bytes | lval_dp | Data pointer to LVAL page (if needed) | | 0x00 | 4 bytes | unknown | | +------+---------+-------------+------------------------------------------+ Values for the bitmask: -0x8000= the memo is in a string at the end of this header (memo_len bytes) -0x4000= the memo is in a unique LVAL page in a record type 1 -0x0000= the memo is in n LVAL pages in a record type 2 +0x80 = the memo is in a string at the end of this header (memo_len bytes) +0x40 = the memo is in a unique LVAL page in a record type 1 +0x00 = the memo is in n LVAL pages in a record type 2 If the memo is in a LVAL page, we use row_id of lval_dp to find the row. offset_start of memo = (int16*) LVAL_page[offset_num_rows + (row_id * 2) + 2] diff --git a/src/libmdb/data.c b/src/libmdb/data.c index d739df0..d7f992c 100644 --- a/src/libmdb/data.c +++ b/src/libmdb/data.c @@ -605,8 +605,7 @@ int mdb_copy_ole(MdbHandle *mdb, char *dest, int start, int size) } static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) { - guint16 memo_len; - guint16 memo_flags; + guint32 memo_len; guint32 row_start, pg_row; guint32 len; char *buf; @@ -618,21 +617,22 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) } #if MDB_DEBUG - buffer_dump(mdb->pg_buf, start, start + MDB_MEMO_OVERHEAD); + buffer_dump(mdb->pg_buf, start, start + MDB_MEMO_OVERHEAD - 1); #endif - /* The 16 bit integer at offset 0 is the length of the memo field. + /* The 32 bit integer at offset 0 is the length of the memo field + * with some flags in the high bits. * The 32 bit integer at offset 4 contains page and row information. */ - memo_len = mdb_pg_get_int16(mdb, start); - memo_flags = mdb_pg_get_int16(mdb, start+2); + memo_len = mdb_pg_get_int32(mdb, start); - if (memo_flags & 0x8000) { + if (memo_len & 0x80000000) { /* inline memo field */ mdb_unicode2ascii(mdb, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD], size - MDB_MEMO_OVERHEAD, text, MDB_BIND_SIZE); return text; - } else if (memo_flags & 0x4000) { + } else if (memo_len & 0x40000000) { + /* single-page memo field */ pg_row = mdb_get_int32(mdb->pg_buf, start+4); #if MDB_DEBUG printf("Reading LVAL page %06x\n", pg_row >> 8); @@ -644,20 +644,24 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) #if MDB_DEBUG printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); - buffer_dump(mdb->pg_buf, row_start, row_start + len); + buffer_dump(buf, row_start, row_start + len - 1); #endif mdb_unicode2ascii(mdb, buf + row_start, len, text, MDB_BIND_SIZE); return text; - } else { /* if (memo_flags == 0x0000) { */ + } else { + /* multi-page memo field */ + int tmpoff = 0; char *tmp; + + memo_len &= 0x3fffffff; + tmp = (char *) g_malloc(memo_len); pg_row = mdb_get_int32(mdb->pg_buf, start+4); -#if MDB_DEBUG - printf("Reading LVAL page %06x\n", pg_row >> 8); -#endif - tmp = (char *) g_malloc(MDB_BIND_SIZE); - tmp[0] = '\0'; do { +#if MDB_DEBUG + printf("Reading LVAL page %06x\n", pg_row >> 8); +#endif if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { + g_free(tmp); strcpy(text, ""); return text; } @@ -665,14 +669,16 @@ static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) printf("row num %d start %d len %d\n", pg_row & 0xff, row_start, len); #endif - strncat(tmp, buf + row_start + 4, - strlen(tmp) + len - 4 > MDB_BIND_SIZE ? - MDB_BIND_SIZE - strlen(tmp) : len - 4); - - /* find next lval page */ - pg_row = mdb_get_int32(mdb->pg_buf, row_start); - } while ((pg_row >> 8)); - mdb_unicode2ascii(mdb, tmp, strlen(tmp), text, MDB_BIND_SIZE); + if (tmpoff + len - 4 > memo_len) { + break; + } + memcpy(tmp + tmpoff, buf + row_start + 4, len - 4); + tmpoff += len - 4; + } while (( pg_row = mdb_get_int32(buf, row_start) )); + if (tmpoff < memo_len) { + fprintf(stderr, "Warning: incorrect memo length\n"); + } + mdb_unicode2ascii(mdb, tmp, tmpoff, text, MDB_BIND_SIZE); g_free(tmp); return text; /* diff --git a/src/libmdb/iconv.c b/src/libmdb/iconv.c index 9c67f72..59b8bd5 100644 --- a/src/libmdb/iconv.c +++ b/src/libmdb/iconv.c @@ -18,6 +18,7 @@ */ #include "mdbtools.h" +#include "errno.h" #ifdef DMALLOC #include "dmalloc.h" @@ -69,7 +70,7 @@ mdb_unicode2ascii(MdbHandle *mdb, unsigned char *src, unsigned int slen, unsigne //printf("1 len_in %d len_out %d\n",len_in, len_out); while (1) { iconv(mdb->iconv_in, &in_ptr, &len_in, &out_ptr, &len_out); - if (!len_in) break; + if ((!len_in) || (errno == E2BIG)) break; /* Don't bail if impossible conversion is encountered */ in_ptr += (IS_JET4(mdb)) ? 2 : 1; len_in -= (IS_JET4(mdb)) ? 2 : 1;