]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/iconv/citrus_db.c
Merge clang trunk r338150 (just before the 7.0.0 branch point), and
[FreeBSD/FreeBSD.git] / lib / libc / iconv / citrus_db.c
1 /* $FreeBSD$ */
2 /* $NetBSD: citrus_db.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
3
4 /*-
5  * SPDX-License-Identifier: BSD-2-Clause
6  *
7  * Copyright (c)2003 Citrus Project,
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 #include <sys/endian.h>
34 #include <sys/types.h>
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <limits.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "citrus_namespace.h"
44 #include "citrus_bcs.h"
45 #include "citrus_region.h"
46 #include "citrus_memstream.h"
47 #include "citrus_mmap.h"
48 #include "citrus_db.h"
49 #include "citrus_db_factory.h"
50 #include "citrus_db_file.h"
51
52 struct _citrus_db {
53         struct _region           db_region;
54         _citrus_db_hash_func_t   db_hashfunc;
55         void                    *db_hashfunc_closure;
56 };
57
58 int
59 _citrus_db_open(struct _citrus_db **rdb, struct _region *r, const char *magic,
60     _citrus_db_hash_func_t hashfunc, void *hashfunc_closure)
61 {
62         struct _citrus_db *db;
63         struct _citrus_db_header_x *dhx;
64         struct _memstream ms;
65
66         _memstream_bind(&ms, r);
67
68         /* sanity check */
69         dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
70         if (dhx == NULL)
71                 return (EFTYPE);
72         if (strncmp(dhx->dhx_magic, magic, _CITRUS_DB_MAGIC_SIZE) != 0)
73                 return (EFTYPE);
74         if (_memstream_seek(&ms, be32toh(dhx->dhx_entry_offset), SEEK_SET))
75                 return (EFTYPE);
76
77         if (be32toh(dhx->dhx_num_entries)*_CITRUS_DB_ENTRY_SIZE >
78             _memstream_remainder(&ms))
79                 return (EFTYPE);
80
81         db = malloc(sizeof(*db));
82         if (db == NULL)
83                 return (errno);
84         db->db_region = *r;
85         db->db_hashfunc = hashfunc;
86         db->db_hashfunc_closure = hashfunc_closure;
87         *rdb = db;
88
89         return (0);
90 }
91
92 void
93 _citrus_db_close(struct _citrus_db *db)
94 {
95
96         free(db);
97 }
98
99 int
100 _citrus_db_lookup(struct _citrus_db *db, struct _citrus_region *key,
101     struct _citrus_region *data, struct _citrus_db_locator *dl)
102 {
103         struct _citrus_db_entry_x *dex;
104         struct _citrus_db_header_x *dhx;
105         struct _citrus_region r;
106         struct _memstream ms;
107         uint32_t hashval, num_entries;
108         size_t offset;
109
110         _memstream_bind(&ms, &db->db_region);
111
112         dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
113         num_entries = be32toh(dhx->dhx_num_entries);
114         if (num_entries == 0)
115                 return (ENOENT);
116
117         if (dl != NULL && dl->dl_offset>0) {
118                 hashval = dl->dl_hashval;
119                 offset = dl->dl_offset;
120                 if (offset >= _region_size(&db->db_region))
121                         return (ENOENT);
122         } else {
123                 hashval = db->db_hashfunc(key)%num_entries;
124                 offset = be32toh(dhx->dhx_entry_offset) +
125                     hashval * _CITRUS_DB_ENTRY_SIZE;
126                 if (dl)
127                         dl->dl_hashval = hashval;
128         }
129         do {
130                 /* seek to the next entry */
131                 if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
132                         return (EFTYPE);
133                 /* get the entry record */
134                 dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
135                 if (dex == NULL)
136                         return (EFTYPE);
137
138                 /* jump to next entry having the same hash value. */
139                 offset = be32toh(dex->dex_next_offset);
140
141                 /* save the current position */
142                 if (dl) {
143                         dl->dl_offset = offset;
144                         if (offset == 0)
145                                 dl->dl_offset = _region_size(&db->db_region);
146                 }
147
148                 /* compare hash value. */
149                 if (be32toh(dex->dex_hash_value) != hashval)
150                         /* not found */
151                         break;
152                 /* compare key length */
153                 if (be32toh(dex->dex_key_size) == _region_size(key)) {
154                         /* seek to the head of the key. */
155                         if (_memstream_seek(&ms, be32toh(dex->dex_key_offset),
156                             SEEK_SET))
157                                 return (EFTYPE);
158                         /* get the region of the key */
159                         if (_memstream_getregion(&ms, &r,
160                             _region_size(key)) == NULL)
161                                 return (EFTYPE);
162                         /* compare key byte stream */
163                         if (memcmp(_region_head(&r), _region_head(key),
164                             _region_size(key)) == 0) {
165                                 /* match */
166                                 if (_memstream_seek(
167                                     &ms, be32toh(dex->dex_data_offset),
168                                     SEEK_SET))
169                                         return (EFTYPE);
170                                 if (_memstream_getregion(
171                                     &ms, data,
172                                     be32toh(dex->dex_data_size)) == NULL)
173                                         return (EFTYPE);
174                                 return (0);
175                         }
176                 }
177         } while (offset != 0);
178
179         return (ENOENT);
180 }
181
182 int
183 _citrus_db_lookup_by_string(struct _citrus_db *db, const char *key,
184     struct _citrus_region *data, struct _citrus_db_locator *dl)
185 {
186         struct _region r;
187
188         _region_init(&r, __DECONST(void *, key), strlen(key));
189
190         return (_citrus_db_lookup(db, &r, data, dl));
191 }
192
193 int
194 _citrus_db_lookup8_by_string(struct _citrus_db *db, const char *key,
195     uint8_t *rval, struct _citrus_db_locator *dl)
196 {
197         struct _region r;
198         int ret;
199
200         ret = _citrus_db_lookup_by_string(db, key, &r, dl);
201         if (ret)
202                 return (ret);
203
204         if (_region_size(&r) != 1)
205                 return (EFTYPE);
206
207         if (rval)
208                 memcpy(rval, _region_head(&r), 1);
209
210         return (0);
211 }
212
213 int
214 _citrus_db_lookup16_by_string(struct _citrus_db *db, const char *key,
215     uint16_t *rval, struct _citrus_db_locator *dl)
216 {
217         struct _region r;
218         int ret;
219         uint16_t val;
220
221         ret = _citrus_db_lookup_by_string(db, key, &r, dl);
222         if (ret)
223                 return (ret);
224
225         if (_region_size(&r) != 2)
226                 return (EFTYPE);
227
228         if (rval) {
229                 memcpy(&val, _region_head(&r), 2);
230                 *rval = be16toh(val);
231         }
232
233         return (0);
234 }
235
236 int
237 _citrus_db_lookup32_by_string(struct _citrus_db *db, const char *key,
238     uint32_t *rval, struct _citrus_db_locator *dl)
239 {
240         struct _region r;
241         uint32_t val;
242         int ret;
243
244         ret = _citrus_db_lookup_by_string(db, key, &r, dl);
245         if (ret)
246                 return (ret);
247
248         if (_region_size(&r) != 4)
249                 return (EFTYPE);
250
251         if (rval) {
252                 memcpy(&val, _region_head(&r), 4);
253                 *rval = be32toh(val);
254         }
255
256         return (0);
257 }
258
259 int
260 _citrus_db_lookup_string_by_string(struct _citrus_db *db, const char *key,
261     const char **rdata, struct _citrus_db_locator *dl)
262 {
263         struct _region r;
264         int ret;
265
266         ret = _citrus_db_lookup_by_string(db, key, &r, dl);
267         if (ret)
268                 return (ret);
269
270         /* check whether the string is null terminated */
271         if (_region_size(&r) == 0)
272                 return (EFTYPE);
273         if (*((const char*)_region_head(&r)+_region_size(&r)-1) != '\0')
274                 return (EFTYPE);
275
276         if (rdata)
277                 *rdata = _region_head(&r);
278
279         return (0);
280 }
281
282 int
283 _citrus_db_get_number_of_entries(struct _citrus_db *db)
284 {
285         struct _citrus_db_header_x *dhx;
286         struct _memstream ms;
287
288         _memstream_bind(&ms, &db->db_region);
289
290         dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
291         return ((int)be32toh(dhx->dhx_num_entries));
292 }
293
294 int
295 _citrus_db_get_entry(struct _citrus_db *db, int idx, struct _region *key,
296     struct _region *data)
297 {
298         struct _citrus_db_entry_x *dex;
299         struct _citrus_db_header_x *dhx;
300         struct _memstream ms;
301         uint32_t num_entries;
302         size_t offset;
303
304         _memstream_bind(&ms, &db->db_region);
305
306         dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
307         num_entries = be32toh(dhx->dhx_num_entries);
308         if (idx < 0 || (uint32_t)idx >= num_entries)
309                 return (EINVAL);
310
311         /* seek to the next entry */
312         offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
313         if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
314                 return (EFTYPE);
315         /* get the entry record */
316         dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
317         if (dex == NULL)
318                 return (EFTYPE);
319         /* seek to the head of the key. */
320         if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
321                 return (EFTYPE);
322         /* get the region of the key. */
323         if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
324                 return (EFTYPE);
325         /* seek to the head of the data. */
326         if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
327                 return (EFTYPE);
328         /* get the region of the data. */
329         if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
330                 return (EFTYPE);
331
332         return (0);
333 }