summaryrefslogtreecommitdiff
path: root/tableconverter.c
blob: ffff8cfbd3701f2dfec08c8da93488ccc9ff7552 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "uniconv.h"
#include "converter.h"
#include "multibytecodec.h"
#include "singlebytecodec.h"

#include <stdlib.h>
#include <string.h>

struct tabconverter {
    struct converter base;

    MultibyteCodecState mstate;
    SingleByteCodecState sstate;
    int singlebyte;
};

static void
tabconverter_close(struct converter *uc)
{
    free(uc);
}


static int
tabconverter_encode(struct converter *suc,
		    const uc_char_t **inbuf,
		    size_t inleft,
		    char **outbuf,
		    size_t outbytesleft)
{
    struct tabconverter *uc = (struct tabconverter*)suc;
    int ret;

    if (uc->singlebyte) {
	/* flush */
	if (!inbuf)
	    return UNICONV_SUCCESS;

	ret = sbcs_encode(&uc->sstate, inbuf, inleft, outbuf, outbytesleft);
    } else {
	/* flush */
	if (!inbuf)
	    ret = mbcs_encode_reset(&uc->mstate, outbuf, outbytesleft);
	else
	    ret = mbcs_encode(&uc->mstate, inbuf, inleft, outbuf, outbytesleft, 0);
	if (ret == MBERR_TOOFEW)
	    ret = UNICONV_EINVAL;
	else if (ret == MBERR_TOOSMALL)
	    ret = UNICONV_E2BIG;
	else if (ret < 0 || ret > 0)
	    ret = UNICONV_EILSEQ;
    }

    return ret;
}

static int
tabconverter_decode(struct converter *suc,
		    const char **inbuf,
		    size_t inbytesleft,
		    uc_char_t **outbuf,
		    size_t outleft)
{
    struct tabconverter *uc = (struct tabconverter*)suc;
    int ret;

    if (uc->singlebyte) {
	ret = sbcs_decode(&uc->sstate, inbuf, inbytesleft, outbuf, outleft);
    } else {
	ret = mbcs_decode(&uc->mstate, inbuf, inbytesleft, outbuf, outleft);
	if (ret == MBERR_TOOFEW)
	    ret = UNICONV_EINVAL;
	else if (ret == MBERR_TOOSMALL)
	    ret = UNICONV_E2BIG;
	else if (ret < 0 || ret > 0)
	    ret = UNICONV_EILSEQ;
    }

    return ret;
}

static void
tabconverter_reset(struct converter *suc)
{
    struct tabconverter *uc = (struct tabconverter *)suc;

    if (!uc->singlebyte) {
	mbcs_encode_init(&uc->mstate);
	mbcs_decode_init(&uc->mstate);
    }
}

struct converter*
tabconverter_open(const char *charset)
{
    struct tabconverter sconv, *conv;

    if (!sbcs_init(&sconv.sstate, charset)) {
	sconv.singlebyte = 1;
    } else {
	static const char* modules[] = {
	    "cn", "hk", "hz", "jp", "kr", "tw", NULL
	};
	size_t i;

	for (i = 0; modules[i]; i++)
	    if (!mbcs_init(&sconv.mstate, modules[i], charset))
		break;
	if (!modules[i])
	    return NULL;
	sconv.singlebyte = 0;
    }

    conv = malloc(sizeof(struct tabconverter));
    if (!conv)
	return NULL;
    *conv = sconv;
    conv->base.encode = tabconverter_encode;
    conv->base.decode = tabconverter_decode;
    conv->base.close = tabconverter_close;
    conv->base.reset = tabconverter_reset;
    return &conv->base;
}