Coverage Report

Created: 2026-03-31 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/oficonv/libsrc/citrus_dechanyu.c
Line
Count
Source
1
/*-
2
 * Copyright (c)2007 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_dechanyu.h"
29
30
#include <sys/types.h>
31
#ifndef __CONCAT
32
#define __CONCAT(x,y) x ## y
33
#endif
34
35
#include <errno.h>
36
#include <limits.h>
37
#include <stddef.h>
38
#include <stdint.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <wchar.h>
43
44
#include "citrus_bcs.h"
45
#include "citrus_types.h"
46
#include "citrus_module.h"
47
#include "citrus_stdenc.h"
48
49
/* ----------------------------------------------------------------------
50
 * private stuffs used by templates
51
 */
52
53
typedef struct {
54
    size_t   chlen;
55
    char     ch[4];
56
} _DECHanyuState;
57
58
typedef struct {
59
    int  dummy;
60
} _DECHanyuEncodingInfo;
61
62
#define _CEI_TO_EI(_cei_)       (&(_cei_)->ei)
63
#define _CEI_TO_STATE(_cei_, _func_)    (_cei_)->states.__CONCAT(s_,_func_)
64
65
0
#define _FUNCNAME(m)            __CONCAT(_citrus_DECHanyu_,m)
66
0
#define _ENCODING_INFO          _DECHanyuEncodingInfo
67
#define _ENCODING_STATE         _DECHanyuState
68
0
#define _ENCODING_MB_CUR_MAX(_ei_)      4
69
0
#define _ENCODING_IS_STATE_DEPENDENT        0
70
#define _STATE_NEEDS_EXPLICIT_INIT(_ps_)    0
71
72
static __inline void
73
/*ARGSUSED*/
74
_citrus_DECHanyu_init_state(_DECHanyuEncodingInfo * ei ,
75
    _DECHanyuState * psenc)
76
0
{
77
0
    (void) ei;
78
0
    psenc->chlen = 0;
79
0
}
80
81
#if 0
82
static __inline void
83
/*ARGSUSED*/
84
_citrus_DECHanyu_pack_state(_DECHanyuEncodingInfo * ei ,
85
    void * pspriv, const _DECHanyuState * psenc)
86
{
87
    (void) ei;
88
    memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
89
}
90
91
static __inline void
92
/*ARGSUSED*/
93
_citrus_DECHanyu_unpack_state(_DECHanyuEncodingInfo * ei ,
94
    _DECHanyuState * psenc,
95
    const void * pspriv)
96
{
97
    (void) ei;
98
    memcpy((void *)psenc, pspriv, sizeof(*psenc));
99
}
100
#endif
101
102
static void
103
/*ARGSUSED*/
104
_citrus_DECHanyu_encoding_module_uninit(_DECHanyuEncodingInfo *ei )
105
0
{
106
    /* ei may be null */
107
0
    (void) ei;
108
0
}
109
110
static int
111
/*ARGSUSED*/
112
_citrus_DECHanyu_encoding_module_init(_DECHanyuEncodingInfo * ei ,
113
    const void * var , size_t lenvar )
114
0
{
115
    /* ei may be null */
116
0
    (void) ei;
117
0
    (void) var;
118
0
    (void) lenvar;
119
0
    return (0);
120
0
}
121
122
static __inline bool
123
is_singlebyte(int c)
124
0
{
125
126
0
    return (c <= 0x7F);
127
0
}
128
129
static __inline bool
130
is_leadbyte(int c)
131
0
{
132
133
0
    return (c >= 0xA1 && c <= 0xFE);
134
0
}
135
136
static __inline bool
137
is_trailbyte(int c)
138
0
{
139
140
0
    c &= ~0x80;
141
0
    return (c >= 0x21 && c <= 0x7E);
142
0
}
143
144
static __inline bool
145
is_hanyu1(int c)
146
0
{
147
148
0
    return (c == 0xC2);
149
0
}
150
151
static __inline bool
152
is_hanyu2(int c)
153
0
{
154
155
0
    return (c == 0xCB);
156
0
}
157
158
0
#define HANYUBIT    0xC2CB0000
159
160
static __inline bool
161
is_94charset(int c)
162
0
{
163
164
0
    return (c >= 0x21 && c <= 0x7E);
165
0
}
166
167
static int
168
/*ARGSUSED*/
169
_citrus_DECHanyu_mbrtowc_priv(_DECHanyuEncodingInfo * ei,
170
    _citrus_wc_t * pwc, char ** s, size_t n,
171
    _DECHanyuState * psenc, size_t * nresult)
172
0
{
173
0
    char *s0;
174
0
    _citrus_wc_t wc;
175
0
    int ch;
176
177
0
    if (*s == NULL) {
178
0
        _citrus_DECHanyu_init_state(ei, psenc);
179
0
        *nresult = _ENCODING_IS_STATE_DEPENDENT;
180
0
        return (0);
181
0
    }
182
0
    s0 = *s;
183
184
0
    wc = (_citrus_wc_t)0;
185
0
    switch (psenc->chlen) {
186
0
    case 0:
187
0
        if (n-- < 1)
188
0
            goto restart;
189
0
        ch = *s0++ & 0xFF;
190
0
        if (is_singlebyte(ch)) {
191
0
            if (pwc != NULL)
192
0
                *pwc = (_citrus_wc_t)ch;
193
0
            *nresult = (size_t)((ch == 0) ? 0 : 1);
194
0
            *s = s0;
195
0
            return (0);
196
0
        }
197
0
        if (!is_leadbyte(ch))
198
0
            goto ilseq;
199
0
        psenc->ch[psenc->chlen++] = (char) ch;
200
0
        break;
201
0
    case 1:
202
0
        ch = psenc->ch[0] & 0xFF;
203
0
        if (!is_leadbyte(ch))
204
0
            return (EINVAL);
205
0
        break;
206
0
    case 2: case 3:
207
0
        ch = psenc->ch[0] & 0xFF;
208
0
        if (is_hanyu1(ch)) {
209
0
            ch = psenc->ch[1] & 0xFF;
210
0
            if (is_hanyu2(ch)) {
211
0
                wc |= (_citrus_wc_t)HANYUBIT;
212
0
                break;
213
0
            }
214
0
        }
215
    /*FALLTHROUGH*/
216
0
    default:
217
0
        return (EINVAL);
218
0
    }
219
220
0
    switch (psenc->chlen) {
221
0
    case 1:
222
0
        if (is_hanyu1(ch)) {
223
0
            if (n-- < 1)
224
0
                goto restart;
225
0
            ch = *s0++ & 0xFF;
226
0
            if (!is_hanyu2(ch))
227
0
                goto ilseq;
228
0
            psenc->ch[psenc->chlen++] = (char) ch;
229
0
            wc |= (_citrus_wc_t)HANYUBIT;
230
0
            if (n-- < 1)
231
0
                goto restart;
232
0
            ch = *s0++ & 0xFF;
233
0
            if (!is_leadbyte(ch))
234
0
                goto ilseq;
235
0
            psenc->ch[psenc->chlen++] = (char) ch;
236
0
        }
237
0
        break;
238
0
    case 2:
239
0
        if (n-- < 1)
240
0
            goto restart;
241
0
        ch = *s0++ & 0xFF;
242
0
        if (!is_leadbyte(ch))
243
0
            goto ilseq;
244
0
        psenc->ch[psenc->chlen++] = (char) ch;
245
0
        break;
246
0
    case 3:
247
0
        ch = psenc->ch[2] & 0xFF;
248
0
        if (!is_leadbyte(ch))
249
0
            return (EINVAL);
250
0
    }
251
0
    if (n-- < 1)
252
0
        goto restart;
253
0
    wc |= (_citrus_wc_t)(ch << 8);
254
0
    ch = *s0++ & 0xFF;
255
0
    if (!is_trailbyte(ch))
256
0
        goto ilseq;
257
0
    wc |= (_citrus_wc_t)ch;
258
0
    if (pwc != NULL)
259
0
        *pwc = wc;
260
0
    *nresult = (size_t)(s0 - *s);
261
0
    *s = s0;
262
0
    psenc->chlen = 0;
263
264
0
    return (0);
265
266
0
restart:
267
0
    *nresult = (size_t)-2;
268
0
    *s = s0;
269
0
    return (0);
270
271
0
ilseq:
272
0
    *nresult = (size_t)-1;
273
0
    return (EILSEQ);
274
0
}
275
276
static int
277
/*ARGSUSED*/
278
_citrus_DECHanyu_wcrtomb_priv(_DECHanyuEncodingInfo * ei ,
279
    char * s, size_t n, _citrus_wc_t wc,
280
    _DECHanyuState * psenc, size_t * nresult)
281
0
{
282
0
    int ch;
283
0
    (void) ei;
284
285
0
    if (psenc->chlen != 0)
286
0
        return (EINVAL);
287
288
    /* XXX: assume _citrus_wc_t as int */
289
0
    if ((uint32_t)wc <= 0x7F) {
290
0
        ch = wc & 0xFF;
291
0
    } else {
292
0
        if ((uint32_t)wc > 0xFFFF) {
293
0
            if ((wc & ~0xFFFF) != (_citrus_wc_t)HANYUBIT)
294
0
                goto ilseq;
295
0
            psenc->ch[psenc->chlen++] = (wc >> 24) & 0xFF;
296
0
            psenc->ch[psenc->chlen++] = (wc >> 16) & 0xFF;
297
0
            wc &= 0xFFFF;
298
0
        }
299
0
        ch = (wc >> 8) & 0xFF;
300
0
        if (!is_leadbyte(ch))
301
0
            goto ilseq;
302
0
        psenc->ch[psenc->chlen++] = (char) ch;
303
0
        ch = wc & 0xFF;
304
0
        if (!is_trailbyte(ch))
305
0
            goto ilseq;
306
0
    }
307
0
    psenc->ch[psenc->chlen++] = (char) ch;
308
0
    if (n < psenc->chlen) {
309
0
        *nresult = (size_t)-1;
310
0
        return (E2BIG);
311
0
    }
312
0
    memcpy(s, psenc->ch, psenc->chlen);
313
0
    *nresult = psenc->chlen;
314
0
    psenc->chlen = 0;
315
316
0
    return (0);
317
318
0
ilseq:
319
0
    *nresult = (size_t)-1;
320
0
    return (EILSEQ);
321
0
}
322
323
static __inline int
324
/*ARGSUSED*/
325
_citrus_DECHanyu_stdenc_wctocs(_DECHanyuEncodingInfo * ei ,
326
    _citrus_csid_t * csid, _citrus_index_t * idx, _citrus_wc_t wc)
327
0
{
328
0
    _citrus_wc_t mask;
329
0
    int plane;
330
0
    (void) ei;
331
332
0
    plane = 0;
333
0
    mask = 0x7F;
334
    /* XXX: assume _citrus_wc_t as int */
335
0
    if ((uint32_t)wc > 0x7F) {
336
0
        if ((uint32_t)wc > 0xFFFF) {
337
0
            if ((wc & ~0xFFFF) != (_citrus_wc_t)HANYUBIT)
338
0
                return (EILSEQ);
339
0
            plane += 2;
340
0
        }
341
0
        if (!is_leadbyte((wc >> 8) & 0xFF) ||
342
0
            !is_trailbyte(wc & 0xFF))
343
0
            return (EILSEQ);
344
0
        plane += (wc & 0x80) ? 1 : 2;
345
0
        mask |= 0x7F00;
346
0
    }
347
0
    *csid = plane;
348
0
    *idx = (_citrus_index_t)(wc & mask);
349
350
0
    return (0);
351
0
}
352
353
static __inline int
354
/*ARGSUSED*/
355
_citrus_DECHanyu_stdenc_cstowc(_DECHanyuEncodingInfo * ei ,
356
    _citrus_wc_t * wc, _citrus_csid_t csid, _citrus_index_t idx)
357
0
{
358
0
    (void) ei;
359
360
0
    if (csid == 0) {
361
0
        if (idx > 0x7F)
362
0
            return (EILSEQ);
363
0
    } else if (csid <= 4) {
364
0
        if (!is_94charset(idx >> 8))
365
0
            return (EILSEQ);
366
0
        if (!is_94charset(idx & 0xFF))
367
0
            return (EILSEQ);
368
0
        if (csid % 2)
369
0
            idx |= 0x80;
370
0
        idx |= 0x8000;
371
0
        if (csid > 2)
372
0
            idx |= HANYUBIT;
373
0
    } else
374
0
        return (EILSEQ);
375
0
    *wc = (_citrus_wc_t)idx;
376
0
    return (0);
377
0
}
378
379
static __inline int
380
/*ARGSUSED*/
381
_citrus_DECHanyu_stdenc_get_state_desc_generic(
382
    _DECHanyuEncodingInfo * ei ,
383
    _DECHanyuState * psenc, int * rstate)
384
0
{
385
0
    (void) ei;
386
387
0
    *rstate = (psenc->chlen == 0)
388
0
        ? _CITRUS_STDENC_SDGEN_INITIAL
389
0
        : _CITRUS_STDENC_SDGEN_INCOMPLETE_CHAR;
390
0
    return (0);
391
0
}
392
393
/* ----------------------------------------------------------------------
394
 * public interface for stdenc
395
 */
396
397
_CITRUS_STDENC_DECLS(DECHanyu);
398
_CITRUS_STDENC_DEF_OPS(DECHanyu);
399
400
#include "citrus_stdenc_template.h"