1 /* MDB Tools - A library for reading MS Access database files
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
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19 #ifndef _mdbtools_h_
20 #define _mdbtools_h_
21 
22 #ifdef __cplusplus
23   extern "C" {
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <glib.h>
35 
36 #ifdef HAVE_ICONV
37 #include <iconv.h>
38 #endif
39 
40 #define MDB_DEBUG 0
41 
42 #define MDB_PGSIZE 4096
43 #define MDB_MAX_OBJ_NAME 256
44 #define MDB_MAX_COLS 256
45 #define MDB_MAX_IDX_COLS 10
46 #define MDB_CATALOG_PG 18
47 #define MDB_MEMO_OVERHEAD 12
48 #define MDB_BIND_SIZE 16384
49 
50 enum {
51 	MDB_PAGE_DB = 0,
52 	MDB_PAGE_DATA,
53 	MDB_PAGE_TABLE,
54 	MDB_PAGE_INDEX,
55 	MDB_PAGE_LEAF,
56 	MDB_PAGE_MAP
57 };
58 enum {
59 	MDB_VER_JET3 = 0,
60 	MDB_VER_JET4 = 1
61 };
62 enum {
63 	MDB_FORM = 0,
64 	MDB_TABLE,
65 	MDB_MACRO,
66 	MDB_SYSTEM_TABLE,
67 	MDB_REPORT,
68 	MDB_QUERY,
69 	MDB_LINKED_TABLE,
70 	MDB_MODULE,
71 	MDB_RELATIONSHIP,
72 	MDB_UNKNOWN_09,
73 	MDB_UNKNOWN_0A,
74 	MDB_DATABASE_PROPERTY,
75 	MDB_ANY = -1
76 };
77 enum {
78 	MDB_BOOL = 0x01,
79 	MDB_BYTE = 0x02,
80 	MDB_INT = 0x03,
81 	MDB_LONGINT = 0x04,
82 	MDB_MONEY = 0x05,
83 	MDB_FLOAT = 0x06,
84 	MDB_DOUBLE = 0x07,
85 	MDB_SDATETIME = 0x08,
86 	MDB_TEXT = 0x0a,
87 	MDB_OLE = 0x0b,
88 	MDB_MEMO = 0x0c,
89 	MDB_REPID = 0x0f,
90 	MDB_NUMERIC = 0x10
91 };
92 
93 /* SARG operators */
94 enum {
95 	MDB_OR = 1,
96 	MDB_AND,
97 	MDB_NOT,
98 	MDB_EQUAL,
99 	MDB_GT,
100 	MDB_LT,
101 	MDB_GTEQ,
102 	MDB_LTEQ,
103 	MDB_LIKE,
104 	MDB_ISNULL,
105 	MDB_NOTNULL
106 };
107 
108 typedef enum {
109 	MDB_TABLE_SCAN,
110 	MDB_LEAF_SCAN,
111 	MDB_INDEX_SCAN
112 } MdbStrategy;
113 
114 typedef enum {
115 	MDB_NOFLAGS = 0x00,
116 	MDB_WRITABLE = 0x01
117 } MdbFileFlags;
118 
119 enum {
120 	MDB_DEBUG_LIKE = 0x0001,
121 	MDB_DEBUG_WRITE = 0x0002,
122 	MDB_DEBUG_USAGE = 0x0004,
123 	MDB_DEBUG_OLE = 0x0008,
124 	MDB_DEBUG_ROW = 0x0010,
125 	MDB_USE_INDEX = 0x0020,
126 	MDB_NO_MEMO = 0x0040 /* don't follow memo fields */
127 };
128 
129 #define mdb_is_logical_op(x) (x == MDB_OR || \
130 				x == MDB_AND || \
131 				x == MDB_NOT )
132 
133 #define mdb_is_relational_op(x) (x == MDB_EQUAL || \
134 				x == MDB_GT || \
135 				x == MDB_LT || \
136 				x == MDB_GTEQ || \
137 				x == MDB_LTEQ || \
138 				x == MDB_LIKE || \
139 				x == MDB_ISNULL || \
140 				x == MDB_NOTNULL )
141 
142 enum {
143 	MDB_ASC,
144 	MDB_DESC
145 };
146 
147 enum {
148 	MDB_IDX_UNIQUE = 0x01,
149 	MDB_IDX_IGNORENULLS = 0x02,
150 	MDB_IDX_REQUIRED = 0x08
151 };
152 
153 #define IS_JET4(mdb) (mdb->f->jet_version==MDB_VER_JET4)
154 #define IS_JET3(mdb) (mdb->f->jet_version==MDB_VER_JET3)
155 
156 /* hash to store registered backends */
157 extern GHashTable	*mdb_backends;
158 
159 /* forward declarations */
160 typedef struct mdbindex MdbIndex;
161 typedef struct mdbsargtree MdbSargNode;
162 
163 typedef struct {
164 	char *name;
165 	unsigned char needs_length; /* or precision */
166 	unsigned char needs_scale;
167 	unsigned char needs_quotes;
168 } MdbBackendType;
169 
170 typedef struct {
171 	 MdbBackendType *types_table;
172 } MdbBackend;
173 
174 typedef struct {
175 	gboolean collect;
176 	unsigned long pg_reads;
177 } MdbStatistics;
178 
179 typedef struct {
180 	int           fd;
181 	gboolean      writable;
182 	char          *filename;
183 	guint32		jet_version;
184 	guint32		db_key;
185 	char		db_passwd[14];
186 	MdbBackend	*default_backend;
187 	char			*backend_name;
188 	MdbStatistics	*stats;
189 	/* free map */
190 	int  map_sz;
191 	unsigned char *free_map;
192 	/* reference count */
193 	int refs;
194 } MdbFile;
195 
196 /* offset to row count on data pages...version dependant */
197 typedef struct {
198 	ssize_t		pg_size;
199 	guint16		row_count_offset;
200 	guint16		tab_num_rows_offset;
201 	guint16		tab_num_cols_offset;
202 	guint16		tab_num_idxs_offset;
203 	guint16		tab_num_ridxs_offset;
204 	guint16		tab_usage_map_offset;
205 	guint16		tab_first_dpg_offset;
206 	guint16		tab_cols_start_offset;
207 	guint16		tab_ridx_entry_size;
208 	guint16		col_fixed_offset;
209 	guint16		col_size_offset;
210 	guint16		col_num_offset;
211 	guint16		tab_col_entry_size;
212 	guint16         tab_free_map_offset;
213 	guint16		tab_col_offset_var;
214 	guint16		tab_col_offset_fixed;
215 	guint16		tab_row_col_num_offset;
216 } MdbFormatConstants;
217 
218 typedef struct {
219 	MdbFile       *f;
220 	guint32       cur_pg;
221 	guint16       row_num;
222 	unsigned int  cur_pos;
223 	unsigned char pg_buf[MDB_PGSIZE];
224 	unsigned char alt_pg_buf[MDB_PGSIZE];
225 	unsigned int  num_catalog;
226 	GPtrArray	*catalog;
227 	MdbBackend	*default_backend;
228 	char		*backend_name;
229 	MdbFormatConstants *fmt;
230 	MdbStatistics *stats;
231 #ifdef HAVE_ICONV
232 	iconv_t	iconv_in;
233 	iconv_t	iconv_out;
234 #endif
235 } MdbHandle;
236 
237 typedef struct {
238 	MdbHandle	*mdb;
239 	char           object_name[MDB_MAX_OBJ_NAME+1];
240 	int            object_type;
241 	unsigned long  table_pg; /* misnomer since object may not be a table */
242 	unsigned long  kkd_pg;
243 	unsigned int   kkd_rowid;
244 	int			num_props;
245 	GArray		*props;
246 	GArray		*columns;
247 	int		flags;
248 } MdbCatalogEntry;
249 
250 typedef struct {
251 	gchar *name;
252 	GHashTable	*hash;
253 } MdbProperties;
254 
255 typedef union {
256 	int	i;
257 	double	d;
258 	char	s[256];
259 } MdbAny;
260 
261 typedef struct {
262 	char		name[MDB_MAX_OBJ_NAME+1];
263 	int		col_type;
264 	int		col_size;
265 	void	*bind_ptr;
266 	int		*len_ptr;
267 	GHashTable	*properties;
268 	unsigned int	num_sargs;
269 	GPtrArray	*sargs;
270 	GPtrArray	*idx_sarg_cache;
271 	unsigned char   is_fixed;
272 	int		query_order;
273 	/* col_num is the current column order,
274 	 * does not include deletes */
275 	int		col_num;
276 	int		cur_value_start;
277 	int 		cur_value_len;
278 	/* MEMO/OLE readers */
279 	guint32		cur_blob_pg_row;
280 	int		chunk_size;
281 	/* numerics only */
282 	int		col_prec;
283 	int		col_scale;
284 	MdbProperties	*props;
285 	/* info needed for handling deleted/added columns */
286 	int 		fixed_offset;
287 	unsigned int	var_col_num;
288 	/* row_col_num is the row column number order,
289 	 * including deleted columns */
290 	int		row_col_num;
291 } MdbColumn;
292 
293 struct mdbsargtree {
294 	int       op;
295 	MdbColumn *col;
296 	MdbAny    value;
297 	void      *parent;
298 	MdbSargNode *left;
299 	MdbSargNode *right;
300 };
301 
302 typedef struct {
303 	guint32 pg;
304 	int start_pos;
305 	int offset;
306 	int len;
307 	guint16 idx_starts[2000];
308 	unsigned char cache_value[256];
309 } MdbIndexPage;
310 
311 typedef int (*MdbSargTreeFunc)(MdbSargNode *, gpointer data);
312 
313 #define MDB_MAX_INDEX_DEPTH 10
314 
315 typedef struct {
316 	int cur_depth;
317 	guint32 last_leaf_found;
318 	int clean_up_mode;
319 	MdbIndexPage pages[MDB_MAX_INDEX_DEPTH];
320 } MdbIndexChain;
321 
322 typedef struct {
323 	MdbCatalogEntry *entry;
324 	char	name[MDB_MAX_OBJ_NAME+1];
325 	unsigned int    num_cols;
326 	GPtrArray	*columns;
327 	unsigned int    num_rows;
328 	int	index_start;
329 	unsigned int    num_real_idxs;
330 	unsigned int    num_idxs;
331 	GPtrArray	*indices;
332 	guint32	first_data_pg;
333 	guint32	cur_pg_num;
334 	guint32	cur_phys_pg;
335 	unsigned int    cur_row;
336 	int  noskip_del;  /* don't skip deleted rows */
337 	/* object allocation map */
338 	guint32  map_base_pg;
339 	unsigned int  map_sz;
340 	unsigned char *usage_map;
341 	/* pages with free space left */
342 	guint32  freemap_base_pg;
343 	unsigned int  freemap_sz;
344 	unsigned char *free_usage_map;
345 	/* query planner */
346 	MdbSargNode *sarg_tree;
347 	MdbStrategy strategy;
348 	MdbIndex *scan_idx;
349 	MdbHandle *mdbidx;
350 	MdbIndexChain *chain;
351 	MdbProperties	*props;
352 	unsigned int num_var_cols;  /* to know if row has variable columns */
353 	/* temp table */
354 	unsigned int  is_temp_table;
355 	GPtrArray     *temp_table_pages;
356 } MdbTableDef;
357 
358 struct mdbindex {
359 	int		index_num;
360 	char		name[MDB_MAX_OBJ_NAME+1];
361 	unsigned char	index_type;
362 	guint32		first_pg;
363 	int		num_rows;  /* number rows in index */
364 	unsigned int	num_keys;
365 	short	key_col_num[MDB_MAX_IDX_COLS];
366 	unsigned char	key_col_order[MDB_MAX_IDX_COLS];
367 	unsigned char	flags;
368 	MdbTableDef	*table;
369 };
370 
371 typedef struct {
372 	char		name[MDB_MAX_OBJ_NAME+1];
373 } MdbColumnProp;
374 
375 typedef struct {
376 	void *value;
377 	int siz;
378 	int start;
379 	unsigned char is_null;
380 	unsigned char is_fixed;
381 	int colnum;
382 	int offset;
383 } MdbField;
384 
385 typedef struct {
386 	int	op;
387 	MdbAny	value;
388 } MdbSarg;
389 
390 /* mem.c */
391 extern void mdb_init();
392 extern void mdb_exit();
393 
394 /* file.c */
395 extern ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg);
396 extern ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg);
397 extern unsigned char mdb_get_byte(unsigned char *buf, int offset);
398 extern int    mdb_get_int16(unsigned char *buf, int offset);
399 extern gint32   mdb_get_int24(unsigned char *buf, int offset);
400 extern long   mdb_get_int32(unsigned char *buf, int offset);
401 extern float  mdb_get_single(unsigned char *buf, int offset);
402 extern double mdb_get_double(unsigned char *buf, int offset);
403 extern unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset);
404 extern int    mdb_pg_get_int16(MdbHandle *mdb, int offset);
405 extern gint32   mdb_pg_get_int24(MdbHandle *mdb, int offset);
406 extern long   mdb_pg_get_int32(MdbHandle *mdb, int offset);
407 extern float  mdb_pg_get_single(MdbHandle *mdb, int offset);
408 extern double mdb_pg_get_double(MdbHandle *mdb, int offset);
409 extern gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset);
410 extern MdbHandle *mdb_open(const char *filename, MdbFileFlags flags);
411 extern void mdb_close(MdbHandle *mdb);
412 extern MdbHandle *mdb_clone_handle(MdbHandle *mdb);
413 extern void mdb_swap_pgbuf(MdbHandle *mdb);
414 extern long _mdb_get_int32(unsigned char *buf, int offset);
415 
416 /* catalog.c */
417 extern void mdb_free_catalog(MdbHandle *mdb);
418 extern GPtrArray *mdb_read_catalog(MdbHandle *mdb, int obj_type);
419 extern void mdb_dump_catalog(MdbHandle *mdb, int obj_type);
420 extern char *mdb_get_objtype_string(int obj_type);
421 
422 /* table.c */
423 extern MdbTableDef *mdb_alloc_tabledef(MdbCatalogEntry *entry);
424 extern void mdb_free_tabledef(MdbTableDef *table);
425 extern MdbTableDef *mdb_read_table(MdbCatalogEntry *entry);
426 extern MdbTableDef *mdb_read_table_by_name(MdbHandle *mdb, gchar *table_name, int obj_type);
427 extern void mdb_append_column(GPtrArray *columns, MdbColumn *in_col);
428 extern void mdb_free_columns(GPtrArray *columns);
429 extern GPtrArray *mdb_read_columns(MdbTableDef *table);
430 extern void mdb_table_dump(MdbCatalogEntry *entry);
431 extern guint16 read_pg_if_16(MdbHandle *mdb, int *cur_pos);
432 extern guint32 read_pg_if_32(MdbHandle *mdb, int *cur_pos);
433 extern int read_pg_if(MdbHandle *mdb, int *cur_pos, int offset);
434 extern guint16 read_pg_if_n(MdbHandle *mdb, unsigned char *buf, int *cur_pos, int len);
435 extern int mdb_is_user_table(MdbCatalogEntry *entry);
436 extern int mdb_is_system_table(MdbCatalogEntry *entry);
437 
438 /* data.c */
439 extern int mdb_bind_column_by_name(MdbTableDef *table, gchar *col_name, void *bind_ptr, int *len_ptr);
440 extern void mdb_data_dump(MdbTableDef *table);
441 extern void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr, int *len_ptr);
442 extern int mdb_rewind_table(MdbTableDef *table);
443 extern int mdb_fetch_row(MdbTableDef *table);
444 extern int mdb_is_fixed_col(MdbColumn *col);
445 extern char *mdb_col_to_string(MdbHandle *mdb, unsigned char *buf, int start, int datatype, int size);
446 extern int mdb_find_pg_row(MdbHandle *mdb, int pg_row, void **buf, int *off, size_t *len);
447 extern int mdb_find_row(MdbHandle *mdb, int row, int *start, int *len);
448 extern int mdb_find_end_of_row(MdbHandle *mdb, int row);
449 extern int mdb_col_fixed_size(MdbColumn *col);
450 extern int mdb_col_disp_size(MdbColumn *col);
451 extern size_t mdb_ole_read_next(MdbHandle *mdb, MdbColumn *col, void *ole_ptr);
452 extern size_t mdb_ole_read(MdbHandle *mdb, MdbColumn *col, void *ole_ptr, int chunk_size);
453 extern void mdb_set_date_fmt(const char *);
454 extern int mdb_read_row(MdbTableDef *table, unsigned int row);
455 
456 /* dump.c */
457 extern void buffer_dump(const unsigned char* buf, int start, int end);
458 
459 /* backend.c */
460 extern char *mdb_get_coltype_string(MdbBackend *backend, int col_type);
461 extern int  mdb_coltype_takes_length(MdbBackend *backend, int col_type);
462 extern void mdb_init_backends();
463 extern void mdb_register_backend(MdbBackendType *backend, char *backend_name);
464 extern void mdb_remove_backends();
465 extern int  mdb_set_default_backend(MdbHandle *mdb, char *backend_name);
466 extern char *mdb_get_relationships(MdbHandle *mdb);
467 
468 /* sargs.c */
469 extern int mdb_test_sargs(MdbTableDef *table, MdbField *fields, int num_fields);
470 extern int mdb_test_sarg(MdbHandle *mdb, MdbColumn *col, MdbSargNode *node, MdbField *field);
471 extern void mdb_sql_walk_tree(MdbSargNode *node, MdbSargTreeFunc func, gpointer data);
472 extern int mdb_find_indexable_sargs(MdbSargNode *node, gpointer data);
473 extern int mdb_add_sarg_by_name(MdbTableDef *table, char *colname, MdbSarg *in_sarg);
474 extern int mdb_test_string(MdbSargNode *node, char *s);
475 extern int mdb_test_int(MdbSargNode *node, gint32 i);
476 extern int mdb_add_sarg(MdbColumn *col, MdbSarg *in_sarg);
477 
478 
479 
480 /* index.c */
481 extern GPtrArray *mdb_read_indices(MdbTableDef *table);
482 extern void mdb_index_dump(MdbTableDef *table, MdbIndex *idx);
483 extern void mdb_index_scan_free(MdbTableDef *table);
484 extern int mdb_index_find_next_on_page(MdbHandle *mdb, MdbIndexPage *ipg);
485 extern int mdb_index_find_next(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 *pg, guint16 *row);
486 extern void mdb_index_hash_text(guchar *text, guchar *hash);
487 extern void mdb_index_scan_init(MdbHandle *mdb, MdbTableDef *table);
488 extern int mdb_index_find_row(MdbHandle *mdb, MdbIndex *idx, MdbIndexChain *chain, guint32 pg, guint16 row);
489 extern void mdb_index_swap_n(unsigned char *src, int sz, unsigned char *dest);
490 extern void mdb_free_indices(GPtrArray *indices);
491 void mdb_index_page_reset(MdbIndexPage *ipg);
492 extern int mdb_index_pack_bitmap(MdbHandle *mdb, MdbIndexPage *ipg);
493 
494 /* stats.c */
495 extern void mdb_stats_on(MdbHandle *mdb);
496 extern void mdb_stats_off(MdbHandle *mdb);
497 extern void mdb_dump_stats(MdbHandle *mdb);
498 
499 /* like.c */
500 extern int mdb_like_cmp(char *s, char *r);
501 
502 /* write.c */
503 extern int mdb_crack_row(MdbTableDef *table, int row_start, int row_end, MdbField *fields);
504 extern guint16 mdb_add_row_to_pg(MdbTableDef *table, unsigned char *row_buffer, int new_row_size);
505 extern int mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum);
506 extern int mdb_pack_row(MdbTableDef *table, unsigned char *row_buffer, unsigned int num_fields, MdbField *fields);
507 extern int mdb_replace_row(MdbTableDef *table, int row, unsigned char *new_row, int new_row_size);
508 extern int mdb_pg_get_freespace(MdbHandle *mdb);
509 extern int mdb_update_row(MdbTableDef *table);
510 extern unsigned char *mdb_new_data_pg(MdbCatalogEntry *entry);
511 
512 /* map.c */
513 extern guint32 mdb_map_find_next_freepage(MdbTableDef *table, int row_size);
514 extern guint32 mdb_map_find_next(MdbHandle *mdb, unsigned char *map, unsigned int map_sz, guint32 start_pg);
515 
516 /* props.c */
517 extern GPtrArray *mdb_read_props_list(gchar *kkd, int len);
518 extern void mdb_free_props(MdbProperties *props);
519 extern MdbProperties *mdb_read_props(MdbHandle *mdb, GPtrArray *names, gchar *kkd, int len);
520 
521 /* worktable.c */
522 extern MdbTableDef *mdb_create_temp_table(MdbHandle *mdb, char *name);
523 extern void mdb_temp_table_add_col(MdbTableDef *table, MdbColumn *col);
524 extern void mdb_fill_temp_col(MdbColumn *tcol, char *col_name, int col_size, int col_type, int is_fixed);
525 extern void mdb_fill_temp_field(MdbField *field, void *value, int siz, int is_fixed, int is_null, int start, int column);
526 extern void mdb_temp_columns_end(MdbTableDef *table);
527 
528 /* options.c */
529 extern int mdb_get_option(unsigned long optnum);
530 extern void mdb_debug(int klass, char *fmt, ...);
531 
532 /* iconv.c */
533 extern int mdb_unicode2ascii(MdbHandle *mdb, unsigned char *src, unsigned int slen, unsigned char *dest, unsigned int dlen);
534 extern int mdb_ascii2unicode(MdbHandle *mdb, unsigned char *src, unsigned int slen, unsigned char *dest, unsigned int dlen);
535 extern void mdb_iconv_init(MdbHandle *mdb);
536 extern void mdb_iconv_close(MdbHandle *mdb);
537 
538 #ifdef __cplusplus
539   }
540 #endif
541 
542 #endif /* _mdbtools_h_ */
543