Branch data 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 : : }
|