Coverage Report

Created: 2026-06-30 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oficonv/libsrc/citrus_lookup.c
Line
Count
Source
1
/*-
2
 * Copyright (c)2003 Citrus Project,
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 */
26
27
#include "dcmtk/config/osconfig.h"
28
#include "citrus_lookup.h"
29
30
#include <sys/types.h>
31
#ifdef HAVE_DIRENT_H
32
#include <dirent.h>
33
#endif
34
#include <errno.h>
35
#include <limits.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#ifdef HAVE_UNISTD_H
40
#include <unistd.h>
41
#endif
42
43
#include "citrus_bcs.h"
44
#include "citrus_region.h"
45
#include "citrus_memstream.h"
46
#include "citrus_mmap.h"
47
#include "citrus_db.h"
48
#include "citrus_db_hash.h"
49
#include "citrus_lookup_file.h"
50
51
struct _citrus_lookup {
52
    union {
53
        struct {
54
            struct _citrus_db *db;
55
            struct _citrus_region file;
56
            int num, idx;
57
            struct _citrus_db_locator locator;
58
        } db;
59
        struct {
60
            struct _citrus_region r;
61
            struct _citrus_memory_stream ms;
62
        } plain;
63
    } u;
64
0
#define cl_db       u.db.db
65
0
#define cl_dbidx    u.db.idx
66
0
#define cl_dbfile   u.db.file
67
0
#define cl_dbnum    u.db.num
68
0
#define cl_dblocator    u.db.locator
69
0
#define cl_plainr   u.plain.r
70
0
#define cl_plainms  u.plain.ms
71
    int cl_ignore_case;
72
    int cl_rewind;
73
    char *cl_key;
74
    size_t cl_keylen;
75
    int (*cl_next)(struct _citrus_lookup *, struct _citrus_region *,
76
               struct _citrus_region *);
77
    int (*cl_lookup)(struct _citrus_lookup *, const char *,
78
             struct _citrus_region *);
79
    int (*cl_num_entries)(struct _citrus_lookup *);
80
    void (*cl_close)(struct _citrus_lookup *);
81
};
82
83
static int
84
seq_get_num_entries_db(struct _citrus_lookup *cl)
85
0
{
86
87
0
    return (cl->cl_dbnum);
88
0
}
89
90
static int
91
seq_next_db(struct _citrus_lookup *cl, struct _citrus_region *key,
92
    struct _citrus_region *data)
93
0
{
94
95
0
    if (cl->cl_key) {
96
0
        if (key)
97
0
            _citrus_region_init(key, cl->cl_key, cl->cl_keylen);
98
0
        return (_citrus_db_lookup_by_string(cl->cl_db, cl->cl_key, data,
99
0
            &cl->cl_dblocator));
100
0
    }
101
102
0
    if (cl->cl_rewind) {
103
0
        cl->cl_dbidx = 0;
104
0
    }
105
0
    cl->cl_rewind = 0;
106
0
    if (cl->cl_dbidx >= cl->cl_dbnum)
107
0
        return (ENOENT);
108
109
0
    return (_citrus_db_get_entry(cl->cl_db, cl->cl_dbidx++, key, data));
110
0
}
111
112
static int
113
seq_lookup_db(struct _citrus_lookup *cl, const char *key, struct _citrus_region *data)
114
0
{
115
116
0
    cl->cl_rewind = 0;
117
0
    free(cl->cl_key);
118
0
    cl->cl_key = strdup(key);
119
0
    if (cl->cl_ignore_case)
120
0
        _citrus_bcs_convert_to_lower(cl->cl_key);
121
0
    cl->cl_keylen = strlen(cl->cl_key);
122
0
    _citrus_db_locator_init(&cl->cl_dblocator);
123
0
    return (_citrus_db_lookup_by_string(cl->cl_db, cl->cl_key, data,
124
0
        &cl->cl_dblocator));
125
0
}
126
127
static void
128
seq_close_db(struct _citrus_lookup *cl)
129
0
{
130
131
0
    _citrus_db_close(cl->cl_db);
132
0
    _citrus_unmap_file(&cl->cl_dbfile);
133
0
}
134
135
static int
136
seq_open_db(struct _citrus_lookup *cl, const char *name)
137
0
{
138
0
    struct _citrus_region r;
139
0
    char path[OFICONV_PATH_MAX];
140
0
    int ret;
141
142
0
    snprintf(path, sizeof(path), "%s.db", name);
143
0
    ret = _citrus_map_file(&r, path);
144
0
    if (ret)
145
0
        return (ret);
146
147
0
    ret = _citrus_db_open(&cl->cl_db, &r, _CITRUS_LOOKUP_MAGIC,
148
0
        _citrus_db_hash_std, NULL);
149
0
    if (ret) {
150
0
        _citrus_unmap_file(&r);
151
0
        return (ret);
152
0
    }
153
154
0
    cl->cl_dbfile = r;
155
0
    cl->cl_dbnum = _citrus_db_get_number_of_entries(cl->cl_db);
156
0
    cl->cl_dbidx = 0;
157
0
    cl->cl_rewind = 1;
158
0
    cl->cl_lookup = &seq_lookup_db;
159
0
    cl->cl_next = &seq_next_db;
160
0
    cl->cl_num_entries = &seq_get_num_entries_db;
161
0
    cl->cl_close = &seq_close_db;
162
163
0
    return (0);
164
0
}
165
166
0
#define T_COMM '#'
167
static int
168
seq_next_plain(struct _citrus_lookup *cl, struct _citrus_region *key,
169
           struct _citrus_region *data)
170
0
{
171
0
    const char *p, *q;
172
0
    size_t len;
173
174
0
    if (cl->cl_rewind)
175
0
        _citrus_memory_stream_bind(&cl->cl_plainms, &cl->cl_plainr);
176
0
    cl->cl_rewind = 0;
177
178
0
retry:
179
0
    p = _citrus_memory_stream_getln(&cl->cl_plainms, &len);
180
0
    if (p == NULL)
181
0
        return (ENOENT);
182
    /* ignore comment */
183
0
    q = memchr(p, T_COMM, len);
184
0
    if (q) {
185
0
        len = q - p;
186
0
    }
187
    /* ignore trailing spaces */
188
0
    _citrus_bcs_trunc_rws_len(p, &len);
189
0
    p = _citrus_bcs_skip_ws_len(p, &len);
190
0
    q = _citrus_bcs_skip_nonws_len(p, &len);
191
0
    if (p == q)
192
0
        goto retry;
193
0
    if (cl->cl_key && ((size_t)(q - p) != cl->cl_keylen ||
194
0
        memcmp(p, cl->cl_key, (size_t)(q - p)) != 0))
195
0
        goto retry;
196
197
    /* found a entry */
198
0
    if (key)
199
0
        _citrus_region_init(key, CITRUS_DECONST(void *, p), (size_t)(q - p));
200
0
    p = _citrus_bcs_skip_ws_len(q, &len);
201
0
    if (data)
202
0
        _citrus_region_init(data, len ? CITRUS_DECONST(void *, p) : NULL, len);
203
204
0
    return (0);
205
0
}
206
207
static int
208
seq_get_num_entries_plain(struct _citrus_lookup *cl)
209
0
{
210
0
    int num;
211
212
0
    num = 0;
213
0
    while (seq_next_plain(cl, NULL, NULL) == 0)
214
0
        num++;
215
216
0
    return (num);
217
0
}
218
219
static int
220
seq_lookup_plain(struct _citrus_lookup *cl, const char *key,
221
    struct _citrus_region *data)
222
0
{
223
0
    size_t len;
224
0
    const char *p;
225
226
0
    cl->cl_rewind = 0;
227
0
    free(cl->cl_key);
228
0
    cl->cl_key = strdup(key);
229
0
    if (cl->cl_ignore_case)
230
0
        _citrus_bcs_convert_to_lower(cl->cl_key);
231
0
    cl->cl_keylen = strlen(cl->cl_key);
232
0
    _citrus_memory_stream_bind(&cl->cl_plainms, &cl->cl_plainr);
233
0
    p = _citrus_memory_stream_matchline(&cl->cl_plainms, cl->cl_key, &len, 0);
234
0
    if (p == NULL)
235
0
        return (ENOENT);
236
0
    if (data)
237
0
        _citrus_region_init(data, CITRUS_DECONST(void *, p), len);
238
239
0
    return (0);
240
0
}
241
242
static void
243
seq_close_plain(struct _citrus_lookup *cl)
244
0
{
245
246
0
    _citrus_unmap_file(&cl->cl_plainr);
247
0
}
248
249
static int
250
seq_open_plain(struct _citrus_lookup *cl, const char *name)
251
0
{
252
0
    int ret;
253
254
    /* open read stream */
255
0
    ret = _citrus_map_file(&cl->cl_plainr, name);
256
0
    if (ret)
257
0
        return (ret);
258
259
0
    cl->cl_rewind = 1;
260
0
    cl->cl_next = &seq_next_plain;
261
0
    cl->cl_lookup = &seq_lookup_plain;
262
0
    cl->cl_num_entries = &seq_get_num_entries_plain;
263
0
    cl->cl_close = &seq_close_plain;
264
265
0
    return (0);
266
0
}
267
268
int
269
_citrus_lookup_seq_open(struct _citrus_lookup **rcl, const char *name,
270
    int ignore_case)
271
0
{
272
0
    int ret;
273
0
    struct _citrus_lookup *cl;
274
275
0
    cl = malloc(sizeof(*cl));
276
0
    if (cl == NULL)
277
0
        return (errno);
278
279
0
    cl->cl_key = NULL;
280
0
    cl->cl_keylen = 0;
281
0
    cl->cl_ignore_case = ignore_case;
282
0
    ret = seq_open_db(cl, name);
283
0
    if (ret == ENOENT)
284
0
        ret = seq_open_plain(cl, name);
285
0
    if (!ret)
286
0
        *rcl = cl;
287
0
    else
288
0
        free(cl);
289
290
0
    return (ret);
291
0
}
292
293
void
294
_citrus_lookup_seq_rewind(struct _citrus_lookup *cl)
295
0
{
296
297
0
    cl->cl_rewind = 1;
298
0
    free(cl->cl_key);
299
0
    cl->cl_key = NULL;
300
0
    cl->cl_keylen = 0;
301
0
}
302
303
int
304
_citrus_lookup_seq_next(struct _citrus_lookup *cl,
305
    struct _citrus_region *key, struct _citrus_region *data)
306
0
{
307
308
0
    return ((*cl->cl_next)(cl, key, data));
309
0
}
310
311
int
312
_citrus_lookup_seq_lookup(struct _citrus_lookup *cl, const char *key,
313
    struct _citrus_region *data)
314
0
{
315
0
    return ((*cl->cl_lookup)(cl, key, data));
316
0
}
317
318
int
319
_citrus_lookup_get_number_of_entries(struct _citrus_lookup *cl)
320
0
{
321
322
0
    return ((*cl->cl_num_entries)(cl));
323
0
}
324
325
void
326
_citrus_lookup_seq_close(struct _citrus_lookup *cl)
327
0
{
328
329
0
    free(cl->cl_key);
330
0
    (*cl->cl_close)(cl);
331
0
    free(cl);
332
0
}
333
334
char *
335
_citrus_lookup_simple(const char *name, const char *key,
336
    char *linebuf, size_t linebufsize, int ignore_case)
337
0
{
338
0
    struct _citrus_lookup *cl;
339
0
    struct _citrus_region data;
340
0
    int ret;
341
0
    cl = NULL;
342
343
0
    ret = _citrus_lookup_seq_open(&cl, name, ignore_case);
344
0
    if (ret)
345
0
        return (NULL);
346
347
0
    ret = _citrus_lookup_seq_lookup(cl, key, &data);
348
0
    if (ret) {
349
0
        _citrus_lookup_seq_close(cl);
350
0
        return (NULL);
351
0
    }
352
353
0
    snprintf(linebuf, linebufsize, "%.*s", (int)_citrus_region_size(&data),
354
0
        (const char *)_citrus_region_head(&data));
355
356
0
    _citrus_lookup_seq_close(cl);
357
358
0
    return (linebuf);
359
0
}