From: dw <lim...@ya...> - 2011-02-26 23:08:02
|
So, my first proposed modification is to replace the mdb_ole_read_full routine in data.c. While the current routine does work, it has a number of inefficiencies: - Performs unnecessary memory allocation/memcpy of the Memo Field Definition - Performs (repeated) unnecessary memcpys - Performs (repeated) unnecessary reallocs (which also do memcpys) - Allocates more memory than is needed to hold the data - Uses an inconsistent memory allocator (malloc vs g_malloc) - Leaves the col->bind_ptr in an unusable state My replacement (below) does: - Zero memcpys - Zero reallocs - A single, correctly-sized allocation using g_malloc - Preserves the Memo Field Definition in col->bind_ptr - Fully commented My next proposed modification is more substantive, but this seemed like a good place to start. dw /* * mdb_ole_read_full - reads the entire OLE field * * mdb - the database pointer * col - the column to read * size - outputs the size of the buffer returned (may be NULL) * * returns - the result in a big buffer. The number of data bytes is * returned in the size parameter. The returned buffer must freed * using g_free(). * * On return, col->bind_ptr still points to the 12 byte Memo Field * Definition, NOT the data. This means the OLE field can be * re-read if necessary. * */ void* mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size) { void *pOldBind; unsigned char *result; size_t pos, iTotSize; // What's the total length of the field? Drop off flags iTotSize = mdb_get_int32(col->bind_ptr, 0)& 0x3fffffff; // Allocate room for the entire field. result = (unsigned char *)g_malloc(iTotSize); // Save the old pointer which points to the 12 byte Memo Field Definition pOldBind = col->bind_ptr; // mdb_ole_read& mdb_ole_read_next always write to col->bind_ptr. // So we adjust it to point to our full sized buffer col->bind_ptr = result; // Reads at most 1 data page pos = mdb_ole_read(mdb, col, pOldBind, iTotSize); // Is there more to read? while (pos< iTotSize) { // Adjust col->bind_ptr so the next call will write to // the appropriate offset in the buffer col->bind_ptr = result + pos; // Read the next chunk (at most 1 data page). Passing NULL // for the 3rd parameter avoids redundant error checking pos += mdb_ole_read_next(mdb, col, NULL); } // assert pos == iTotSize if (size) *size = pos; // restore the 12 byte Memo Field Definition col->bind_ptr = pOldBind; return result; } |