Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * EUC_TW and BIG5
4 : *
5 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
6 : * Portions Copyright (c) 1994, Regents of the University of California
7 : *
8 : * IDENTIFICATION
9 : * src/backend/utils/mb/conversion_procs/euc_tw_and_big5/euc_tw_and_big5.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 :
14 : #include "postgres.h"
15 : #include "fmgr.h"
16 : #include "mb/pg_wchar.h"
17 :
18 4 : PG_MODULE_MAGIC_EXT(
19 : .name = "euc_tw_and_big5",
20 : .version = PG_VERSION
21 : );
22 :
23 4 : PG_FUNCTION_INFO_V1(euc_tw_to_big5);
24 4 : PG_FUNCTION_INFO_V1(big5_to_euc_tw);
25 :
26 : /* ----------
27 : * conv_proc(
28 : * INTEGER, -- source encoding id
29 : * INTEGER, -- destination encoding id
30 : * CSTRING, -- source string (null terminated C string)
31 : * CSTRING, -- destination string (null terminated C string)
32 : * INTEGER, -- source string length
33 : * BOOL -- if true, don't throw an error if conversion fails
34 : * ) returns INTEGER;
35 : *
36 : * Returns the number of bytes successfully converted.
37 : * ----------
38 : */
39 :
40 : static int euc_tw2big5(const unsigned char *euc, unsigned char *p, int len, bool noError);
41 : static int big52euc_tw(const unsigned char *big5, unsigned char *p, int len, bool noError);
42 :
43 : Datum
44 4 : euc_tw_to_big5(PG_FUNCTION_ARGS)
45 : {
46 4 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
47 4 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
48 4 : int len = PG_GETARG_INT32(4);
49 4 : bool noError = PG_GETARG_BOOL(5);
50 : int converted;
51 :
52 4 : CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_TW, PG_BIG5);
53 :
54 4 : converted = euc_tw2big5(src, dest, len, noError);
55 :
56 4 : PG_RETURN_INT32(converted);
57 : }
58 :
59 : Datum
60 4 : big5_to_euc_tw(PG_FUNCTION_ARGS)
61 : {
62 4 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
63 4 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
64 4 : int len = PG_GETARG_INT32(4);
65 4 : bool noError = PG_GETARG_BOOL(5);
66 : int converted;
67 :
68 4 : CHECK_ENCODING_CONVERSION_ARGS(PG_BIG5, PG_EUC_TW);
69 :
70 4 : converted = big52euc_tw(src, dest, len, noError);
71 :
72 4 : PG_RETURN_INT32(converted);
73 : }
74 :
75 : static int
76 4 : euc_tw2big5(const unsigned char *euc, unsigned char *p, int len, bool noError)
77 : {
78 4 : const unsigned char *start = euc;
79 : unsigned char c1;
80 : unsigned short big5buf,
81 : cnsBuf;
82 : unsigned char lc;
83 : int l;
84 :
85 16 : while (len > 0)
86 : {
87 12 : c1 = *euc;
88 12 : if (IS_HIGHBIT_SET(c1))
89 : {
90 : /* Verify and decode the next EUC_TW input character */
91 0 : l = pg_encoding_verifymbchar(PG_EUC_TW, (const char *) euc, len);
92 0 : if (l < 0)
93 : {
94 0 : if (noError)
95 0 : break;
96 0 : report_invalid_encoding(PG_EUC_TW,
97 : (const char *) euc, len);
98 : }
99 0 : if (c1 == SS2)
100 : {
101 0 : c1 = euc[1]; /* plane No. */
102 0 : if (c1 == 0xa1)
103 0 : lc = LC_CNS11643_1;
104 0 : else if (c1 == 0xa2)
105 0 : lc = LC_CNS11643_2;
106 : else
107 0 : lc = c1 - 0xa3 + LC_CNS11643_3;
108 0 : cnsBuf = (euc[2] << 8) | euc[3];
109 : }
110 : else
111 : { /* CNS11643-1 */
112 0 : lc = LC_CNS11643_1;
113 0 : cnsBuf = (c1 << 8) | euc[1];
114 : }
115 :
116 : /* Write it out in Big5 */
117 0 : big5buf = CNStoBIG5(cnsBuf, lc);
118 0 : if (big5buf == 0)
119 : {
120 0 : if (noError)
121 0 : break;
122 0 : report_untranslatable_char(PG_EUC_TW, PG_BIG5,
123 : (const char *) euc, len);
124 : }
125 0 : *p++ = (big5buf >> 8) & 0x00ff;
126 0 : *p++ = big5buf & 0x00ff;
127 :
128 0 : euc += l;
129 0 : len -= l;
130 : }
131 : else
132 : { /* should be ASCII */
133 12 : if (c1 == 0)
134 : {
135 0 : if (noError)
136 0 : break;
137 0 : report_invalid_encoding(PG_EUC_TW,
138 : (const char *) euc, len);
139 : }
140 12 : *p++ = c1;
141 12 : euc++;
142 12 : len--;
143 : }
144 : }
145 4 : *p = '\0';
146 :
147 4 : return euc - start;
148 : }
149 :
150 : /*
151 : * Big5 ---> EUC_TW
152 : */
153 : static int
154 4 : big52euc_tw(const unsigned char *big5, unsigned char *p, int len, bool noError)
155 : {
156 4 : const unsigned char *start = big5;
157 : unsigned short c1;
158 : unsigned short big5buf,
159 : cnsBuf;
160 : unsigned char lc;
161 : int l;
162 :
163 16 : while (len > 0)
164 : {
165 : /* Verify and decode the next Big5 input character */
166 12 : c1 = *big5;
167 12 : if (IS_HIGHBIT_SET(c1))
168 : {
169 0 : l = pg_encoding_verifymbchar(PG_BIG5, (const char *) big5, len);
170 0 : if (l < 0)
171 : {
172 0 : if (noError)
173 0 : break;
174 0 : report_invalid_encoding(PG_BIG5,
175 : (const char *) big5, len);
176 : }
177 0 : big5buf = (c1 << 8) | big5[1];
178 0 : cnsBuf = BIG5toCNS(big5buf, &lc);
179 :
180 0 : if (lc == LC_CNS11643_1)
181 : {
182 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
183 0 : *p++ = cnsBuf & 0x00ff;
184 : }
185 0 : else if (lc == LC_CNS11643_2)
186 : {
187 0 : *p++ = SS2;
188 0 : *p++ = 0xa2;
189 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
190 0 : *p++ = cnsBuf & 0x00ff;
191 : }
192 0 : else if (lc >= LC_CNS11643_3 && lc <= LC_CNS11643_7)
193 : {
194 0 : *p++ = SS2;
195 0 : *p++ = lc - LC_CNS11643_3 + 0xa3;
196 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
197 0 : *p++ = cnsBuf & 0x00ff;
198 : }
199 : else
200 : {
201 0 : if (noError)
202 0 : break;
203 0 : report_untranslatable_char(PG_BIG5, PG_EUC_TW,
204 : (const char *) big5, len);
205 : }
206 :
207 0 : big5 += l;
208 0 : len -= l;
209 : }
210 : else
211 : {
212 : /* ASCII */
213 12 : if (c1 == 0)
214 : {
215 0 : if (noError)
216 0 : break;
217 0 : report_invalid_encoding(PG_BIG5,
218 : (const char *) big5, len);
219 : }
220 12 : *p++ = c1;
221 12 : big5++;
222 12 : len--;
223 12 : continue;
224 : }
225 : }
226 4 : *p = '\0';
227 :
228 4 : return big5 - start;
229 : }
|