Annotation of kernel/bsd/hfs/hfscommon/Unicode/ConvertUTF.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* ================================================================ */
                     26: /*
                     27: File:  ConvertUTF.c
                     28: Author: Mark E. Davis
                     29: Copyright (C) 1994 Taligent, Inc. All rights reserved.
                     30: 
                     31: This code is copyrighted. Under the copyright laws, this code may not
                     32: be copied, in whole or part, without prior written consent of Taligent. 
                     33: 
                     34: Taligent grants the right to use or reprint this code as long as this
                     35: ENTIRE copyright notice is reproduced in the code or reproduction.
                     36: The code is provided AS-IS, AND TALIGENT DISCLAIMS ALL WARRANTIES,
                     37: EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO IMPLIED
                     38: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
                     39: NO EVENT WILL TALIGENT BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING,
                     40: WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS
                     41: INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY
                     42: LOSS) ARISING OUT OF THE USE OR INABILITY TO USE THIS CODE, EVEN
                     43: IF TALIGENT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
                     44: BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF
                     45: LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE
                     46: LIMITATION MAY NOT APPLY TO YOU.
                     47: 
                     48: RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
                     49: government is subject to restrictions as set forth in subparagraph
                     50: (c)(l)(ii) of the Rights in Technical Data and Computer Software
                     51: clause at DFARS 252.227-7013 and FAR 52.227-19.
                     52: 
                     53: This code may be protected by one or more U.S. and International
                     54: Patents.
                     55: 
                     56: TRADEMARKS: Taligent and the Taligent Design Mark are registered
                     57: trademarks of Taligent, Inc.
                     58: 
                     59: HISTORY:
                     60: 
                     61:        22-Jan-1999     Don Brady               Add decomposition to ConvertUTF8toUTF16.
                     62:        17-Nov-1998     Don Brady               Add ":" to "/" conversions.
                     63: */
                     64: /* ================================================================ */
                     65: 
                     66: #include "ConvertUTF.h"
                     67: 
                     68: /* ================================================================ */
                     69: 
                     70: const int halfShift                            = 10;
                     71: const UCS4 halfBase                            = 0x0010000UL;
                     72: const UCS4 halfMask                            = 0x3FFUL;
                     73: const UCS4 kSurrogateHighStart = 0xD800UL;
                     74: const UCS4 kSurrogateHighEnd   = 0xDBFFUL;
                     75: const UCS4 kSurrogateLowStart  = 0xDC00UL;
                     76: const UCS4 kSurrogateLowEnd            = 0xDFFFUL;
                     77: 
                     78: const UCS4 kReplacementCharacter =     0x0000FFFDUL;
                     79: const UCS4 kMaximumUCS2 =                      0x0000FFFFUL;
                     80: const UCS4 kMaximumUTF16 =                     0x0010FFFFUL;
                     81: const UCS4 kMaximumUCS4 =                      0x7FFFFFFFUL;
                     82: 
                     83: /* ================================================================ */
                     84: 
                     85: UCS4 offsetsFromUTF8[6] =      {0x00000000UL, 0x00003080UL, 0x000E2080UL, 
                     86:                                                         0x03C82080UL, 0xFA082080UL, 0x82082080UL};
                     87: char bytesFromUTF8[256] = {
                     88:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     89:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     90:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     91:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     92:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     93:        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                     94:        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
                     95:        2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5};
                     96: 
                     97: UTF8 firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
                     98: 
                     99: static UTF16 Decomposer(register UTF16 srcChar, UTF16 *cmbChar);
                    100: 
                    101: /* ================================================================ */
                    102: /*     This code is similar in effect to making successive calls on the
                    103: * mbtowc and wctomb routines in FSS-UTF. However, it is considerably
                    104: * different in code:
                    105: * it is adapted to be consistent with UTF16,
                    106: * the interface converts a whole buffer to avoid function-call overhead
                    107: * constants have been gathered.
                    108: * loops & conditionals have been removed as much as possible for
                    109: * efficiency, in favor of drop-through switch statements.
                    110: */
                    111: 
                    112: /*
                    113:  * Colons vs. Slash
                    114:  *
                    115:  * The VFS layer uses a "/" as a pathname separator but HFS disks
                    116:  * use a ":".  So when converting from UTF-8, ":" characters need
                    117:  * to be changed to "/" so that colons don't end up on HFS disks.
                    118:  * Likewise when converting into UTF-8, "/" characters need to be
                    119:  * changed to ":" so that a "/" in a filename is not returned 
                    120:  * through the VFS layer.
                    121:  *
                    122:  * We do not need to worry about full-width slash or colons since
                    123:  * their respective representations outside of Unicode are never
                    124:  * the 7-bit versions (0x2f or 0x3a).
                    125:  */
                    126: 
                    127: 
                    128: /* ================================================================ */
                    129: ConversionResult       ConvertUTF16toUTF8 (
                    130:                UTF16** sourceStart, const UTF16* sourceEnd, 
                    131:                UTF8** targetStart, const UTF8* targetEnd)
                    132: {
                    133:        ConversionResult result = ok;
                    134:        register UTF16* source = *sourceStart;
                    135:        register UTF8* target = *targetStart;
                    136:        while (source < sourceEnd) {
                    137:                register UCS4 ch;
                    138:                register unsigned short bytesToWrite = 0;
                    139:                register const UCS4 byteMask = 0xBF;
                    140:                register const UCS4 byteMark = 0x80; 
                    141:                register const UCS4 slash = '/'; 
                    142:                ch = *source++;
                    143:                if (ch == slash) {
                    144:                        ch = ':';       /* VFS doesn't like slash */
                    145:                } else if (ch >= kSurrogateHighStart && ch <= kSurrogateHighEnd
                    146:                                && source < sourceEnd) {
                    147:                        register UCS4 ch2 = *source;
                    148:                        if (ch2 >= kSurrogateLowStart && ch2 <= kSurrogateLowEnd) {
                    149:                                ch = ((ch - kSurrogateHighStart) << halfShift)
                    150:                                        + (ch2 - kSurrogateLowStart) + halfBase;
                    151:                                ++source;
                    152:                        };
                    153:                };
                    154:                if (ch < 0x80) {                                bytesToWrite = 1;
                    155:                } else if (ch < 0x800) {                bytesToWrite = 2;
                    156:                } else if (ch < 0x10000) {              bytesToWrite = 3;
                    157:                } else if (ch < 0x200000) {             bytesToWrite = 4;
                    158:                } else if (ch < 0x4000000) {    bytesToWrite = 5;
                    159:                } else if (ch <= kMaximumUCS4){ bytesToWrite = 6;
                    160:                } else {                                                bytesToWrite = 2;
                    161:                                                                                ch = kReplacementCharacter;
                    162:                }; /* I wish there were a smart way to avoid this conditional */
                    163:                
                    164:                target += bytesToWrite;
                    165:                if (target > targetEnd) {
                    166:                        target -= bytesToWrite; result = targetExhausted; break;
                    167:                };
                    168:                switch (bytesToWrite) { /* note: code falls through cases! */
                    169:                        case 6: *--target = (ch | byteMark) & byteMask; ch >>= 6;
                    170:                        case 5: *--target = (ch | byteMark) & byteMask; ch >>= 6;
                    171:                        case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6;
                    172:                        case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6;
                    173:                        case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6;
                    174:                        case 1: *--target =  ch | firstByteMark[bytesToWrite];
                    175:                };
                    176:                target += bytesToWrite;
                    177:        };
                    178:        *sourceStart = source;
                    179:        *targetStart = target;
                    180:        return result;
                    181: };
                    182: 
                    183: /* ================================================================ */
                    184: 
                    185: ConversionResult       ConvertUTF8toUTF16 (
                    186:                UTF8** sourceStart, UTF8* sourceEnd, 
                    187:                UTF16** targetStart, const UTF16* targetEnd)
                    188: {
                    189:        ConversionResult result = ok;
                    190:        register UTF8* source = *sourceStart;
                    191:        register UTF16* target = *targetStart;
                    192:        while (source < sourceEnd) {
                    193:                register UCS4 ch = 0;
                    194:                register const UCS4 colon = ':'; 
                    195:                register unsigned short extraBytesToWrite = bytesFromUTF8[*source];
                    196:                if (source + extraBytesToWrite > sourceEnd) {
                    197:                        result = sourceExhausted; break;
                    198:                };
                    199:                switch(extraBytesToWrite) {     /* note: code falls through cases! */
                    200:                        case 5: ch += *source++; ch <<= 6;
                    201:                        case 4: ch += *source++; ch <<= 6;
                    202:                        case 3: ch += *source++; ch <<= 6;
                    203:                        case 2: ch += *source++; ch <<= 6;
                    204:                        case 1: ch += *source++; ch <<= 6;
                    205:                        case 0: ch += *source++;
                    206:                };
                    207:                ch -= offsetsFromUTF8[extraBytesToWrite];
                    208: 
                    209:                if (target >= targetEnd) {
                    210:                        result = targetExhausted; break;
                    211:                };
                    212:                if (ch <= kMaximumUCS2) {
                    213:                        UTF16 combine;
                    214: 
                    215:                        if (ch == colon) {
                    216:                                ch = '/';       /* HFS doesn't like colons */
                    217:                        }
                    218:                        *target++ = Decomposer(ch, &combine);
                    219: 
                    220:                        if (combine) {
                    221:                                if (target >= targetEnd) {
                    222:                                        result = targetExhausted; break;
                    223:                                };
                    224:                                *target++ = combine;
                    225:                        }
                    226:                } else if (ch > kMaximumUTF16) {
                    227:                        *target++ = kReplacementCharacter;
                    228:                } else {
                    229:                        if (target + 1 >= targetEnd) {
                    230:                                result = targetExhausted; break;
                    231:                        };
                    232:                        ch -= halfBase;
                    233:                        *target++ = (ch >> halfShift) + kSurrogateHighStart;
                    234:                        *target++ = (ch & halfMask) + kSurrogateLowStart;
                    235:                };
                    236:        };
                    237:        *sourceStart = source;
                    238:        *targetStart = target;
                    239:        return result;
                    240: };
                    241: 
                    242: /*
                    243:  * Lookup tables for Unicode chars 0x00C0 thru 0x00FF
                    244:  * primary_char yields first decomposed char. If this
                    245:  * char is an alpha char then get the combining char
                    246:  * from the combining_char table and add 0x0300 to it.
                    247:  */
                    248: 
                    249: static unsigned char primary_char[64] = {
                    250:        0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43,
                    251: 
                    252:        0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
                    253: 
                    254:        0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7,
                    255: 
                    256:        0xD8, 0x55, 0x55, 0x55, 0x55, 0x59, 0xDE, 0xDF,
                    257: 
                    258:        0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xE6, 0x63,
                    259: 
                    260:        0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69,
                    261: 
                    262:        0xF0, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0xF7,
                    263: 
                    264:        0xF8, 0x75, 0x75, 0x75, 0x75, 0x79, 0xFE, 0x79,
                    265: };
                    266: 
                    267: static unsigned char combining_char[64] = {
                    268:        0x00, 0x01, 0x02, 0x03, 0x08, 0x0A, 0xFF, 0x27,
                    269: 
                    270:        0x00, 0x01, 0x02, 0x08, 0x00, 0x01, 0x02, 0x08,
                    271: 
                    272:        0xFF, 0x03, 0x00, 0x01, 0x02, 0x03, 0x08, 0xFF,
                    273: 
                    274:        0xFF, 0x00, 0x01, 0x02, 0x08, 0x01, 0xFF, 0xFF,
                    275: 
                    276:        0x00, 0x01, 0x02, 0x03, 0x08, 0x0A, 0xFF, 0x27,
                    277: 
                    278:        0x00, 0x01, 0x02, 0x08, 0x00, 0x01, 0x02, 0x08,
                    279: 
                    280:        0xFF, 0x03, 0x00, 0x01, 0x02, 0x03, 0x08, 0xFF,
                    281: 
                    282:        0xFF, 0x00, 0x01, 0x02, 0x08, 0x01, 0xFF, 0x08
                    283: };
                    284: 
                    285: 
                    286: static const unsigned long __CJKDecompBitmap[] = {     // 0x3000 ~ 0x30FF
                    287:     0x00000000, 0x00000000, 0x000AAAAA, 0xA540DB6C,    // 0x3000
                    288:     0x00000802, 0x000AAAAA, 0xA540DB6C, 0x000009E2,    // 0x3080
                    289: };
                    290: 
                    291: #define IS_DECOMPOSABLE(table,unicodeVal) (table[(unicodeVal) / 32] & (1 << (31 - ((unicodeVal) % 32))))
                    292: 
                    293: 
                    294: /*
                    295:  * Decomposer
                    296:  *
                    297:  * Composed Unicode characters are forbidden on
                    298:  * HFS Plus volumes. Decomposer will convert a
                    299:  * composed character into its correct decomposed
                    300:  * sequence.
                    301:  *
                    302:  * Currently only MacRoman and MacJapanese chars
                    303:  * are handled.  Other composed characters are
                    304:  * passed unchanged.
                    305:  */
                    306: static UTF16
                    307: Decomposer(register UTF16 srcChar, UTF16 *cmbChar)
                    308: {
                    309:        UTF16 dstChar;
                    310:        
                    311:        *cmbChar = 0;
                    312: 
                    313:        if ((srcChar <= 0x00FF) && (srcChar >= 0x00C0)) {
                    314:                srcChar -= 0x00C0;
                    315:                
                    316:                dstChar = (UTF16) primary_char[srcChar];
                    317: 
                    318:                if (dstChar <= 'z') {
                    319:                        *cmbChar = (UTF16) 0x0300 + (UTF16) combining_char[srcChar];
                    320:                }
                    321:        } else if ((srcChar > 0x3000) && (srcChar < 0x3100) &&
                    322:                                IS_DECOMPOSABLE(__CJKDecompBitmap, srcChar - 0x3000)) {
                    323:                switch(srcChar) {
                    324:                case 0x3071: dstChar = 0x306F; *cmbChar = 0x309A; break;        // HIRAGANA LETTER PA
                    325:                case 0x3074: dstChar = 0x3072; *cmbChar = 0x309A; break;        // HIRAGANA LETTER PI
                    326:                case 0x3077: dstChar = 0x3075; *cmbChar = 0x309A; break;        // HIRAGANA LETTER PU
                    327:                case 0x307A: dstChar = 0x3078; *cmbChar = 0x309A; break;        // HIRAGANA LETTER PE
                    328: 
                    329:                case 0x307D: dstChar = 0x307B; *cmbChar = 0x309A; break;        // HIRAGANA LETTER PO
                    330:                case 0x3094: dstChar = 0x3046; *cmbChar = 0x3099; break;        // HIRAGANA LETTER VU
                    331:                case 0x30D1: dstChar = 0x30CF; *cmbChar = 0x309A; break;        // KATAKANA LETTER PA
                    332:                case 0x30D4: dstChar = 0x30D2; *cmbChar = 0x309A; break;        // KATAKANA LETTER PI
                    333: 
                    334:                case 0x30D7: dstChar = 0x30D5; *cmbChar = 0x309A; break;        // KATAKANA LETTER PU
                    335:                case 0x30DA: dstChar = 0x30D8; *cmbChar = 0x309A; break;        // KATAKANA LETTER PE
                    336:                case 0x30DD: dstChar = 0x30DB; *cmbChar = 0x309A; break;        // KATAKANA LETTER PO
                    337:                case 0x30F4: dstChar = 0x30A6; *cmbChar = 0x3099; break;        // KATAKANA LETTER VU
                    338: 
                    339:                case 0x30F7: dstChar = 0x30EF; *cmbChar = 0x3099; break;        // KATAKANA LETTER VA
                    340:                case 0x30F8: dstChar = 0x30F0; *cmbChar = 0x3099; break;        // KATAKANA LETTER VI
                    341:                case 0x30F9: dstChar = 0x30F1; *cmbChar = 0x3099; break;        // KATAKANA LETTER VE
                    342:                case 0x30FA: dstChar = 0x30F2; *cmbChar = 0x3099; break;        // KATAKANA LETTER VO
                    343:                
                    344:                default:
                    345:                        /* the rest (41 of them) have a simple conversion */
                    346:                        dstChar = srcChar - 1;
                    347:                        *cmbChar = 0x3099;
                    348:                };
                    349:        } else {
                    350:                dstChar = srcChar;
                    351:        }
                    352:        
                    353:        return dstChar;
                    354: }
                    355: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.