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_mapper_std.c
Line
Count
Source
1
/*-
2
 * Copyright (c)2003, 2006 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_mapper_std.h"
29
30
#ifdef HAVE_SYS_QUEUE_H
31
#include <sys/queue.h>
32
#else
33
#include "dcmtk/oficonv/queue.h"
34
#endif
35
36
#include <errno.h>
37
#include <limits.h>
38
#include <stdint.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
43
#include "citrus_bcs.h"
44
#include "citrus_types.h"
45
#include "citrus_region.h"
46
#include "citrus_mmap.h"
47
#include "citrus_module.h"
48
#include "citrus_hash.h"
49
#include "citrus_mapper.h"
50
#include "citrus_db.h"
51
#include "citrus_db_hash.h"
52
53
#include "citrus_mapper_std_file.h"
54
55
/* ---------------------------------------------------------------------- */
56
57
_CITRUS_MAPPER_DECLS(mapper_std);
58
_CITRUS_MAPPER_DEF_OPS(mapper_std);
59
60
61
/* ---------------------------------------------------------------------- */
62
63
int
64
_citrus_mapper_std_mapper_getops(struct _citrus_mapper_ops *ops)
65
0
{
66
67
0
    memcpy(ops, &_citrus_mapper_std_mapper_ops,
68
0
        sizeof(_citrus_mapper_std_mapper_ops));
69
70
0
    return (0);
71
0
}
72
73
/* ---------------------------------------------------------------------- */
74
75
static int
76
/*ARGSUSED*/
77
rowcol_convert(struct _citrus_mapper_std * ms,
78
    _citrus_index_t * dst, _citrus_index_t src, void * ps )
79
0
{
80
0
    struct _citrus_mapper_std_linear_zone *lz;
81
0
    struct _citrus_mapper_std_rowcol *rc;
82
0
    _citrus_index_t idx = 0, n;
83
0
    size_t i;
84
0
    uint32_t conv;
85
0
    (void) ps;
86
87
    /* ps may be unused */
88
0
    rc = &ms->ms_rowcol;
89
90
0
    for (i = rc->rc_src_rowcol_len * rc->rc_src_rowcol_bits,
91
0
        lz = &rc->rc_src_rowcol[0]; i > 0; ++lz) {
92
0
        i -= rc->rc_src_rowcol_bits;
93
0
        n = (src >> i) & rc->rc_src_rowcol_mask;
94
0
        if (n < lz->begin || n > lz->end) {
95
0
            switch (rc->rc_oob_mode) {
96
0
            case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
97
0
                *dst = rc->rc_dst_invalid;
98
0
                return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
99
0
            case _CITRUS_MAPPER_STD_OOB_ILSEQ:
100
0
                return (_CITRUS_MAPPER_CONVERT_ILSEQ);
101
0
            default:
102
0
                return (_CITRUS_MAPPER_CONVERT_FATAL);
103
0
            }
104
0
        }
105
0
        idx = idx * lz->width + n - lz->begin;
106
0
    }
107
0
    switch (rc->rc_dst_unit_bits) {
108
0
    case 8:
109
0
        conv = _citrus_region_peek8(&rc->rc_table, idx);
110
0
        break;
111
0
    case 16:
112
0
        conv = be16toh(_citrus_region_peek16(&rc->rc_table, idx*2));
113
0
        break;
114
0
    case 32:
115
0
        conv = be32toh(_citrus_region_peek32(&rc->rc_table, idx*4));
116
0
        break;
117
0
    default:
118
0
        return (_CITRUS_MAPPER_CONVERT_FATAL);
119
0
    }
120
121
0
    if (conv == rc->rc_dst_invalid) {
122
0
        *dst = rc->rc_dst_invalid;
123
0
        return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
124
0
    }
125
0
    if (conv == rc->rc_dst_ilseq)
126
0
        return (_CITRUS_MAPPER_CONVERT_ILSEQ);
127
128
0
    *dst = conv;
129
130
0
    return (_CITRUS_MAPPER_CONVERT_SUCCESS);
131
0
}
132
133
static __inline int
134
set_linear_zone(struct _citrus_mapper_std_linear_zone *lz,
135
    uint32_t begin, uint32_t end)
136
0
{
137
138
0
    if (begin > end)
139
0
        return (EFTYPE);
140
141
0
    lz->begin = begin;
142
0
    lz->end = end;
143
0
    lz->width= end - begin + 1;
144
145
0
    return (0);
146
0
}
147
148
static __inline int
149
rowcol_parse_variable_compat(struct _citrus_mapper_std_rowcol *rc,
150
    struct _citrus_region *r)
151
0
{
152
0
    const struct _citrus_mapper_std_rowcol_info_compat_x *rcx;
153
0
    struct _citrus_mapper_std_linear_zone *lz;
154
0
    uint32_t m, n;
155
0
    int ret;
156
157
0
    rcx = _citrus_region_head(r);
158
159
0
    rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
160
0
    rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
161
0
    m = be32toh(rcx->rcx_src_col_bits);
162
0
    n = 1U << (m - 1);
163
0
    n |= n - 1;
164
0
    rc->rc_src_rowcol_bits = m;
165
0
    rc->rc_src_rowcol_mask = n;
166
167
0
    rc->rc_src_rowcol = malloc(2 *
168
0
        sizeof(*rc->rc_src_rowcol));
169
0
    if (rc->rc_src_rowcol == NULL)
170
0
        return (ENOMEM);
171
0
    lz = rc->rc_src_rowcol;
172
0
    rc->rc_src_rowcol_len = 1;
173
0
    m = be32toh(rcx->rcx_src_row_begin);
174
0
    n = be32toh(rcx->rcx_src_row_end);
175
0
    if (m + n > 0) {
176
0
        ret = set_linear_zone(lz, m, n);
177
0
        if (ret != 0) {
178
0
            free(rc->rc_src_rowcol);
179
0
            rc->rc_src_rowcol = NULL;
180
0
            return (ret);
181
0
        }
182
0
        ++rc->rc_src_rowcol_len, ++lz;
183
0
    }
184
0
    m = be32toh(rcx->rcx_src_col_begin);
185
0
    n = be32toh(rcx->rcx_src_col_end);
186
187
0
    return (set_linear_zone(lz, m, n));
188
0
}
189
190
static __inline int
191
rowcol_parse_variable(struct _citrus_mapper_std_rowcol *rc,
192
    struct _citrus_region *r)
193
0
{
194
0
    const struct _citrus_mapper_std_rowcol_info_x *rcx;
195
0
    struct _citrus_mapper_std_linear_zone *lz;
196
0
    size_t i;
197
0
    uint32_t m, n;
198
0
    int ret;
199
200
0
    rcx = _citrus_region_head(r);
201
202
0
    rc->rc_dst_invalid = be32toh(rcx->rcx_dst_invalid);
203
0
    rc->rc_dst_unit_bits = be32toh(rcx->rcx_dst_unit_bits);
204
205
0
    m = be32toh(rcx->rcx_src_rowcol_bits);
206
0
    n = 1 << (m - 1);
207
0
    n |= n - 1;
208
0
    rc->rc_src_rowcol_bits = m;
209
0
    rc->rc_src_rowcol_mask = n;
210
211
0
    rc->rc_src_rowcol_len = be32toh(rcx->rcx_src_rowcol_len);
212
0
    if (rc->rc_src_rowcol_len > _CITRUS_MAPPER_STD_ROWCOL_MAX)
213
0
        return (EFTYPE);
214
0
    rc->rc_src_rowcol = malloc(rc->rc_src_rowcol_len *
215
0
        sizeof(*rc->rc_src_rowcol));
216
0
    if (rc->rc_src_rowcol == NULL)
217
0
        return (ENOMEM);
218
0
    for (i = 0, lz = rc->rc_src_rowcol;
219
0
        i < rc->rc_src_rowcol_len; ++i, ++lz) {
220
0
        m = be32toh(rcx->rcx_src_rowcol[i].begin),
221
0
        n = be32toh(rcx->rcx_src_rowcol[i].end);
222
0
        ret = set_linear_zone(lz, m, n);
223
0
        if (ret != 0) {
224
0
            free(rc->rc_src_rowcol);
225
0
            rc->rc_src_rowcol = NULL;
226
0
            return (ret);
227
0
        }
228
0
    }
229
0
    return (0);
230
0
}
231
232
static void
233
rowcol_uninit(struct _citrus_mapper_std *ms)
234
0
{
235
0
    struct _citrus_mapper_std_rowcol *rc;
236
237
0
    rc = &ms->ms_rowcol;
238
0
    free(rc->rc_src_rowcol);
239
0
}
240
241
static int
242
rowcol_init(struct _citrus_mapper_std *ms)
243
0
{
244
0
    struct _citrus_mapper_std_linear_zone *lz;
245
0
    struct _citrus_mapper_std_rowcol *rc;
246
0
    const struct _citrus_mapper_std_rowcol_ext_ilseq_info_x *eix;
247
0
    struct _citrus_region r;
248
0
    uint64_t table_size;
249
0
    size_t i;
250
0
    int ret;
251
252
0
    ms->ms_convert = &rowcol_convert;
253
0
    ms->ms_uninit = &rowcol_uninit;
254
0
    rc = &ms->ms_rowcol;
255
256
    /* get table region */
257
0
    ret = _citrus_db_lookup_by_string(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TABLE,
258
0
        &rc->rc_table, NULL);
259
0
    if (ret) {
260
0
        if (ret == ENOENT)
261
0
            ret = EFTYPE;
262
0
        return (ret);
263
0
    }
264
265
    /* get table information */
266
0
    ret = _citrus_db_lookup_by_string(ms->ms_db, _CITRUS_MAPPER_STD_SYM_INFO, &r, NULL);
267
0
    if (ret) {
268
0
        if (ret == ENOENT)
269
0
            ret = EFTYPE;
270
0
        return (ret);
271
0
    }
272
0
    switch (_citrus_region_size(&r)) {
273
0
    case _CITRUS_MAPPER_STD_ROWCOL_INFO_COMPAT_SIZE:
274
0
        ret = rowcol_parse_variable_compat(rc, &r);
275
0
        break;
276
0
    case _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE:
277
0
        ret = rowcol_parse_variable(rc, &r);
278
0
        break;
279
0
    default:
280
0
        return (EFTYPE);
281
0
    }
282
0
    if (ret != 0)
283
0
        return (ret);
284
    /* sanity check */
285
0
    switch (rc->rc_src_rowcol_bits) {
286
0
    case 8: case 16: case 32:
287
0
        if (rc->rc_src_rowcol_len <= 32 / rc->rc_src_rowcol_bits)
288
0
            break;
289
    /*FALLTHROUGH*/
290
0
    default:
291
0
        return (EFTYPE);
292
0
    }
293
294
    /* ilseq extension */
295
0
    rc->rc_oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
296
0
    rc->rc_dst_ilseq = rc->rc_dst_invalid;
297
0
    ret = _citrus_db_lookup_by_string(ms->ms_db,
298
0
        _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &r, NULL);
299
0
    if (ret && ret != ENOENT)
300
0
        return (ret);
301
0
    if (_citrus_region_size(&r) < sizeof(*eix))
302
0
        return (EFTYPE);
303
0
    if (ret == 0) {
304
0
        eix = _citrus_region_head(&r);
305
0
        rc->rc_oob_mode = be32toh(eix->eix_oob_mode);
306
0
        rc->rc_dst_ilseq = be32toh(eix->eix_dst_ilseq);
307
0
    }
308
309
    /* calcurate expected table size */
310
0
    i = rc->rc_src_rowcol_len;
311
0
    lz = &rc->rc_src_rowcol[--i];
312
0
    table_size = lz->width;
313
0
    while (i > 0) {
314
0
        lz = &rc->rc_src_rowcol[--i];
315
0
        table_size *= lz->width;
316
0
    }
317
0
    table_size *= rc->rc_dst_unit_bits/8;
318
319
0
    if (table_size > UINT32_MAX ||
320
0
        _citrus_region_size(&rc->rc_table) < table_size)
321
0
        return (EFTYPE);
322
323
0
    return (0);
324
0
}
325
326
typedef int (*initfunc_t)(struct _citrus_mapper_std *);
327
static const struct {
328
    initfunc_t           t_init;
329
    const char          *t_name;
330
} types[] = {
331
    { &rowcol_init, _CITRUS_MAPPER_STD_TYPE_ROWCOL },
332
};
333
0
#define NUM_OF_TYPES ((int)(sizeof(types)/sizeof(types[0])))
334
335
static int
336
/*ARGSUSED*/
337
_citrus_mapper_std_mapper_init(struct _citrus_mapper_area * ma ,
338
    struct _citrus_csmapper * cm, const char * curdir,
339
    const void * var, size_t lenvar,
340
    struct _citrus_mapper_traits * mt, size_t lenmt)
341
0
{
342
0
    struct _citrus_mapper_std *ms;
343
0
    char path[OFICONV_PATH_MAX];
344
0
    const char *type;
345
0
    int id, ret;
346
0
    (void) ma;
347
348
    /* set traits */
349
0
    if (lenmt < sizeof(*mt)) {
350
0
        ret = EINVAL;
351
0
        goto err0;
352
0
    }
353
0
    mt->mt_src_max = mt->mt_dst_max = 1;    /* 1:1 converter */
354
0
    mt->mt_state_size = 0;          /* stateless */
355
356
    /* alloc mapper std structure */
357
0
    ms = malloc(sizeof(*ms));
358
0
    if (ms == NULL) {
359
0
        ret = errno;
360
0
        goto err0;
361
0
    }
362
363
    /* open mapper file */
364
0
    snprintf(path, sizeof(path), "%s/%.*s", curdir, (int)lenvar,
365
0
        (const char *)var);
366
0
    ret = _citrus_map_file(&ms->ms_file, path);
367
0
    if (ret)
368
0
        goto err1;
369
370
0
    ret = _citrus_db_open(&ms->ms_db, &ms->ms_file, _CITRUS_MAPPER_STD_MAGIC,
371
0
        &_citrus_db_hash_std, NULL);
372
0
    if (ret)
373
0
        goto err2;
374
375
    /* get mapper type */
376
0
    ret = _citrus_db_lookup_string_by_string(ms->ms_db, _CITRUS_MAPPER_STD_SYM_TYPE,
377
0
        &type, NULL);
378
0
    if (ret) {
379
0
        if (ret == ENOENT)
380
0
            ret = EFTYPE;
381
0
        goto err3;
382
0
    }
383
0
    for (id = 0; id < NUM_OF_TYPES; id++)
384
0
        if (_citrus_bcs_strcasecmp(type, types[id].t_name) == 0)
385
0
            break;
386
387
0
    if (id == NUM_OF_TYPES)
388
0
        goto err3;
389
390
    /* init the per-type structure */
391
0
    ret = (*types[id].t_init)(ms);
392
0
    if (ret)
393
0
        goto err3;
394
395
0
    cm->cm_closure = ms;
396
397
0
    return (0);
398
399
0
err3:
400
0
    _citrus_db_close(ms->ms_db);
401
0
err2:
402
0
    _citrus_unmap_file(&ms->ms_file);
403
0
err1:
404
0
    free(ms);
405
0
err0:
406
0
    return (ret);
407
0
}
408
409
static void
410
/*ARGSUSED*/
411
_citrus_mapper_std_mapper_uninit(struct _citrus_csmapper *cm)
412
0
{
413
0
    struct _citrus_mapper_std *ms;
414
415
0
    ms = cm->cm_closure;
416
0
    if (ms->ms_uninit)
417
0
        (*ms->ms_uninit)(ms);
418
0
    _citrus_db_close(ms->ms_db);
419
0
    _citrus_unmap_file(&ms->ms_file);
420
0
    free(ms);
421
0
}
422
423
static void
424
/*ARGSUSED*/
425
_citrus_mapper_std_mapper_init_state(void)
426
0
{
427
428
0
}
429
430
static int
431
/*ARGSUSED*/
432
_citrus_mapper_std_mapper_convert(struct _citrus_csmapper * cm,
433
    _citrus_index_t * dst, _citrus_index_t src, void * ps)
434
0
{
435
0
    struct _citrus_mapper_std *ms;
436
437
0
    ms = cm->cm_closure;
438
0
    return ((*ms->ms_convert)(ms, dst, src, ps));
439
0
}