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