Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * EUC_JP and SJIS
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_jp_and_sjis/euc_jp_and_sjis.c
10 : *
11 : *-------------------------------------------------------------------------
12 : */
13 :
14 : #include "postgres.h"
15 : #include "fmgr.h"
16 : #include "mb/pg_wchar.h"
17 :
18 : /*
19 : * SJIS alternative code.
20 : * this code is used if a mapping EUC -> SJIS is not defined.
21 : */
22 : #define PGSJISALTCODE 0x81ac
23 : #define PGEUCALTCODE 0xa2ae
24 :
25 : /*
26 : * conversion table between SJIS UDC (IBM kanji) and EUC_JP
27 : */
28 : #include "sjis.map"
29 :
30 4 : PG_MODULE_MAGIC_EXT(
31 : .name = "euc_jp_and_sjis",
32 : .version = PG_VERSION
33 : );
34 :
35 4 : PG_FUNCTION_INFO_V1(euc_jp_to_sjis);
36 4 : PG_FUNCTION_INFO_V1(sjis_to_euc_jp);
37 :
38 : /* ----------
39 : * conv_proc(
40 : * INTEGER, -- source encoding id
41 : * INTEGER, -- destination encoding id
42 : * CSTRING, -- source string (null terminated C string)
43 : * CSTRING, -- destination string (null terminated C string)
44 : * INTEGER, -- source string length
45 : * BOOL -- if true, don't throw an error if conversion fails
46 : * ) returns INTEGER;
47 : *
48 : * Returns the number of bytes successfully converted.
49 : * ----------
50 : */
51 :
52 : static int euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len, bool noError);
53 : static int sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len, bool noError);
54 :
55 : Datum
56 4 : euc_jp_to_sjis(PG_FUNCTION_ARGS)
57 : {
58 4 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
59 4 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
60 4 : int len = PG_GETARG_INT32(4);
61 4 : bool noError = PG_GETARG_BOOL(5);
62 : int converted;
63 :
64 4 : CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_JP, PG_SJIS);
65 :
66 4 : converted = euc_jp2sjis(src, dest, len, noError);
67 :
68 4 : PG_RETURN_INT32(converted);
69 : }
70 :
71 : Datum
72 4 : sjis_to_euc_jp(PG_FUNCTION_ARGS)
73 : {
74 4 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
75 4 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
76 4 : int len = PG_GETARG_INT32(4);
77 4 : bool noError = PG_GETARG_BOOL(5);
78 : int converted;
79 :
80 4 : CHECK_ENCODING_CONVERSION_ARGS(PG_SJIS, PG_EUC_JP);
81 :
82 4 : converted = sjis2euc_jp(src, dest, len, noError);
83 :
84 4 : PG_RETURN_INT32(converted);
85 : }
86 :
87 : /*
88 : * EUC_JP -> SJIS
89 : */
90 : static int
91 4 : euc_jp2sjis(const unsigned char *euc, unsigned char *p, int len, bool noError)
92 : {
93 4 : const unsigned char *start = euc;
94 : int c1,
95 : c2,
96 : k;
97 : int l;
98 :
99 16 : while (len > 0)
100 : {
101 12 : c1 = *euc;
102 12 : if (!IS_HIGHBIT_SET(c1))
103 : {
104 : /* ASCII */
105 12 : if (c1 == 0)
106 : {
107 0 : if (noError)
108 0 : break;
109 0 : report_invalid_encoding(PG_EUC_JP,
110 : (const char *) euc, len);
111 : }
112 12 : *p++ = c1;
113 12 : euc++;
114 12 : len--;
115 12 : continue;
116 : }
117 0 : l = pg_encoding_verifymbchar(PG_EUC_JP, (const char *) euc, len);
118 0 : if (l < 0)
119 : {
120 0 : if (noError)
121 0 : break;
122 0 : report_invalid_encoding(PG_EUC_JP,
123 : (const char *) euc, len);
124 : }
125 0 : if (c1 == SS2)
126 : {
127 : /* hankaku kana? */
128 0 : *p++ = euc[1];
129 : }
130 0 : else if (c1 == SS3)
131 : {
132 : /* JIS X0212 kanji? */
133 0 : c1 = euc[1];
134 0 : c2 = euc[2];
135 0 : k = c1 << 8 | c2;
136 0 : if (k >= 0xf5a1)
137 : {
138 : /* UDC2 */
139 0 : c1 -= 0x54;
140 0 : *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x74;
141 0 : *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
142 : }
143 : else
144 : {
145 : int i,
146 : k2;
147 :
148 : /* IBM kanji */
149 0 : for (i = 0;; i++)
150 : {
151 0 : k2 = ibmkanji[i].euc & 0xffff;
152 0 : if (k2 == 0xffff)
153 : {
154 0 : *p++ = PGSJISALTCODE >> 8;
155 0 : *p++ = PGSJISALTCODE & 0xff;
156 0 : break;
157 : }
158 0 : if (k2 == k)
159 : {
160 0 : k = ibmkanji[i].sjis;
161 0 : *p++ = k >> 8;
162 0 : *p++ = k & 0xff;
163 0 : break;
164 : }
165 : }
166 : }
167 : }
168 : else
169 : {
170 : /* JIS X0208 kanji? */
171 0 : c2 = euc[1];
172 0 : k = (c1 << 8) | (c2 & 0xff);
173 0 : if (k >= 0xf5a1)
174 : {
175 : /* UDC1 */
176 0 : c1 -= 0x54;
177 0 : *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1) + 0x6f;
178 : }
179 : else
180 0 : *p++ = ((c1 - 0xa1) >> 1) + ((c1 < 0xdf) ? 0x81 : 0xc1);
181 0 : *p++ = c2 - ((c1 & 1) ? ((c2 < 0xe0) ? 0x61 : 0x60) : 2);
182 : }
183 0 : euc += l;
184 0 : len -= l;
185 : }
186 4 : *p = '\0';
187 :
188 4 : return euc - start;
189 : }
190 :
191 : /*
192 : * SJIS ---> EUC_JP
193 : */
194 : static int
195 4 : sjis2euc_jp(const unsigned char *sjis, unsigned char *p, int len, bool noError)
196 : {
197 4 : const unsigned char *start = sjis;
198 : int c1,
199 : c2,
200 : i,
201 : k,
202 : k2;
203 : int l;
204 :
205 16 : while (len > 0)
206 : {
207 12 : c1 = *sjis;
208 12 : if (!IS_HIGHBIT_SET(c1))
209 : {
210 : /* ASCII */
211 12 : if (c1 == 0)
212 : {
213 0 : if (noError)
214 0 : break;
215 0 : report_invalid_encoding(PG_SJIS,
216 : (const char *) sjis, len);
217 : }
218 12 : *p++ = c1;
219 12 : sjis++;
220 12 : len--;
221 12 : continue;
222 : }
223 0 : l = pg_encoding_verifymbchar(PG_SJIS, (const char *) sjis, len);
224 0 : if (l < 0)
225 : {
226 0 : if (noError)
227 0 : break;
228 0 : report_invalid_encoding(PG_SJIS,
229 : (const char *) sjis, len);
230 : }
231 0 : if (c1 >= 0xa1 && c1 <= 0xdf)
232 : {
233 : /* JIS X0201 (1 byte kana) */
234 0 : *p++ = SS2;
235 0 : *p++ = c1;
236 : }
237 : else
238 : {
239 : /*
240 : * JIS X0208, X0212, user defined extended characters
241 : */
242 0 : c2 = sjis[1];
243 0 : k = (c1 << 8) + c2;
244 0 : if (k >= 0xed40 && k < 0xf040)
245 : {
246 : /* NEC selection IBM kanji */
247 0 : for (i = 0;; i++)
248 : {
249 0 : k2 = ibmkanji[i].nec;
250 0 : if (k2 == 0xffff)
251 0 : break;
252 0 : if (k2 == k)
253 : {
254 0 : k = ibmkanji[i].sjis;
255 0 : c1 = (k >> 8) & 0xff;
256 0 : c2 = k & 0xff;
257 : }
258 : }
259 : }
260 :
261 0 : if (k < 0xeb3f)
262 : {
263 : /* JIS X0208 */
264 0 : *p++ = ((c1 & 0x3f) << 1) + 0x9f + (c2 > 0x9e);
265 0 : *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
266 : }
267 0 : else if ((k >= 0xeb40 && k < 0xf040) || (k >= 0xfc4c && k <= 0xfcfc))
268 : {
269 : /* NEC selection IBM kanji - Other undecided justice */
270 0 : *p++ = PGEUCALTCODE >> 8;
271 0 : *p++ = PGEUCALTCODE & 0xff;
272 : }
273 0 : else if (k >= 0xf040 && k < 0xf540)
274 : {
275 : /*
276 : * UDC1 mapping to X0208 85 ku - 94 ku JIS code 0x7521 -
277 : * 0x7e7e EUC 0xf5a1 - 0xfefe
278 : */
279 0 : c1 -= 0x6f;
280 0 : *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
281 0 : *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
282 : }
283 0 : else if (k >= 0xf540 && k < 0xfa40)
284 : {
285 : /*
286 : * UDC2 mapping to X0212 85 ku - 94 ku JIS code 0x7521 -
287 : * 0x7e7e EUC 0x8ff5a1 - 0x8ffefe
288 : */
289 0 : *p++ = SS3;
290 0 : c1 -= 0x74;
291 0 : *p++ = ((c1 & 0x3f) << 1) + 0xf3 + (c2 > 0x9e);
292 0 : *p++ = c2 + ((c2 > 0x9e) ? 2 : 0x60) + (c2 < 0x80);
293 : }
294 0 : else if (k >= 0xfa40)
295 : {
296 : /*
297 : * mapping IBM kanji to X0208 and X0212
298 : *
299 : */
300 0 : for (i = 0;; i++)
301 : {
302 0 : k2 = ibmkanji[i].sjis;
303 0 : if (k2 == 0xffff)
304 0 : break;
305 0 : if (k2 == k)
306 : {
307 0 : k = ibmkanji[i].euc;
308 0 : if (k >= 0x8f0000)
309 : {
310 0 : *p++ = SS3;
311 0 : *p++ = 0x80 | ((k & 0xff00) >> 8);
312 0 : *p++ = 0x80 | (k & 0xff);
313 : }
314 : else
315 : {
316 0 : *p++ = 0x80 | (k >> 8);
317 0 : *p++ = 0x80 | (k & 0xff);
318 : }
319 : }
320 : }
321 : }
322 : }
323 0 : sjis += l;
324 0 : len -= l;
325 : }
326 4 : *p = '\0';
327 :
328 4 : return sjis - start;
329 : }
|