Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * EUC_TW, BIG5 and MULE_INTERNAL
4 : *
5 : * Portions Copyright (c) 1996-2025, 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 12 : PG_MODULE_MAGIC_EXT(
19 : .name = "euc_tw_and_big5",
20 : .version = PG_VERSION
21 : );
22 :
23 6 : PG_FUNCTION_INFO_V1(euc_tw_to_big5);
24 6 : PG_FUNCTION_INFO_V1(big5_to_euc_tw);
25 6 : PG_FUNCTION_INFO_V1(euc_tw_to_mic);
26 6 : PG_FUNCTION_INFO_V1(mic_to_euc_tw);
27 12 : PG_FUNCTION_INFO_V1(big5_to_mic);
28 12 : PG_FUNCTION_INFO_V1(mic_to_big5);
29 :
30 : /* ----------
31 : * conv_proc(
32 : * INTEGER, -- source encoding id
33 : * INTEGER, -- destination encoding id
34 : * CSTRING, -- source string (null terminated C string)
35 : * CSTRING, -- destination string (null terminated C string)
36 : * INTEGER, -- source string length
37 : * BOOL -- if true, don't throw an error if conversion fails
38 : * ) returns INTEGER;
39 : *
40 : * Returns the number of bytes successfully converted.
41 : * ----------
42 : */
43 :
44 : static int euc_tw2big5(const unsigned char *euc, unsigned char *p, int len, bool noError);
45 : static int big52euc_tw(const unsigned char *big5, unsigned char *p, int len, bool noError);
46 : static int big52mic(const unsigned char *big5, unsigned char *p, int len, bool noError);
47 : static int mic2big5(const unsigned char *mic, unsigned char *p, int len, bool noError);
48 : static int euc_tw2mic(const unsigned char *euc, unsigned char *p, int len, bool noError);
49 : static int mic2euc_tw(const unsigned char *mic, unsigned char *p, int len, bool noError);
50 :
51 : Datum
52 6 : euc_tw_to_big5(PG_FUNCTION_ARGS)
53 : {
54 6 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
55 6 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
56 6 : int len = PG_GETARG_INT32(4);
57 6 : bool noError = PG_GETARG_BOOL(5);
58 : int converted;
59 :
60 6 : CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_TW, PG_BIG5);
61 :
62 6 : converted = euc_tw2big5(src, dest, len, noError);
63 :
64 6 : PG_RETURN_INT32(converted);
65 : }
66 :
67 : Datum
68 6 : big5_to_euc_tw(PG_FUNCTION_ARGS)
69 : {
70 6 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
71 6 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
72 6 : int len = PG_GETARG_INT32(4);
73 6 : bool noError = PG_GETARG_BOOL(5);
74 : int converted;
75 :
76 6 : CHECK_ENCODING_CONVERSION_ARGS(PG_BIG5, PG_EUC_TW);
77 :
78 6 : converted = big52euc_tw(src, dest, len, noError);
79 :
80 6 : PG_RETURN_INT32(converted);
81 : }
82 :
83 : Datum
84 6 : euc_tw_to_mic(PG_FUNCTION_ARGS)
85 : {
86 6 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
87 6 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
88 6 : int len = PG_GETARG_INT32(4);
89 6 : bool noError = PG_GETARG_BOOL(5);
90 : int converted;
91 :
92 6 : CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_TW, PG_MULE_INTERNAL);
93 :
94 6 : converted = euc_tw2mic(src, dest, len, noError);
95 :
96 6 : PG_RETURN_INT32(converted);
97 : }
98 :
99 : Datum
100 6 : mic_to_euc_tw(PG_FUNCTION_ARGS)
101 : {
102 6 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
103 6 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
104 6 : int len = PG_GETARG_INT32(4);
105 6 : bool noError = PG_GETARG_BOOL(5);
106 : int converted;
107 :
108 6 : CHECK_ENCODING_CONVERSION_ARGS(PG_MULE_INTERNAL, PG_EUC_TW);
109 :
110 6 : converted = mic2euc_tw(src, dest, len, noError);
111 :
112 6 : PG_RETURN_INT32(converted);
113 : }
114 :
115 : Datum
116 132 : big5_to_mic(PG_FUNCTION_ARGS)
117 : {
118 132 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
119 132 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
120 132 : int len = PG_GETARG_INT32(4);
121 132 : bool noError = PG_GETARG_BOOL(5);
122 : int converted;
123 :
124 132 : CHECK_ENCODING_CONVERSION_ARGS(PG_BIG5, PG_MULE_INTERNAL);
125 :
126 132 : converted = big52mic(src, dest, len, noError);
127 :
128 96 : PG_RETURN_INT32(converted);
129 : }
130 :
131 : Datum
132 330 : mic_to_big5(PG_FUNCTION_ARGS)
133 : {
134 330 : unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2);
135 330 : unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3);
136 330 : int len = PG_GETARG_INT32(4);
137 330 : bool noError = PG_GETARG_BOOL(5);
138 : int converted;
139 :
140 330 : CHECK_ENCODING_CONVERSION_ARGS(PG_MULE_INTERNAL, PG_BIG5);
141 :
142 330 : converted = mic2big5(src, dest, len, noError);
143 :
144 186 : PG_RETURN_INT32(converted);
145 : }
146 :
147 :
148 : /*
149 : * EUC_TW ---> Big5
150 : */
151 : static int
152 6 : euc_tw2big5(const unsigned char *euc, unsigned char *p, int len, bool noError)
153 : {
154 6 : const unsigned char *start = euc;
155 : unsigned char c1;
156 : unsigned short big5buf,
157 : cnsBuf;
158 : unsigned char lc;
159 : int l;
160 :
161 24 : while (len > 0)
162 : {
163 18 : c1 = *euc;
164 18 : if (IS_HIGHBIT_SET(c1))
165 : {
166 : /* Verify and decode the next EUC_TW input character */
167 0 : l = pg_encoding_verifymbchar(PG_EUC_TW, (const char *) euc, len);
168 0 : if (l < 0)
169 : {
170 0 : if (noError)
171 0 : break;
172 0 : report_invalid_encoding(PG_EUC_TW,
173 : (const char *) euc, len);
174 : }
175 0 : if (c1 == SS2)
176 : {
177 0 : c1 = euc[1]; /* plane No. */
178 0 : if (c1 == 0xa1)
179 0 : lc = LC_CNS11643_1;
180 0 : else if (c1 == 0xa2)
181 0 : lc = LC_CNS11643_2;
182 : else
183 0 : lc = c1 - 0xa3 + LC_CNS11643_3;
184 0 : cnsBuf = (euc[2] << 8) | euc[3];
185 : }
186 : else
187 : { /* CNS11643-1 */
188 0 : lc = LC_CNS11643_1;
189 0 : cnsBuf = (c1 << 8) | euc[1];
190 : }
191 :
192 : /* Write it out in Big5 */
193 0 : big5buf = CNStoBIG5(cnsBuf, lc);
194 0 : if (big5buf == 0)
195 : {
196 0 : if (noError)
197 0 : break;
198 0 : report_untranslatable_char(PG_EUC_TW, PG_BIG5,
199 : (const char *) euc, len);
200 : }
201 0 : *p++ = (big5buf >> 8) & 0x00ff;
202 0 : *p++ = big5buf & 0x00ff;
203 :
204 0 : euc += l;
205 0 : len -= l;
206 : }
207 : else
208 : { /* should be ASCII */
209 18 : if (c1 == 0)
210 : {
211 0 : if (noError)
212 0 : break;
213 0 : report_invalid_encoding(PG_EUC_TW,
214 : (const char *) euc, len);
215 : }
216 18 : *p++ = c1;
217 18 : euc++;
218 18 : len--;
219 : }
220 : }
221 6 : *p = '\0';
222 :
223 6 : return euc - start;
224 : }
225 :
226 : /*
227 : * Big5 ---> EUC_TW
228 : */
229 : static int
230 6 : big52euc_tw(const unsigned char *big5, unsigned char *p, int len, bool noError)
231 : {
232 6 : const unsigned char *start = big5;
233 : unsigned short c1;
234 : unsigned short big5buf,
235 : cnsBuf;
236 : unsigned char lc;
237 : int l;
238 :
239 24 : while (len > 0)
240 : {
241 : /* Verify and decode the next Big5 input character */
242 18 : c1 = *big5;
243 18 : if (IS_HIGHBIT_SET(c1))
244 : {
245 0 : l = pg_encoding_verifymbchar(PG_BIG5, (const char *) big5, len);
246 0 : if (l < 0)
247 : {
248 0 : if (noError)
249 0 : break;
250 0 : report_invalid_encoding(PG_BIG5,
251 : (const char *) big5, len);
252 : }
253 0 : big5buf = (c1 << 8) | big5[1];
254 0 : cnsBuf = BIG5toCNS(big5buf, &lc);
255 :
256 0 : if (lc == LC_CNS11643_1)
257 : {
258 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
259 0 : *p++ = cnsBuf & 0x00ff;
260 : }
261 0 : else if (lc == LC_CNS11643_2)
262 : {
263 0 : *p++ = SS2;
264 0 : *p++ = 0xa2;
265 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
266 0 : *p++ = cnsBuf & 0x00ff;
267 : }
268 0 : else if (lc >= LC_CNS11643_3 && lc <= LC_CNS11643_7)
269 : {
270 0 : *p++ = SS2;
271 0 : *p++ = lc - LC_CNS11643_3 + 0xa3;
272 0 : *p++ = (cnsBuf >> 8) & 0x00ff;
273 0 : *p++ = cnsBuf & 0x00ff;
274 : }
275 : else
276 : {
277 0 : if (noError)
278 0 : break;
279 0 : report_untranslatable_char(PG_BIG5, PG_EUC_TW,
280 : (const char *) big5, len);
281 : }
282 :
283 0 : big5 += l;
284 0 : len -= l;
285 : }
286 : else
287 : {
288 : /* ASCII */
289 18 : if (c1 == 0)
290 : {
291 0 : if (noError)
292 0 : break;
293 0 : report_invalid_encoding(PG_BIG5,
294 : (const char *) big5, len);
295 : }
296 18 : *p++ = c1;
297 18 : big5++;
298 18 : len--;
299 18 : continue;
300 : }
301 : }
302 6 : *p = '\0';
303 :
304 6 : return big5 - start;
305 : }
306 :
307 : /*
308 : * EUC_TW ---> MIC
309 : */
310 : static int
311 6 : euc_tw2mic(const unsigned char *euc, unsigned char *p, int len, bool noError)
312 : {
313 6 : const unsigned char *start = euc;
314 : int c1;
315 : int l;
316 :
317 24 : while (len > 0)
318 : {
319 18 : c1 = *euc;
320 18 : if (IS_HIGHBIT_SET(c1))
321 : {
322 0 : l = pg_encoding_verifymbchar(PG_EUC_TW, (const char *) euc, len);
323 0 : if (l < 0)
324 : {
325 0 : if (noError)
326 0 : break;
327 0 : report_invalid_encoding(PG_EUC_TW,
328 : (const char *) euc, len);
329 : }
330 0 : if (c1 == SS2)
331 : {
332 0 : c1 = euc[1]; /* plane No. */
333 0 : if (c1 == 0xa1)
334 0 : *p++ = LC_CNS11643_1;
335 0 : else if (c1 == 0xa2)
336 0 : *p++ = LC_CNS11643_2;
337 : else
338 : {
339 : /* other planes are MULE private charsets */
340 0 : *p++ = LCPRV2_B;
341 0 : *p++ = c1 - 0xa3 + LC_CNS11643_3;
342 : }
343 0 : *p++ = euc[2];
344 0 : *p++ = euc[3];
345 : }
346 : else
347 : { /* CNS11643-1 */
348 0 : *p++ = LC_CNS11643_1;
349 0 : *p++ = c1;
350 0 : *p++ = euc[1];
351 : }
352 0 : euc += l;
353 0 : len -= l;
354 : }
355 : else
356 : { /* should be ASCII */
357 18 : if (c1 == 0)
358 : {
359 0 : if (noError)
360 0 : break;
361 0 : report_invalid_encoding(PG_EUC_TW,
362 : (const char *) euc, len);
363 : }
364 18 : *p++ = c1;
365 18 : euc++;
366 18 : len--;
367 : }
368 : }
369 6 : *p = '\0';
370 :
371 6 : return euc - start;
372 : }
373 :
374 : /*
375 : * MIC ---> EUC_TW
376 : */
377 : static int
378 6 : mic2euc_tw(const unsigned char *mic, unsigned char *p, int len, bool noError)
379 : {
380 6 : const unsigned char *start = mic;
381 : int c1;
382 : int l;
383 :
384 24 : while (len > 0)
385 : {
386 18 : c1 = *mic;
387 18 : if (!IS_HIGHBIT_SET(c1))
388 : {
389 : /* ASCII */
390 18 : if (c1 == 0)
391 : {
392 0 : if (noError)
393 0 : break;
394 0 : report_invalid_encoding(PG_MULE_INTERNAL,
395 : (const char *) mic, len);
396 : }
397 18 : *p++ = c1;
398 18 : mic++;
399 18 : len--;
400 18 : continue;
401 : }
402 0 : l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len);
403 0 : if (l < 0)
404 : {
405 0 : if (noError)
406 0 : break;
407 0 : report_invalid_encoding(PG_MULE_INTERNAL,
408 : (const char *) mic, len);
409 : }
410 0 : if (c1 == LC_CNS11643_1)
411 : {
412 0 : *p++ = mic[1];
413 0 : *p++ = mic[2];
414 : }
415 0 : else if (c1 == LC_CNS11643_2)
416 : {
417 0 : *p++ = SS2;
418 0 : *p++ = 0xa2;
419 0 : *p++ = mic[1];
420 0 : *p++ = mic[2];
421 : }
422 0 : else if (c1 == LCPRV2_B &&
423 0 : mic[1] >= LC_CNS11643_3 && mic[1] <= LC_CNS11643_7)
424 : {
425 0 : *p++ = SS2;
426 0 : *p++ = mic[1] - LC_CNS11643_3 + 0xa3;
427 0 : *p++ = mic[2];
428 0 : *p++ = mic[3];
429 : }
430 : else
431 : {
432 0 : if (noError)
433 0 : break;
434 0 : report_untranslatable_char(PG_MULE_INTERNAL, PG_EUC_TW,
435 : (const char *) mic, len);
436 : }
437 0 : mic += l;
438 0 : len -= l;
439 : }
440 6 : *p = '\0';
441 :
442 6 : return mic - start;
443 : }
444 :
445 : /*
446 : * Big5 ---> MIC
447 : */
448 : static int
449 132 : big52mic(const unsigned char *big5, unsigned char *p, int len, bool noError)
450 : {
451 132 : const unsigned char *start = big5;
452 : unsigned short c1;
453 : unsigned short big5buf,
454 : cnsBuf;
455 : unsigned char lc;
456 : int l;
457 :
458 600 : while (len > 0)
459 : {
460 540 : c1 = *big5;
461 540 : if (!IS_HIGHBIT_SET(c1))
462 : {
463 : /* ASCII */
464 432 : if (c1 == 0)
465 : {
466 36 : if (noError)
467 18 : break;
468 18 : report_invalid_encoding(PG_BIG5,
469 : (const char *) big5, len);
470 : }
471 396 : *p++ = c1;
472 396 : big5++;
473 396 : len--;
474 396 : continue;
475 : }
476 108 : l = pg_encoding_verifymbchar(PG_BIG5, (const char *) big5, len);
477 108 : if (l < 0)
478 : {
479 36 : if (noError)
480 18 : break;
481 18 : report_invalid_encoding(PG_BIG5,
482 : (const char *) big5, len);
483 : }
484 72 : big5buf = (c1 << 8) | big5[1];
485 72 : cnsBuf = BIG5toCNS(big5buf, &lc);
486 72 : if (lc != 0)
487 : {
488 : /* Planes 3 and 4 are MULE private charsets */
489 72 : if (lc == LC_CNS11643_3 || lc == LC_CNS11643_4)
490 0 : *p++ = LCPRV2_B;
491 72 : *p++ = lc; /* Plane No. */
492 72 : *p++ = (cnsBuf >> 8) & 0x00ff;
493 72 : *p++ = cnsBuf & 0x00ff;
494 : }
495 : else
496 : {
497 0 : if (noError)
498 0 : break;
499 0 : report_untranslatable_char(PG_BIG5, PG_MULE_INTERNAL,
500 : (const char *) big5, len);
501 : }
502 72 : big5 += l;
503 72 : len -= l;
504 : }
505 96 : *p = '\0';
506 :
507 96 : return big5 - start;
508 : }
509 :
510 : /*
511 : * MIC ---> Big5
512 : */
513 : static int
514 330 : mic2big5(const unsigned char *mic, unsigned char *p, int len, bool noError)
515 : {
516 330 : const unsigned char *start = mic;
517 : unsigned short c1;
518 : unsigned short big5buf,
519 : cnsBuf;
520 : int l;
521 :
522 582 : while (len > 0)
523 : {
524 540 : c1 = *mic;
525 540 : if (!IS_HIGHBIT_SET(c1))
526 : {
527 : /* ASCII */
528 234 : if (c1 == 0)
529 : {
530 0 : if (noError)
531 0 : break;
532 0 : report_invalid_encoding(PG_MULE_INTERNAL,
533 : (const char *) mic, len);
534 : }
535 234 : *p++ = c1;
536 234 : mic++;
537 234 : len--;
538 234 : continue;
539 : }
540 306 : l = pg_encoding_verifymbchar(PG_MULE_INTERNAL, (const char *) mic, len);
541 306 : if (l < 0)
542 : {
543 144 : if (noError)
544 72 : break;
545 72 : report_invalid_encoding(PG_MULE_INTERNAL,
546 : (const char *) mic, len);
547 : }
548 162 : if (c1 == LC_CNS11643_1 || c1 == LC_CNS11643_2 || c1 == LCPRV2_B)
549 : {
550 18 : if (c1 == LCPRV2_B)
551 : {
552 0 : c1 = mic[1]; /* get plane no. */
553 0 : cnsBuf = (mic[2] << 8) | mic[3];
554 : }
555 : else
556 : {
557 18 : cnsBuf = (mic[1] << 8) | mic[2];
558 : }
559 18 : big5buf = CNStoBIG5(cnsBuf, c1);
560 18 : if (big5buf == 0)
561 : {
562 0 : if (noError)
563 0 : break;
564 0 : report_untranslatable_char(PG_MULE_INTERNAL, PG_BIG5,
565 : (const char *) mic, len);
566 : }
567 18 : *p++ = (big5buf >> 8) & 0x00ff;
568 18 : *p++ = big5buf & 0x00ff;
569 : }
570 : else
571 : {
572 144 : if (noError)
573 72 : break;
574 72 : report_untranslatable_char(PG_MULE_INTERNAL, PG_BIG5,
575 : (const char *) mic, len);
576 : }
577 18 : mic += l;
578 18 : len -= l;
579 : }
580 186 : *p = '\0';
581 :
582 186 : return mic - start;
583 : }
|