Coverage Report

Created: 2026-05-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oficonv/libsrc/citrus_esdb.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_esdb.h"
29
30
#include <sys/types.h>
31
#include <errno.h>
32
#include <limits.h>
33
#include <stdbool.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "citrus_bcs.h"
39
#include "citrus_types.h"
40
#include "citrus_region.h"
41
#include "citrus_memstream.h"
42
#include "citrus_mmap.h"
43
#include "citrus_lookup.h"
44
#include "citrus_db.h"
45
#include "citrus_db_hash.h"
46
#include "citrus_esdb_file.h"
47
48
0
#define ESDB_DIR    "esdb.dir"
49
0
#define ESDB_ALIAS  "esdb.alias"
50
51
/* write the full path to the ESDB directory and the given filename (which may be NULL)
52
 * to the path_out buffer, which is expected to be OFICONV_PATH_MAX in size.
53
 */
54
static void getESDBPath(char *path_out, size_t path_size, const char *filename)
55
0
{
56
0
    get_data_path(path_out, path_size, OFICONV_ESDB_DIR, filename);
57
0
}
58
59
60
/*
61
 * _citrus_esdb_alias:
62
 *  resolve encoding scheme name aliases.
63
 */
64
const char *
65
_citrus_esdb_alias(const char *esname, char *buf, size_t bufsize)
66
0
{
67
0
    char esdb_path[OFICONV_PATH_MAX];
68
0
    getESDBPath(esdb_path, sizeof(esdb_path), ESDB_ALIAS);
69
0
    return (_citrus_lookup_alias(esdb_path, esname, buf, bufsize, _CITRUS_LOOKUP_CASE_IGNORE));
70
0
}
71
72
73
/*
74
 * conv_esdb:
75
 *  external representation -> local structure.
76
 */
77
static int
78
conv_esdb(struct _citrus_esdb *esdb, struct _citrus_region *fr)
79
0
{
80
0
    struct _citrus_db *db;
81
0
    const char *str;
82
0
    char buf[100];
83
0
    uint32_t csid, i, num_charsets, tmp, version;
84
0
    int ret;
85
86
    /* open db */
87
0
    ret = _citrus_db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_citrus_db_hash_std, NULL);
88
0
    if (ret)
89
0
        goto err0;
90
91
    /* check version */
92
0
    ret = _citrus_db_lookup32_by_string(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL);
93
0
    if (ret)
94
0
        goto err1;
95
0
    switch (version) {
96
0
    case 0x00000001:
97
        /* current version */
98
        /* initial version */
99
0
        break;
100
0
    default:
101
0
        ret = EFTYPE;
102
0
        goto err1;
103
0
    }
104
105
    /* get encoding/variable */
106
0
    ret = _citrus_db_lookup_string_by_string(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL);
107
0
    if (ret)
108
0
        goto err1;
109
0
    esdb->db_encname = strdup(str);
110
0
    if (esdb->db_encname == NULL) {
111
0
        ret = errno;
112
0
        goto err1;
113
0
    }
114
115
0
    esdb->db_len_variable = 0;
116
0
    esdb->db_variable = NULL;
117
0
    ret = _citrus_db_lookup_string_by_string(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL);
118
0
    if (ret == 0) {
119
0
        esdb->db_len_variable = strlen(str) + 1;
120
0
        esdb->db_variable = strdup(str);
121
0
        if (esdb->db_variable == NULL) {
122
0
            ret = errno;
123
0
            goto err2;
124
0
        }
125
0
    } else if (ret != ENOENT)
126
0
        goto err2;
127
128
    /* get number of charsets */
129
0
    ret = _citrus_db_lookup32_by_string(db, _CITRUS_ESDB_SYM_NUM_CHARSETS,
130
0
        &num_charsets, NULL);
131
0
    if (ret)
132
0
        goto err3;
133
0
    esdb->db_num_charsets = num_charsets;
134
135
    /* get invalid character */
136
0
    ret = _citrus_db_lookup32_by_string(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL);
137
0
    if (ret == 0) {
138
0
        esdb->db_use_invalid = 1;
139
0
        esdb->db_invalid = tmp;
140
0
    } else if (ret == ENOENT)
141
0
        esdb->db_use_invalid = 0;
142
0
    else
143
0
        goto err3;
144
145
    /* get charsets */
146
0
    esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets));
147
0
    if (esdb->db_charsets == NULL) {
148
0
        ret = errno;
149
0
        goto err3;
150
0
    }
151
0
    for (i = 0; i < num_charsets; i++) {
152
0
        snprintf(buf, sizeof(buf),
153
0
            _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
154
0
        ret = _citrus_db_lookup32_by_string(db, buf, &csid, NULL);
155
0
        if (ret)
156
0
            goto err4;
157
0
        esdb->db_charsets[i].ec_csid = csid;
158
159
0
        snprintf(buf, sizeof(buf),
160
0
            _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
161
0
        ret = _citrus_db_lookup_string_by_string(db, buf, &str, NULL);
162
0
        if (ret)
163
0
            goto err4;
164
0
        esdb->db_charsets[i].ec_csname = strdup(str);
165
0
        if (esdb->db_charsets[i].ec_csname == NULL) {
166
0
            ret = errno;
167
0
            goto err4;
168
0
        }
169
0
    }
170
171
0
    _citrus_db_close(db);
172
0
    return (0);
173
174
0
err4:
175
0
    for (; i > 0; i--)
176
0
        free(esdb->db_charsets[i - 1].ec_csname);
177
0
    free(esdb->db_charsets);
178
0
err3:
179
0
    free(esdb->db_variable);
180
0
err2:
181
0
    free(esdb->db_encname);
182
0
err1:
183
0
    _citrus_db_close(db);
184
0
    if (ret == ENOENT)
185
0
        ret = EFTYPE;
186
0
err0:
187
0
    return (ret);
188
0
}
189
190
/*
191
 * _citrus_esdb_open:
192
 *  open an ESDB file.
193
 */
194
int
195
_citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
196
0
{
197
0
    struct _citrus_region fr;
198
0
    const char *realname, *encfile;
199
0
    char buf1[OFICONV_PATH_MAX], buf2[OFICONV_PATH_MAX], path[OFICONV_PATH_MAX];
200
0
    int ret;
201
202
0
    getESDBPath(path, sizeof(path), ESDB_ALIAS);
203
0
    realname = _citrus_lookup_alias(path, esname, buf1, sizeof(buf1),
204
0
        _CITRUS_LOOKUP_CASE_IGNORE);
205
206
0
    getESDBPath(path, sizeof(path), ESDB_DIR);
207
0
    encfile = _citrus_lookup_simple(path, realname, buf2, sizeof(buf2),
208
0
        _CITRUS_LOOKUP_CASE_IGNORE);
209
0
    if (encfile == NULL)
210
0
        return (ENOENT);
211
212
    /* open file */
213
0
    getESDBPath(path, sizeof(path), encfile);
214
0
    ret = _citrus_map_file(&fr, path);
215
0
    if (ret)
216
0
        return (ret);
217
218
0
    ret = conv_esdb(db, &fr);
219
220
0
    _citrus_unmap_file(&fr);
221
222
0
    return (ret);
223
0
}
224
225
/*
226
 * _citrus_esdb_close:
227
 *  free an ESDB.
228
 */
229
void
230
_citrus_esdb_close(struct _citrus_esdb *db)
231
0
{
232
0
    int i;
233
0
    for (i = 0; i < db->db_num_charsets; i++)
234
0
        free(db->db_charsets[i].ec_csname);
235
0
    db->db_num_charsets = 0;
236
0
    free(db->db_charsets); db->db_charsets = NULL;
237
0
    free(db->db_encname); db->db_encname = NULL;
238
0
    db->db_len_variable = 0;
239
0
    free(db->db_variable); db->db_variable = NULL;
240
0
}
241
242
/*
243
 * _citrus_esdb_free_list:
244
 *  free the list.
245
 */
246
void
247
_citrus_esdb_free_list(char **list, size_t num)
248
0
{
249
0
    size_t i;
250
0
    for (i = 0; i < num; i++)
251
0
        free(list[i]);
252
0
    free(list);
253
0
}
254
255
/*
256
 * _citrus_esdb_get_list:
257
 *  get esdb entries.
258
 */
259
int
260
_citrus_esdb_get_list(char ***rlist, size_t *rnum, bool sorted)
261
0
{
262
0
    struct _citrus_lookup *cla, *cld;
263
0
    struct _citrus_region key, data;
264
0
    char **list, **q;
265
0
    char buf[OFICONV_PATH_MAX];
266
0
    size_t num;
267
0
    int ret;
268
0
    char esdb_path[OFICONV_PATH_MAX];
269
270
0
    num = 0;
271
272
0
    getESDBPath(esdb_path, sizeof(esdb_path), ESDB_ALIAS);
273
0
    ret = _citrus_lookup_seq_open(&cla, esdb_path, _CITRUS_LOOKUP_CASE_IGNORE);
274
0
    if (ret)
275
0
        goto quit0;
276
277
0
    getESDBPath(esdb_path, sizeof(esdb_path), ESDB_DIR);
278
0
    ret = _citrus_lookup_seq_open(&cld, esdb_path, _CITRUS_LOOKUP_CASE_IGNORE);
279
0
    if (ret)
280
0
        goto quit1;
281
282
    /* count number of entries */
283
0
    num = _citrus_lookup_get_number_of_entries(cla) + _citrus_lookup_get_number_of_entries(cld);
284
285
0
    _citrus_lookup_seq_rewind(cla);
286
0
    _citrus_lookup_seq_rewind(cld);
287
288
    /* allocate list pointer space */
289
0
    list = malloc(num * sizeof(char *));
290
0
    num = 0;
291
0
    if (list == NULL) {
292
0
        ret = errno;
293
0
        goto quit3;
294
0
    }
295
296
    /* get alias entries */
297
0
    while ((ret = _citrus_lookup_seq_next(cla, &key, &data)) == 0) {
298
#if 0
299
        /* this code fragment is disabled in FreeBSD */
300
        if (sorted)
301
            snprintf(buf, sizeof(buf), "%.*s/%.*s",
302
                (int)_citrus_region_size(&data),
303
                (const char *)_citrus_region_head(&data),
304
                (int)_citrus_region_size(&key),
305
                (const char *)_citrus_region_head(&key));
306
        else
307
#endif
308
0
            snprintf(buf, sizeof(buf), "%.*s/%.*s",
309
0
                (int)_citrus_region_size(&data),
310
0
                (const char *)_citrus_region_head(&data),
311
0
                (int)_citrus_region_size(&key),
312
0
                (const char *)_citrus_region_head(&key));
313
0
        _citrus_bcs_convert_to_upper(buf);
314
0
        list[num] = strdup(buf);
315
0
        if (list[num] == NULL) {
316
0
            ret = errno;
317
0
            goto quit3;
318
0
        }
319
0
        num++;
320
0
    }
321
0
    if (ret != ENOENT)
322
0
        goto quit3;
323
    /* get dir entries */
324
0
    while ((ret = _citrus_lookup_seq_next(cld, &key, &data)) == 0) {
325
0
        if (!sorted)
326
0
            snprintf(buf, sizeof(buf), "%.*s",
327
0
                (int)_citrus_region_size(&key),
328
0
                (const char *)_citrus_region_head(&key));
329
0
        else {
330
            /* check duplicated entry */
331
0
            char *p;
332
0
            char buf1[OFICONV_PATH_MAX];
333
334
0
            snprintf(buf1, sizeof(buf1), "%.*s",
335
0
                (int)_citrus_region_size(&data),
336
0
                (const char *)_citrus_region_head(&data));
337
0
            if ((p = strchr(buf1, '/')) != NULL)
338
0
                memmove(buf1, p + 1, strlen(p) - 1);
339
0
            if ((p = strstr(buf1, ".esdb")) != NULL)
340
0
                *p = '\0';
341
342
#if ( defined(__GNUC__) && (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 1 ) ) )
343
#pragma GCC diagnostic push
344
#pragma GCC diagnostic ignored "-Wformat-truncation"
345
#endif
346
347
0
            snprintf(buf, sizeof(buf), "%s/%.*s", buf1,
348
0
                (int)_citrus_region_size(&key),
349
0
                (const char *)_citrus_region_head(&key));
350
351
#if ( defined(__GNUC__) && (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 1 ) ) )
352
#pragma GCC diagnostic pop
353
#endif
354
355
0
        }
356
0
        _citrus_bcs_convert_to_upper(buf);
357
0
        ret = _citrus_lookup_seq_lookup(cla, buf, NULL);
358
0
        if (ret) {
359
0
            if (ret != ENOENT)
360
0
                goto quit3;
361
            /* not duplicated */
362
0
            list[num] = strdup(buf);
363
0
            if (list[num] == NULL) {
364
0
                ret = errno;
365
0
                goto quit3;
366
0
            }
367
0
            num++;
368
0
        }
369
0
    }
370
0
    if (ret != ENOENT)
371
0
        goto quit3;
372
373
0
    ret = 0;
374
    /* XXX: why reallocing the list space posteriorly?
375
        shouldn't be done earlier? */
376
0
    q = realloc(list, num * sizeof(char *));
377
378
0
    if (!q) {
379
0
        ret = ENOMEM;
380
0
        goto quit3;
381
0
    }
382
0
    list = q;
383
0
    *rlist = list;
384
0
    *rnum = num;
385
0
quit3:
386
0
    if (ret)
387
0
        _citrus_esdb_free_list(list, num);
388
0
    _citrus_lookup_seq_close(cld);
389
0
quit1:
390
0
    _citrus_lookup_seq_close(cla);
391
0
quit0:
392
0
    return (ret);
393
0
}