Ignore:
Timestamp:
2012-02-03T02:28:14+01:00 (4 years ago)
Author:
jow
Message:

[packages] libiconv: implement UTF-8 encode/decode
Implement own UTF-8 encoding and decoding routines as uClibc's wchar procedures are mostly stubbed.
Add Latin9 (ISO-8859-15) decoding support while we're at it.

Location:
branches/packages_10.03.1/libs/libiconv
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/packages_10.03.1/libs/libiconv/Makefile

    r26775 r30005  
    11# 
    2 # Copyright (C) 2010-2011 OpenWrt.org 
     2# Copyright (C) 2010-2012 OpenWrt.org 
    33# 
    44# This Makefile and the code shipped in src/ is free software, licensed 
     
    1212 
    1313PKG_NAME:=libiconv 
    14 PKG_RELEASE:=5 
     14PKG_RELEASE:=6 
    1515 
    1616include $(INCLUDE_DIR)/package.mk 
  • branches/packages_10.03.1/libs/libiconv/src/iconv.c

    r26775 r30005  
    100100        int m; 
    101101 
    102         if ((t = find_charset(to)) >= 8) 
     102        if ((t = find_charset(to)) > 8) 
    103103                return -1; 
    104104 
    105105        if ((f = find_charset(from)) < 255) 
    106                 return 0 | (t<<1) | (f<<4); 
     106                return 0 | (t<<1) | (f<<8); 
    107107 
    108108        if ((m = find_charmap(from)) > -1) 
    109                 return 1 | (t<<1) | (m<<4); 
     109                return 1 | (t<<1) | (m<<8); 
    110110 
    111111        return -1; 
     
    130130} 
    131131 
     132static inline int utf8enc_wchar(char *outb, wchar_t c) 
     133{ 
     134        if (c <= 0x7F) { 
     135                *outb = c; 
     136                return 1; 
     137        } 
     138        else if (c <= 0x7FF) { 
     139                *outb++ = ((c >>  6) & 0x1F) | 0xC0; 
     140                *outb++ = ( c        & 0x3F) | 0x80; 
     141                return 2; 
     142        } 
     143        else if (c <= 0xFFFF) { 
     144                *outb++ = ((c >> 12) & 0x0F) | 0xE0; 
     145                *outb++ = ((c >>  6) & 0x3F) | 0x80; 
     146                *outb++ = ( c        & 0x3F) | 0x80; 
     147                return 3; 
     148        } 
     149        else if (c <= 0x10FFFF) { 
     150                *outb++ = ((c >> 18) & 0x07) | 0xF0; 
     151                *outb++ = ((c >> 12) & 0x3F) | 0x80; 
     152                *outb++ = ((c >>  6) & 0x3F) | 0x80; 
     153                *outb++ = ( c        & 0x3F) | 0x80; 
     154                return 4; 
     155        } 
     156        else { 
     157                *outb++ = '?'; 
     158                return 1; 
     159        } 
     160} 
     161 
     162static inline int utf8seq_is_overlong(char *s, int n) 
     163{ 
     164        switch (n) 
     165        { 
     166        case 2: 
     167                /* 1100000x (10xxxxxx) */ 
     168                return (((*s >> 1) == 0x60) && 
     169                                ((*(s+1) >> 6) == 0x02)); 
     170 
     171        case 3: 
     172                /* 11100000 100xxxxx (10xxxxxx) */ 
     173                return ((*s == 0xE0) && 
     174                                ((*(s+1) >> 5) == 0x04) && 
     175                                ((*(s+2) >> 6) == 0x02)); 
     176 
     177        case 4: 
     178                /* 11110000 1000xxxx (10xxxxxx 10xxxxxx) */ 
     179                return ((*s == 0xF0) && 
     180                                ((*(s+1) >> 4) == 0x08) && 
     181                                ((*(s+2) >> 6) == 0x02) && 
     182                                ((*(s+3) >> 6) == 0x02)); 
     183        } 
     184 
     185        return 0; 
     186} 
     187 
     188static inline int utf8seq_is_surrogate(char *s, int n) 
     189{ 
     190        return ((n == 3) && (*s == 0xED) && (*(s+1) >= 0xA0) && (*(s+1) <= 0xBF)); 
     191} 
     192 
     193static inline int utf8seq_is_illegal(char *s, int n) 
     194{ 
     195        return ((n == 3) && (*s == 0xEF) && (*(s+1) == 0xBF) && 
     196                (*(s+2) >= 0xBE) && (*(s+2) <= 0xBF)); 
     197} 
     198 
     199static inline int utf8dec_wchar(wchar_t *c, unsigned char *in, size_t inb) 
     200{ 
     201        int i; 
     202        int n = -1; 
     203 
     204        /* trivial char */ 
     205        if (*in <= 0x7F) { 
     206                *c = *in; 
     207                return 1; 
     208        } 
     209 
     210        /* find utf8 sequence length */ 
     211        if      ((*in & 0xE0) == 0xC0) n = 2; 
     212        else if ((*in & 0xF0) == 0xE0) n = 3; 
     213        else if ((*in & 0xF8) == 0xF0) n = 4; 
     214        else if ((*in & 0xFC) == 0xF8) n = 5; 
     215        else if ((*in & 0xFE) == 0xFC) n = 6; 
     216 
     217        /* starved? */ 
     218        if (n > inb) 
     219                return -2; 
     220 
     221        /* decode ... */ 
     222        if (n > 1 && n < 5) { 
     223                /* reject invalid sequences */ 
     224                if (utf8seq_is_overlong(in, n) || 
     225                        utf8seq_is_surrogate(in, n) || 
     226                        utf8seq_is_illegal(in, n)) 
     227                        return -1; 
     228 
     229                /* decode ... */ 
     230                *c = (char)(*in++ & (0x7F >> n)); 
     231 
     232                for (i = 1; i < n; i++) { 
     233                        /* illegal continuation byte */ 
     234                        if (*in < 0x80 || *in > 0xBF) 
     235                                return -1; 
     236 
     237                        *c = (*c << 6) | (*in++ & 0x3F); 
     238                } 
     239 
     240                return n; 
     241        } 
     242 
     243        /* unmapped sequence (> 4) */ 
     244        return -1; 
     245} 
     246 
     247static inline char latin9_translit(wchar_t c) 
     248{ 
     249        /* a number of trivial iso-8859-15 <> utf-8 transliterations */ 
     250        switch (c) { 
     251        case 0x20AC: return 0xA4; /* Euro */ 
     252        case 0x0160: return 0xA6; /* S caron */ 
     253        case 0x0161: return 0xA8; /* s caron */ 
     254        case 0x017D: return 0xB4; /* Z caron */ 
     255        case 0x017E: return 0xB8; /* z caron */ 
     256        case 0x0152: return 0xBC; /* OE */ 
     257        case 0x0153: return 0xBD; /* oe */ 
     258        case 0x0178: return 0xBE; /* Y diaeresis */ 
     259        default:     return '?'; 
     260        } 
     261} 
     262 
    132263size_t iconv(iconv_t cd, char **in, size_t *inb, char **out, size_t *outb) 
    133264{ 
    134265        size_t x=0; 
    135         unsigned char to = (cd>>1)&7; 
     266        unsigned char to = (cd>>1)&127; 
    136267        unsigned char from = 255; 
    137268        const unsigned char *map = 0; 
    138         mbstate_t st = {0}; 
    139269        char tmp[MB_LEN_MAX]; 
    140270        wchar_t c, d; 
     
    145275 
    146276        if (cd & 1) 
    147                 map = charmaps[cd>>4].map; 
     277                map = charmaps[cd>>8].map; 
    148278        else 
    149                 from = cd>>4; 
     279                from = cd>>8; 
    150280 
    151281        for (; *inb; *in+=l, *inb-=l) { 
     
    160290                        break; 
    161291                case UTF_8: 
    162                         l = mbrtowc(&c, *in, *inb, &st); 
     292                        l = utf8dec_wchar(&c, *in, *inb); 
    163293                        if (!l) l++; 
    164294                        else if (l == (size_t)-1) goto ilseq; 
     
    250380                case UTF_8: 
    251381                        if (*outb < 4) { 
    252                                 k = wctomb(tmp, c); 
     382                                k = utf8enc_wchar(tmp, c); 
    253383                                if (*outb < k) goto toobig; 
    254384                                memcpy(*out, tmp, k); 
    255                         } else k = wctomb(*out, c); 
     385                        } else k = utf8enc_wchar(*out, c); 
    256386                        *out += k; 
    257387                        *outb -= k; 
     
    260390                        if (c > 0x7f) c = 0xfffd; 
    261391                        /* fall thru and count replacement in latin1 case */ 
     392                case LATIN_9: 
     393                        if (c >= 0x100 && c != 0xfffd) 
     394                                c = latin9_translit(c); 
     395                        /* fall through */ 
    262396                case LATIN_1: 
    263397                        if (!*outb) goto toobig; 
Note: See TracChangeset for help on using the changeset viewer.