Coverage Report

Created: 2026-09-28 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oficonv/libsrc/citrus_mapper_zone.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_mapper_zone.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 <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "citrus_bcs.h"
42
#include "citrus_types.h"
43
#include "citrus_module.h"
44
#include "citrus_region.h"
45
#include "citrus_memstream.h"
46
#include "citrus_mmap.h"
47
#include "citrus_hash.h"
48
#include "citrus_mapper.h"
49
50
/* ---------------------------------------------------------------------- */
51
52
_CITRUS_MAPPER_DECLS(mapper_zone);
53
_CITRUS_MAPPER_DEF_OPS(mapper_zone);
54
55
56
/* ---------------------------------------------------------------------- */
57
58
struct _zone {
59
    uint32_t     z_begin;
60
    uint32_t     z_end;
61
};
62
63
struct _citrus_mapper_zone {
64
    struct _zone     mz_col;
65
    struct _zone     mz_row;
66
    int32_t      mz_col_offset;
67
    int32_t      mz_row_offset;
68
    int      mz_col_bits;
69
};
70
71
struct _parse_state {
72
    enum { S_BEGIN, S_OFFSET }  ps_state;
73
    union {
74
        uint32_t    u_imm;
75
        int32_t     s_imm;
76
        struct _zone    zone;
77
    } u;
78
0
#define ps_u_imm    u.u_imm
79
0
#define ps_s_imm    u.s_imm
80
#define ps_zone     u.zone
81
    int ps_top;
82
};
83
84
int
85
_citrus_mapper_zone_mapper_getops(struct _citrus_mapper_ops *ops)
86
0
{
87
88
0
    memcpy(ops, &_citrus_mapper_zone_mapper_ops,
89
0
           sizeof(_citrus_mapper_zone_mapper_ops));
90
91
0
    return (0);
92
0
}
93
94
0
#define BUFSIZE 20
95
0
#define T_ERR   0x100
96
0
#define T_IMM   0x101
97
98
static int
99
get_imm(struct _citrus_memory_stream *ms, struct _parse_state *ps)
100
0
{
101
0
    int c, i, sign = 0;
102
0
    char buf[BUFSIZE + 1];
103
0
    char *p;
104
105
0
    for (i = 0; i < BUFSIZE; i++) {
106
0
retry:
107
0
        c = _citrus_memory_stream_peek(ms);
108
0
        if (i == 0) {
109
0
            if (sign == 0 && (c == '+' || c == '-')) {
110
0
                sign = c;
111
0
                _citrus_memory_stream_getc(ms);
112
0
                goto retry;
113
0
            } else if (!_citrus_bcs_isdigit((uint8_t)c))
114
0
                break;
115
0
        } else if (!_citrus_bcs_isxdigit((uint8_t)c))
116
0
            if (!(i == 1 && c == 'x'))
117
0
                break;
118
0
        buf[i] = (char) _citrus_memory_stream_getc(ms);
119
0
    }
120
0
    buf[i] = '\0';
121
0
    ps->ps_u_imm = strtoul(buf, &p, 0);
122
0
    if ((p - buf) != i)
123
0
        return (T_ERR);
124
0
    if (sign == '-')
125
0
        ps->ps_u_imm = (unsigned long)-(long)ps->ps_u_imm;
126
0
    return (T_IMM);
127
0
}
128
129
static int
130
get_tok(struct _citrus_memory_stream *ms, struct _parse_state *ps)
131
0
{
132
0
    int c;
133
134
0
loop:
135
0
    c = _citrus_memory_stream_peek(ms);
136
0
    if (c == 0x00)
137
0
        return (EOF);
138
0
    if (_citrus_bcs_isspace((uint8_t)c)) {
139
0
        _citrus_memory_stream_getc(ms);
140
0
        goto loop;
141
0
    }
142
143
0
    switch (ps->ps_state) {
144
0
    case S_BEGIN:
145
0
        switch (c) {
146
0
        case ':':
147
0
        case '-':
148
0
        case '/':
149
0
            _citrus_memory_stream_getc(ms);
150
0
            return (c);
151
0
        case '0':
152
0
        case '1':
153
0
        case '2':
154
0
        case '3':
155
0
        case '4':
156
0
        case '5':
157
0
        case '6':
158
0
        case '7':
159
0
        case '8':
160
0
        case '9':
161
0
            return (get_imm(ms, ps));
162
0
        }
163
0
        break;
164
0
    case S_OFFSET:
165
0
        switch (c) {
166
0
        case '/':
167
0
            _citrus_memory_stream_getc(ms);
168
0
            return (c);
169
0
        case '+':
170
0
        case '-':
171
0
        case '0':
172
0
        case '1':
173
0
        case '2':
174
0
        case '3':
175
0
        case '4':
176
0
        case '5':
177
0
        case '6':
178
0
        case '7':
179
0
        case '8':
180
0
        case '9':
181
0
            return (get_imm(ms, ps));
182
0
        }
183
0
        break;
184
0
    }
185
0
    return (T_ERR);
186
0
}
187
188
static int
189
parse_zone(struct _citrus_memory_stream *ms, struct _parse_state *ps, struct _zone *z)
190
0
{
191
192
0
    if (get_tok(ms, ps) != T_IMM)
193
0
        return (-1);
194
0
    z->z_begin = ps->ps_u_imm;
195
0
    if (get_tok(ms, ps) != '-')
196
0
        return (-1);
197
0
    if (get_tok(ms, ps) != T_IMM)
198
0
        return (-1);
199
0
    z->z_end = ps->ps_u_imm;
200
201
0
    if (z->z_begin > z->z_end)
202
0
        return (-1);
203
204
0
    return (0);
205
0
}
206
207
static int
208
check_rowcol(struct _zone *z, int32_t ofs, uint32_t maxval)
209
0
{
210
0
    uint32_t remain;
211
212
0
    if (maxval != 0 && z->z_end >= maxval)
213
0
        return (-1);
214
215
0
    if (ofs > 0) {
216
0
        if (maxval == 0)
217
            /* this should 0x100000000 - z->z_end */
218
0
            remain = (z->z_end == 0) ? 0xFFFFFFFF :
219
0
                0xFFFFFFFF - z->z_end + 1;
220
0
        else
221
0
            remain = maxval - z->z_end;
222
0
        if ((uint32_t)ofs > remain)
223
0
            return (-1);
224
0
    } else if (ofs < 0) {
225
0
        if (z->z_begin < (uint32_t)-ofs)
226
0
            return (-1);
227
0
    }
228
229
0
    return (0);
230
0
}
231
232
static int
233
parse_var(struct _citrus_mapper_zone *mz, struct _citrus_memory_stream *ms)
234
0
{
235
0
    struct _parse_state ps;
236
0
    uint32_t colmax, rowmax;
237
0
    int isrc, ret;
238
239
0
    ps.ps_state = S_BEGIN;
240
241
0
    if (parse_zone(ms, &ps, &mz->mz_col))
242
0
        return (-1);
243
244
0
    ret = get_tok(ms, &ps);
245
0
    if (ret == '/') {
246
        /* rowzone / colzone / bits */
247
0
        isrc = 1;
248
0
        mz->mz_row = mz->mz_col;
249
250
0
        if (parse_zone(ms, &ps, &mz->mz_col))
251
0
            return (-1);
252
0
        if (get_tok(ms, &ps) != '/')
253
0
            return (-1);
254
0
        if (get_tok(ms, &ps) != T_IMM)
255
0
            return (-1);
256
0
        mz->mz_col_bits = ps.ps_u_imm;
257
0
        if (mz->mz_col_bits < 0 || mz->mz_col_bits > 32)
258
0
            return (-1);
259
0
        ret = get_tok(ms, &ps);
260
0
    } else {
261
        /* colzone */
262
0
        isrc = 0;
263
0
        mz->mz_col_bits = 32;
264
0
        mz->mz_row.z_begin = mz->mz_row.z_end = 0;
265
0
    }
266
0
    if (ret == ':') {
267
        /* offset */
268
0
        ps.ps_state = S_OFFSET;
269
0
        if (get_tok(ms, &ps) != T_IMM)
270
0
            return (-1);
271
0
        mz->mz_col_offset = ps.ps_s_imm;
272
0
        if (isrc) {
273
            /* row/col */
274
0
            mz->mz_row_offset = mz->mz_col_offset;
275
0
            if (get_tok(ms, &ps) != '/')
276
0
                return (-1);
277
0
            if (get_tok(ms, &ps) != T_IMM)
278
0
                return (-1);
279
0
            mz->mz_col_offset = ps.ps_s_imm;
280
0
        } else
281
0
            mz->mz_row_offset = 0;
282
0
        ret = get_tok(ms, &ps);
283
0
    }
284
0
    if (ret != EOF)
285
0
        return (-1);
286
287
    /* sanity check */
288
0
    colmax = (mz->mz_col_bits == 32) ? 0 : 1 << mz->mz_col_bits;
289
0
    rowmax = (mz->mz_col_bits == 0) ? 0 : 1 << (32-mz->mz_col_bits);
290
0
    if (check_rowcol(&mz->mz_col, mz->mz_col_offset, colmax))
291
0
        return (-1);
292
0
    if (check_rowcol(&mz->mz_row, mz->mz_row_offset, rowmax))
293
0
        return (-1);
294
295
0
    return (0);
296
0
}
297
298
static int
299
/*ARGSUSED*/
300
_citrus_mapper_zone_mapper_init(struct _citrus_mapper_area * ma ,
301
    struct _citrus_csmapper * cm, const char * dir ,
302
    const void * var, size_t lenvar,
303
    struct _citrus_mapper_traits * mt, size_t lenmt)
304
0
{
305
0
    struct _citrus_mapper_zone *mz;
306
0
    struct _citrus_memory_stream ms;
307
0
    struct _citrus_region r;
308
0
    (void) ma;
309
0
    (void) dir;
310
311
0
    if (lenmt < sizeof(*mt))
312
0
        return (EINVAL);
313
314
0
    mz = malloc(sizeof(*mz));
315
0
    if (mz == NULL)
316
0
        return (errno);
317
318
0
    mz->mz_col.z_begin = mz->mz_col.z_end = 0;
319
0
    mz->mz_row.z_begin = mz->mz_row.z_end = 0;
320
0
    mz->mz_col_bits = 0;
321
0
    mz->mz_row_offset = 0;
322
0
    mz->mz_col_offset = 0;
323
324
0
    _citrus_region_init(&r, CITRUS_DECONST(void *, var), lenvar);
325
0
    _citrus_memory_stream_bind(&ms, &r);
326
0
    if (parse_var(mz, &ms)) {
327
0
        free(mz);
328
0
        return (EINVAL);
329
0
    }
330
0
    cm->cm_closure = mz;
331
0
    mt->mt_src_max = mt->mt_dst_max = 1;    /* 1:1 converter */
332
0
    mt->mt_state_size = 0;          /* stateless */
333
334
0
    return (0);
335
0
}
336
337
static void
338
/*ARGSUSED*/
339
_citrus_mapper_zone_mapper_uninit(struct _citrus_csmapper *cm )
340
0
{
341
0
    if (cm && cm->cm_closure)
342
0
        free(cm->cm_closure);
343
0
}
344
345
static int
346
/*ARGSUSED*/
347
_citrus_mapper_zone_mapper_convert(struct _citrus_csmapper * cm,
348
    _citrus_index_t * dst, _citrus_index_t src,
349
    void * ps )
350
0
{
351
0
    struct _citrus_mapper_zone *mz = cm->cm_closure;
352
0
    uint32_t col, row;
353
0
    (void) ps;
354
355
0
    if (mz->mz_col_bits == 32) {
356
0
        col = src;
357
0
        row = 0;
358
0
        if (col < mz->mz_col.z_begin || col > mz->mz_col.z_end)
359
0
            return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
360
0
        if (mz->mz_col_offset > 0)
361
0
            col += (uint32_t)mz->mz_col_offset;
362
0
        else
363
0
            col -= (uint32_t)-mz->mz_col_offset;
364
0
        *dst = col;
365
0
    } else {
366
0
        col = src & (((uint32_t)1 << mz->mz_col_bits) - 1);
367
0
        row = src >> mz->mz_col_bits;
368
0
        if (row < mz->mz_row.z_begin || row > mz->mz_row.z_end ||
369
0
            col < mz->mz_col.z_begin || col > mz->mz_col.z_end)
370
0
            return (_CITRUS_MAPPER_CONVERT_NONIDENTICAL);
371
0
        if (mz->mz_col_offset > 0)
372
0
            col += (uint32_t)mz->mz_col_offset;
373
0
        else
374
0
            col -= (uint32_t)-mz->mz_col_offset;
375
0
        if (mz->mz_row_offset > 0)
376
0
            row += (uint32_t)mz->mz_row_offset;
377
0
        else
378
0
            row -= (uint32_t)-mz->mz_row_offset;
379
0
        *dst = col | (row << mz->mz_col_bits);
380
0
    }
381
0
    return (_CITRUS_MAPPER_CONVERT_SUCCESS);
382
0
}
383
384
static void
385
/*ARGSUSED*/
386
_citrus_mapper_zone_mapper_init_state(void)
387
0
{
388
389
0
}