changed render levels for labels/place names
[navit-package] / src / data / poi_geodownload / libmdb / file.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "mdbtools.h"
21
22 #ifdef DMALLOC
23 #include "dmalloc.h"
24 #endif
25
26 /*
27 typedef struct {
28         int             pg_size;
29         guint16         row_count_offset; 
30         guint16         tab_num_rows_offset;
31         guint16         tab_num_cols_offset;
32         guint16         tab_num_idxs_offset;
33         guint16         tab_num_ridxs_offset;
34         guint16         tab_usage_map_offset;
35         guint16         tab_first_dpg_offset;
36         guint16         tab_cols_start_offset;
37         guint16         tab_ridx_entry_size;
38         guint16         col_fixed_offset;
39         guint16         col_size_offset;
40         guint16         col_num_offset;
41         guint16         tab_col_entry_size;
42         guint16         tab_free_map_offset;
43         guint16         tab_col_offset_var;
44         guint16         tab_col_offset_fixed;
45         guint16         tab_row_col_num_offset;
46 } MdbFormatConstants; 
47 */
48 MdbFormatConstants MdbJet4Constants = {
49         4096, 0x0c, 16, 45, 47, 51, 55, 56, 63, 12, 15, 23, 5, 25, 59, 7, 21, 9
50 };
51 MdbFormatConstants MdbJet3Constants = {
52         2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5 /* not sure on 5, need to check */
53 };
54
55 static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg);
56
57 /**
58  * mdb_find_file:
59  * @filename: path to MDB (database) file
60  *
61  * Finds and returns the absolute path to an MDB file.  Function will first try
62  * to fstat file as passed, then search through the $MDBPATH if not found.
63  *
64  * Return value: gchar pointer to absolute path. Caller is responsible for
65  * freeing.
66  **/
67
68 static gchar *mdb_find_file(char *file_name)
69 {
70         struct stat status;
71         gchar *mdbpath, **dir, *tmpfname;
72         unsigned int i = 0;
73
74         /* try the provided file name first */
75         if (!stat(file_name, &status)) {
76                 return g_strdup(file_name);
77         }
78         
79         /* Now pull apart $MDBPATH and try those */
80         mdbpath = (gchar *) getenv("MDBPATH");
81         /* no path, can't find file */
82         if (!mdbpath || !strlen(mdbpath)) return NULL;
83
84         dir = g_strsplit(mdbpath, ":", 0); 
85         while (dir[i]) {
86                 if (!strlen(dir[i])) continue;
87                 tmpfname = g_strconcat(dir[i++], "/", file_name, NULL);
88                 if (!stat(tmpfname, &status)) {
89                         g_strfreev(dir);
90                         return tmpfname;
91                 }
92                 g_free(tmpfname);
93         }
94         g_strfreev(dir);
95         return NULL;
96 }
97 /**
98  * mdb_open:
99  * @filename: path to MDB (database) file
100  * @flags: MDB_NOFLAGS for read-only, MDB_WRITABLE for read/write
101  *
102  * Opens an MDB file and returns an MdbHandle to it.  MDB File may be relative
103  * to the current directory, a full path to the file, or relative to a 
104  * component of $MDBPATH.
105  *
106  * Return value: pointer to MdbHandle structure.
107  **/
108 MdbHandle *mdb_open(char *filename, MdbFileFlags flags)
109 {
110         MdbHandle *mdb;
111
112         mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle));
113         mdb_set_default_backend(mdb, "access");
114         /* need something to bootstrap with, reassign after page 0 is read */
115         mdb->fmt = &MdbJet3Constants;
116         mdb->f = (MdbFile *) g_malloc0(sizeof(MdbFile));
117         mdb->f->refs = 1;
118         mdb->f->fd = -1;
119         mdb->f->filename = (char *) mdb_find_file(filename);
120         if (!mdb->f->filename) { 
121                 fprintf(stderr, "Can't alloc filename\n");
122                 mdb_close(mdb);
123                 return NULL; 
124         }
125         if (flags & MDB_WRITABLE) {
126                 mdb->f->writable = TRUE;
127                 mdb->f->fd = open(mdb->f->filename,O_RDWR);
128         } else {
129                 mdb->f->fd = open(mdb->f->filename,O_RDONLY);
130         }
131
132         if (mdb->f->fd==-1) {
133                 fprintf(stderr,"Couldn't open file %s\n",mdb->f->filename); 
134                 mdb_close(mdb);
135                 return NULL;
136         }
137         if (!mdb_read_pg(mdb, 0)) {
138                 fprintf(stderr,"Couldn't read first page.\n");
139                 mdb_close(mdb);
140                 return NULL;
141         }
142         if (mdb->pg_buf[0] != 0) {
143                 mdb_close(mdb);
144                 return NULL; 
145         }
146         mdb->f->jet_version = mdb_pg_get_int32(mdb, 0x14);
147         if (IS_JET4(mdb)) {
148                 mdb->fmt = &MdbJet4Constants;
149         } else if (IS_JET3(mdb)) {
150                 mdb->fmt = &MdbJet3Constants;
151         } else {
152                 fprintf(stderr,"Unknown Jet version.\n");
153                 mdb_close(mdb);
154                 return NULL; 
155         }
156
157         return mdb;
158 }
159
160 /**
161  * mdb_close:
162  * @mdb: Handle to open MDB database file
163  *
164  * Dereferences MDB file, closes if reference count is 0, and destroys handle.
165  *
166  **/
167 void 
168 mdb_close(MdbHandle *mdb)
169 {
170         if (!mdb) return;       
171         mdb_free_catalog(mdb);
172         g_free(mdb->stats);
173         g_free(mdb->backend_name);
174
175         if (mdb->f) {
176                 if (mdb->f->refs > 1) {
177                         mdb->f->refs--;
178                 } else {
179                         if (mdb->f->fd != -1) close(mdb->f->fd);
180                         g_free(mdb->f->filename);
181                         g_free(mdb->f);
182                 }
183         }
184
185         g_free(mdb);
186 }
187 /**
188  * mdb_clone_handle:
189  * @mdb: Handle to open MDB database file
190  *
191  * Clones an existing database handle.  Cloned handle shares the file descriptor
192  * but has its own page buffer, page position, and similar internal variables.
193  *
194  * Return value: new handle to the database.
195  */
196 MdbHandle *mdb_clone_handle(MdbHandle *mdb)
197 {
198         MdbHandle *newmdb;
199         MdbCatalogEntry *entry, *data;
200         unsigned int i;
201
202         newmdb = (MdbHandle *) g_memdup(mdb, sizeof(MdbHandle));
203         newmdb->stats = NULL;
204         newmdb->catalog = g_ptr_array_new();
205         for (i=0;i<mdb->num_catalog;i++) {
206                 entry = g_ptr_array_index(mdb->catalog,i);
207                 data = g_memdup(entry,sizeof(MdbCatalogEntry));
208                 g_ptr_array_add(newmdb->catalog, data);
209         }
210         mdb->backend_name = NULL;
211         if (mdb->f) {
212                 mdb->f->refs++;
213         }
214         return newmdb;
215 }
216
217 /* 
218 ** mdb_read a wrapper for read that bails if anything is wrong 
219 */
220 ssize_t mdb_read_pg(MdbHandle *mdb, unsigned long pg)
221 {
222         ssize_t len;
223
224         if (pg && mdb->cur_pg == pg) return mdb->fmt->pg_size;
225
226         len = _mdb_read_pg(mdb, mdb->pg_buf, pg);
227         //fprintf(stderr, "read page %d type %02x\n", pg, mdb->pg_buf[0]);
228         mdb->cur_pg = pg;
229         /* kan - reset the cur_pos on a new page read */
230         mdb->cur_pos = 0; /* kan */
231         return len;
232 }
233 ssize_t mdb_read_alt_pg(MdbHandle *mdb, unsigned long pg)
234 {
235         ssize_t len;
236
237         len = _mdb_read_pg(mdb, mdb->alt_pg_buf, pg);
238         return len;
239 }
240 static ssize_t _mdb_read_pg(MdbHandle *mdb, unsigned char *pg_buf, unsigned long pg)
241 {
242         ssize_t len;
243         struct stat status;
244         off_t offset = pg * mdb->fmt->pg_size;
245
246         fstat(mdb->f->fd, &status);
247         if (status.st_size < offset) { 
248                 fprintf(stderr,"offset %lu is beyond EOF\n",offset);
249                 return 0;
250         }
251         if (mdb->stats && mdb->stats->collect) 
252                 mdb->stats->pg_reads++;
253
254         lseek(mdb->f->fd, offset, SEEK_SET);
255         len = read(mdb->f->fd,pg_buf,mdb->fmt->pg_size);
256         if (len==-1) {
257                 perror("read");
258                 return 0;
259         }
260         else if (len<mdb->fmt->pg_size) {
261                 /* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */
262                 return 0;
263         } 
264         return len;
265 }
266 void mdb_swap_pgbuf(MdbHandle *mdb)
267 {
268 char tmpbuf[MDB_PGSIZE];
269
270         memcpy(tmpbuf,mdb->pg_buf, MDB_PGSIZE);
271         memcpy(mdb->pg_buf,mdb->alt_pg_buf, MDB_PGSIZE);
272         memcpy(mdb->alt_pg_buf,tmpbuf,MDB_PGSIZE);
273 }
274
275
276 /* really stupid, just here for consistancy */
277 unsigned char mdb_get_byte(unsigned char *buf, int offset)
278 {
279         return buf[offset];
280 }
281 unsigned char mdb_pg_get_byte(MdbHandle *mdb, int offset)
282 {
283         if (offset < 0 || offset+1 > mdb->fmt->pg_size) return -1;
284         mdb->cur_pos++;
285         return mdb->pg_buf[offset];
286 }
287
288 int mdb_get_int16(unsigned char *buf, int offset)
289 {
290         return buf[offset+1]*256+buf[offset];
291 }
292 int mdb_pg_get_int16(MdbHandle *mdb, int offset)
293 {
294         if (offset < 0 || offset+2 > mdb->fmt->pg_size) return -1;
295         mdb->cur_pos+=2;
296         return mdb_get_int16(mdb->pg_buf, offset);
297 }
298
299 gint32 mdb_pg_get_int24_msb(MdbHandle *mdb, int offset)
300 {
301         gint32 l = 0;
302         if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1;
303         mdb->cur_pos+=3;
304         memcpy((char *)&l+1, &(mdb->pg_buf[offset]), 3);
305 #if 0
306         printf("l=0x%08x 0x%08x\n",l,GINT32_FROM_BE(l));
307 #endif
308         return GINT32_FROM_BE(l);
309 }
310 gint32 mdb_get_int24(unsigned char *buf, int offset)
311 {
312         gint32 l = 0;
313         memcpy(&l, &buf[offset], 3);
314         return GINT32_FROM_LE(l);
315 }
316 gint32 mdb_pg_get_int24(MdbHandle *mdb, int offset)
317 {
318         if (offset <0 || offset+3 > mdb->fmt->pg_size) return -1;
319         mdb->cur_pos+=3;
320         return mdb_get_int24(mdb->pg_buf, offset);
321 }
322
323 long mdb_get_int32(unsigned char *buf, int offset)
324 {
325         guint32 l;
326         memcpy(&l, &buf[offset], 4);
327         return (long)GINT32_FROM_LE(l);
328 }
329 long mdb_pg_get_int32(MdbHandle *mdb, int offset)
330 {
331         if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1;
332         mdb->cur_pos+=4;
333         return mdb_get_int32(mdb->pg_buf, offset);
334 }
335
336 float mdb_get_single(unsigned char *buf, int offset)
337 {
338         union {guint32 g; float f;} f;
339         memcpy(&f, &buf[offset], 4);
340         f.g = GUINT32_FROM_LE(f.g);
341         return f.f;
342 }
343 float mdb_pg_get_single(MdbHandle *mdb, int offset)
344 {
345        if (offset <0 || offset+4 > mdb->fmt->pg_size) return -1;
346        mdb->cur_pos+=4;
347        return mdb_get_single(mdb->pg_buf, offset);
348 }
349
350 double mdb_get_double(unsigned char *buf, int offset)
351 {
352         union {guint64 g; double d;} d;
353         memcpy(&d, &buf[offset], 8);
354         d.g = GUINT64_FROM_LE(d.g);
355         return d.d;
356 }
357 double mdb_pg_get_double(MdbHandle *mdb, int offset)
358 {
359         if (offset <0 || offset+8 > mdb->fmt->pg_size) return -1;
360         mdb->cur_pos+=8;
361         return mdb_get_double(mdb->pg_buf, offset);
362 }
363
364
365 int 
366 mdb_set_pos(MdbHandle *mdb, int pos)
367 {
368         if (pos<0 || pos >= mdb->fmt->pg_size) return 0;
369
370         mdb->cur_pos=pos;
371         return pos;
372 }
373 int mdb_get_pos(MdbHandle *mdb)
374 {
375         return mdb->cur_pos;
376 }