/src/mdbtools/src/libmdb/data.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* MDB Tools - A library for reading MS Access database file |
2 | | * Copyright (C) 2000 Brian Bruns |
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 | | #include <time.h> |
22 | | |
23 | 357k | #define OFFSET_MASK 0x1fff |
24 | 1.86k | #define OLE_BUFFER_SIZE (MDB_BIND_SIZE*64) |
25 | | |
26 | | static int _mdb_attempt_bind(MdbHandle *mdb, |
27 | | MdbColumn *col, unsigned char isnull, int offset, int len); |
28 | | static char *mdb_date_to_string(MdbHandle *mdb, const char *fmt, void *buf, int start); |
29 | | #ifdef MDB_COPY_OLE |
30 | | static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size); |
31 | | #endif |
32 | | |
33 | | #ifndef HAVE_REALLOCF |
34 | 0 | static void *reallocf(void *ptr, size_t len) { |
35 | 0 | void *ptr2 = realloc(ptr, len); |
36 | 0 | if (!ptr2) { |
37 | 0 | free(ptr); |
38 | 0 | return NULL; |
39 | 0 | } |
40 | 0 | return ptr2; |
41 | 0 | } |
42 | | #endif |
43 | | |
44 | | static const int noleap_cal[] = {0,31,59,90,120,151,181,212,243,273,304,334,365}; |
45 | | static const int leap_cal[] = {0,31,60,91,121,152,182,213,244,274,305,335,366}; |
46 | | |
47 | | /* Some databases (eg PostgreSQL) do not understand integer 0/1 values |
48 | | * as TRUE/FALSE, so provide a means to override the values used to be |
49 | | * the SQL Standard TRUE/FALSE values. |
50 | | */ |
51 | | static const char boolean_false_number[] = "0"; |
52 | | static const char boolean_true_number[] = "1"; |
53 | | |
54 | | static const char boolean_false_word[] = "FALSE"; |
55 | | static const char boolean_true_word[] = "TRUE"; |
56 | | |
57 | 19 | void mdb_set_bind_size(MdbHandle *mdb, size_t bind_size) { |
58 | 19 | mdb->bind_size = bind_size; |
59 | 19 | } |
60 | | |
61 | | void mdb_set_date_fmt(MdbHandle *mdb, const char *fmt) |
62 | 38 | { |
63 | 38 | snprintf(mdb->date_fmt, sizeof(mdb->date_fmt), "%s", fmt); |
64 | 38 | } |
65 | | |
66 | | void mdb_set_shortdate_fmt(MdbHandle *mdb, const char *fmt) |
67 | 38 | { |
68 | 38 | snprintf(mdb->shortdate_fmt, sizeof(mdb->shortdate_fmt), "%s", fmt); |
69 | 38 | } |
70 | | |
71 | | void mdb_set_repid_fmt(MdbHandle *mdb, MdbUuidFormat format) |
72 | 19 | { |
73 | 19 | mdb->repid_fmt = format; |
74 | 19 | } |
75 | | |
76 | | void mdb_set_boolean_fmt_numbers(MdbHandle *mdb) |
77 | 19 | { |
78 | 19 | mdb->boolean_false_value = boolean_false_number; |
79 | 19 | mdb->boolean_true_value = boolean_true_number; |
80 | 19 | } |
81 | | |
82 | | void mdb_set_boolean_fmt_words(MdbHandle *mdb) |
83 | 0 | { |
84 | 0 | mdb->boolean_false_value = boolean_false_word; |
85 | 0 | mdb->boolean_true_value = boolean_true_word; |
86 | 0 | } |
87 | | |
88 | | int mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr) |
89 | 0 | { |
90 | 0 | MdbColumn *col = NULL; |
91 | |
|
92 | 0 | if (!table->columns) |
93 | 0 | return -1; |
94 | | /* |
95 | | ** the column arrary is 0 based, so decrement to get 1 based parameter |
96 | | */ |
97 | 0 | col_num--; |
98 | |
|
99 | 0 | if (col_num >= 0 && col_num < (int)table->num_cols) { |
100 | 0 | col=g_ptr_array_index(table->columns, col_num); |
101 | |
|
102 | 0 | if (col) { |
103 | 0 | if (bind_ptr) |
104 | 0 | col->bind_ptr = bind_ptr; |
105 | 0 | if (len_ptr) |
106 | 0 | col->len_ptr = len_ptr; |
107 | |
|
108 | 0 | return col_num + 1; |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | 0 | return -1; |
113 | 0 | } |
114 | | |
115 | | int |
116 | | mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr) |
117 | 85 | { |
118 | 85 | unsigned int i; |
119 | 85 | int col_num = -1; |
120 | 85 | MdbColumn *col; |
121 | | |
122 | 85 | if (!table->columns) |
123 | 0 | return -1; |
124 | | |
125 | 632 | for (i=0;i<table->num_cols;i++) { |
126 | 632 | col=g_ptr_array_index(table->columns,i); |
127 | 632 | if (!g_ascii_strcasecmp(col->name,col_name)) { |
128 | 85 | col_num = i + 1; |
129 | 85 | if (bind_ptr) |
130 | 85 | col->bind_ptr = bind_ptr; |
131 | 85 | if (len_ptr) |
132 | 17 | col->len_ptr = len_ptr; |
133 | 85 | break; |
134 | 85 | } |
135 | 632 | } |
136 | | |
137 | 85 | return col_num; |
138 | 85 | } |
139 | | |
140 | | /** |
141 | | * mdb_find_pg_row |
142 | | * @mdb: Database file handle |
143 | | * @pg_row: Lower byte contains the row number, the upper three contain page |
144 | | * @buf: Pointer for returning a pointer to the page |
145 | | * @off: Pointer for returning an offset to the row |
146 | | * @len: Pointer for returning the length of the row |
147 | | * |
148 | | * Returns: 0 on success. -1 on failure. |
149 | | */ |
150 | | int mdb_find_pg_row(MdbHandle *mdb, int pg_row, void **buf, int *off, size_t *len) |
151 | 931 | { |
152 | 931 | unsigned int pg = pg_row >> 8; |
153 | 931 | unsigned int row = pg_row & 0xff; |
154 | 931 | int result = 0; |
155 | | |
156 | 931 | if (mdb_read_alt_pg(mdb, pg) != mdb->fmt->pg_size) |
157 | 156 | return -1; |
158 | 775 | mdb_swap_pgbuf(mdb); |
159 | 775 | result = mdb_find_row(mdb, row, off, len); |
160 | 775 | mdb_swap_pgbuf(mdb); |
161 | 775 | *off &= OFFSET_MASK; |
162 | 775 | *buf = mdb->alt_pg_buf; |
163 | 775 | return result; |
164 | 931 | } |
165 | | |
166 | | int mdb_find_row(MdbHandle *mdb, int row, int *start, size_t *len) |
167 | 1.13M | { |
168 | 1.13M | int rco = mdb->fmt->row_count_offset; |
169 | 1.13M | int next_start; |
170 | | |
171 | 1.13M | if (row > 1000) return -1; |
172 | | |
173 | 73.8k | *start = mdb_get_int16(mdb->pg_buf, rco + 2 + row*2); |
174 | 73.8k | next_start = (row == 0) ? mdb->fmt->pg_size : |
175 | 73.8k | mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; |
176 | 73.8k | *len = next_start - (*start & OFFSET_MASK); |
177 | | |
178 | 73.8k | if ((*start & OFFSET_MASK) >= mdb->fmt->pg_size || |
179 | 73.8k | (*start & OFFSET_MASK) > next_start || |
180 | 73.8k | next_start > mdb->fmt->pg_size) |
181 | 46.4k | return -1; |
182 | | |
183 | 27.3k | return 0; |
184 | 73.8k | } |
185 | | |
186 | | int |
187 | | mdb_find_end_of_row(MdbHandle *mdb, int row) |
188 | 0 | { |
189 | 0 | int rco = mdb->fmt->row_count_offset; |
190 | 0 | int row_end; |
191 | |
|
192 | 0 | #if 1 |
193 | 0 | if (row > 1000) return -1; |
194 | | |
195 | 0 | row_end = (row == 0) ? mdb->fmt->pg_size : |
196 | 0 | mdb_get_int16(mdb->pg_buf, rco + row*2) & OFFSET_MASK; |
197 | | #else |
198 | | /* Search the previous "row start" values for the first non-'lookupflag' |
199 | | * one. If we don't find one, then the end of the page is the correct |
200 | | * value. |
201 | | */ |
202 | | int i, row_start; |
203 | | |
204 | | if (row > 1000) return -1; |
205 | | |
206 | | /* if lookupflag is not set, it's good (deleteflag is ok) */ |
207 | | for (i = row; i > 0; i--) { |
208 | | row_start = mdb_get_int16(mdb->pg_buf, (rco + i*2)); |
209 | | if (!(row_start & 0x8000)) { |
210 | | break; |
211 | | } |
212 | | } |
213 | | |
214 | | row_end = (i == 0) ? mdb->fmt->pg_size : row_start & OFFSET_MASK; |
215 | | #endif |
216 | 0 | return row_end - 1; |
217 | 0 | } |
218 | | int mdb_is_null(unsigned char *null_mask, int col_num) |
219 | 0 | { |
220 | 0 | int byte_num = (col_num - 1) / 8; |
221 | 0 | int bit_num = (col_num - 1) % 8; |
222 | |
|
223 | 0 | if ((1 << bit_num) & null_mask[byte_num]) { |
224 | 0 | return 0; |
225 | 0 | } else { |
226 | 0 | return 1; |
227 | 0 | } |
228 | 0 | } |
229 | | /* bool has to be handled specially because it uses the null bit to store its |
230 | | ** value*/ |
231 | | static size_t |
232 | | mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value) |
233 | 20.1k | { |
234 | 20.1k | col->cur_value_len = value; |
235 | 20.1k | if (col->bind_ptr) { |
236 | 5.68k | strcpy(col->bind_ptr, |
237 | 5.68k | value ? mdb->boolean_false_value : mdb->boolean_true_value); |
238 | 5.68k | } |
239 | 20.1k | if (col->len_ptr) { |
240 | 1.94k | *col->len_ptr = strlen(col->bind_ptr); |
241 | 1.94k | } |
242 | | |
243 | 20.1k | return 1; |
244 | 20.1k | } |
245 | | static size_t |
246 | | mdb_xfer_bound_ole(MdbHandle *mdb, int start, MdbColumn *col, int len) |
247 | 131 | { |
248 | 131 | size_t ret = 0; |
249 | 131 | if (len) { |
250 | 115 | col->cur_value_start = start; |
251 | 115 | col->cur_value_len = len; |
252 | 115 | } else { |
253 | 16 | col->cur_value_start = 0; |
254 | 16 | col->cur_value_len = 0; |
255 | 16 | } |
256 | | #ifdef MDB_COPY_OLE |
257 | | if (col->bind_ptr || col->len_ptr) { |
258 | | ret = mdb_copy_ole(mdb, col->bind_ptr, start, len); |
259 | | } |
260 | | #else |
261 | 131 | if (col->bind_ptr) { |
262 | 18 | memcpy(col->bind_ptr, mdb->pg_buf + start, MDB_MEMO_OVERHEAD); |
263 | 18 | } |
264 | 131 | ret = MDB_MEMO_OVERHEAD; |
265 | 131 | #endif |
266 | 131 | if (col->len_ptr) { |
267 | 18 | *col->len_ptr = ret; |
268 | 18 | } |
269 | 131 | return ret; |
270 | 131 | } |
271 | | static size_t |
272 | | mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len) |
273 | 143k | { |
274 | 143k | int ret; |
275 | | //if (!strcmp("Name",col->name)) { |
276 | | //printf("start %d %d\n",start, len); |
277 | | //} |
278 | 143k | if (len) { |
279 | 11.2k | col->cur_value_start = start; |
280 | 11.2k | col->cur_value_len = len; |
281 | 132k | } else { |
282 | 132k | col->cur_value_start = 0; |
283 | 132k | col->cur_value_len = 0; |
284 | 132k | } |
285 | 143k | if (col->bind_ptr) { |
286 | 12.9k | if (!len) { |
287 | 10.8k | strcpy(col->bind_ptr, ""); |
288 | 10.8k | } else { |
289 | | //fprintf(stdout,"len %d size %d\n",len, col->col_size); |
290 | 2.02k | char *str; |
291 | 2.02k | if (col->col_type == MDB_NUMERIC) { |
292 | 19 | str = mdb_numeric_to_string(mdb, start, col->col_scale, col->col_prec); |
293 | 2.00k | } else if (col->col_type == MDB_DATETIME) { |
294 | 42 | if (mdb_col_is_shortdate(col)) { |
295 | 0 | str = mdb_date_to_string(mdb, mdb->shortdate_fmt, mdb->pg_buf, start); |
296 | 42 | } else { |
297 | 42 | str = mdb_date_to_string(mdb, mdb->date_fmt, mdb->pg_buf, start); |
298 | 42 | } |
299 | 1.96k | } else { |
300 | 1.96k | str = mdb_col_to_string(mdb, mdb->pg_buf, start, col->col_type, len); |
301 | 1.96k | } |
302 | 2.02k | snprintf(col->bind_ptr, mdb->bind_size, "%s", str); |
303 | 2.02k | g_free(str); |
304 | 2.02k | } |
305 | 12.9k | ret = strlen(col->bind_ptr); |
306 | 12.9k | if (col->len_ptr) { |
307 | 1.76k | *col->len_ptr = ret; |
308 | 1.76k | } |
309 | 12.9k | return ret; |
310 | 12.9k | } |
311 | 131k | return 0; |
312 | 143k | } |
313 | | int mdb_read_row(MdbTableDef *table, unsigned int row) |
314 | 1.13M | { |
315 | 1.13M | MdbHandle *mdb = table->entry->mdb; |
316 | 1.13M | MdbColumn *col; |
317 | 1.13M | unsigned int i; |
318 | 1.13M | int row_start; |
319 | 1.13M | size_t row_size = 0; |
320 | 1.13M | int delflag, lookupflag; |
321 | 1.13M | MdbField *fields; |
322 | 1.13M | int num_fields; |
323 | | |
324 | 1.13M | if (table->num_cols == 0 || !table->columns) |
325 | 2 | return 0; |
326 | | |
327 | 1.13M | if (mdb_find_row(mdb, row, &row_start, &row_size) == -1 || row_size == 0) { |
328 | | /* Emitting a warning here isn't especially helpful. The row metadata |
329 | | * could be bogus for a number of reasons, so just skip to the next one |
330 | | * without comment. */ |
331 | | // fprintf(stderr, "warning: mdb_find_row failed.\n"); |
332 | | // fprintf(stderr, "warning: row_size = 0.\n"); |
333 | 1.11M | return 0; |
334 | 1.11M | } |
335 | | |
336 | 19.3k | delflag = lookupflag = 0; |
337 | 19.3k | if (row_start & 0x8000) lookupflag++; |
338 | 19.3k | if (row_start & 0x4000) delflag++; |
339 | 19.3k | row_start &= OFFSET_MASK; /* remove flags */ |
340 | | #if MDB_DEBUG |
341 | | fprintf(stdout,"Row %d bytes %d to %d %s %s\n", |
342 | | row, row_start, row_start + row_size - 1, |
343 | | lookupflag ? "[lookup]" : "", |
344 | | delflag ? "[delflag]" : ""); |
345 | | #endif |
346 | | |
347 | 19.3k | if (!table->noskip_del && delflag) { |
348 | 1.79k | return 0; |
349 | 1.79k | } |
350 | | |
351 | 17.5k | fields = malloc(sizeof(MdbField) * table->num_cols); |
352 | | |
353 | 17.5k | num_fields = mdb_crack_row(table, row_start, row_size, fields); |
354 | 17.5k | if (num_fields < 0 || !mdb_test_sargs(table, fields, num_fields)) { |
355 | 7.52k | free(fields); |
356 | 7.52k | return 0; |
357 | 7.52k | } |
358 | | |
359 | | #if MDB_DEBUG |
360 | | fprintf(stdout,"sarg test passed row %d \n", row); |
361 | | #endif |
362 | | |
363 | | #if MDB_DEBUG |
364 | | mdb_buffer_dump(mdb->pg_buf, row_start, row_size); |
365 | | #endif |
366 | | |
367 | | /* take advantage of mdb_crack_row() to clean up binding */ |
368 | | /* use num_cols instead of num_fields -- bsb 03/04/02 */ |
369 | 174k | for (i = 0; i < table->num_cols; i++) { |
370 | 164k | col = g_ptr_array_index(table->columns,fields[i].colnum); |
371 | 164k | _mdb_attempt_bind(mdb, col, fields[i].is_null, |
372 | 164k | fields[i].start, fields[i].siz); |
373 | 164k | } |
374 | | |
375 | 10.0k | free(fields); |
376 | | |
377 | 10.0k | return 1; |
378 | 17.5k | } |
379 | | static int _mdb_attempt_bind(MdbHandle *mdb, |
380 | | MdbColumn *col, |
381 | | unsigned char isnull, |
382 | | int offset, |
383 | | int len) |
384 | 164k | { |
385 | 164k | if (col->col_type == MDB_BOOL) { |
386 | 20.1k | mdb_xfer_bound_bool(mdb, col, isnull); |
387 | 144k | } else if (isnull) { |
388 | 126k | mdb_xfer_bound_data(mdb, 0, col, 0); |
389 | 126k | } else if (col->col_type == MDB_OLE) { |
390 | 131 | mdb_xfer_bound_ole(mdb, offset, col, len); |
391 | 17.8k | } else { |
392 | | //if (!mdb_test_sargs(mdb, col, offset, len)) { |
393 | | //return 0; |
394 | | //} |
395 | 17.8k | mdb_xfer_bound_data(mdb, offset, col, len); |
396 | 17.8k | } |
397 | 164k | return 1; |
398 | 164k | } |
399 | | |
400 | | /* Read next data page into mdb->pg_buf */ |
401 | | int mdb_read_next_dpg(MdbTableDef *table) |
402 | 113 | { |
403 | 113 | MdbCatalogEntry *entry = table->entry; |
404 | 113 | MdbHandle *mdb = entry->mdb; |
405 | 113 | int next_pg; |
406 | | |
407 | 113 | #ifndef SLOW_READ |
408 | 1.41k | while (1) { |
409 | 1.41k | next_pg = mdb_map_find_next(mdb, table->usage_map, |
410 | 1.41k | table->map_sz, table->cur_phys_pg); |
411 | 1.41k | if (next_pg < 0) |
412 | 107 | break; /* unknow map type: goto fallback */ |
413 | 1.31k | if (!next_pg) |
414 | 0 | return 0; |
415 | 1.31k | if ((guint32)next_pg == table->cur_phys_pg) |
416 | 0 | return 0; /* Infinite loop */ |
417 | | |
418 | 1.31k | if (!mdb_read_pg(mdb, next_pg)) { |
419 | 4 | fprintf(stderr, "error: reading page %d failed.\n", next_pg); |
420 | 4 | return 0; |
421 | 4 | } |
422 | | |
423 | 1.30k | table->cur_phys_pg = next_pg; |
424 | 1.30k | if (mdb->pg_buf[0]==MDB_PAGE_DATA && mdb_get_int32(mdb->pg_buf, 4)==(long)entry->table_pg) |
425 | 2 | return table->cur_phys_pg; |
426 | | |
427 | | /* On rare occasion, mdb_map_find_next will return a wrong page */ |
428 | | /* Found in a big file, over 4,000,000 records */ |
429 | 1.30k | fprintf(stderr, |
430 | 1.30k | "warning: page %d from map doesn't match: Type=%d, buf[4..7]=%ld Expected table_pg=%ld\n", |
431 | 1.30k | next_pg, mdb->pg_buf[0], mdb_get_int32(mdb->pg_buf, 4), entry->table_pg); |
432 | 1.30k | } |
433 | 107 | fprintf(stderr, "Warning: defaulting to brute force read\n"); |
434 | 107 | #endif |
435 | | /* can't do a fast read, go back to the old way */ |
436 | 7.59k | do { |
437 | 7.59k | if (!mdb_read_pg(mdb, table->cur_phys_pg++)) |
438 | 32 | return 0; |
439 | 7.59k | } while (mdb->pg_buf[0]!=MDB_PAGE_DATA || mdb_get_int32(mdb->pg_buf, 4)!=(long)entry->table_pg); |
440 | | /* fprintf(stderr,"returning new page %ld\n", table->cur_phys_pg); */ |
441 | 75 | return table->cur_phys_pg; |
442 | 107 | } |
443 | | int mdb_rewind_table(MdbTableDef *table) |
444 | 36 | { |
445 | 36 | table->cur_pg_num=0; |
446 | 36 | table->cur_phys_pg=0; |
447 | 36 | table->cur_row=0; |
448 | | |
449 | 36 | return 0; |
450 | 36 | } |
451 | | int |
452 | | mdb_fetch_row(MdbTableDef *table) |
453 | 10.0k | { |
454 | 10.0k | MdbHandle *mdb = table->entry->mdb; |
455 | 10.0k | MdbFormatConstants *fmt = mdb->fmt; |
456 | 10.0k | unsigned int rows; |
457 | 10.0k | int rc; |
458 | 10.0k | guint32 pg; |
459 | | |
460 | | /* initialize */ |
461 | 10.0k | if (!table->cur_pg_num) { |
462 | 36 | table->cur_pg_num=1; |
463 | 36 | table->cur_row=0; |
464 | 36 | if ((!table->is_temp_table)&&(table->strategy!=MDB_INDEX_SCAN)) |
465 | 36 | if (!mdb_read_next_dpg(table)) return 0; |
466 | 36 | } |
467 | | |
468 | 1.13M | do { |
469 | 1.13M | if (table->is_temp_table) { |
470 | 0 | GPtrArray *pages = table->temp_table_pages; |
471 | 0 | if (pages->len == 0) |
472 | 0 | return 0; |
473 | 0 | rows = mdb_get_int16( |
474 | 0 | g_ptr_array_index(pages, table->cur_pg_num-1), |
475 | 0 | fmt->row_count_offset); |
476 | 0 | if (table->cur_row >= rows) { |
477 | 0 | table->cur_row = 0; |
478 | 0 | if (++table->cur_pg_num > (unsigned int)pages->len) |
479 | 0 | return 0; |
480 | 0 | } |
481 | 0 | memcpy(mdb->pg_buf, |
482 | 0 | g_ptr_array_index(pages, table->cur_pg_num-1), |
483 | 0 | fmt->pg_size); |
484 | 1.13M | } else if (table->strategy==MDB_INDEX_SCAN) { |
485 | | |
486 | 0 | if (!mdb_index_find_next(table->mdbidx, table->scan_idx, table->chain, &pg, (guint16 *) &(table->cur_row))) { |
487 | 0 | mdb_index_scan_free(table); |
488 | 0 | return 0; |
489 | 0 | } |
490 | 0 | mdb_read_pg(mdb, pg); |
491 | 1.13M | } else { |
492 | 1.13M | rows = mdb_get_int16(mdb->pg_buf,fmt->row_count_offset); |
493 | | |
494 | | /* if at end of page, find a new data page */ |
495 | 1.13M | if (table->cur_row >= rows) { |
496 | 77 | table->cur_row=0; |
497 | | |
498 | 77 | if (!mdb_read_next_dpg(table)) { |
499 | 23 | return 0; |
500 | 23 | } |
501 | 77 | } |
502 | 1.13M | } |
503 | | |
504 | | /* printf("page %d row %d\n",table->cur_phys_pg, table->cur_row); */ |
505 | 1.13M | rc = mdb_read_row(table, table->cur_row); |
506 | 1.13M | table->cur_row++; |
507 | 1.13M | } while (!rc); |
508 | | |
509 | 10.0k | return 1; |
510 | 10.0k | } |
511 | | void mdb_data_dump(MdbTableDef *table) |
512 | 0 | { |
513 | 0 | unsigned int i; |
514 | 0 | int ret; |
515 | 0 | char **bound_values = calloc(table->num_cols, sizeof(char *)); |
516 | |
|
517 | 0 | for (i=0;i<table->num_cols;i++) { |
518 | 0 | bound_values[i] = g_malloc(MDB_BIND_SIZE); |
519 | 0 | ret = mdb_bind_column(table, i+1, bound_values[i], NULL); |
520 | 0 | if (ret == -1) { |
521 | 0 | fprintf(stderr, "error binding column %d\n", i+1); |
522 | 0 | g_free(bound_values[i]); |
523 | 0 | bound_values[i] = NULL; |
524 | 0 | } |
525 | 0 | } |
526 | 0 | mdb_rewind_table(table); |
527 | 0 | while (mdb_fetch_row(table)) { |
528 | 0 | for (i=0;i<table->num_cols;i++) { |
529 | 0 | if (bound_values[i]) { |
530 | 0 | fprintf(stdout, "column %d is %s\n", i+1, bound_values[i]); |
531 | 0 | } |
532 | 0 | } |
533 | 0 | } |
534 | 0 | for (i=0;i<table->num_cols;i++) { |
535 | 0 | g_free(bound_values[i]); |
536 | 0 | } |
537 | 0 | free(bound_values); |
538 | 0 | } |
539 | | |
540 | | int mdb_is_fixed_col(MdbColumn *col) |
541 | 0 | { |
542 | 0 | return col->is_fixed; |
543 | 0 | } |
544 | | #if 0 |
545 | | static char *mdb_data_to_hex(MdbHandle *mdb, char *text, int start, int size) |
546 | | { |
547 | | int i; |
548 | | |
549 | | for (i=start; i<start+size; i++) { |
550 | | sprintf(&text[(i-start)*2],"%02x", mdb->pg_buf[i]); |
551 | | } |
552 | | text[(i-start)*2]='\0'; |
553 | | |
554 | | return text; |
555 | | } |
556 | | #endif |
557 | | /* |
558 | | * ole_ptr should point to the original blob value of the field. |
559 | | * If omited, there will be no multi-page check to that the caller is |
560 | | * responsible for not calling this function. Then, it doesn't have to |
561 | | * preserve the original value. |
562 | | */ |
563 | | size_t |
564 | | mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr) |
565 | 622 | { |
566 | 622 | guint32 ole_len; |
567 | 622 | void *buf; |
568 | 622 | int row_start; |
569 | 622 | size_t len; |
570 | | |
571 | 622 | if (ole_ptr) { |
572 | 622 | ole_len = mdb_get_int32(ole_ptr, 0); |
573 | 622 | mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", |
574 | 622 | ole_len & 0x00ffffff, ole_len >> 24); |
575 | | |
576 | 622 | if ((ole_len & 0x80000000) |
577 | 622 | || (ole_len & 0x40000000)) |
578 | | /* inline or single-page fields don't have a next */ |
579 | 612 | return 0; |
580 | 622 | } |
581 | 10 | mdb_debug(MDB_DEBUG_OLE, "pg_row %d", col->cur_blob_pg_row); |
582 | 10 | if (!col->cur_blob_pg_row) |
583 | 9 | return 0; /* we are done */ |
584 | 1 | if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, |
585 | 1 | &buf, &row_start, &len)) { |
586 | 1 | return 0; |
587 | 1 | } |
588 | 0 | if (len < 4) |
589 | 0 | return 0; |
590 | 0 | mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); |
591 | |
|
592 | 0 | if (col->bind_ptr) |
593 | 0 | memcpy(col->bind_ptr, (char*)buf + row_start + 4, len - 4); |
594 | 0 | col->cur_blob_pg_row = mdb_get_int32(buf, row_start); |
595 | |
|
596 | 0 | return len - 4; |
597 | 0 | } |
598 | | size_t |
599 | | mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, size_t chunk_size) |
600 | 622 | { |
601 | 622 | guint32 ole_len; |
602 | 622 | void *buf; |
603 | 622 | int row_start; |
604 | 622 | size_t len; |
605 | | |
606 | 622 | ole_len = mdb_get_int32(ole_ptr, 0); |
607 | 622 | mdb_debug(MDB_DEBUG_OLE,"ole len = %d ole flags = %02x", |
608 | 622 | ole_len & 0x00ffffff, ole_len >> 24); |
609 | | |
610 | 622 | col->chunk_size = chunk_size; |
611 | | |
612 | 622 | if (ole_len & 0x80000000) { |
613 | | /* inline ole field, if we can satisfy it, then do it */ |
614 | 0 | len = col->cur_value_len - MDB_MEMO_OVERHEAD; |
615 | 0 | if (chunk_size < len) |
616 | 0 | return 0; |
617 | 0 | if (col->bind_ptr) |
618 | 0 | memcpy(col->bind_ptr, &mdb->pg_buf[col->cur_value_start + |
619 | 0 | MDB_MEMO_OVERHEAD], len); |
620 | 0 | return len; |
621 | 622 | } else if (ole_len & 0x40000000) { |
622 | 612 | col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); |
623 | 612 | mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", |
624 | 612 | col->cur_blob_pg_row & 0xff, |
625 | 612 | col->cur_blob_pg_row >> 8); |
626 | | |
627 | 612 | if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, |
628 | 612 | &buf, &row_start, &len)) { |
629 | 612 | return 0; |
630 | 612 | } |
631 | 0 | mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); |
632 | |
|
633 | 0 | if (col->bind_ptr) { |
634 | 0 | memcpy(col->bind_ptr, (char*)buf + row_start, len); |
635 | 0 | if (mdb_get_option(MDB_DEBUG_OLE)) |
636 | 0 | mdb_buffer_dump(col->bind_ptr, 0, 16); |
637 | 0 | } |
638 | 0 | return len; |
639 | 612 | } else if ((ole_len & 0xf0000000) == 0) { |
640 | 0 | col->cur_blob_pg_row = mdb_get_int32(ole_ptr, 4); |
641 | 0 | mdb_debug(MDB_DEBUG_OLE,"ole row = %d ole pg = %ld", |
642 | 0 | col->cur_blob_pg_row & 0xff, |
643 | 0 | col->cur_blob_pg_row >> 8); |
644 | |
|
645 | 0 | if (mdb_find_pg_row(mdb, col->cur_blob_pg_row, |
646 | 0 | &buf, &row_start, &len) || len < 4) { |
647 | 0 | return 0; |
648 | 0 | } |
649 | 0 | mdb_debug(MDB_DEBUG_OLE,"start %d len %d", row_start, len); |
650 | |
|
651 | 0 | if (col->bind_ptr) |
652 | 0 | memcpy(col->bind_ptr, (char*)buf + row_start + 4, len - 4); |
653 | 0 | col->cur_blob_pg_row = mdb_get_int32(buf, row_start); |
654 | 0 | mdb_debug(MDB_DEBUG_OLE, "next pg_row %d", col->cur_blob_pg_row); |
655 | |
|
656 | 0 | return len - 4; |
657 | 10 | } else { |
658 | 10 | fprintf(stderr,"Unhandled ole field flags = %02x\n", ole_len >> 24); |
659 | 10 | return 0; |
660 | 10 | } |
661 | 622 | } |
662 | | /* |
663 | | * mdb_ole_read_full calls mdb_ole_read then loop over mdb_ole_read_next as much as necessary. |
664 | | * returns the result in a big buffer. |
665 | | * The call must free it. |
666 | | * Note that this function is not idempotent: It may be called only once per column after each bind. |
667 | | */ |
668 | | void* |
669 | | mdb_ole_read_full(MdbHandle *mdb, MdbColumn *col, size_t *size) |
670 | 622 | { |
671 | 622 | char ole_ptr[MDB_MEMO_OVERHEAD]; |
672 | 622 | char *result = malloc(OLE_BUFFER_SIZE); |
673 | 622 | size_t result_buffer_size = OLE_BUFFER_SIZE; |
674 | 622 | size_t len, pos; |
675 | | |
676 | 622 | memcpy(ole_ptr, col->bind_ptr, MDB_MEMO_OVERHEAD); |
677 | | |
678 | 622 | len = mdb_ole_read(mdb, col, ole_ptr, OLE_BUFFER_SIZE); |
679 | 622 | memcpy(result, col->bind_ptr, len); |
680 | 622 | pos = len; |
681 | 622 | while ((len = mdb_ole_read_next(mdb, col, ole_ptr))) { |
682 | 0 | if (pos+len >= result_buffer_size) { |
683 | 0 | result_buffer_size += OLE_BUFFER_SIZE; |
684 | 0 | if ((result = reallocf(result, result_buffer_size)) == NULL) { |
685 | 0 | fprintf(stderr, "Out of memory while reading OLE object\n"); |
686 | 0 | return NULL; |
687 | 0 | } |
688 | 0 | } |
689 | 0 | memcpy(result + pos, col->bind_ptr, len); |
690 | 0 | pos += len; |
691 | 0 | } |
692 | 622 | if (size) |
693 | 622 | *size = pos; |
694 | 622 | return result; |
695 | 622 | } |
696 | | |
697 | | #ifdef MDB_COPY_OLE |
698 | | static size_t mdb_copy_ole(MdbHandle *mdb, void *dest, int start, int size) |
699 | | { |
700 | | guint32 ole_len; |
701 | | gint32 row_start, pg_row; |
702 | | size_t len; |
703 | | void *buf, *pg_buf = mdb->pg_buf; |
704 | | |
705 | | if (size<MDB_MEMO_OVERHEAD) { |
706 | | return 0; |
707 | | } |
708 | | |
709 | | /* The 16 bit integer at offset 0 is the length of the memo field. |
710 | | * The 32 bit integer at offset 4 contains page and row information. |
711 | | */ |
712 | | ole_len = mdb_get_int32(pg_buf, start); |
713 | | |
714 | | if (ole_len & 0x80000000) { |
715 | | /* inline */ |
716 | | len = size - MDB_MEMO_OVERHEAD; |
717 | | if (dest) memcpy(dest, pg_buf + start + MDB_MEMO_OVERHEAD, len); |
718 | | return len; |
719 | | } else if (ole_len & 0x40000000) { |
720 | | /* single page */ |
721 | | pg_row = mdb_get_int32(pg_buf, start+4); |
722 | | mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", pg_row >> 8); |
723 | | |
724 | | if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { |
725 | | return 0; |
726 | | } |
727 | | mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", |
728 | | pg_row & 0xff, row_start, len); |
729 | | |
730 | | if (dest) |
731 | | memcpy(dest, buf + row_start, len); |
732 | | return len; |
733 | | } else if ((ole_len & 0xff000000) == 0) { // assume all flags in MSB |
734 | | /* multi-page */ |
735 | | int cur = 0; |
736 | | pg_row = mdb_get_int32(pg_buf, start+4); |
737 | | do { |
738 | | mdb_debug(MDB_DEBUG_OLE,"Reading LVAL page %06x", |
739 | | pg_row >> 8); |
740 | | |
741 | | if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len) || len < 4) { |
742 | | return 0; |
743 | | } |
744 | | |
745 | | mdb_debug(MDB_DEBUG_OLE,"row num %d start %d len %d", |
746 | | pg_row & 0xff, row_start, len); |
747 | | |
748 | | if (dest) |
749 | | memcpy(dest+cur, buf + row_start + 4, len - 4); |
750 | | cur += len - 4; |
751 | | |
752 | | /* find next lval page */ |
753 | | pg_row = mdb_get_int32(buf, row_start); |
754 | | } while ((pg_row >> 8)); |
755 | | return cur; |
756 | | } else { |
757 | | fprintf(stderr, "Unhandled ole field flags = %02x\n", ole_len >> 24); |
758 | | return 0; |
759 | | } |
760 | | } |
761 | | #endif |
762 | | static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size) |
763 | 9 | { |
764 | 9 | guint32 memo_len; |
765 | 9 | gint32 row_start, pg_row; |
766 | 9 | size_t len; |
767 | 9 | void *buf, *pg_buf = mdb->pg_buf; |
768 | 9 | char *text = g_malloc(mdb->bind_size); |
769 | | |
770 | 9 | if (size<MDB_MEMO_OVERHEAD) { |
771 | 7 | strcpy(text, ""); |
772 | 7 | return text; |
773 | 7 | } |
774 | | |
775 | | #if MDB_DEBUG |
776 | | mdb_buffer_dump(pg_buf, start, MDB_MEMO_OVERHEAD); |
777 | | #endif |
778 | | |
779 | | /* The 32 bit integer at offset 0 is the length of the memo field |
780 | | * with some flags in the high bits. |
781 | | * The 32 bit integer at offset 4 contains page and row information. |
782 | | */ |
783 | 2 | memo_len = mdb_get_int32(pg_buf, start); |
784 | | |
785 | 2 | if (memo_len & 0x80000000) { |
786 | | /* inline memo field */ |
787 | 0 | mdb_unicode2ascii(mdb, (char*)pg_buf + start + MDB_MEMO_OVERHEAD, |
788 | 0 | size - MDB_MEMO_OVERHEAD, text, mdb->bind_size); |
789 | 0 | return text; |
790 | 2 | } else if (memo_len & 0x40000000) { |
791 | | /* single-page memo field */ |
792 | 1 | pg_row = mdb_get_int32(pg_buf, start+4); |
793 | | #if MDB_DEBUG |
794 | | printf("Reading LVAL page %06x\n", pg_row >> 8); |
795 | | #endif |
796 | 1 | if (mdb_find_pg_row(mdb, pg_row, &buf, &row_start, &len)) { |
797 | 1 | strcpy(text, ""); |
798 | 1 | return text; |
799 | 1 | } |
800 | | #if MDB_DEBUG |
801 | | printf("row num %d start %d len %d\n", |
802 | | pg_row & 0xff, row_start, len); |
803 | | mdb_buffer_dump(buf, row_start, len); |
804 | | #endif |
805 | 0 | mdb_unicode2ascii(mdb, (char*)buf + row_start, len, text, mdb->bind_size); |
806 | 0 | return text; |
807 | 1 | } else if ((memo_len & 0xff000000) == 0) { // assume all flags in MSB |
808 | | /* multi-page memo field */ |
809 | 1 | guint32 tmpoff = 0; |
810 | 1 | char *tmp; |
811 | | |
812 | 1 | tmp = g_malloc(memo_len); |
813 | 1 | pg_row = mdb_get_int32(pg_buf, start+4); |
814 | 1 | do { |
815 | | #if MDB_DEBUG |
816 | | printf("Reading LVAL page %06x\n", pg_row >> 8); |
817 | | #endif |
818 | 1 | if (mdb_find_pg_row(mdb,pg_row,&buf,&row_start,&len)) { |
819 | 0 | g_free(tmp); |
820 | 0 | strcpy(text, ""); |
821 | 0 | return text; |
822 | 0 | } |
823 | | #if MDB_DEBUG |
824 | | printf("row num %d start %d len %d\n", |
825 | | pg_row & 0xff, row_start, len); |
826 | | #endif |
827 | 1 | if (tmpoff + len - 4 > memo_len) |
828 | 1 | break; |
829 | | |
830 | | /* Stop processing on zero length multiple page memo fields */ |
831 | 0 | if (len < 4) |
832 | 0 | break; |
833 | | |
834 | 0 | memcpy(tmp + tmpoff, (char*)buf + row_start + 4, len - 4); |
835 | 0 | tmpoff += len - 4; |
836 | 0 | } while (( pg_row = mdb_get_int32(buf, row_start) )); |
837 | 1 | if (tmpoff < memo_len) { |
838 | 0 | fprintf(stderr, "Warning: incorrect memo length\n"); |
839 | 0 | } |
840 | 1 | mdb_unicode2ascii(mdb, tmp, tmpoff, text, mdb->bind_size); |
841 | 1 | g_free(tmp); |
842 | 1 | return text; |
843 | 1 | } else { |
844 | 0 | fprintf(stderr, "Unhandled memo field flags = %02x\n", memo_len >> 24); |
845 | 0 | strcpy(text, ""); |
846 | 0 | return text; |
847 | 0 | } |
848 | 2 | } |
849 | | |
850 | | #if 0 |
851 | | static int trim_trailing_zeros(char * buff) |
852 | | { |
853 | | char *p; |
854 | | int n = strlen(buff); |
855 | | |
856 | | /* Don't need to trim strings with no decimal portion */ |
857 | | if(!strchr(buff,'.')) |
858 | | return 0; |
859 | | |
860 | | /* Trim the zeros */ |
861 | | p = buff + n - 1; |
862 | | while (p >= buff && *p == '0') |
863 | | *p-- = '\0'; |
864 | | |
865 | | /* If a decimal sign is left at the end, remove it too */ |
866 | | if (*p == '.') |
867 | | *p = '\0'; |
868 | | |
869 | | return 0; |
870 | | } |
871 | | #endif |
872 | | |
873 | | |
874 | | /* Date/Time is stored as a double, where the whole |
875 | | part is the days from 12/30/1899 and the fractional |
876 | | part is the fractional part of one day. */ |
877 | | |
878 | | void |
879 | | mdb_tm_to_date(struct tm *t, double *td) |
880 | 0 | { |
881 | 0 | short yr = t->tm_year + 1900; |
882 | 0 | char leap = ((yr & 3) == 0) && ((yr % 100) != 0 || (yr % 400) == 0); |
883 | 0 | const int *cal = leap ? leap_cal : noleap_cal; |
884 | 0 | long int time = (yr*365+(yr/4)-(yr/100)+(yr/400)+cal[t->tm_mon]+t->tm_mday)-693959; |
885 | |
|
886 | 0 | *td = (((long)t->tm_hour * 3600)+((long)t->tm_min * 60)+((long)t->tm_sec)) / 86400.0; |
887 | 0 | if (time>=0) *td+=time; else *td=time-*td; |
888 | 0 | } |
889 | | |
890 | | void |
891 | | mdb_date_to_tm(double td, struct tm *t) |
892 | 42 | { |
893 | 42 | long day, time; |
894 | 42 | long yr, q; |
895 | 42 | const int *cal; |
896 | | |
897 | 42 | if (td < 0.0 || td > 1e6) // About 2700 AD |
898 | 12 | return; |
899 | | |
900 | 30 | yr = 1; |
901 | 30 | day = (long)(td); |
902 | 30 | time = (long)((td - day) * 86400.0 + 0.5); |
903 | 30 | t->tm_hour = time / 3600; |
904 | 30 | t->tm_min = (time / 60) % 60; |
905 | 30 | t->tm_sec = time % 60; |
906 | | |
907 | 30 | day += 693593; /* Days from 1/1/1 to 12/31/1899 */ |
908 | 30 | t->tm_wday = (day+1) % 7; |
909 | | |
910 | 30 | q = day / 146097; /* 146097 days in 400 years */ |
911 | 30 | yr += 400 * q; |
912 | 30 | day -= q * 146097; |
913 | | |
914 | 30 | q = day / 36524; /* 36524 days in 100 years */ |
915 | 30 | if (q > 3) q = 3; |
916 | 30 | yr += 100 * q; |
917 | 30 | day -= q * 36524; |
918 | | |
919 | 30 | q = day / 1461; /* 1461 days in 4 years */ |
920 | 30 | yr += 4 * q; |
921 | 30 | day -= q * 1461; |
922 | | |
923 | 30 | q = day / 365; /* 365 days in 1 year */ |
924 | 30 | if (q > 3) q = 3; |
925 | 30 | yr += q; |
926 | 30 | day -= q * 365; |
927 | | |
928 | 30 | cal = ((yr)%4==0 && ((yr)%100!=0 || (yr)%400==0)) ? |
929 | 30 | leap_cal : noleap_cal; |
930 | 360 | for (t->tm_mon=0; t->tm_mon<12; t->tm_mon++) { |
931 | 360 | if (day < cal[t->tm_mon+1]) break; |
932 | 360 | } |
933 | 30 | t->tm_year = yr - 1900; |
934 | 30 | t->tm_mday = day - cal[t->tm_mon] + 1; |
935 | 30 | t->tm_yday = day; |
936 | 30 | t->tm_isdst = -1; |
937 | 30 | } |
938 | | |
939 | | static char * |
940 | | mdb_date_to_string(MdbHandle *mdb, const char *fmt, void *buf, int start) |
941 | 42 | { |
942 | 42 | struct tm t = { 0 }; |
943 | 42 | char *text = g_malloc(mdb->bind_size); |
944 | 42 | double td = mdb_get_double(buf, start); |
945 | | |
946 | 42 | mdb_date_to_tm(td, &t); |
947 | | |
948 | 42 | strftime(text, mdb->bind_size, mdb->date_fmt, &t); |
949 | | |
950 | 42 | return text; |
951 | 42 | } |
952 | | |
953 | | char *mdb_uuid_to_string(const void *buf, int pos) |
954 | 0 | { |
955 | 0 | return mdb_uuid_to_string_fmt(buf,pos,MDB_BRACES_4_2_2_8); |
956 | 0 | } |
957 | | |
958 | | char *mdb_uuid_to_string_fmt(const void *buf, int pos, MdbUuidFormat format) |
959 | 0 | { |
960 | 0 | const unsigned char *kkd = (const unsigned char *)buf; |
961 | 0 | return g_strdup_printf(format == MDB_BRACES_4_2_2_8 |
962 | 0 | ? "{%02X%02X%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X%02X%02X%02X%02X%02X%02X}" |
963 | 0 | : "%02X%02X%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X" "-" "%02X%02X%02X%02X%02X%02X", |
964 | 0 | kkd[pos+3], kkd[pos+2], kkd[pos+1], kkd[pos], // little-endian |
965 | 0 | kkd[pos+5], kkd[pos+4], // little-endian |
966 | 0 | kkd[pos+7], kkd[pos+6], // little-endian |
967 | 0 | kkd[pos+8], kkd[pos+9], // big-endian |
968 | 0 | kkd[pos+10], kkd[pos+11], |
969 | 0 | kkd[pos+12], kkd[pos+13], |
970 | 0 | kkd[pos+14], kkd[pos+15]); // big-endian |
971 | 0 | } |
972 | | |
973 | | #if 0 |
974 | | int floor_log10(double f, int is_single) |
975 | | { |
976 | | unsigned int i; |
977 | | double y = 10.0; |
978 | | |
979 | | if (f < 0.0) |
980 | | f = -f; |
981 | | |
982 | | if ((f == 0.0) || (f == 1.0) || isinf(f)) { |
983 | | return 0; |
984 | | } else if (f < 1.0) { |
985 | | if (is_single) { |
986 | | /* The intermediate value p is necessary to prevent |
987 | | * promotion of the comparison to type double */ |
988 | | float p; |
989 | | for (i=1; (p = f * y) < 1.0; i++) |
990 | | y *= 10.0; |
991 | | } else { |
992 | | for (i=1; f * y < 1.0; i++) |
993 | | y *= 10.0; |
994 | | } |
995 | | return -(int)i; |
996 | | } else { /* (x > 1.0) */ |
997 | | for (i=0; f >= y; i++) |
998 | | y *= 10.0; |
999 | | return (int)i; |
1000 | | } |
1001 | | } |
1002 | | #endif |
1003 | | |
1004 | | char *mdb_col_to_string(MdbHandle *mdb, void *buf, int start, int datatype, int size) |
1005 | 1.96k | { |
1006 | 1.96k | char *text = NULL; |
1007 | 1.96k | float tf; |
1008 | 1.96k | double td; |
1009 | | |
1010 | 1.96k | switch (datatype) { |
1011 | 17 | case MDB_BYTE: |
1012 | 17 | text = g_strdup_printf("%hhu", mdb_get_byte(buf, start)); |
1013 | 17 | break; |
1014 | 0 | case MDB_INT: |
1015 | 0 | text = g_strdup_printf("%hd", |
1016 | 0 | (short)mdb_get_int16(buf, start)); |
1017 | 0 | break; |
1018 | 3 | case MDB_LONGINT: |
1019 | 3 | case MDB_COMPLEX: |
1020 | 3 | text = g_strdup_printf("%d", |
1021 | 3 | (int)mdb_get_int32(buf, start)); |
1022 | 3 | break; |
1023 | 66 | case MDB_FLOAT: |
1024 | 66 | tf = mdb_get_single(buf, start); |
1025 | 66 | text = g_strdup_printf("%.8g", tf); |
1026 | 66 | break; |
1027 | 768 | case MDB_DOUBLE: |
1028 | 768 | td = mdb_get_double(buf, start); |
1029 | 768 | text = g_strdup_printf("%.16lg", td); |
1030 | 768 | break; |
1031 | 17 | case MDB_BINARY: |
1032 | 17 | if (size<0) { |
1033 | 10 | text = g_strdup(""); |
1034 | 10 | } else { |
1035 | 7 | text = g_malloc(size+1); |
1036 | 7 | memcpy(text, (char*)buf+start, size); |
1037 | 7 | text[size] = '\0'; |
1038 | 7 | } |
1039 | 17 | break; |
1040 | 13 | case MDB_TEXT: |
1041 | 13 | if (size<0) { |
1042 | 10 | text = g_strdup(""); |
1043 | 10 | } else { |
1044 | 3 | text = g_malloc(mdb->bind_size); |
1045 | 3 | mdb_unicode2ascii(mdb, (char*)buf + start, |
1046 | 3 | size, text, mdb->bind_size); |
1047 | 3 | } |
1048 | 13 | break; |
1049 | 0 | case MDB_DATETIME: |
1050 | 0 | text = mdb_date_to_string(mdb, mdb->date_fmt, buf, start); |
1051 | 0 | break; |
1052 | 9 | case MDB_MEMO: |
1053 | 9 | text = mdb_memo_to_string(mdb, start, size); |
1054 | 9 | break; |
1055 | 454 | case MDB_MONEY: |
1056 | 454 | text = mdb_money_to_string(mdb, start); |
1057 | 454 | break; |
1058 | 0 | case MDB_REPID: |
1059 | 0 | text = mdb_uuid_to_string_fmt(buf, start, mdb->repid_fmt); |
1060 | 0 | break; |
1061 | 615 | default: |
1062 | | /* shouldn't happen. bools are handled specially |
1063 | | ** by mdb_xfer_bound_bool() */ |
1064 | 615 | fprintf(stderr, "Warning: mdb_col_to_string called on unsupported data type %d.\n", datatype); |
1065 | 615 | text = g_strdup(""); |
1066 | 615 | break; |
1067 | 1.96k | } |
1068 | 1.96k | return text; |
1069 | 1.96k | } |
1070 | | int mdb_col_disp_size(MdbColumn *col) |
1071 | 0 | { |
1072 | 0 | switch (col->col_type) { |
1073 | 0 | case MDB_BOOL: |
1074 | 0 | return 1; |
1075 | 0 | break; |
1076 | 0 | case MDB_BYTE: |
1077 | 0 | return 4; |
1078 | 0 | break; |
1079 | 0 | case MDB_INT: |
1080 | 0 | return 6; |
1081 | 0 | break; |
1082 | 0 | case MDB_LONGINT: |
1083 | 0 | case MDB_COMPLEX: |
1084 | 0 | return 11; |
1085 | 0 | break; |
1086 | 0 | case MDB_FLOAT: |
1087 | 0 | return 10; |
1088 | 0 | break; |
1089 | 0 | case MDB_DOUBLE: |
1090 | 0 | return 10; |
1091 | 0 | break; |
1092 | 0 | case MDB_TEXT: |
1093 | 0 | return col->col_size; |
1094 | 0 | break; |
1095 | 0 | case MDB_DATETIME: |
1096 | 0 | return 20; |
1097 | 0 | break; |
1098 | 0 | case MDB_MEMO: |
1099 | 0 | return 64000; |
1100 | 0 | break; |
1101 | 0 | case MDB_MONEY: |
1102 | 0 | return 21; |
1103 | 0 | break; |
1104 | 0 | } |
1105 | 0 | return 0; |
1106 | 0 | } |
1107 | | int mdb_col_fixed_size(MdbColumn *col) |
1108 | 0 | { |
1109 | 0 | switch (col->col_type) { |
1110 | 0 | case MDB_BOOL: |
1111 | 0 | return 1; |
1112 | 0 | break; |
1113 | 0 | case MDB_BYTE: |
1114 | 0 | return -1; |
1115 | 0 | break; |
1116 | 0 | case MDB_INT: |
1117 | 0 | return 2; |
1118 | 0 | break; |
1119 | 0 | case MDB_LONGINT: |
1120 | 0 | case MDB_COMPLEX: |
1121 | 0 | return 4; |
1122 | 0 | break; |
1123 | 0 | case MDB_FLOAT: |
1124 | 0 | return 4; |
1125 | 0 | break; |
1126 | 0 | case MDB_DOUBLE: |
1127 | 0 | return 8; |
1128 | 0 | break; |
1129 | 0 | case MDB_TEXT: |
1130 | 0 | return -1; |
1131 | 0 | break; |
1132 | 0 | case MDB_DATETIME: |
1133 | 0 | return 4; |
1134 | 0 | break; |
1135 | 0 | case MDB_BINARY: |
1136 | 0 | return -1; |
1137 | 0 | break; |
1138 | 0 | case MDB_MEMO: |
1139 | 0 | return -1; |
1140 | 0 | break; |
1141 | 0 | case MDB_MONEY: |
1142 | 0 | return 8; |
1143 | 0 | break; |
1144 | 0 | } |
1145 | 0 | return 0; |
1146 | 0 | } |