|
|
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: File: UnicodeWrappers.c ! 27: ! 28: Contains: Wrapper routines for Unicode conversion and comparison. ! 29: ! 30: Version: HFS Plus 1.0 ! 31: ! 32: Written by: Mark Day ! 33: ! 34: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved. ! 35: ! 36: File Ownership: ! 37: ! 38: DRI: Mark Day ! 39: ! 40: Other Contact: Don Brady ! 41: ! 42: Technology: xxx put technology here xxx ! 43: ! 44: Writers: ! 45: ! 46: (DSH) Deric Horn ! 47: (msd) Mark Day ! 48: (djb) Don Brady ! 49: ! 50: Change History (most recent first): ! 51: <Rhap> 2/09/99 djb Fix UnicodeToMacRoman to handle a terminating decomposed char. ! 52: <Rhap> 1/22/99 djb Add more TARGET_OS_MAC conditionals to remove orphaned code. ! 53: <Rhap> 7/6/98 djb Handle hi-bit Mac Roman characters in basic latin conversions (radar #2247519). ! 54: <Rhap> 6/11/98 PPD Added a few special-case ASCII/Unicode mappings to cover installer's needs. ! 55: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file. ! 56: ! 57: <CS41> 1/28/98 msd Bug 2207446: When mangling a name, check to see if the Unicode ! 58: Converter is installed before we call it. ! 59: <CS40> 1/21/98 msd Bug 2206836: If a name contains a colon, change it to question ! 60: mark and mangle the name. ! 61: <CS39> 12/11/97 msd For Metrowerks and test tools, call the Get_xxx routines to get ! 62: the Unicode table addresses. ! 63: <CS38> 12/10/97 djb Radar #2005461, don't use fallback chars when converting to ! 64: Unicode, instead let the client (Catalog) retry with MacRoman. ! 65: <CS37> 12/2/97 DSH Conditionalize out some unicode related routines for DFA ! 66: <CS36> 11/26/97 djb Radar #2005461,2005688 don't swallow kTECPartialCharErr errors! ! 67: <CS35> 11/17/97 djb Name mangling was broken with decomposed Unicode. ! 68: <CS34> 11/16/97 djb Radar #2001928 - use kUnicodeCanonicalDecompVariant variant. ! 69: <CS33> 11/11/97 DSH Use Get_gLowerCaseTable for DiskFirstAid builds to avoid loading ! 70: in a branch to the table. ! 71: <CS32> 11/7/97 msd Replace FastSimpleCompareStrings with FastUnicodeCompare (which ! 72: handles ignorable Unicode characters). Remove the wrapper ! 73: routine, CompareUnicodeNames, and have its callers call ! 74: FastUnicodeCompare directly. ! 75: <CS31> 10/17/97 djb Change kUnicodeUseHFSPlusMapping to kUnicodeUseLatestMapping. ! 76: <CS30> 10/17/97 msd Fix some type casts for char pointers. ! 77: <CS29> 10/13/97 djb Add new SPIs for Finder View font (radar #1679073). ! 78: <CS28> 10/1/97 djb Preserve current heap zone in InitializeEncodingContext routine ! 79: (radar #1682686). ! 80: <CS27> 9/17/97 djb Handle kTECPartialCharErr errors in ConvertHFSNameToUnicode. ! 81: <CS26> 9/16/97 msd In MockConvertFromPStringToUnicode, use pragma unused instead of ! 82: commenting out unused parameter (so SC will compile it). ! 83: <CS25> 9/15/97 djb Fix MockConverters to do either 7-bit ascii or else mangle the ! 84: name (radar #1672388). Use 'p2u#' resource for bootstrapping ! 85: Unicode. Make sure InitializeEncodingContext uses System heap. ! 86: <CS24> 9/10/97 msd Make InitializeEncodingContext public. ! 87: <CS23> 9/7/97 djb Handle '�' char in BasicLatinUnicode converter. ! 88: <CS22> 9/4/97 djb Add logging to BasicLatinUnicodeToPascal. ! 89: <CS21> 8/26/97 djb Make FastSimpleCompareStrings faster. Add ! 90: BasicLatinUnicodeToPascal to make 7-bit ascii conversions ! 91: faster. ! 92: <CS20> 8/14/97 djb Add FastRelString here (to be next to the data tables). ! 93: <CS19> 7/21/97 djb LogEndTime now takes an error code. ! 94: <CS18> 7/18/97 msd Include LowMemPriv.h, Gestalt.h, TextUtils.h. ! 95: <CS17> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 96: collision ! 97: <CS16> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 98: <CS15> 7/8/97 DSH InitializeUnicode changed its API ! 99: <CS14> 7/1/97 DSH SC, DFA complier, requires parameters in functions. #pragma'd ! 100: them out to eliminate C warnings. ! 101: <CS13> 6/30/97 msd Remove unused parameter warnings in FallbackProc by commenting ! 102: out unused parameter names. ! 103: <CS12> 6/26/97 DSH FallbackProc declare variables before useage for SC, ! 104: MockConverters no longer static for DFA. ! 105: <CS11> 6/25/97 msd In function InitStaticUnicodeConverter, the variable fsVars was ! 106: being used before being initialized. ! 107: <CS10> 6/24/97 DSH Runtime checks to call through CFM or static linked routines. ! 108: <CS9> 6/20/97 msd Re-introduce fix from <CS7>. Fix another missing cast. Remove a ! 109: spurious semicolon. ! 110: <CS8> 6/18/97 djb Add more ConversionContexts routines. Improved file mangling. ! 111: <CS7> 6/16/97 msd Add a missing cast in GetFileIDString. ! 112: <CS6> 6/13/97 djb Added support for long filenames. Switched to ! 113: ConvertUnicodeToHFSName, ConvertHFSNameToUnicode, and ! 114: CompareUnicodeNames. ! 115: <CS5> 6/4/97 djb Use system script instead of macRoman. ! 116: <CS4> 5/19/97 djb Add call to LockMappingTable so tables won't move! ! 117: <CS3> 5/9/97 djb Include HFSInstrumentation.h ! 118: <CS2> 5/7/97 djb Add summary traces. Add FastSimpleCompareStrings routine. ! 119: <CS1> 4/24/97 djb first checked in ! 120: <HFS5> 3/27/97 djb Add calls to real Unicode conversion routines. ! 121: <HFS4> 2/6/97 msd Add conditional code to use real Unicode comparison routines ! 122: (default to off). ! 123: <HFS3> 1/6/97 djb Fix HFSUnicodeCompare - the final comparison of length1 and ! 124: length2 was backwards. ! 125: <HFS2> 12/12/96 msd Use precompiled headers. ! 126: <HFS1> 12/12/96 msd first checked in ! 127: ! 128: */ ! 129: ! 130: #if ( PRAGMA_LOAD_SUPPORTED ) ! 131: #pragma load PrecompiledHeaders ! 132: #else ! 133: #if TARGET_OS_MAC ! 134: #include <CodeFragments.h> ! 135: #include <Errors.h> ! 136: #include <MixedModePriv.h> ! 137: #include <Script.h> ! 138: #include <UnicodeConverter.h> ! 139: #include <LowMemPriv.h> ! 140: #include <Gestalt.h> ! 141: #include <TextUtils.h> ! 142: #else ! 143: #include "../headers/system/MacOSStubs.h" ! 144: #endif /* TARGET_OS_MAC */ ! 145: #endif /* PRAGMA_LOAD_SUPPORTED */ ! 146: ! 147: #if TARGET_OS_MAC ! 148: #include <IntlResources.h> ! 149: #include <TextCommonPriv.h> ! 150: #include <UnicodeConverterPriv.h> ! 151: #include <FileMgrResources.h> ! 152: #endif /* TARGET_OS_MAC */ ! 153: ! 154: #if TARGET_OS_RHAPSODY ! 155: #include "UCStringCompareData.h" ! 156: #endif /* TARGET_OS_RHAPSODY */ ! 157: ! 158: #include "../headers/FileMgrInternal.h" ! 159: #include "../headers/system/HFSUnicodeWrappers.h" ! 160: #include "../headers/system/HFSInstrumentation.h" ! 161: ! 162: #include "ConvertUTF.h" ! 163: ! 164: #ifdef __MWERKS__ ! 165: #define USE_TABLE_ACCESSORS 1 ! 166: #endif ! 167: ! 168: #ifndef USE_TABLE_ACCESSORS ! 169: #define USE_TABLE_ACCESSORS 0 ! 170: #endif ! 171: ! 172: ! 173: #if TARGET_OS_MAC ! 174: enum { ! 175: uupCreateTextToUnicodeInfoProcInfo = ! 176: kPascalStackBased ! 177: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 178: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ConstUnicodeMappingPtr))) ! 179: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(TextToUnicodeInfo*))), ! 180: ! 181: ! 182: uppCreateUnicodeToTextInfoProcInfo = ! 183: kPascalStackBased ! 184: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 185: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ConstUnicodeMappingPtr))) ! 186: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(UnicodeToTextInfo*))), ! 187: ! 188: ! 189: uppConvertFromTextToUnicodeProcInfo = ! 190: kPascalStackBased ! 191: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 192: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(TextToUnicodeInfo))) ! 193: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(ByteCount))) ! 194: | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(ConstLogicalAddress))) ! 195: | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(OptionBits))) ! 196: | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(ItemCount))) ! 197: | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(ByteOffset*))) ! 198: | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(ItemCount*))) ! 199: | STACK_ROUTINE_PARAMETER(8, SIZE_CODE(sizeof(ByteOffset*))) ! 200: | STACK_ROUTINE_PARAMETER(9, SIZE_CODE(sizeof(ByteCount))) ! 201: | STACK_ROUTINE_PARAMETER(10, SIZE_CODE(sizeof(ByteCount*))) ! 202: | STACK_ROUTINE_PARAMETER(11, SIZE_CODE(sizeof(ByteCount*))) ! 203: | STACK_ROUTINE_PARAMETER(12, SIZE_CODE(sizeof(UniCharArrayPtr))), ! 204: ! 205: ! 206: uppConvertFromUnicodeToTextProcInfo = ! 207: kPascalStackBased ! 208: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 209: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(UnicodeToTextInfo))) ! 210: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(ByteCount))) ! 211: | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(ConstUniCharArrayPtr))) ! 212: | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(OptionBits))) ! 213: | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(ItemCount))) ! 214: | STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(ByteOffset*))) ! 215: | STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(ItemCount*))) ! 216: | STACK_ROUTINE_PARAMETER(8, SIZE_CODE(sizeof(ByteOffset*))) ! 217: | STACK_ROUTINE_PARAMETER(9, SIZE_CODE(sizeof(ByteCount))) ! 218: | STACK_ROUTINE_PARAMETER(10, SIZE_CODE(sizeof(ByteCount*))) ! 219: | STACK_ROUTINE_PARAMETER(11, SIZE_CODE(sizeof(ByteCount*))) ! 220: | STACK_ROUTINE_PARAMETER(12, SIZE_CODE(sizeof(LogicalAddress))), ! 221: ! 222: ! 223: uppUpgradeScriptInfoToTextEncodingProcInfo = ! 224: kPascalStackBased ! 225: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 226: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(ScriptCode))) ! 227: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(LangCode))) ! 228: | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(RegionCode))) ! 229: | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(ConstStr255Param))) ! 230: | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(TextEncoding*))), ! 231: ! 232: ! 233: uppRevertTextEncodingToScriptInfoProcInfo = ! 234: kPascalStackBased ! 235: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 236: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(TextEncoding))) ! 237: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(ScriptCode*))) ! 238: | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(LangCode*))) ! 239: | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(StringPtr))), ! 240: ! 241: ! 242: // NOTE: this one uses "C" calling conventions... ! 243: uppLockMappingTableProcInfo = ! 244: kCStackBased ! 245: | RESULT_SIZE(SIZE_CODE(sizeof(OSStatus))) ! 246: | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(UnicodeMapping*))) ! 247: | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(Boolean))) ! 248: }; ! 249: #endif /* TARGET_OS_MAC */ ! 250: ! 251: ! 252: enum { ! 253: smLargestScript = 32, ! 254: ! 255: kMinFileExtensionChars = 1, // does not include dot ! 256: kMaxFileExtensionChars = 5 // does not include dot ! 257: }; ! 258: ! 259: #define kASCIIPiSymbol 0xB9 ! 260: #define kASCIIMicroSign 0xB5 ! 261: #define kASCIIGreekDelta 0xC6 ! 262: ! 263: ! 264: #define Is7BitASCII(c) ( (c) >= 0x20 && (c) <= 0x7F ) ! 265: ! 266: #define IsSpecialASCIIChar(c) ( (c) == (UInt8) kASCIIMicroSign || (c) == (UInt8) kASCIIPiSymbol || (c) == (UInt8) kASCIIGreekDelta ) ! 267: ! 268: // Note: '�' has two Unicode representations 0x00B5 (micro sign) and 0x03BC (greek) ! 269: // '�' has two Unicode representations 0x2206 (increment) and 0x0394 (greek) ! 270: #define IsSpecialUnicodeChar(c) ( (c) == 0x00B5 || (c) == 0x03BC || (c) == 0x03C0 || (c) == 0x2206 || (c) == 0x0394 ) ! 271: ! 272: #define IsHexDigit(c) ( ((c) >= (UInt8) '0' && (c) <= (UInt8) '9') || ((c) >= (UInt8) 'A' && (c) <= (UInt8) 'F') ) ! 273: ! 274: // ! 275: // PToUTable and PToUEntry describe the 'p2u#' resource ! 276: // This resource is used to map pascal to Unicode before ! 277: // the real Unicode converter is initialize. ! 278: // ! 279: struct PToUEntry { ! 280: Str31 pascalString; // pascal representation ! 281: UInt16 unicodeChars; // unicode char count ! 282: UniChar unicodeString[63]; // unicode representation ! 283: }; ! 284: typedef struct PToUEntry PToUEntry; ! 285: ! 286: ! 287: struct PToUTable { ! 288: UInt16 entries; // number of entries ! 289: PToUEntry entry[1]; ! 290: }; ! 291: typedef struct PToUTable PToUTable; ! 292: ! 293: ! 294: extern UniChar * Get_gLowerCaseTable(void); ! 295: ! 296: // Unicode Glue routines ! 297: // WARNING: These Glue APIs must match the APIs in UnicodeConverter.h (the glue assumes they are the same) ! 298: // for example CreateTextToUnicodeInfo_Glue and CreateTextToUnicodeInfo must have identical parameters and calling conventions ! 299: ! 300: extern pascal OSStatus CreateTextToUnicodeInfo_Glue(ConstUnicodeMappingPtr iUnicodeMapping, TextToUnicodeInfo *oTextToUnicodeInfo); ! 301: extern pascal OSStatus CreateUnicodeToTextInfo_Glue(ConstUnicodeMappingPtr iUnicodeMapping, UnicodeToTextInfo *oUnicodeToTextInfo); ! 302: extern pascal OSStatus ConvertFromTextToUnicode_Glue(TextToUnicodeInfo iTextToUnicodeInfo, ByteCount iSourceLen, ConstLogicalAddress iSourceStr, OptionBits iControlFlags, ItemCount iOffsetCount, ByteOffset iOffsetArray[], ItemCount *oOffsetCount, ByteOffset oOffsetArray[], ByteCount iBufLen, ByteCount *oSourceRead, ByteCount *oUnicodeLen, UniCharArrayPtr oUnicodeStr); ! 303: extern pascal OSStatus ConvertFromUnicodeToText_Glue(UnicodeToTextInfo iUnicodeToTextInfo, ByteCount iUnicodeLen, ConstUniCharArrayPtr iUnicodeStr, OptionBits iControlFlags, ItemCount iOffsetCount, ByteOffset iOffsetArray[], ItemCount *oOffsetCount, ByteOffset oOffsetArray[], ByteCount iBufLen, ByteCount *oInputRead, ByteCount *oOutputLen, LogicalAddress oOutputStr); ! 304: extern pascal OSStatus UpgradeScriptInfoToTextEncoding_Glue(ScriptCode textScriptID, LangCode textLanguageID, RegionCode regionID, ConstStr255Param textFontname, TextEncoding *encoding); ! 305: extern pascal OSStatus RevertTextEncodingToScriptInfo_Glue(TextEncoding encoding, ScriptCode *textScriptID, LangCode *textLanguageID, Str255 textFontname); ! 306: ! 307: // EXCEPTION: this one uses "C" calling conventions (why?) ! 308: extern OSStatus LockMappingTable_Glue(UnicodeMapping *unicodeMappingPtr, Boolean lockIt); ! 309: ! 310: #if TARGET_OS_MAC ! 311: static OSErr InitStaticUnicodeConverter(void); ! 312: static OSErr InitDynamicUnicodeConverter( Boolean forBootVolume ); ! 313: #endif /* TARGET_OS_MAC */ ! 314: ! 315: ! 316: #if TARGET_OS_MAC ! 317: static OSErr InstallConversionContexts( FSVarsRec *fsVars ); ! 318: ! 319: static OSErr InstallLibraryVector( CFragConnectionID connectionID, ConstStr255Param symbolName, ! 320: ProcInfoType procInfo, UniversalProcPtr *vector ); ! 321: ! 322: static OSErr InstallSystemConversionContext( FSVarsRec *fsVars, Boolean forBootVolume ); ! 323: #endif /* TARGET_OS_MAC */ ! 324: ! 325: static void GetFilenameExtension( ItemCount length, ConstUniCharArrayPtr unicodeStr, Str15 extStr ); ! 326: ! 327: static void GetFileIDString( HFSCatalogNodeID fileID, Str15 fileIDStr ); ! 328: ! 329: static void AppendPascalString( ConstStr15Param src, Str31 dst ); ! 330: ! 331: static UInt32 HexStringToInteger( UInt32 length, const UInt8 *hexStr ); ! 332: ! 333: ! 334: pascal OSStatus FallbackProc( UniChar *srcUniStr, ByteCount srcUniStrLen, ByteCount *srcConvLen, ! 335: TextPtr destStr, ByteCount destStrLen, ByteCount *destConvLen, ! 336: LogicalAddress contextPtr, ConstUnicodeMappingPtr unicodeMappingPtr ); ! 337: ! 338: ! 339: static OSErr MacRomanToUnicode (ConstStr255Param pascalString, ItemCount *unicodeChars, UniCharArrayPtr unicodeString); ! 340: static OSErr UnicodeToMacRoman (ItemCount unicodeChars, ConstUniCharArrayPtr unicodeString, Str31 pascalString); ! 341: ! 342: ! 343: /* ! 344: Get the base encoding used by the File System ! 345: ! 346: If no HFS Plus volumes have been mounted yet then ! 347: the default encoding could be kTextEncodingUndefined ! 348: */ ! 349: #if TARGET_OS_MAC ! 350: TextEncoding ! 351: GetDefaultTextEncoding(void) ! 352: { ! 353: FSVarsRec *fsVars; ! 354: ! 355: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 356: ! 357: return fsVars->gDefaultBaseEncoding; ! 358: } ! 359: #endif ! 360: ! 361: ! 362: /* ! 363: Set the base encoding used by the File System ! 364: */ ! 365: #if TARGET_OS_MAC ! 366: OSErr ! 367: SetDefaultTextEncoding(TextEncoding encoding) ! 368: { ! 369: FSVarsRec *fsVars; ! 370: OSErr result; ! 371: ! 372: ! 373: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 374: ! 375: ! 376: // undefined only makes sense when Unicode Library is not installed ! 377: if ( encoding == kTextEncodingUndefined ) ! 378: { ! 379: if ( fsVars->gIsUnicodeInstalled == false ) ! 380: fsVars->gDefaultBaseEncoding = encoding; ! 381: ! 382: return noErr; ! 383: } ! 384: ! 385: encoding = GetTextEncodingBasePriv(encoding); ! 386: ! 387: if ( !ValidMacEncoding(encoding) ) ! 388: return paramErr; // we only support Mac encodings! ! 389: ! 390: // if Unicode Library is installed then setup context for this encoding ! 391: // otherwise it will occur when the first HFS Plus volume gets mounted ! 392: if ( fsVars->gIsUnicodeInstalled ) ! 393: { ! 394: result = InitializeEncodingContext( encoding, fsVars ); ! 395: if ( result != noErr ) ! 396: return result; ! 397: } ! 398: ! 399: // make it the default... ! 400: fsVars->gDefaultBaseEncoding = encoding; ! 401: ! 402: return noErr; ! 403: } ! 404: #endif /* TARGET_OS_MAC */ ! 405: ! 406: /* ! 407: Get the encoding that matches font ! 408: */ ! 409: ! 410: #if TARGET_OS_MAC ! 411: OSErr ! 412: GetTextEncodingForFont( ConstStr255Param fontName, UInt32 * textEncoding ) ! 413: { ! 414: FSVarsRec * fsVars; ! 415: OSErr result; ! 416: ! 417: ! 418: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 419: ! 420: // if Unicode Library is installed then we can get the encoding... ! 421: if ( fsVars->gIsUnicodeInstalled ) ! 422: { ! 423: result = UpgradeScriptInfoToTextEncoding_Glue ( kTextScriptDontCare, ! 424: kTextLanguageDontCare, ! 425: kTextRegionDontCare, ! 426: fontName, ! 427: textEncoding ); ! 428: } ! 429: else // Unicode Library not installed so save font name for later... ! 430: { ! 431: StringPtr savedFontName; ! 432: UInt16 stringByteSize; ! 433: ! 434: stringByteSize = fontName[0] + 1; ! 435: savedFontName = fsVars->gTextEncodingFontName; ! 436: ! 437: // if we already had one then get rid of it ! 438: if ( savedFontName != NULL ) ! 439: DisposePtr( (Ptr) savedFontName ); ! 440: ! 441: savedFontName = (StringPtr) NewPtrSys( stringByteSize ); ! 442: ! 443: if ( savedFontName != NULL ) ! 444: BlockMoveData(fontName, savedFontName, stringByteSize); ! 445: ! 446: fsVars->gTextEncodingFontName = savedFontName; ! 447: ! 448: *textEncoding = kTextEncodingUndefined; ! 449: result = noErr; ! 450: } ! 451: ! 452: return result; ! 453: } ! 454: #endif /* TARGET_OS_MAC */ ! 455: ! 456: /* ! 457: Count the number of encodings installed by the File System ! 458: */ ! 459: #if TARGET_OS_MAC ! 460: ItemCount ! 461: CountInstalledEncodings(void) ! 462: { ! 463: FSVarsRec *fsVars; ! 464: ! 465: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 466: ! 467: return fsVars->gInstalledEncodings; ! 468: } ! 469: #endif ! 470: ! 471: /* ! 472: Convert a Unicode string to a Pascal string (Str31) for use in an HFS file/folder name. ! 473: */ ! 474: #if 0 ! 475: OSErr ! 476: ConvertUnicodeToHFSName( ConstHFSUniStr255Param unicodeName, TextEncoding encoding, HFSCatalogNodeID cnid, Str31 hfsName ) ! 477: { ! 478: ByteCount unicodeByteLength; ! 479: ByteCount pascalSizeLimit; ! 480: OSErr result; ! 481: ! 482: hfsName[0] = 0; // in case we get errors, make sure output is valid ! 483: unicodeByteLength = unicodeName->length * sizeof(UniChar); ! 484: ! 485: if ( unicodeByteLength == 0 ) ! 486: return noErr; ! 487: ! 488: if ( cnid == kHFSRootFolderID ) ! 489: pascalSizeLimit = kHFSMaxVolumeNameChars; // an HFS volume name ! 490: else ! 491: pascalSizeLimit = kHFSMaxFileNameChars; // an HFS file name ! 492: ! 493: result = MockConvertFromUnicodeToPString( unicodeByteLength, unicodeName->unicode, hfsName ); ! 494: ! 495: // Check if name was too long or some characters were unrepresentable... ! 496: // if so we need to mangle the name so that the file can be found by ! 497: // name later ! 498: ! 499: if ( result == kTECOutputBufferFullStatus || result == kTECUsedFallbacksStatus ) ! 500: { ! 501: Str15 fileIDStr; // file ID as a pascal string ! 502: Str15 extStr; // dot extension as a pascal string ! 503: ! 504: GetFileIDString(cnid, fileIDStr); ! 505: ! 506: // Get a filename extension only if it is a file. ! 507: if ( pascalSizeLimit == kHFSMaxFileNameChars) ! 508: GetFilenameExtension(unicodeName->length, unicodeName->unicode, extStr); ! 509: else ! 510: extStr[0] = (UInt8) 0; // volumes don't have extensions ! 511: ! 512: // calculate free space for filename prefix ! 513: pascalSizeLimit -= StrLength(extStr) + StrLength(fileIDStr); ! 514: ! 515: // Generate the prefix part of the name (before extension or File ID string). ! 516: // Since the Unicode converter wasn't installed, use the PString we already have, ! 517: // shortening it if needed. ! 518: if (hfsName[0] > pascalSizeLimit) ! 519: hfsName[0] = pascalSizeLimit; ! 520: else ! 521: hfsName[0] -= StrLength(extStr); // remove extension chars (if any) from source ! 522: ! 523: strcat(hfsName, fileIDStr); ! 524: strcat(hfsName, extStr); ! 525: ! 526: result = noErr; ! 527: } ! 528: ! 529: return result; ! 530: ! 531: } // end ConvertUnicodeToHFSName ! 532: #endif ! 533: ! 534: /* ! 535: Convert a Pascal string (Str31, such as a file/folder name) to Unicode. ! 536: */ ! 537: #if TARGET_OS_MAC ! 538: OSErr ! 539: ConvertHFSNameToUnicode( ConstStr31Param hfsName, TextEncoding encoding, HFSUniStr255 *unicodeName ) ! 540: { ! 541: ByteCount unicodeByteLength; ! 542: OSErr result; ! 543: ! 544: ! 545: result = MockConvertFromPStringToUnicode( hfsName, sizeof(unicodeName->unicode), &unicodeByteLength, unicodeName->unicode ); ! 546: ! 547: unicodeName->length = unicodeByteLength / sizeof(UniChar); // Note: from byte count to char count ! 548: ! 549: return result; ! 550: ! 551: } // end ConvertHFSNameToUnicode ! 552: #endif ! 553: ! 554: ! 555: /* ! 556: MockConvertFromUnicodeToPString ! 557: */ ! 558: #if TARGET_OS_MAC ! 559: OSErr ! 560: MockConvertFromUnicodeToPString( ByteCount unicodeLength, ConstUniCharArrayPtr unicodeStr, Str31 pascalStr ) ! 561: { ! 562: return UnicodeToMacRoman(unicodeLength / sizeof(UniChar), unicodeStr, pascalStr); ! 563: } ! 564: #endif ! 565: ! 566: /* ! 567: MockConvertFromPStringToUnicode ! 568: */ ! 569: #if TARGET_OS_MAC ! 570: OSErr ! 571: MockConvertFromPStringToUnicode(ConstStr31Param pascalStr, ByteCount maxUnicodeLen, ByteCount *actualUnicodeLen, UniCharArrayPtr unicodeStr) ! 572: { ! 573: #pragma unused(maxUnicodeLen) ! 574: ! 575: UInt32 unicodeChars; ! 576: OSErr result; ! 577: ! 578: result = MacRomanToUnicode (pascalStr, &unicodeChars, unicodeStr); ! 579: ! 580: *actualUnicodeLen = unicodeChars * sizeof(UniChar); // return length in bytes ! 581: ! 582: return result; ! 583: } ! 584: #endif ! 585: ! 586: /* ! 587: Initialize the Unicode Converter library ! 588: ! 589: If the library cannot be initialized the wrapper code will default to using 7-bit ASCII or mangled names. ! 590: ! 591: WARNING: This cannot be called from within a file system call (since it calls the file system)! ! 592: */ ! 593: #if TARGET_OS_MAC ! 594: OSErr InitUnicodeConverter(Boolean forBootVolume) ! 595: { ! 596: FSVarsRec *fsVars; ! 597: Handle resourceHandle; ! 598: long response; ! 599: OSErr err; ! 600: ! 601: ! 602: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 603: ! 604: if ( fsVars->gIsUnicodeInstalled == true ) // Has Unicode already been installed ! 605: return ( noErr ); ! 606: ! 607: err = Gestalt( gestaltSysArchitecture, &response ); //�� Runtime check to load static or dynamic libraries ! 608: if ( (response == gestaltPowerPC) && (err == noErr) ) ! 609: { ! 610: SInt32 savedOffsetToUTC; ! 611: ! 612: if (forBootVolume) ! 613: { ! 614: savedOffsetToUTC = fsVars->offsetToUTC; // save offset from GMT to local time ! 615: fsVars->offsetToUTC = 0; // trick CFM into caching an older mod date for the extensions folder ! 616: ! 617: // For bootstrap PascalToUnicode conversions we need to load the p2u table ! 618: resourceHandle = GetResource ('p2u#', 0); // get our special mapping table ! 619: if (resourceHandle != NULL) ! 620: { ! 621: HLock(resourceHandle); ! 622: fsVars->gBootPToUTable = *resourceHandle; ! 623: } ! 624: } ! 625: ! 626: ! 627: err = InitDynamicUnicodeConverter( forBootVolume ); ! 628: ! 629: ! 630: if (forBootVolume) ! 631: { ! 632: fsVars->offsetToUTC = savedOffsetToUTC; // restore offset from GMT to local time ! 633: ! 634: // The real converters should be online now so we can jettison the table ! 635: if (resourceHandle != NULL) ! 636: { ! 637: HUnlock(resourceHandle); ! 638: fsVars->gBootPToUTable = NULL; ! 639: ReleaseResource(resourceHandle); // we no longer need this table ! 640: } ! 641: } ! 642: } ! 643: ! 644: if ( (err != noErr) || (response != gestaltPowerPC) ) // If we got an error or on a 68K mac ! 645: { ! 646: err = InitStaticUnicodeConverter(); // Init the 68K static version of the converters ! 647: } ! 648: ! 649: ! 650: return ( err ); ! 651: } ! 652: #endif /* TARGET_OS_MAC */ ! 653: ! 654: ! 655: /* ! 656: Initialize the Staticly linked 68K Unicode Converter library ! 657: ! 658: If the library cannot be initialized the wrapper code will default to using 7-bit ASCII or mangled names. ! 659: WARNING: This cannot be called from within a file system call (since it calls the file system)! ! 660: */ ! 661: #if TARGET_OS_MAC ! 662: static OSErr ! 663: InitStaticUnicodeConverter(void) ! 664: { ! 665: FSVarsRec *fsVars; ! 666: THz savedHeapZone; ! 667: OSErr err; ! 668: Str31 textEncodingConverterName; ! 669: ! 670: // use the system context ! 671: savedHeapZone = GetZone(); ! 672: SetZone( SystemZone() ); ! 673: ! 674: GetIndString( textEncodingConverterName, kBaseHFSPlusResourceID, rTextEncodingConverterName ); //���need real string!! ! 675: err = InitializeUnicode( textEncodingConverterName ); ! 676: ExitOnError( err ); ! 677: ! 678: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 679: fsVars->gUseDynamicUnicodeConverters = false; ! 680: ! 681: err = InstallSystemConversionContext( fsVars, false ); ! 682: ExitOnError( err ); ! 683: ! 684: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 685: fsVars->gIsUnicodeInstalled = true; ! 686: ! 687: ! 688: ErrorExit: ! 689: ! 690: SetZone( savedHeapZone ); ! 691: ! 692: return( err ); ! 693: } ! 694: #endif /* TARGET_OS_MAC */ ! 695: ! 696: ! 697: ! 698: /* ! 699: Initialize the PPC CFM dynamically linked 68K Unicode Converter library ! 700: If the library cannot be initialized the wrapper code will default to ! 701: using the 68K staticly linked library. ! 702: */ ! 703: #if TARGET_OS_MAC ! 704: static OSErr ! 705: InitDynamicUnicodeConverter( Boolean forBootVolume ) ! 706: { ! 707: CFragConnectionID unicodeLib = 0; ! 708: CFragConnectionID textLib = 0; ! 709: Ptr tempMainAddr; ! 710: Str255 errMessage; ! 711: FSVarsRec *fsVars; ! 712: THz savedHeapZone; ! 713: OSErr result; ! 714: ! 715: ! 716: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 717: ! 718: // use the system context ! 719: savedHeapZone = GetZone(); ! 720: SetZone( SystemZone() ); ! 721: #if 0 ! 722: (void) BeginSystemMode(); ! 723: #endif ! 724: ! 725: result = GetSharedLibrary("\pUnicodeConverter", kPowerPCCFragArch, kPrivateCFragCopy, &unicodeLib, &tempMainAddr, errMessage); ! 726: ExitOnError( result ); ! 727: ! 728: result = GetSharedLibrary("\pTextCommon", kPowerPCCFragArch, kPrivateCFragCopy, &textLib, &tempMainAddr, errMessage); ! 729: ExitOnError( result ); ! 730: ! 731: ! 732: fsVars->gUseDynamicUnicodeConverters = true; ! 733: ! 734: result = InstallLibraryVector( unicodeLib, ! 735: "\pCreateTextToUnicodeInfo", ! 736: uupCreateTextToUnicodeInfoProcInfo, ! 737: &fsVars->uppCreateTextToUnicodeInfo ); ! 738: ExitOnError( result ); ! 739: ! 740: ! 741: result = InstallLibraryVector( unicodeLib, ! 742: "\pCreateUnicodeToTextInfo", ! 743: uppCreateUnicodeToTextInfoProcInfo, ! 744: &fsVars->uppCreateUnicodeToTextInfo ); ! 745: ExitOnError( result ); ! 746: ! 747: ! 748: result = InstallLibraryVector( unicodeLib, ! 749: "\pConvertFromTextToUnicode", ! 750: uppConvertFromTextToUnicodeProcInfo, ! 751: &fsVars->uppConvertFromTextToUnicode ); // don't set vector yet ! 752: ExitOnError( result ); ! 753: ! 754: ! 755: result = InstallLibraryVector( unicodeLib, ! 756: "\pConvertFromUnicodeToText", ! 757: uppConvertFromUnicodeToTextProcInfo, ! 758: &fsVars->uppConvertFromUnicodeToText ); // don't set vector yet ! 759: ExitOnError( result ); ! 760: ! 761: ! 762: result = InstallLibraryVector( unicodeLib, ! 763: "\pLockMappingTable", ! 764: uppLockMappingTableProcInfo, ! 765: &fsVars->uppLockMappingTable ); ! 766: ExitOnError( result ); ! 767: ! 768: ! 769: result = InstallLibraryVector( textLib, ! 770: "\pUpgradeScriptInfoToTextEncoding", ! 771: uppUpgradeScriptInfoToTextEncodingProcInfo, ! 772: &fsVars->uppUpgradeScriptInfoToTextEncoding ); ! 773: ExitOnError( result ); ! 774: ! 775: #if 0 ! 776: result = InstallLibraryVector( textLib, ! 777: "\pRevertTextEncodingToScriptInfo", ! 778: uppRevertTextEncodingToScriptInfoProcInfo, ! 779: &fsVars->uppRevertTextEncodingToScriptInfo ); ! 780: ExitOnError( result ); ! 781: #endif ! 782: ! 783: // NOTE: Real Unicode filename conversion is not enabled yet but that's OK. ! 784: // We can still call the converter library since it finds it's data files by ! 785: // matching file type and creator (not by name). ! 786: ! 787: result = InstallSystemConversionContext(fsVars, forBootVolume); ! 788: ExitOnError( result ); ! 789: ! 790: fsVars->gIsUnicodeInstalled = true; // Unicode binding and setup succesful, and now enabled ! 791: ! 792: // restore previous context ! 793: #if 0 ! 794: (void) EndSystemMode(); ! 795: #endif ! 796: SetZone( savedHeapZone ); ! 797: ! 798: return noErr; ! 799: ! 800: ErrorExit: ! 801: ! 802: fsVars->uppCreateTextToUnicodeInfo = NULL; ! 803: fsVars->uppCreateUnicodeToTextInfo = NULL; ! 804: fsVars->uppConvertFromTextToUnicode = NULL; ! 805: fsVars->uppConvertFromUnicodeToText = NULL; ! 806: fsVars->uppLockMappingTable = NULL; ! 807: ! 808: if ( unicodeLib ) ! 809: (void) CloseConnection( &unicodeLib ); ! 810: ! 811: if ( textLib ) ! 812: (void) CloseConnection( &textLib ); ! 813: ! 814: #if 0 ! 815: (void) EndSystemMode(); ! 816: #endif ! 817: SetZone( savedHeapZone ); ! 818: ! 819: return result; ! 820: ! 821: } // end InitDynamicUnicodeConverter ! 822: #endif /* TARGET_OS_MAC */ ! 823: ! 824: ! 825: ! 826: // ! 827: // Install a conversion context for the system script (call early in boot) ! 828: // ! 829: #if TARGET_OS_MAC ! 830: static OSErr ! 831: InstallSystemConversionContext( FSVarsRec *fsVars, Boolean forBootVolume ) ! 832: { ! 833: TextEncoding defaultEncoding; ! 834: ScriptCode script; ! 835: RegionCode region; ! 836: OSErr result; ! 837: ! 838: // The Script Manager does not setup the region until later in boot ! 839: // so if we're booting from HFS Plus we need to "manually" determine ! 840: // the system script and region using the 'itlc' resource. ! 841: ! 842: if ( forBootVolume ) ! 843: { ! 844: Handle configResource; ! 845: ItlcRecord *itlConfig; ! 846: ! 847: configResource = GetResource( 'itlc', 0 ); ! 848: ! 849: if ( configResource != NULL ) ! 850: { ! 851: itlConfig = (ItlcRecord*) *configResource; ! 852: ! 853: script = itlConfig->itlcSystem; ! 854: region = itlConfig->itlcRegionCode; ! 855: ! 856: ReleaseResource( configResource ); ! 857: } ! 858: else ! 859: { ! 860: script = GetScriptManagerVariable(smSysScript); ! 861: region = kTextRegionDontCare; ! 862: } ! 863: } ! 864: else ! 865: { ! 866: script = GetScriptManagerVariable(smSysScript); ! 867: region = GetScriptManagerVariable(smRegionCode); ! 868: } ! 869: ! 870: result = UpgradeScriptInfoToTextEncoding_Glue( script, ! 871: kTextLanguageDontCare, ! 872: region, ! 873: NULL, ! 874: &defaultEncoding ); ! 875: if ( result == paramErr ) ! 876: { ! 877: // ok, last ditch effort to get an encoding... ! 878: result = UpgradeScriptInfoToTextEncoding_Glue( script, ! 879: kTextLanguageDontCare, ! 880: kTextRegionDontCare, ! 881: NULL, ! 882: &defaultEncoding ); ! 883: } ! 884: ReturnIfError(result); ! 885: ! 886: defaultEncoding = GetTextEncodingBasePriv(defaultEncoding); ! 887: ! 888: result = InitializeEncodingContext( defaultEncoding, fsVars ); ! 889: ReturnIfError(result); ! 890: ! 891: if ( defaultEncoding != kTextEncodingMacRoman ) ! 892: { ! 893: result = InitializeEncodingContext( kTextEncodingMacRoman, fsVars ); // always install Roman ! 894: ReturnIfError(result); ! 895: } ! 896: ! 897: // Since a call to set the default text encoding can occur ! 898: // before any HFS Plus volumes are mounted we need to check ! 899: // gDefaultBaseEncoding and gTextEncodingFontName to see if ! 900: // the default encoding needs to change... ! 901: if ( !forBootVolume ) ! 902: { ! 903: TextEncoding requestedEncoding; ! 904: ! 905: requestedEncoding = fsVars->gDefaultBaseEncoding; ! 906: ! 907: if ( requestedEncoding == kTextEncodingUndefined && fsVars->gTextEncodingFontName != NULL ) ! 908: { ! 909: result = UpgradeScriptInfoToTextEncoding_Glue ( kTextScriptDontCare, ! 910: kTextLanguageDontCare, ! 911: kTextRegionDontCare, ! 912: fsVars->gTextEncodingFontName, ! 913: &requestedEncoding ); ! 914: if ( result != noErr ) ! 915: requestedEncoding = kTextEncodingUndefined; ! 916: ! 917: DisposePtr((Ptr) fsVars->gTextEncodingFontName); // we no longer need font name ! 918: fsVars->gTextEncodingFontName = NULL; ! 919: } ! 920: ! 921: if ( requestedEncoding != kTextEncodingUndefined && requestedEncoding != defaultEncoding ) ! 922: { ! 923: result = InitializeEncodingContext( requestedEncoding, fsVars ); ! 924: if ( result == noErr ) ! 925: defaultEncoding = requestedEncoding; ! 926: } ! 927: } ! 928: ! 929: ! 930: // remember the default text encoding... ! 931: fsVars->gDefaultBaseEncoding = defaultEncoding; ! 932: ! 933: return noErr; ! 934: ! 935: } // end InstallSystemConversionContext ! 936: #endif /* TARGET_OS_MAC */ ! 937: ! 938: ! 939: ! 940: // ! 941: // Install any addition scripts that were installed by the system (call late in boot) ! 942: // ! 943: #if TARGET_OS_MAC ! 944: OSErr ! 945: InstallConversionContextsForInstalledScripts( void ) ! 946: { ! 947: FSVarsRec* fsVars; ! 948: TextEncoding encoding; ! 949: UInt32 scriptCount; ! 950: ScriptCode systemScript; ! 951: ScriptCode script; ! 952: OSErr result; ! 953: ! 954: ! 955: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 956: ! 957: scriptCount = GetScriptManagerVariable(smEnabled); ! 958: systemScript = GetScriptManagerVariable(smSysScript); ! 959: ! 960: script = 0; ! 961: ! 962: while ( (scriptCount > 0) && (script <= smLargestScript) ) ! 963: { ! 964: if ( GetScriptVariable(script, smScriptEnabled) != 0 ) // is this script enabled? ! 965: { ! 966: --scriptCount; ! 967: ! 968: if ( script != systemScript ) // we already did systemScript ! 969: { ! 970: LangCode language; ! 971: ! 972: language = GetScriptVariable( script, smScriptLang ); ! 973: ! 974: result = UpgradeScriptInfoToTextEncoding_Glue( script, language, kTextRegionDontCare, NULL, &encoding ); ! 975: if ( result == noErr ) ! 976: (void) InitializeEncodingContext( encoding, fsVars ); ! 977: } ! 978: } ! 979: ! 980: ++script; // on to the next one ! 981: } ! 982: ! 983: return noErr; ! 984: ! 985: } // end InstallConversionContextsForInstalledScripts ! 986: #endif /* TARGET_OS_MAC */ ! 987: ! 988: ! 989: ! 990: // ! 991: // Install any addition scripts that were used by an HFS Plus volume (called at volume mount time) ! 992: // ! 993: #if TARGET_OS_MAC ! 994: OSErr ! 995: InstallVolumeConversionContexts( UInt64 encodingsBitmap ) ! 996: { ! 997: FSVarsRec * fsVars; ! 998: UInt32 encodingMask; ! 999: UInt32 index; ! 1000: UInt32 encoding; ! 1001: OSErr result; ! 1002: ! 1003: ! 1004: fsVars = (FSVarsRec*) LMGetFSMVars(); ! 1005: ! 1006: index = 0; ! 1007: encodingMask = 1; ! 1008: ! 1009: while ( encodingMask != 0 ) ! 1010: { ! 1011: if ( encodingMask & encodingsBitmap.lo ) // encodings 0 - 31 ! 1012: { ! 1013: encoding = MapIndexToEncoding(index); ! 1014: result = InitializeEncodingContext( encoding, fsVars ); ! 1015: } ! 1016: ! 1017: if ( encodingMask & encodingsBitmap.hi ) // encodings 32 - 64 ! 1018: { ! 1019: encoding = MapIndexToEncoding(index + 32); ! 1020: result = InitializeEncodingContext( encoding, fsVars ); ! 1021: } ! 1022: ! 1023: encodingMask = encodingMask << 1; ! 1024: ++index; ! 1025: } ! 1026: ! 1027: return noErr; ! 1028: ! 1029: } // end InstallVolumeConversionContexts ! 1030: #endif /* TARGET_OS_MAC */ ! 1031: ! 1032: ! 1033: // ! 1034: // Initialze a conversion context for a single encoding (if not already installed) ! 1035: // ! 1036: #if TARGET_OS_MAC ! 1037: OSErr InitializeEncodingContext( TextEncoding encoding, FSVarsRec *fsVars ) ! 1038: { ! 1039: UInt32 index; ! 1040: UnicodeMapping unicodeMapping; ! 1041: THz savedHeapZone; ! 1042: OSStatus result; ! 1043: ! 1044: ! 1045: encoding = GetTextEncodingBasePriv( encoding ); ! 1046: index = MapEncodingToIndex(encoding); ! 1047: ! 1048: if ( fsVars->gConversionContext[index].toUnicode != 0 ) ! 1049: return noErr; // this one is already installed! ! 1050: ! 1051: savedHeapZone = GetZone(); ! 1052: SetZone( SystemZone() ); // always use the system heap since Conversion Contexts are global ! 1053: ! 1054: ! 1055: // Note: by default kTextEncodingUnicodeV2_0 allows corporate use characters ! 1056: unicodeMapping.unicodeEncoding = CreateTextEncodingPriv( kTextEncodingUnicodeV2_0, kUnicodeCanonicalDecompVariant, 0 ); ! 1057: unicodeMapping.otherEncoding = encoding; ! 1058: unicodeMapping.mappingVersion = kUnicodeUseHFSPlusMapping; ! 1059: ! 1060: ! 1061: if ( fsVars->gUseDynamicUnicodeConverters == false ) ! 1062: result = LockMappingTable( &unicodeMapping, true ); ! 1063: else ! 1064: result = LockMappingTable_Glue( &unicodeMapping, true ); ! 1065: ExitOnError( result ); ! 1066: ! 1067: result = CreateTextToUnicodeInfo_Glue( &unicodeMapping, &fsVars->gConversionContext[index].toUnicode ); ! 1068: ExitOnError( result ); ! 1069: ! 1070: result = CreateUnicodeToTextInfo_Glue( &unicodeMapping, &fsVars->gConversionContext[index].fromUnicode ); ! 1071: ExitOnError( result ); ! 1072: ! 1073: ++(fsVars->gInstalledEncodings); // keep track of how many we've installed ! 1074: ! 1075: #if 0 ! 1076: result = SetFallbackUnicodeToText( fsVars->gConversionContext[index].fromUnicode, ! 1077: NewUnicodeToTextFallbackProc(FallbackProc), // since we are compiled 68K no routine descriptor is needed ! 1078: kUnicodeFallbackCustomOnly, ! 1079: NULL ); ! 1080: ! 1081: #endif ! 1082: ! 1083: ErrorExit: ! 1084: ! 1085: SetZone( savedHeapZone ); ! 1086: ! 1087: return result; ! 1088: ! 1089: } // end InitializeEncodingContext ! 1090: #endif /* TARGET_OS_MAC */ ! 1091: ! 1092: ! 1093: #if TARGET_OS_MAC ! 1094: pascal OSStatus ! 1095: FallbackProc( UniChar * srcUniStr, ByteCount srcUniStrLen, ByteCount *srcConvLen, ! 1096: TextPtr destStr, ByteCount destStrLen, ByteCount *destConvLen, ! 1097: LogicalAddress contextPtr, ConstUnicodeMappingPtr unicodeMappingPtr) ! 1098: { ! 1099: #pragma unused (srcUniStr, destStrLen, contextPtr, unicodeMappingPtr) ! 1100: *srcConvLen = srcUniStrLen; ! 1101: *destStr = '_'; ! 1102: *destConvLen = sizeof(unsigned char); ! 1103: ! 1104: return noErr; ! 1105: } ! 1106: #endif ! 1107: ! 1108: #if TARGET_OS_MAC ! 1109: static OSErr ! 1110: InstallLibraryVector ( CFragConnectionID connectionID, ConstStr255Param symbolName, ProcInfoType procInfo, UniversalProcPtr *vector) ! 1111: { ! 1112: UniversalProcPtr routineDescriptor; ! 1113: CFragSymbolClass symClass; ! 1114: ProcPtr tVector; ! 1115: OSErr result; ! 1116: ! 1117: ! 1118: result = FindSymbol(connectionID, symbolName, (Ptr *) &tVector, &symClass); ! 1119: ReturnIfError( result ); ! 1120: ! 1121: routineDescriptor = NewRoutineDescriptorTrap(tVector, procInfo, kPowerPCISA); ! 1122: ! 1123: if ( routineDescriptor != NULL ) ! 1124: *vector = routineDescriptor; ! 1125: else ! 1126: result = memFullErr; ! 1127: ! 1128: return result; ! 1129: } ! 1130: #endif ! 1131: ! 1132: ! 1133: // ! 1134: // Get filename extension (if any) as a pascal string ! 1135: // ! 1136: #if TARGET_OS_MAC ! 1137: static void ! 1138: GetFilenameExtension( ItemCount length, ConstUniCharArrayPtr unicodeStr, Str15 extStr ) ! 1139: { ! 1140: UInt32 i; ! 1141: UniChar c; ! 1142: UInt16 extChars; // number of extension characters (excluding the dot) ! 1143: UInt16 maxExtChars; ! 1144: Boolean foundExtension; ! 1145: ! 1146: ! 1147: extStr[0] = (UInt8) 0; // assume there's no extension ! 1148: ! 1149: if ( length < 3 ) ! 1150: return; // sorry, "x.y" is smallest possible extension ! 1151: ! 1152: if ( length < (kMaxFileExtensionChars + 2) ) ! 1153: maxExtChars = length - 2; // we need at least one prefix character and dot ! 1154: else ! 1155: maxExtChars = kMaxFileExtensionChars; ! 1156: ! 1157: i = length; ! 1158: extChars = 0; ! 1159: foundExtension = false; ! 1160: ! 1161: while ( extChars <= maxExtChars ) ! 1162: { ! 1163: c = unicodeStr[--i]; ! 1164: ! 1165: if ( c == (UniChar) '.' ) // look for leading dot ! 1166: { ! 1167: if ( extChars > 0 ) // cannot end with a dot ! 1168: foundExtension = true; ! 1169: break; ! 1170: } ! 1171: ! 1172: if ( Is7BitASCII(c) || IsSpecialUnicodeChar(c) ) ! 1173: ++extChars; ! 1174: else ! 1175: break; ! 1176: } ! 1177: ! 1178: // if we found one then copy it ! 1179: if ( foundExtension ) ! 1180: { ! 1181: UInt8 *extStrPtr = extStr; ! 1182: const UniChar *unicodeStrPtr = &unicodeStr[i]; // point to dot char ! 1183: ! 1184: *(extStrPtr++) = extChars + 1; // set length to extension chars plus dot ! 1185: ! 1186: for ( i = 0; i <= extChars; ++i ) ! 1187: { ! 1188: c = *(unicodeStrPtr++); ! 1189: ! 1190: // map any special characters ! 1191: switch (c) ! 1192: { ! 1193: case 0x00B5: // micro sign ! 1194: case 0x03BC: // greek mu ! 1195: c = (UniChar) '�'; ! 1196: break; ! 1197: ! 1198: case 0x03C0: // greek pi ! 1199: c = (UniChar) '�'; ! 1200: break; ! 1201: ! 1202: case 0x2206: // increment sign ! 1203: case 0x0394: // greek capital delta ! 1204: c = (UniChar) '�'; ! 1205: break; ! 1206: } ! 1207: ! 1208: *(extStrPtr++) = (UInt8) c; // copy/convert to ascii ! 1209: } ! 1210: } ! 1211: ! 1212: } // end GetFilenameExtension ! 1213: #endif /* TARGET_OS_MAC */ ! 1214: ! 1215: ! 1216: // ! 1217: // Count filename extension characters (if any) ! 1218: // ! 1219: static UInt32 ! 1220: CountFilenameExtensionChars( const unsigned char * filename ) ! 1221: { ! 1222: UInt32 i; ! 1223: UniChar c; ! 1224: UInt32 extChars; // number of extension characters (excluding the dot) ! 1225: UInt32 length; ! 1226: UInt16 maxExtChars; ! 1227: Boolean foundExtension; ! 1228: ! 1229: ! 1230: length = strlen(filename); ! 1231: ! 1232: if ( length < 3 ) ! 1233: return 0; // sorry, "x.y" is smallest possible extension ! 1234: ! 1235: if ( length < (kMaxFileExtensionChars + 2) ) ! 1236: maxExtChars = length - 2; // we need at least on prefix character and dot ! 1237: else ! 1238: maxExtChars = kMaxFileExtensionChars; ! 1239: ! 1240: extChars = 0; // assume there's no extension ! 1241: i = length - 1; // index to last ascii character ! 1242: foundExtension = false; ! 1243: ! 1244: while ( extChars <= maxExtChars ) ! 1245: { ! 1246: c = filename[i--]; ! 1247: ! 1248: if ( c == (UInt8) '.' ) // look for leading dot ! 1249: { ! 1250: if ( extChars > 0 ) // cannot end with a dot ! 1251: return (extChars); ! 1252: ! 1253: break; ! 1254: } ! 1255: ! 1256: if ( Is7BitASCII(c) || IsSpecialASCIIChar(c) ) ! 1257: ++extChars; ! 1258: else ! 1259: break; ! 1260: } ! 1261: ! 1262: return 0; ! 1263: ! 1264: } // end CountFilenameExtensionChars ! 1265: ! 1266: ! 1267: // ! 1268: // Convert file ID into a hexidecimal string with no leading zeros ! 1269: // ! 1270: #if TARGET_OS_MAC ! 1271: static void ! 1272: GetFileIDString( HFSCatalogNodeID fileID, Str15 fileIDStr ) ! 1273: { ! 1274: SInt32 i, b; ! 1275: static UInt8 *translate = (UInt8 *) "0123456789ABCDEF"; ! 1276: UInt8 c; ! 1277: ! 1278: fileIDStr[1] = '#'; ! 1279: ! 1280: for ( i = 1, b = 28; b >= 0; b -= 4 ) ! 1281: { ! 1282: c = *(translate + ((fileID >> b) & 0x0000000F)); ! 1283: ! 1284: // if its not a leading zero add it to our string ! 1285: if ( (c != (UInt8) '0') || (i > 1) || (b == 0) ) ! 1286: fileIDStr[++i] = c; ! 1287: } ! 1288: ! 1289: fileIDStr[0] = (UInt8) i; ! 1290: ! 1291: } // end GetFileIDString ! 1292: #endif /* TARGET_OS_MAC */ ! 1293: ! 1294: ! 1295: // ! 1296: // Append a suffix to a pascal string ! 1297: // ! 1298: #if TARGET_OS_MAC ! 1299: static void ! 1300: AppendPascalString( ConstStr15Param src, Str31 dst ) ! 1301: { ! 1302: UInt32 i, j; ! 1303: UInt32 srcLen; ! 1304: ! 1305: srcLen = StrLength(src); ! 1306: ! 1307: if ( (srcLen + StrLength(dst)) > 31 ) // safety net ! 1308: return; ! 1309: ! 1310: i = dst[0] + 1; // get end of dst ! 1311: ! 1312: for (j = 1; j <= srcLen; ++j) ! 1313: dst[i++] = src[j]; ! 1314: ! 1315: dst[0] += srcLen; ! 1316: ! 1317: } // end AppendPascalString ! 1318: #endif /* TARGET_OS_MAC */ ! 1319: ! 1320: ! 1321: HFSCatalogNodeID ! 1322: GetEmbeddedFileID(const unsigned char * filename, UInt32 *prefixLength) ! 1323: { ! 1324: short length; ! 1325: short extChars; ! 1326: short i; ! 1327: UInt8 c; // current character in filename ! 1328: ! 1329: *prefixLength = 0; ! 1330: ! 1331: if ( filename == NULL ) ! 1332: return 0; ! 1333: ! 1334: length = strlen(filename); ! 1335: ! 1336: if ( length < 4 ) ! 1337: return 0; // too small to have a file ID ! 1338: ! 1339: if ( length >= 6 ) // big enough for a file ID (#10) and an extension (.x) ? ! 1340: extChars = CountFilenameExtensionChars(filename); ! 1341: else ! 1342: extChars = 0; ! 1343: ! 1344: if ( extChars > 0 ) ! 1345: length -= (extChars + 1); // skip dot plus extension characters ! 1346: ! 1347: // scan for file id digits... ! 1348: for ( i = length - 1; i >= 0; --i) ! 1349: { ! 1350: c = filename[i]; ! 1351: ! 1352: if ( c == '#' ) // look for file ID marker ! 1353: { ! 1354: if ( (length - i) < 3 ) ! 1355: break; // too small to be a file ID ! 1356: ! 1357: *prefixLength = i; ! 1358: return HexStringToInteger(length - i - 1, &filename[i+1]); ! 1359: } ! 1360: ! 1361: if ( !IsHexDigit(c) ) ! 1362: break; // file ID string must have hex digits ! 1363: } ! 1364: ! 1365: return 0; ! 1366: ! 1367: } // end GetEmbeddedFileID ! 1368: ! 1369: ! 1370: //_______________________________________________________________________ ! 1371: ! 1372: static UInt32 ! 1373: HexStringToInteger (UInt32 length, const UInt8 *hexStr) ! 1374: { ! 1375: UInt32 value; // decimal value represented by the string ! 1376: short i; ! 1377: UInt8 c; // next character in buffer ! 1378: const UInt8 *p; // pointer to character string ! 1379: ! 1380: value = 0; ! 1381: p = hexStr; ! 1382: ! 1383: for ( i = 0; i < length; ++i ) ! 1384: { ! 1385: c = *p++; ! 1386: ! 1387: if (c >= '0' && c <= '9') ! 1388: { ! 1389: value = value << 4; ! 1390: value += (UInt32) c - (UInt32) '0'; ! 1391: } ! 1392: else if (c >= 'A' && c <= 'F') ! 1393: { ! 1394: value = value << 4; ! 1395: value += 10 + ((unsigned int) c - (unsigned int) 'A'); ! 1396: } ! 1397: else ! 1398: { ! 1399: return 0; // oops, how did this character get in here? ! 1400: } ! 1401: } ! 1402: ! 1403: return value; ! 1404: ! 1405: } // end HexStringToInteger ! 1406: ! 1407: ! 1408: //_______________________________________________________________________ ! 1409: // ! 1410: // Routine: FastRelString ! 1411: // ! 1412: // Output: returns -1 if str1 < str2 ! 1413: // returns 1 if str1 > str2 ! 1414: // return 0 if equal ! 1415: // ! 1416: //_______________________________________________________________________ ! 1417: ! 1418: #if USE_TABLE_ACCESSORS ! 1419: UInt16 *Get_gCompareTable(void); ! 1420: #else ! 1421: extern unsigned short gCompareTable[]; ! 1422: #endif ! 1423: ! 1424: SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ) ! 1425: { ! 1426: UInt16* compareTable; ! 1427: SInt32 bestGuess; ! 1428: UInt8 length, length2; ! 1429: ! 1430: ! 1431: length = *(str1++); ! 1432: length2 = *(str2++); ! 1433: ! 1434: if (length == length2) ! 1435: bestGuess = 0; ! 1436: else if (length < length2) ! 1437: bestGuess = -1; ! 1438: else ! 1439: { ! 1440: bestGuess = 1; ! 1441: length = length2; ! 1442: } ! 1443: ! 1444: #if USE_TABLE_ACCESSORS ! 1445: compareTable = Get_gCompareTable(); ! 1446: #else ! 1447: compareTable = (UInt16*) gCompareTable; ! 1448: #endif ! 1449: ! 1450: while (length--) ! 1451: { ! 1452: UInt8 aChar, bChar; ! 1453: ! 1454: aChar = *(str1++); ! 1455: bChar = *(str2++); ! 1456: ! 1457: if (aChar != bChar) // If they don't match exacly, do case conversion ! 1458: { ! 1459: UInt16 aSortWord, bSortWord; ! 1460: ! 1461: aSortWord = compareTable[aChar]; ! 1462: bSortWord = compareTable[bChar]; ! 1463: ! 1464: if (aSortWord > bSortWord) ! 1465: return 1; ! 1466: ! 1467: if (aSortWord < bSortWord) ! 1468: return -1; ! 1469: } ! 1470: ! 1471: // If characters match exactly, then go on to next character immediately without ! 1472: // doing any extra work. ! 1473: } ! 1474: ! 1475: // if you got to here, then return bestGuess ! 1476: return bestGuess; ! 1477: } ! 1478: ! 1479: ! 1480: ! 1481: /* 0x00A0 - 0x00FF = Latin 1 Supplement (30 total) */ ! 1482: UInt8 gLatin1Table[] = ! 1483: { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 1484: /* 0x00A0 */ 0xCA, 0xC1, 0xA2, 0xA3, 0xDB, 0xB4, '?', 0xA4, 0xAC, 0xA9, 0xBB, 0xC7, 0xC2, '?', 0xA8, 0xF8, ! 1485: /* 0x00B0 */ 0xA1, 0XB1, '?', '?', 0xAB, 0xB5, 0xA6, 0xe1, 0xFC, '?', 0xBC, 0xC8, '?', '?', '?', 0xC0, ! 1486: /* 0x00C0 */ '?', '?', '?', '?', '?', '?', 0xAE, '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1487: /* 0x00D0 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xAF, '?', '?', '?', '?', '?', '?', 0xA7, ! 1488: /* 0x00E0 */ '?', '?', '?', '?', '?', '?', 0xBE, '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1489: /* 0x00F0 */ '?', '?', '?', '?', '?', '?', '?', 0xD6, 0xBF, '?', '?', '?', '?', '?', '?', '?' ! 1490: }; ! 1491: ! 1492: ! 1493: /* 0x02C0 - 0x02DF = Spacing Modifiers (8 total) */ ! 1494: UInt8 gSpaceModsTable[] = ! 1495: { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 1496: /* 0x02C0 */ '?', '?', '?', '?', '?', '?', 0xF6, 0xFF, '?', '?', '?', '?', '?', '?', '?', '?', ! 1497: /* 0x02D0 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xF9, 0xFA, 0xFB, 0xFE, 0xF7, 0xFD, '?', '?' ! 1498: }; ! 1499: ! 1500: ! 1501: /* 0x20xx = General Punctuation (16 total) */ ! 1502: UInt8 gPunctTable[] = ! 1503: { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 1504: /* 0x2000 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1505: /* 0x2010 */ '?', '?', '?', 0xd0, 0xd1, '?', '?', '?', 0xd4, 0xd5, 0xe2, '?', 0xd2, 0xd3, 0xe3, '?', ! 1506: /* 0x2020 */ 0xa0, 0xe0, 0xa5, '?', '?', '?', 0xc9, '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1507: /* 0x2030 */ 0xe4, '?', '?', '?', '?', '?', '?', '?', '?', 0xdc, 0xdd, '?', '?', '?', '?', '?', ! 1508: /* 0x2040 */ '?', '?', '?', '?', 0xda, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?' ! 1509: }; ! 1510: ! 1511: ! 1512: /* 0x2200 = Mathematical Operators (11 total) */ ! 1513: UInt8 gMathTable[] = ! 1514: { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 1515: /* 0x2200 */ '?', '?', 0xb6, '?', '?', '?', 0xc6, '?', '?', '?', '?', '?', '?', '?', '?', 0xb8, ! 1516: /* 0x2210 */ '?', 0xb7, '?', '?', '?', '?', '?', '?', '?', '?', 0xc3, '?', '?', '?', 0xb0, '?', ! 1517: /* 0x2220 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0xba, '?', '?', '?', '?', ! 1518: /* 0x2230 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1519: /* 0x2240 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xc5, '?', '?', '?', '?', '?', '?', '?', ! 1520: /* 0x2250 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', ! 1521: /* 0x2260 */ 0xad, '?', '?', '?', 0xb2, 0xb3, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?' ! 1522: }; ! 1523: ! 1524: ! 1525: /* */ ! 1526: UInt8 gReverseCombTable[] = ! 1527: { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ ! 1528: /* 0x40 */ 0xDA, 0x40, 0xDA, 0xDA, 0xDA, 0x56, 0xDA, 0xDA, 0xDA, 0x6C, 0xDA, 0xDA, 0xDA, 0xDA, 0x82, 0x98, ! 1529: /* 0x50 */ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xAE, 0xDA, 0xDA, 0xDA, 0xC4, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, ! 1530: /* 0x60 */ 0xDA, 0x4B, 0xDA, 0xDA, 0xDA, 0x61, 0xDA, 0xDA, 0xDA, 0x77, 0xDA, 0xDA, 0xDA, 0xDA, 0x8D, 0xA3, ! 1531: /* 0x70 */ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xB9, 0xDA, 0xDA, 0xDA, 0xCF, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, ! 1532: ! 1533: /* Combining Diacritical Marks (0x0300 - 0x030A) */ ! 1534: ! 1535: /* 0 1 2 3 4 5 6 7 8 9 A */ ! 1536: /* 'A' */ ! 1537: /* 0x0300 */ 0xCB, 0xE7, 0xE5, 0xCC, '?', '?', '?', '?', 0x80, '?', 0x81, ! 1538: ! 1539: /* 'a' */ ! 1540: /* 0x0300 */ 0x88, 0x87, 0x89, 0x8B, '?', '?', '?', '?', 0x8A, '?', 0x8C, ! 1541: ! 1542: /* 'E' */ ! 1543: /* 0x0300 */ 0xE9, 0x83, 0xE6, '?', '?', '?', '?', '?', 0xE8, '?', '?', ! 1544: ! 1545: /* 'e' */ ! 1546: /* 0x0300 */ 0x8F, 0x8E, 0x90, '?', '?', '?', '?', '?', 0x91, '?', '?', ! 1547: ! 1548: /* 'I' */ ! 1549: /* 0x0300 */ 0xED, 0xEA, 0xEB, '?', '?', '?', '?', '?', 0xEC, '?', '?', ! 1550: ! 1551: /* 'i' */ ! 1552: /* 0x0300 */ 0x93, 0x92, 0x94, '?', '?', '?', '?', '?', 0x95, '?', '?', ! 1553: ! 1554: /* 'N' */ ! 1555: /* 0x0300 */ '?', '?', '?', 0x84, '?', '?', '?', '?', '?', '?', '?', ! 1556: ! 1557: /* 'n' */ ! 1558: /* 0x0300 */ '?', '?', '?', 0x96, '?', '?', '?', '?', '?', '?', '?', ! 1559: ! 1560: /* 'O' */ ! 1561: /* 0x0300 */ 0xF1, 0xEE, 0xEF, 0xCD, '?', '?', '?', '?', 0x85, '?', '?', ! 1562: ! 1563: /* 'o' */ ! 1564: /* 0x0300 */ 0x98, 0x97, 0x99, 0x9B, '?', '?', '?', '?', 0x9A, '?', '?', ! 1565: ! 1566: /* 'U' */ ! 1567: /* 0x0300 */ 0xF4, 0xF2, 0xF3, '?', '?', '?', '?', '?', 0x86, '?', '?', ! 1568: ! 1569: /* 'u' */ ! 1570: /* 0x0300 */ 0x9D, 0x9C, 0x9E, '?', '?', '?', '?', '?', 0x9F, '?', '?', ! 1571: ! 1572: /* 'Y' */ ! 1573: /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xD9, '?', '?', ! 1574: ! 1575: /* 'y' */ ! 1576: /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', 0xD8, '?', '?', ! 1577: ! 1578: /* else */ ! 1579: /* 0x0300 */ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?' ! 1580: }; ! 1581: ! 1582: ! 1583: static OSErr UnicodeToMacRoman (ItemCount unicodeChars, ConstUniCharArrayPtr unicodeString, Str31 pascalString) ! 1584: { ! 1585: UInt8 *p; ! 1586: const UniChar *u; ! 1587: UniChar c; ! 1588: UniChar mask; ! 1589: UInt16 inputChars; ! 1590: UInt16 pascalChars; ! 1591: OSErr result = noErr; ! 1592: UInt8 lsb; ! 1593: UInt8 prevChar; ! 1594: UInt8 mc; ! 1595: ! 1596: ! 1597: mask = (UniChar) 0xFF80; ! 1598: p = &pascalString[1]; ! 1599: u = unicodeString; ! 1600: inputChars = unicodeChars; ! 1601: pascalChars = prevChar = 0; ! 1602: ! 1603: while (inputChars) { ! 1604: c = *(u++); ! 1605: lsb = (UInt8) c; ! 1606: ! 1607: /* ! 1608: * If its not 7-bit ascii, then we need to map it ! 1609: */ ! 1610: if ( c & mask ) { ! 1611: mc = '?'; ! 1612: switch (c & 0xFF00) { ! 1613: case 0x0000: ! 1614: if (lsb >= 0xA0) ! 1615: mc = gLatin1Table[lsb - 0xA0]; ! 1616: break; ! 1617: ! 1618: case 0x0200: ! 1619: if (lsb >= 0xC0 && lsb <= 0xDF) ! 1620: mc = gSpaceModsTable[lsb - 0xC0]; ! 1621: break; ! 1622: ! 1623: case 0x2000: ! 1624: if (lsb <= 0x4F) ! 1625: mc = gPunctTable[lsb]; ! 1626: break; ! 1627: ! 1628: case 0x2200: ! 1629: if (lsb <= 0x6F) ! 1630: mc = gMathTable[lsb]; ! 1631: break; ! 1632: ! 1633: case 0x0300: ! 1634: if (c <= 0x030A) { ! 1635: if (prevChar >= 'A' && prevChar < 'z') { ! 1636: mc = gReverseCombTable[gReverseCombTable[prevChar - 0x40] + lsb]; ! 1637: --p; /* backup over base char */ ! 1638: --pascalChars; ! 1639: } ! 1640: } ! 1641: else { ! 1642: switch (c) { ! 1643: case 0x0327: /* combining cedilla */ ! 1644: if (prevChar == 'C') ! 1645: mc = 0x82; ! 1646: else if (prevChar == 'c') ! 1647: mc = 0x8D; ! 1648: else ! 1649: break; ! 1650: --p; /* backup over base char */ ! 1651: --pascalChars; ! 1652: break; ! 1653: ! 1654: case 0x03A9: mc = 0xBD; break; /* omega */ ! 1655: ! 1656: case 0x03C0: mc = 0xB9; break; /* pi */ ! 1657: } ! 1658: } ! 1659: break; ! 1660: ! 1661: default: ! 1662: switch (c) { ! 1663: case 0x0131: mc = 0xf5; break; /* dotless i */ ! 1664: ! 1665: case 0x0152: mc = 0xce; break; /* OE */ ! 1666: ! 1667: case 0x0153: mc = 0xcf; break; /* oe */ ! 1668: ! 1669: case 0x0192: mc = 0xc4; break; /* � */ ! 1670: ! 1671: case 0x2122: mc = 0xaa; break; /* TM */ ! 1672: ! 1673: case 0x25ca: mc = 0xd7; break; /* diamond */ ! 1674: ! 1675: case 0xf8ff: mc = 0xf0; break; /* apple logo */ ! 1676: ! 1677: case 0xfb01: mc = 0xde; break; /* fi */ ! 1678: ! 1679: case 0xfb02: mc = 0xdf; break; /* fl */ ! 1680: } ! 1681: } /* end switch (c & 0xFF00) */ ! 1682: ! 1683: /* ! 1684: * If we have an unmapped character then we need to mangle the name... ! 1685: */ ! 1686: if (mc == '?') ! 1687: result = kTECUsedFallbacksStatus; ! 1688: ! 1689: prevChar = 0; ! 1690: lsb = mc; ! 1691: ! 1692: } /* end if (c & mask) */ ! 1693: else { ! 1694: prevChar = lsb; ! 1695: } ! 1696: ! 1697: if (pascalChars >= 31) ! 1698: break; ! 1699: ! 1700: *(p++) = lsb; ! 1701: ++pascalChars; ! 1702: --inputChars; ! 1703: ! 1704: } /* end while */ ! 1705: ! 1706: pascalString[0] = pascalChars; ! 1707: ! 1708: if (inputChars > 0) ! 1709: result = kTECOutputBufferFullStatus; /* ran out of room! */ ! 1710: ! 1711: return result; ! 1712: } ! 1713: ! 1714: ! 1715: UniChar gHiBitBaseUnicode[128] = ! 1716: { ! 1717: /* 0x80 */ 0x0041, 0x0041, 0x0043, 0x0045, 0x004e, 0x004f, 0x0055, 0x0061, ! 1718: /* 0x88 */ 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0063, 0x0065, 0x0065, ! 1719: /* 0x90 */ 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069, 0x006e, 0x006f, ! 1720: /* 0x98 */ 0x006f, 0x006f, 0x006f, 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, ! 1721: /* 0xa0 */ 0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df, ! 1722: /* 0xa8 */ 0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8, ! 1723: /* 0xb0 */ 0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211, ! 1724: /* 0xb8 */ 0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x03a9, 0x00e6, 0x00f8, ! 1725: /* 0xc0 */ 0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab, ! 1726: /* 0xc8 */ 0x00bb, 0x2026, 0x00a0, 0x0041, 0x0041, 0x004f, 0x0152, 0x0153, ! 1727: /* 0xd0 */ 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca, ! 1728: /* 0xd8 */ 0x0079, 0x0059, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02, ! 1729: /* 0xe0 */ 0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x0041, 0x0045, 0x0041, ! 1730: /* 0xe8 */ 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, 0x004f, 0x004f, ! 1731: /* 0xf0 */ 0xf8ff, 0x004f, 0x0055, 0x0055, 0x0055, 0x0131, 0x02c6, 0x02dc, ! 1732: /* 0xf8 */ 0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7 ! 1733: }; ! 1734: ! 1735: UniChar gHiBitCombUnicode[128] = ! 1736: { ! 1737: /* 0x80 */ 0x0308, 0x030a, 0x0327, 0x0301, 0x0303, 0x0308, 0x0308, 0x0301, ! 1738: /* 0x88 */ 0x0300, 0x0302, 0x0308, 0x0303, 0x030a, 0x0327, 0x0301, 0x0300, ! 1739: /* 0x90 */ 0x0302, 0x0308, 0x0301, 0x0300, 0x0302, 0x0308, 0x0303, 0x0301, ! 1740: /* 0x98 */ 0x0300, 0x0302, 0x0308, 0x0303, 0x0301, 0x0300, 0x0302, 0x0308, ! 1741: /* 0xa0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1742: /* 0xa8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1743: /* 0xb0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1744: /* 0xb8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1745: /* 0xc0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1746: /* 0xc8 */ 0x0000, 0x0000, 0x0000, 0x0300, 0x0303, 0x0303, 0x0000, 0x0000, ! 1747: /* 0xd0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1748: /* 0xd8 */ 0x0308, 0x0308, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, ! 1749: /* 0xe0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0302, 0x0302, 0x0301, ! 1750: /* 0xe8 */ 0x0308, 0x0300, 0x0301, 0x0302, 0x0308, 0x0300, 0x0301, 0x0302, ! 1751: /* 0xf0 */ 0x0000, 0x0300, 0x0301, 0x0302, 0x0300, 0x0000, 0x0000, 0x0000, ! 1752: /* 0xf8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 ! 1753: }; ! 1754: ! 1755: ! 1756: static OSErr MacRomanToUnicode (ConstStr255Param pascalString, ItemCount *unicodeChars, UniCharArrayPtr unicodeString) ! 1757: { ! 1758: const UInt8 *p; ! 1759: UniChar *u; ! 1760: UInt16 pascalChars; ! 1761: UInt8 c; ! 1762: ! 1763: ! 1764: p = pascalString; ! 1765: u = unicodeString; ! 1766: ! 1767: *unicodeChars = pascalChars = *(p++); // pick up length byte ! 1768: ! 1769: while (pascalChars--) { ! 1770: c = *(p++); ! 1771: ! 1772: if ( (SInt8) c >= 0 ) { // make sure its seven bit ascii ! 1773: *(u++) = (UniChar) c; // pad high byte with zero ! 1774: } ! 1775: else { /* its a hi bit character */ ! 1776: UniChar uc; ! 1777: ! 1778: c &= 0x7F; ! 1779: *(u++) = uc = gHiBitBaseUnicode[c]; ! 1780: ! 1781: /* ! 1782: * if the unicode character (uc) is an alpha char ! 1783: * then we have an additional combining character ! 1784: */ ! 1785: if ((uc <= (UniChar) 'z') && (uc >= (UniChar) 'A')) { ! 1786: *(u++) = gHiBitCombUnicode[c]; ! 1787: ++(*unicodeChars); ! 1788: } ! 1789: } ! 1790: } ! 1791: ! 1792: return noErr; ! 1793: } ! 1794: ! 1795: ! 1796: ! 1797: // ! 1798: // FastUnicodeCompare - Compare two Unicode strings; produce a relative ordering ! 1799: // ! 1800: // IF RESULT ! 1801: // -------------------------- ! 1802: // str1 < str2 => -1 ! 1803: // str1 = str2 => 0 ! 1804: // str1 > str2 => +1 ! 1805: // ! 1806: // The lower case table starts with 256 entries (one for each of the upper bytes ! 1807: // of the original Unicode char). If that entry is zero, then all characters with ! 1808: // that upper byte are already case folded. If the entry is non-zero, then it is ! 1809: // the _index_ (not byte offset) of the start of the sub-table for the characters ! 1810: // with that upper byte. All ignorable characters are folded to the value zero. ! 1811: // ! 1812: // In pseudocode: ! 1813: // ! 1814: // Let c = source Unicode character ! 1815: // Let table[] = lower case table ! 1816: // ! 1817: // lower = table[highbyte(c)] ! 1818: // if (lower == 0) ! 1819: // lower = c ! 1820: // else ! 1821: // lower = table[lower+lowbyte(c)] ! 1822: // ! 1823: // if (lower == 0) ! 1824: // ignore this character ! 1825: // ! 1826: // To handle ignorable characters, we now need a loop to find the next valid character. ! 1827: // Also, we can't pre-compute the number of characters to compare; the string length might ! 1828: // be larger than the number of non-ignorable characters. Further, we must be able to handle ! 1829: // ignorable characters at any point in the string, including as the first or last characters. ! 1830: // We use a zero value as a sentinel to detect both end-of-string and ignorable characters. ! 1831: // Since the File Manager doesn't prevent the NUL character (value zero) as part of a filename, ! 1832: // the case mapping table is assumed to map u+0000 to some non-zero value (like 0xFFFF, which is ! 1833: // an invalid Unicode character). ! 1834: // ! 1835: // Pseudocode: ! 1836: // ! 1837: // while (1) { ! 1838: // c1 = GetNextValidChar(str1) // returns zero if at end of string ! 1839: // c2 = GetNextValidChar(str2) ! 1840: // ! 1841: // if (c1 != c2) break // found a difference ! 1842: // ! 1843: // if (c1 == 0) // reached end of string on both strings at once? ! 1844: // return 0; // yes, so strings are equal ! 1845: // } ! 1846: // ! 1847: // // When we get here, c1 != c2. So, we just need to determine which one is less. ! 1848: // if (c1 < c2) ! 1849: // return -1; ! 1850: // else ! 1851: // return 1; ! 1852: // ! 1853: ! 1854: #if TARGET_OS_MAC ! 1855: extern void gLowerCaseTable(void); // Really an exported data symbol, a table ! 1856: #else ! 1857: extern UInt16 gLowerCaseTable[]; ! 1858: #endif ! 1859: ! 1860: SInt32 FastUnicodeCompare ( register ConstUniCharArrayPtr str1, register ItemCount length1, ! 1861: register ConstUniCharArrayPtr str2, register ItemCount length2) ! 1862: { ! 1863: register UInt16 c1,c2; ! 1864: register UInt16 temp; ! 1865: register UInt16* lowerCaseTable; ! 1866: ! 1867: #if ( FORDISKFIRSTAID || USE_TABLE_ACCESSORS) ! 1868: lowerCaseTable = Get_gLowerCaseTable(); ! 1869: #else ! 1870: lowerCaseTable = (UInt16*) gLowerCaseTable; ! 1871: #endif ! 1872: ! 1873: while (1) { ! 1874: // Set default values for c1, c2 in case there are no more valid chars ! 1875: c1 = 0; ! 1876: c2 = 0; ! 1877: ! 1878: // Find next non-ignorable char from str1, or zero if no more ! 1879: while (length1 && c1 == 0) { ! 1880: c1 = *(str1++); ! 1881: --length1; ! 1882: if ((temp = lowerCaseTable[c1>>8]) != 0) // is there a subtable for this upper byte? ! 1883: c1 = lowerCaseTable[temp + (c1 & 0x00FF)]; // yes, so fold the char ! 1884: } ! 1885: ! 1886: ! 1887: // Find next non-ignorable char from str2, or zero if no more ! 1888: while (length2 && c2 == 0) { ! 1889: c2 = *(str2++); ! 1890: --length2; ! 1891: if ((temp = lowerCaseTable[c2>>8]) != 0) // is there a subtable for this upper byte? ! 1892: c2 = lowerCaseTable[temp + (c2 & 0x00FF)]; // yes, so fold the char ! 1893: } ! 1894: ! 1895: if (c1 != c2) // found a difference, so stop looping ! 1896: break; ! 1897: ! 1898: if (c1 == 0) // did we reach the end of both strings at the same time? ! 1899: return 0; // yes, so strings are equal ! 1900: } ! 1901: ! 1902: if (c1 < c2) ! 1903: return -1; ! 1904: else ! 1905: return 1; ! 1906: } ! 1907: ! 1908: ! 1909: OSErr ! 1910: ConvertUTF8ToUnicode(ByteCount srcLen, const unsigned char* srcStr, ByteCount maxDstLen, ! 1911: ByteCount *actualDstLen, UniCharArrayPtr dstStr) ! 1912: { ! 1913: ConversionResult result; ! 1914: UTF8* sourceStart; ! 1915: UTF8* sourceEnd; ! 1916: UTF16* targetStart; ! 1917: UTF16* targetEnd; ! 1918: ! 1919: sourceStart = (UTF8*) srcStr; ! 1920: sourceEnd = sourceStart + srcLen; ! 1921: targetStart = (UTF16*) dstStr; ! 1922: targetEnd = targetStart + maxDstLen/2; ! 1923: ! 1924: result = ConvertUTF8toUTF16 (&sourceStart, sourceEnd, &targetStart, targetEnd); ! 1925: ! 1926: *actualDstLen = (targetStart - dstStr) * sizeof(UniChar); ! 1927: ! 1928: if (result == targetExhausted) ! 1929: return kTECOutputBufferFullStatus; ! 1930: else if (result == sourceExhausted) ! 1931: return kTextMalformedInputErr; ! 1932: ! 1933: return noErr; ! 1934: } ! 1935: ! 1936: ! 1937: OSErr ! 1938: ConvertUnicodeToUTF8(ByteCount srcLen, ConstUniCharArrayPtr srcStr, ByteCount maxDstLen, ! 1939: ByteCount *actualDstLen, unsigned char* dstStr) ! 1940: { ! 1941: ConversionResult result; ! 1942: UTF16* sourceStart; ! 1943: UTF16* sourceEnd; ! 1944: UTF8* targetStart; ! 1945: UTF8* targetEnd; ! 1946: ByteCount outputLength; ! 1947: ! 1948: sourceStart = (UTF16*) srcStr; ! 1949: sourceEnd = (UTF16*) ((char*) srcStr + srcLen); ! 1950: targetStart = (UTF8*) dstStr; ! 1951: targetEnd = targetStart + maxDstLen; ! 1952: ! 1953: result = ConvertUTF16toUTF8 (&sourceStart, sourceEnd, &targetStart, targetEnd); ! 1954: ! 1955: *actualDstLen = outputLength = targetStart - dstStr; ! 1956: ! 1957: if (result == targetExhausted) ! 1958: return kTECOutputBufferFullStatus; ! 1959: else if (result == sourceExhausted) ! 1960: return kTECPartialCharErr; ! 1961: ! 1962: if (outputLength >= maxDstLen) ! 1963: return kTECOutputBufferFullStatus; ! 1964: ! 1965: dstStr[outputLength] = 0; /* also add null termination */ ! 1966: ! 1967: return noErr; ! 1968: } ! 1969: ! 1970: ! 1971: OSErr ! 1972: ConvertUTF8ToMacRoman(ByteCount srcLen, const unsigned char* srcStr, Str31 dstStr) ! 1973: { ! 1974: UniChar uniStr[64]; ! 1975: ByteCount uniLen; ! 1976: OSErr result; ! 1977: ! 1978: result = ConvertUTF8ToUnicode(srcLen, srcStr, sizeof(uniStr), &uniLen, uniStr); ! 1979: if (result == 0) ! 1980: result = UnicodeToMacRoman(uniLen / sizeof(UniChar), uniStr, dstStr); ! 1981: ! 1982: return result; ! 1983: } ! 1984: ! 1985: ! 1986: OSErr ! 1987: ConvertMacRomanToUTF8(Str31 srcStr, ByteCount maxDstLen, ByteCount *actualDstLen, ! 1988: unsigned char* dstStr) ! 1989: { ! 1990: UniChar uniStr[64]; ! 1991: ItemCount unicodeChars; ! 1992: OSErr result; ! 1993: ! 1994: result = MacRomanToUnicode(srcStr, &unicodeChars, uniStr); ! 1995: ! 1996: if (result == 0) ! 1997: result = ConvertUnicodeToUTF8(unicodeChars * sizeof(UniChar), uniStr, ! 1998: maxDstLen, actualDstLen, dstStr); ! 1999: return result; ! 2000: } ! 2001:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.