|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.