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_big5.c
Line
Count
Source
1
/*-
2
 * Copyright (c)2002, 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
/*-
28
 * Copyright (c) 1993
29
 *  The Regents of the University of California.  All rights reserved.
30
 *
31
 * This code is derived from software contributed to Berkeley by
32
 * Paul Borman at Krystal Technologies.
33
 *
34
 * Redistribution and use in source and binary forms, with or without
35
 * modification, are permitted provided that the following conditions
36
 * are met:
37
 * 1. Redistributions of source code must retain the above copyright
38
 *    notice, this list of conditions and the following disclaimer.
39
 * 2. Redistributions in binary form must reproduce the above copyright
40
 *    notice, this list of conditions and the following disclaimer in the
41
 *    documentation and/or other materials provided with the distribution.
42
 * 3. Neither the name of the University nor the names of its contributors
43
 *    may be used to endorse or promote products derived from this software
44
 *    without specific prior written permission.
45
 *
46
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56
 * SUCH DAMAGE.
57
 */
58
59
#include "dcmtk/config/osconfig.h"
60
#include "citrus_big5.h"
61
62
#ifdef HAVE_SYS_QUEUE_H
63
#include <sys/queue.h>
64
#else
65
#include "dcmtk/oficonv/queue.h"
66
#endif
67
68
#include <sys/types.h>
69
#include <errno.h>
70
#include <limits.h>
71
#include <stddef.h>
72
#include <stdint.h>
73
#include <stdio.h>
74
#include <stdlib.h>
75
#include <string.h>
76
#include <wchar.h>
77
78
#include "citrus_bcs.h"
79
#include "citrus_prop.h"
80
#include "citrus_types.h"
81
#include "citrus_module.h"
82
#include "citrus_stdenc.h"
83
84
/* ----------------------------------------------------------------------
85
 * private stuffs used by templates
86
 */
87
88
typedef struct {
89
    int  chlen;
90
    char     ch[2];
91
} _BIG5State;
92
93
typedef struct _BIG5Exclude {
94
    TAILQ_ENTRY(_BIG5Exclude)    entry;
95
    wint_t               end;
96
    wint_t               start;
97
} _BIG5Exclude;
98
99
typedef TAILQ_HEAD(_BIG5ExcludeList, _BIG5Exclude) _BIG5ExcludeList;
100
101
typedef struct {
102
    _BIG5ExcludeList     excludes;
103
    int          cell[0x100];
104
} _BIG5EncodingInfo;
105
106
#define _CEI_TO_EI(_cei_)       (&(_cei_)->ei)
107
#define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.s_##_func_
108
109
0
#define _FUNCNAME(m)            _citrus_BIG5_##m
110
0
#define _ENCODING_INFO          _BIG5EncodingInfo
111
#define _ENCODING_STATE         _BIG5State
112
0
#define _ENCODING_MB_CUR_MAX(_ei_)  2
113
#define _ENCODING_IS_STATE_DEPENDENT    0
114
#define _STATE_NEEDS_EXPLICIT_INIT(_ps_)    0
115
116
117
static __inline void
118
/*ARGSUSED*/
119
_citrus_BIG5_init_state(_BIG5EncodingInfo * ei ,
120
    _BIG5State * s)
121
0
{
122
0
    (void) ei;
123
0
    memset(s, 0, sizeof(*s));
124
0
}
125
126
#if 0
127
static __inline void
128
/*ARGSUSED*/
129
_citrus_BIG5_pack_state(_BIG5EncodingInfo * ei ,
130
    void * pspriv,
131
    const _BIG5State * s)
132
{
133
    (void) ei;
134
    memcpy(pspriv, (const void *)s, sizeof(*s));
135
}
136
137
static __inline void
138
/*ARGSUSED*/
139
_citrus_BIG5_unpack_state(_BIG5EncodingInfo * ei ,
140
    _BIG5State * s,
141
    const void * pspriv)
142
{
143
    (void) ei;
144
    memcpy((void *)s, pspriv, sizeof(*s));
145
}
146
#endif
147
148
static __inline int
149
_citrus_BIG5_check(_BIG5EncodingInfo *ei, unsigned int c)
150
0
{
151
152
0
    return ((ei->cell[c & 0xFF] & 0x1) ? 2 : 1);
153
0
}
154
155
static __inline int
156
_citrus_BIG5_check2(_BIG5EncodingInfo *ei, unsigned int c)
157
0
{
158
159
0
    return ((ei->cell[c & 0xFF] & 0x2) ? 1 : 0);
160
0
}
161
162
static __inline int
163
_citrus_BIG5_check_excludes(_BIG5EncodingInfo *ei, wint_t c)
164
0
{
165
0
    _BIG5Exclude *exclude;
166
167
0
    TAILQ_FOREACH(exclude, &ei->excludes, entry) {
168
0
        if (c >= exclude->start && c <= exclude->end)
169
0
            return (EILSEQ);
170
0
    }
171
0
    return (0);
172
0
}
173
174
static int
175
_citrus_BIG5_fill_rowcol(void * ctx, const char * s,
176
    uint64_t start, uint64_t end)
177
0
{
178
0
    _BIG5EncodingInfo *ei;
179
0
    uint64_t n;
180
0
    int i;
181
182
0
    if (start > 0xFF || end > 0xFF)
183
0
        return (EINVAL);
184
0
    ei = (_BIG5EncodingInfo *)ctx;
185
0
    i = strcmp("row", s) ? 1 : 0;
186
0
    i = 1 << i;
187
0
    for (n = start; n <= end; ++n)
188
0
        ei->cell[n & 0xFF] |= i;
189
0
    return (0);
190
0
}
191
192
static int
193
/*ARGSUSED*/
194
_citrus_BIG5_fill_excludes(void * ctx,
195
    const char * s , uint64_t start, uint64_t end)
196
0
{
197
0
    _BIG5EncodingInfo *ei;
198
0
    _BIG5Exclude *exclude;
199
200
0
    (void) s;
201
0
    if (start > 0xFFFF || end > 0xFFFF)
202
0
        return (EINVAL);
203
0
    ei = (_BIG5EncodingInfo *)ctx;
204
0
    exclude = TAILQ_LAST(&ei->excludes, _BIG5ExcludeList);
205
0
    if (exclude != NULL && (wint_t)start <= exclude->end)
206
0
        return (EINVAL);
207
0
    exclude = (void *)malloc(sizeof(*exclude));
208
0
    if (exclude == NULL)
209
0
        return (ENOMEM);
210
0
    exclude->start = (wint_t)start;
211
0
    exclude->end = (wint_t)end;
212
0
    TAILQ_INSERT_TAIL(&ei->excludes, exclude, entry);
213
214
0
    return (0);
215
0
}
216
217
static const _citrus_prop_hint_t root_hints[] = {
218
    _CITRUS_PROP_HINT_NUM("row", &_citrus_BIG5_fill_rowcol),
219
    _CITRUS_PROP_HINT_NUM("col", &_citrus_BIG5_fill_rowcol),
220
    _CITRUS_PROP_HINT_NUM("excludes", &_citrus_BIG5_fill_excludes),
221
    _CITRUS_PROP_HINT_END
222
};
223
224
static void
225
/*ARGSUSED*/
226
_citrus_BIG5_encoding_module_uninit(_BIG5EncodingInfo *ei)
227
0
{
228
0
    _BIG5Exclude *exclude;
229
230
0
    while ((exclude = TAILQ_FIRST(&ei->excludes)) != NULL) {
231
0
        TAILQ_REMOVE(&ei->excludes, exclude, entry);
232
0
        free(exclude);
233
0
    }
234
0
}
235
236
static int
237
/*ARGSUSED*/
238
_citrus_BIG5_encoding_module_init(_BIG5EncodingInfo * ei,
239
    const void * var, size_t lenvar)
240
0
{
241
0
    const char *s;
242
0
    int err;
243
244
0
    memset((void *)ei, 0, sizeof(*ei));
245
0
    TAILQ_INIT(&ei->excludes);
246
247
0
    if (lenvar > 0 && var != NULL) {
248
0
        s = _citrus_bcs_skip_ws_len((const char *)var, &lenvar);
249
0
        if (lenvar > 0 && *s != '\0') {
250
0
            err = _citrus_prop_parse_variable(
251
0
                root_hints, (void *)ei, s, lenvar);
252
0
            if (err == 0)
253
0
                return (0);
254
255
0
            _citrus_BIG5_encoding_module_uninit(ei);
256
0
            memset((void *)ei, 0, sizeof(*ei));
257
0
            TAILQ_INIT(&ei->excludes);
258
0
        }
259
0
    }
260
261
    /* fallback Big5-1984, for backward compatibility. */
262
0
    _citrus_BIG5_fill_rowcol(ei, "row", 0xA1, 0xFE);
263
0
    _citrus_BIG5_fill_rowcol(ei, "col", 0x40, 0x7E);
264
0
    _citrus_BIG5_fill_rowcol(ei, "col", 0xA1, 0xFE);
265
266
0
    return (0);
267
0
}
268
269
static int
270
/*ARGSUSED*/
271
_citrus_BIG5_mbrtowc_priv(_BIG5EncodingInfo * ei,
272
    _citrus_wc_t * pwc,
273
    char ** s, size_t n,
274
    _BIG5State * psenc,
275
    size_t * nresult)
276
0
{
277
0
    _citrus_wc_t wchar;
278
0
    char *s0;
279
0
    int c, chlenbak;
280
281
0
    s0 = *s;
282
283
0
    if (s0 == NULL) {
284
0
        _citrus_BIG5_init_state(ei, psenc);
285
0
        *nresult = 0;
286
0
        return (0);
287
0
    }
288
289
0
    chlenbak = psenc->chlen;
290
291
    /* make sure we have the first byte in the buffer */
292
0
    switch (psenc->chlen) {
293
0
    case 0:
294
0
        if (n < 1)
295
0
            goto restart;
296
0
        psenc->ch[0] = *s0++;
297
0
        psenc->chlen = 1;
298
0
        n--;
299
0
        break;
300
0
    case 1:
301
0
        break;
302
0
    default:
303
        /* illegal state */
304
0
        goto ilseq;
305
0
    }
306
307
0
    c = _citrus_BIG5_check(ei, psenc->ch[0] & 0xff);
308
0
    if (c == 0)
309
0
        goto ilseq;
310
0
    while (psenc->chlen < c) {
311
0
        if (n < 1) {
312
0
            goto restart;
313
0
        }
314
0
        psenc->ch[psenc->chlen] = *s0++;
315
0
        psenc->chlen++;
316
0
        n--;
317
0
    }
318
319
0
    switch (c) {
320
0
    case 1:
321
0
        wchar = psenc->ch[0] & 0xff;
322
0
        break;
323
0
    case 2:
324
0
        if (!_citrus_BIG5_check2(ei, psenc->ch[1] & 0xff))
325
0
            goto ilseq;
326
0
        wchar = ((psenc->ch[0] & 0xff) << 8) | (psenc->ch[1] & 0xff);
327
0
        break;
328
0
    default:
329
        /* illegal state */
330
0
        goto ilseq;
331
0
    }
332
333
0
    if (_citrus_BIG5_check_excludes(ei, (wint_t)wchar) != 0)
334
0
        goto ilseq;
335
336
0
    *s = s0;
337
0
    psenc->chlen = 0;
338
0
    if (pwc)
339
0
        *pwc = wchar;
340
0
    *nresult = wchar ? c - chlenbak : 0;
341
342
0
    return (0);
343
344
0
ilseq:
345
0
    psenc->chlen = 0;
346
0
    *nresult = (size_t)-1;
347
0
    return (EILSEQ);
348
349
0
restart:
350
0
    *s = s0;
351
0
    *nresult = (size_t)-2;
352
0
    return (0);
353
0
}
354
355
static int
356
/*ARGSUSED*/
357
_citrus_BIG5_wcrtomb_priv(_BIG5EncodingInfo * ei,
358
    char * s,
359
    size_t n, _citrus_wc_t wc, _BIG5State * psenc ,
360
    size_t * nresult)
361
0
{
362
0
    size_t l;
363
0
    int ret;
364
0
    (void) psenc;
365
366
    /* check invalid sequence */
367
0
    if (wc & ~0xffff ||
368
0
        _citrus_BIG5_check_excludes(ei, (wint_t)wc) != 0) {
369
0
        ret = EILSEQ;
370
0
        goto err;
371
0
    }
372
373
0
    if (wc & 0x8000) {
374
0
        if (_citrus_BIG5_check(ei, (wc >> 8) & 0xff) != 2 ||
375
0
            !_citrus_BIG5_check2(ei, wc & 0xff)) {
376
0
            ret = EILSEQ;
377
0
            goto err;
378
0
        }
379
0
        l = 2;
380
0
    } else {
381
0
        if (wc & ~0xff || !_citrus_BIG5_check(ei, wc & 0xff)) {
382
0
            ret = EILSEQ;
383
0
            goto err;
384
0
        }
385
0
        l = 1;
386
0
    }
387
388
0
    if (n < l) {
389
        /* bound check failure */
390
0
        ret = E2BIG;
391
0
        goto err;
392
0
    }
393
394
0
    if (l == 2) {
395
0
        s[0] = (wc >> 8) & 0xff;
396
0
        s[1] = wc & 0xff;
397
0
    } else
398
0
        s[0] = wc & 0xff;
399
400
0
    *nresult = l;
401
402
0
    return (0);
403
404
0
err:
405
0
    *nresult = (size_t)-1;
406
0
    return (ret);
407
0
}
408
409
static __inline int
410
/*ARGSUSED*/
411
_citrus_BIG5_stdenc_wctocs(_BIG5EncodingInfo * ei ,
412
    _citrus_csid_t * csid,
413
    _citrus_index_t * idx, _citrus_wc_t wc)
414
0
{
415
0
    (void) ei;
416
0
    *csid = (wc < 0x100) ? 0 : 1;
417
0
    *idx = (_citrus_index_t)wc;
418
419
0
    return (0);
420
0
}
421
422
static __inline int
423
/*ARGSUSED*/
424
_citrus_BIG5_stdenc_cstowc(_BIG5EncodingInfo * ei ,
425
    _citrus_wc_t * wc,
426
    _citrus_csid_t csid, _citrus_index_t idx)
427
0
{
428
0
    (void) ei;
429
0
    switch (csid) {
430
0
    case 0:
431
0
    case 1:
432
0
        *wc = (_citrus_wc_t)idx;
433
0
        break;
434
0
    default:
435
0
        return (EILSEQ);
436
0
    }
437
438
0
    return (0);
439
0
}
440
441
static __inline int
442
/*ARGSUSED*/
443
_citrus_BIG5_stdenc_get_state_desc_generic(_BIG5EncodingInfo * ei ,
444
    _BIG5State * psenc,
445
    int * rstate)
446
0
{
447
0
    (void) ei;
448
0
    *rstate = (psenc->chlen == 0) ? _CITRUS_STDENC_SDGEN_INITIAL :
449
0
        _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR;
450
0
    return (0);
451
0
}
452
453
/* ----------------------------------------------------------------------
454
 * public interface for stdenc
455
 */
456
457
_CITRUS_STDENC_DECLS(BIG5);
458
_CITRUS_STDENC_DEF_OPS(BIG5);
459
460
#include "citrus_stdenc_template.h"