LCOV - code coverage report
Current view: top level - src/backend/utils/mb/conversion_procs/euc_tw_and_big5 - euc_tw_and_big5.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 159 276 57.6 %
Date: 2025-04-01 19:15:13 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14