mirror of
https://github.com/mdbtools/mdbtools.git
synced 2026-03-10 00:20:54 +08:00
231 lines
6.0 KiB
C
231 lines
6.0 KiB
C
/* MDB Tools - A library for reading MS Access database file
|
|
* Copyright (C) 2000-2011 Brian Bruns and others
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "mdbtools.h"
|
|
|
|
static GPtrArray *
|
|
mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len)
|
|
{
|
|
guint32 record_len;
|
|
int pos = 0;
|
|
gchar *name;
|
|
GPtrArray *names = NULL;
|
|
int i=0;
|
|
|
|
names = g_ptr_array_new();
|
|
#if MDB_DEBUG
|
|
mdb_buffer_dump(kkd, 0, len);
|
|
#endif
|
|
pos = 0;
|
|
while (pos < len) {
|
|
record_len = mdb_get_int16(kkd, pos);
|
|
pos += 2;
|
|
if (mdb_get_option(MDB_DEBUG_PROPS)) {
|
|
fprintf(stderr, "%02d ",i++);
|
|
mdb_buffer_dump(kkd, pos - 2, record_len + 2);
|
|
}
|
|
name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte in */
|
|
mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len + 1);
|
|
|
|
pos += record_len;
|
|
g_ptr_array_add(names, name);
|
|
#if MDB_DEBUG
|
|
printf("new len = %d\n", names->len);
|
|
#endif
|
|
}
|
|
return names;
|
|
}
|
|
static void
|
|
free_hash_entry(gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
g_free(key);
|
|
g_free(value);
|
|
}
|
|
void
|
|
mdb_free_props(MdbProperties *props)
|
|
{
|
|
if (!props) return;
|
|
|
|
if (props->name) g_free(props->name);
|
|
if (props->hash) {
|
|
g_hash_table_foreach(props->hash, free_hash_entry, 0);
|
|
g_hash_table_destroy(props->hash);
|
|
}
|
|
g_free(props);
|
|
}
|
|
|
|
static void
|
|
do_g_free(gpointer ptr, gpointer user_data) {
|
|
g_free(ptr);
|
|
}
|
|
|
|
static void
|
|
free_names(GPtrArray *names) {
|
|
g_ptr_array_foreach(names, do_g_free, NULL);
|
|
g_ptr_array_free(names, TRUE);
|
|
}
|
|
MdbProperties *
|
|
mdb_alloc_props(void)
|
|
{
|
|
MdbProperties *props;
|
|
|
|
props = g_malloc0(sizeof(MdbProperties));
|
|
|
|
return props;
|
|
}
|
|
static MdbProperties *
|
|
mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len)
|
|
{
|
|
guint32 record_len, name_len;
|
|
int pos = 0;
|
|
guint elem;
|
|
int dtype, dsize;
|
|
gchar *name, *value;
|
|
MdbProperties *props;
|
|
int i=0;
|
|
|
|
#if MDB_DEBUG
|
|
mdb_buffer_dump(kkd, 0, len);
|
|
#endif
|
|
pos = 0;
|
|
|
|
record_len = mdb_get_int16(kkd, pos);
|
|
pos += 4;
|
|
name_len = mdb_get_int16(kkd, pos);
|
|
pos += 2;
|
|
props = mdb_alloc_props();
|
|
if (name_len) {
|
|
props->name = g_malloc(3*name_len + 1);
|
|
mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len + 1);
|
|
mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name);
|
|
}
|
|
pos += name_len;
|
|
|
|
props->hash = g_hash_table_new(g_str_hash, g_str_equal);
|
|
|
|
while (pos < len) {
|
|
record_len = mdb_get_int16(kkd, pos);
|
|
dtype = kkd[pos + 3];
|
|
elem = mdb_get_int16(kkd, pos + 4);
|
|
if (elem >= names->len)
|
|
break;
|
|
dsize = mdb_get_int16(kkd, pos + 6);
|
|
if (dsize < 0 || pos + 8 + dsize > len)
|
|
break;
|
|
value = g_strdup_printf("%.*s", dsize, &kkd[pos+8]);
|
|
name = g_ptr_array_index(names,elem);
|
|
if (mdb_get_option(MDB_DEBUG_PROPS)) {
|
|
fprintf(stderr, "%02d ",i++);
|
|
mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, dtype);
|
|
mdb_buffer_dump(value, 0, dsize);
|
|
}
|
|
if (dtype == MDB_MEMO) {
|
|
dtype = MDB_TEXT;
|
|
} else if (dtype == MDB_BINARY && dsize == 16 && strcmp(name, "GUID") == 0) {
|
|
dtype = MDB_REPID;
|
|
}
|
|
if (dtype == MDB_BOOL) {
|
|
g_hash_table_insert(props->hash, g_strdup(name),
|
|
g_strdup(kkd[pos + 8] ? "yes" : "no"));
|
|
} else if (dtype == MDB_BINARY || dtype == MDB_OLE) {
|
|
g_hash_table_insert(props->hash, g_strdup(name),
|
|
g_strdup_printf("(binary data of length %d)", dsize));
|
|
} else {
|
|
g_hash_table_insert(props->hash, g_strdup(name),
|
|
mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize));
|
|
}
|
|
g_free(value);
|
|
pos += record_len;
|
|
}
|
|
return props;
|
|
|
|
}
|
|
|
|
static void
|
|
print_keyvalue(gpointer key, gpointer value, gpointer outfile)
|
|
{
|
|
fprintf((FILE*)outfile,"\t%s: %s\n", (gchar *)key, (gchar *)value);
|
|
}
|
|
void
|
|
mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) {
|
|
if (show_name)
|
|
fprintf(outfile,"name: %s\n", props->name ? props->name : "(none)");
|
|
g_hash_table_foreach(props->hash, print_keyvalue, outfile);
|
|
if (show_name)
|
|
fputc('\n', outfile);
|
|
}
|
|
|
|
/*
|
|
* That function takes a raw KKD/MR2 binary buffer,
|
|
* typically read from LvProp in table MSysbjects
|
|
* and returns a GPtrArray of MdbProps*
|
|
*/
|
|
GPtrArray*
|
|
mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) {
|
|
guint32 record_len;
|
|
guint16 record_type;
|
|
size_t pos;
|
|
GPtrArray *names = NULL;
|
|
MdbProperties *props;
|
|
GPtrArray *result;
|
|
|
|
#if MDB_DEBUG
|
|
mdb_buffer_dump(buffer, 0, len);
|
|
#endif
|
|
mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", buffer);
|
|
|
|
if (strcmp("KKD", buffer) && strcmp("MR2", buffer)) {
|
|
fprintf(stderr, "Unrecognized format.\n");
|
|
mdb_buffer_dump(buffer, 0, len);
|
|
return NULL;
|
|
}
|
|
|
|
result = g_ptr_array_new();
|
|
|
|
pos = 4;
|
|
while (pos < len) {
|
|
record_len = mdb_get_int32(buffer, pos);
|
|
record_type = mdb_get_int16(buffer, pos + 4);
|
|
mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, record_len);
|
|
//mdb_buffer_dump(buffer, pos+4, record_len);
|
|
switch (record_type) {
|
|
case 0x80:
|
|
if (names) free_names(names);
|
|
names = mdb_read_props_list(mdb, (char*)buffer+pos+6, record_len - 6);
|
|
break;
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
if (!names) {
|
|
fprintf(stderr,"sequence error!\n");
|
|
break;
|
|
}
|
|
props = mdb_read_props(mdb, names, (char*)buffer+pos+6, record_len - 6);
|
|
g_ptr_array_add(result, props);
|
|
//mdb_dump_props(props, stderr, 1);
|
|
break;
|
|
default:
|
|
fprintf(stderr,"Unknown record type %d\n", record_type);
|
|
break;
|
|
}
|
|
pos += record_len;
|
|
}
|
|
if (names) free_names(names);
|
|
return result;
|
|
}
|