/src/mdbtools/src/libmdb/props.c
Line | Count | Source |
1 | | /* MDB Tools - A library for reading MS Access database file |
2 | | * Copyright (C) 2000-2011 Brian Bruns and others |
3 | | * |
4 | | * This library is free software; you can redistribute it and/or |
5 | | * modify it under the terms of the GNU Library General Public |
6 | | * License as published by the Free Software Foundation; either |
7 | | * version 2 of the License, or (at your option) any later version. |
8 | | * |
9 | | * This library 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 GNU |
12 | | * Library General Public License for more details. |
13 | | * |
14 | | * You should have received a copy of the GNU Library General Public |
15 | | * License along with this library; if not, write to the Free Software |
16 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | | */ |
18 | | |
19 | | #include "mdbtools.h" |
20 | | |
21 | | static GPtrArray * |
22 | | mdb_read_props_list(MdbHandle *mdb, gchar *kkd, int len) |
23 | 50 | { |
24 | 50 | guint32 record_len; |
25 | 50 | int pos = 0; |
26 | 50 | gchar *name; |
27 | 50 | GPtrArray *names = NULL; |
28 | 50 | int i=0; |
29 | | |
30 | 50 | names = g_ptr_array_new(); |
31 | | #if MDB_DEBUG |
32 | | mdb_buffer_dump(kkd, 0, len); |
33 | | #endif |
34 | 50 | pos = 0; |
35 | 100 | while (pos < len) { |
36 | 50 | record_len = mdb_get_int16(kkd, pos); |
37 | 50 | pos += 2; |
38 | 50 | if (mdb_get_option(MDB_DEBUG_PROPS)) { |
39 | 0 | fprintf(stderr, "%02d ",i++); |
40 | 0 | mdb_buffer_dump(kkd, pos - 2, record_len + 2); |
41 | 0 | } |
42 | 50 | name = g_malloc(3*record_len + 1); /* worst case scenario is 3 bytes out per byte in */ |
43 | 50 | mdb_unicode2ascii(mdb, &kkd[pos], record_len, name, 3*record_len + 1); |
44 | | |
45 | 50 | pos += record_len; |
46 | 50 | g_ptr_array_add(names, name); |
47 | | #if MDB_DEBUG |
48 | | printf("new len = %d\n", names->len); |
49 | | #endif |
50 | 50 | } |
51 | 50 | return names; |
52 | 50 | } |
53 | | static void |
54 | | free_hash_entry(gpointer key, gpointer value, gpointer user_data) |
55 | 3 | { |
56 | 3 | g_free(key); |
57 | 3 | g_free(value); |
58 | 3 | } |
59 | | void |
60 | | mdb_free_props(MdbProperties *props) |
61 | 49 | { |
62 | 49 | if (!props) return; |
63 | | |
64 | 49 | if (props->name) g_free(props->name); |
65 | 49 | if (props->hash) { |
66 | 49 | g_hash_table_foreach(props->hash, free_hash_entry, 0); |
67 | 49 | g_hash_table_destroy(props->hash); |
68 | 49 | } |
69 | 49 | g_free(props); |
70 | 49 | } |
71 | | |
72 | | static void |
73 | 50 | do_g_free(gpointer ptr, gpointer user_data) { |
74 | 50 | g_free(ptr); |
75 | 50 | } |
76 | | |
77 | | static void |
78 | 50 | free_names(GPtrArray *names) { |
79 | 50 | g_ptr_array_foreach(names, do_g_free, NULL); |
80 | 50 | g_ptr_array_free(names, TRUE); |
81 | 50 | } |
82 | | MdbProperties * |
83 | | mdb_alloc_props(void) |
84 | 49 | { |
85 | 49 | MdbProperties *props; |
86 | | |
87 | 49 | props = g_malloc0(sizeof(MdbProperties)); |
88 | | |
89 | 49 | return props; |
90 | 49 | } |
91 | | static MdbProperties * |
92 | | mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len) |
93 | 49 | { |
94 | 49 | guint32 record_len, name_len; |
95 | 49 | int pos = 0; |
96 | 49 | guint elem; |
97 | 49 | int dtype, dsize; |
98 | 49 | gchar *name, *value; |
99 | 49 | MdbProperties *props; |
100 | 49 | int i=0; |
101 | | |
102 | | #if MDB_DEBUG |
103 | | mdb_buffer_dump(kkd, 0, len); |
104 | | #endif |
105 | 49 | pos = 0; |
106 | | |
107 | 49 | record_len = mdb_get_int16(kkd, pos); |
108 | 49 | pos += 4; |
109 | 49 | name_len = mdb_get_int16(kkd, pos); |
110 | 49 | pos += 2; |
111 | 49 | props = mdb_alloc_props(); |
112 | 49 | if (name_len) { |
113 | 46 | props->name = g_malloc(3*name_len + 1); |
114 | 46 | mdb_unicode2ascii(mdb, kkd+pos, name_len, props->name, 3*name_len + 1); |
115 | 46 | mdb_debug(MDB_DEBUG_PROPS,"prop block named: %s", props->name); |
116 | 46 | } |
117 | 49 | pos += name_len; |
118 | | |
119 | 49 | props->hash = g_hash_table_new(g_str_hash, g_str_equal); |
120 | | |
121 | 52 | while (pos < len) { |
122 | 4 | record_len = mdb_get_int16(kkd, pos); |
123 | 4 | dtype = kkd[pos + 3]; |
124 | 4 | elem = mdb_get_int16(kkd, pos + 4); |
125 | 4 | if (elem >= names->len) |
126 | 1 | break; |
127 | 3 | dsize = mdb_get_int16(kkd, pos + 6); |
128 | 3 | if (dsize < 0 || pos + 8 + dsize > len) |
129 | 0 | break; |
130 | 3 | value = g_strdup_printf("%.*s", dsize, &kkd[pos+8]); |
131 | 3 | name = g_ptr_array_index(names,elem); |
132 | 3 | if (mdb_get_option(MDB_DEBUG_PROPS)) { |
133 | 0 | fprintf(stderr, "%02d ",i++); |
134 | 0 | mdb_debug(MDB_DEBUG_PROPS,"elem %d (%s) dsize %d dtype %d", elem, name, dsize, dtype); |
135 | 0 | mdb_buffer_dump(value, 0, dsize); |
136 | 0 | } |
137 | 3 | if (dtype == MDB_MEMO) { |
138 | 0 | dtype = MDB_TEXT; |
139 | 3 | } else if (dtype == MDB_BINARY && dsize == 16 && strcmp(name, "GUID") == 0) { |
140 | 0 | dtype = MDB_REPID; |
141 | 0 | } |
142 | 3 | if (dtype == MDB_BOOL) { |
143 | 0 | g_hash_table_insert(props->hash, g_strdup(name), |
144 | 0 | g_strdup(kkd[pos + 8] ? "yes" : "no")); |
145 | 3 | } else if (dtype == MDB_BINARY || dtype == MDB_OLE) { |
146 | 0 | g_hash_table_insert(props->hash, g_strdup(name), |
147 | 0 | g_strdup_printf("(binary data of length %d)", dsize)); |
148 | 3 | } else { |
149 | 3 | g_hash_table_insert(props->hash, g_strdup(name), |
150 | 3 | mdb_col_to_string(mdb, kkd, pos + 8, dtype, dsize)); |
151 | 3 | } |
152 | 3 | g_free(value); |
153 | 3 | pos += record_len; |
154 | 3 | } |
155 | 49 | return props; |
156 | | |
157 | 49 | } |
158 | | |
159 | | static void |
160 | | print_keyvalue(gpointer key, gpointer value, gpointer outfile) |
161 | 0 | { |
162 | 0 | fprintf((FILE*)outfile,"\t%s: %s\n", (gchar *)key, (gchar *)value); |
163 | 0 | } |
164 | | void |
165 | 0 | mdb_dump_props(MdbProperties *props, FILE *outfile, int show_name) { |
166 | 0 | if (show_name) |
167 | 0 | fprintf(outfile,"name: %s\n", props->name ? props->name : "(none)"); |
168 | 0 | g_hash_table_foreach(props->hash, print_keyvalue, outfile); |
169 | 0 | if (show_name) |
170 | 0 | fputc('\n', outfile); |
171 | 0 | } |
172 | | |
173 | | /* |
174 | | * That function takes a raw KKD/MR2 binary buffer, |
175 | | * typically read from LvProp in table MSysbjects |
176 | | * and returns a GPtrArray of MdbProps* |
177 | | */ |
178 | | GPtrArray* |
179 | 4.90k | mdb_kkd_to_props(MdbHandle *mdb, void *buffer, size_t len) { |
180 | 4.90k | guint32 record_len; |
181 | 4.90k | guint16 record_type; |
182 | 4.90k | size_t pos; |
183 | 4.90k | GPtrArray *names = NULL; |
184 | 4.90k | MdbProperties *props; |
185 | 4.90k | GPtrArray *result; |
186 | | |
187 | | #if MDB_DEBUG |
188 | | mdb_buffer_dump(buffer, 0, len); |
189 | | #endif |
190 | 4.90k | mdb_debug(MDB_DEBUG_PROPS,"starting prop parsing of type %s", buffer); |
191 | | |
192 | 4.90k | if (strcmp("KKD", buffer) && strcmp("MR2", buffer)) { |
193 | 1.92k | fprintf(stderr, "Unrecognized format.\n"); |
194 | 1.92k | mdb_buffer_dump(buffer, 0, len); |
195 | 1.92k | return NULL; |
196 | 1.92k | } |
197 | | |
198 | 2.97k | result = g_ptr_array_new(); |
199 | | |
200 | 2.97k | pos = 4; |
201 | 3.63k | while (pos < len) { |
202 | 653 | record_len = mdb_get_int32(buffer, pos); |
203 | 653 | record_type = mdb_get_int16(buffer, pos + 4); |
204 | 653 | mdb_debug(MDB_DEBUG_PROPS,"prop chunk type:0x%04x len:%d", record_type, record_len); |
205 | | //mdb_buffer_dump(buffer, pos+4, record_len); |
206 | 653 | switch (record_type) { |
207 | 50 | case 0x80: |
208 | 50 | if (names) free_names(names); |
209 | 50 | names = mdb_read_props_list(mdb, (char*)buffer+pos+6, record_len - 6); |
210 | 50 | break; |
211 | 49 | case 0x00: |
212 | 49 | case 0x01: |
213 | 49 | case 0x02: |
214 | 49 | if (!names) { |
215 | 0 | fprintf(stderr,"sequence error!\n"); |
216 | 0 | break; |
217 | 0 | } |
218 | 49 | props = mdb_read_props(mdb, names, (char*)buffer+pos+6, record_len - 6); |
219 | 49 | g_ptr_array_add(result, props); |
220 | | //mdb_dump_props(props, stderr, 1); |
221 | 49 | break; |
222 | 554 | default: |
223 | 554 | fprintf(stderr,"Unknown record type %d\n", record_type); |
224 | 554 | break; |
225 | 653 | } |
226 | 653 | pos += record_len; |
227 | 653 | } |
228 | 2.97k | if (names) free_names(names); |
229 | 2.97k | return result; |
230 | 2.97k | } |