Annotation of XNU/bsd/hfs/hfscommon/Unicode/UnicodeWrappers.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:        File:           UnicodeWrappers.c
        !            24: 
        !            25:        Contains:       Wrapper routines for Unicode conversion and comparison.
        !            26: 
        !            27:        Version:        HFS Plus 1.0
        !            28: 
        !            29:        Written by:     Mark Day
        !            30: 
        !            31:        Copyright:      � 1996-1999 by Apple Computer, Inc., all rights reserved.
        !            32: 
        !            33:        File Ownership:
        !            34: 
        !            35:                DRI:                            Mark Day
        !            36: 
        !            37:                Other Contact:          Don Brady
        !            38: 
        !            39:                Technology:                     xxx put technology here xxx
        !            40: 
        !            41:        Writers:
        !            42: 
        !            43:                (DSH)   Deric Horn
        !            44:                (msd)   Mark Day
        !            45:                (djb)   Don Brady
        !            46: 
        !            47:        Change History (most recent first):
        !            48:        <MOSXS>  6/10/99        djb             Add support for Euro Sign (0x20AC) to MacRoman/Unicode conversions.
        !            49:        <MOSXS>  2/09/99        djb             Fix UnicodeToMacRoman to handle a terminating decomposed char.
        !            50:        <MOSXS>  1/22/99        djb             Add more TARGET_OS_MAC conditionals to remove orphaned code.
        !            51:        <MOSXS>   7/6/98        djb             Handle hi-bit Mac Roman characters in basic latin conversions (radar #2247519).
        !            52:        <MOSXS>  6/11/98        PPD             Added a few special-case ASCII/Unicode mappings to cover installer's needs.
        !            53: 
        !            54:          <CS41>         1/28/98        msd             Bug 2207446: When mangling a name, check to see if the Unicode
        !            55:                                                                        Converter is installed before we call it.
        !            56:          <CS40>         1/21/98        msd             Bug 2206836: If a name contains a colon, change it to question
        !            57:                                                                        mark and mangle the name.
        !            58:          <CS39>        12/11/97        msd             For Metrowerks and test tools, call the Get_xxx routines to get
        !            59:                                                                        the Unicode table addresses.
        !            60:          <CS38>        12/10/97        djb             Radar #2005461, don't use fallback chars when converting to
        !            61:                                                                        Unicode, instead let the client (Catalog) retry with MacRoman.
        !            62:          <CS37>         12/2/97        DSH             Conditionalize out some unicode related routines for DFA
        !            63:          <CS36>        11/26/97        djb             Radar #2005461,2005688 don't swallow kTECPartialCharErr errors!
        !            64:          <CS35>        11/17/97        djb             Name mangling was broken with decomposed Unicode.
        !            65:          <CS34>        11/16/97        djb             Radar #2001928 - use kUnicodeCanonicalDecompVariant variant.
        !            66:          <CS33>        11/11/97        DSH             Use Get_gLowerCaseTable for DiskFirstAid builds to avoid loading
        !            67:                                                                        in a branch to the table.
        !            68:          <CS32>         11/7/97        msd             Replace FastSimpleCompareStrings with FastUnicodeCompare (which
        !            69:                                                                        handles ignorable Unicode characters). Remove the wrapper
        !            70:                                                                        routine, CompareUnicodeNames, and have its callers call
        !            71:                                                                        FastUnicodeCompare directly.
        !            72:          <CS31>        10/17/97        djb             Change kUnicodeUseHFSPlusMapping to kUnicodeUseLatestMapping.
        !            73:          <CS30>        10/17/97        msd             Fix some type casts for char pointers.
        !            74:          <CS29>        10/13/97        djb             Add new SPIs for Finder View font (radar #1679073).
        !            75:          <CS28>         10/1/97        djb             Preserve current heap zone in InitializeEncodingContext routine
        !            76:                                                                        (radar #1682686).
        !            77:          <CS27>         9/17/97        djb             Handle kTECPartialCharErr errors in ConvertHFSNameToUnicode.
        !            78:          <CS26>         9/16/97        msd             In MockConvertFromPStringToUnicode, use pragma unused instead of
        !            79:                                                                        commenting out unused parameter (so SC will compile it).
        !            80:          <CS25>         9/15/97        djb             Fix MockConverters to do either 7-bit ascii or else mangle the
        !            81:                                                                        name (radar #1672388). Use 'p2u#' resource for bootstrapping
        !            82:                                                                        Unicode. Make sure InitializeEncodingContext uses System heap.
        !            83:          <CS24>         9/10/97        msd             Make InitializeEncodingContext public.
        !            84:          <CS23>          9/7/97        djb             Handle '�' char in BasicLatinUnicode converter.
        !            85:          <CS22>          9/4/97        djb             Add logging to BasicLatinUnicodeToPascal.
        !            86:          <CS21>         8/26/97        djb             Make FastSimpleCompareStrings faster. Add
        !            87:                                                                        BasicLatinUnicodeToPascal to make 7-bit ascii conversions
        !            88:                                                                        faster.
        !            89:          <CS20>         8/14/97        djb             Add FastRelString here (to be next to the data tables).
        !            90:          <CS19>         7/21/97        djb             LogEndTime now takes an error code.
        !            91:          <CS18>         7/18/97        msd             Include LowMemPriv.h, Gestalt.h, TextUtils.h.
        !            92:          <CS17>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
        !            93:                                                                        collision
        !            94:          <CS16>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
        !            95:          <CS15>          7/8/97        DSH             InitializeUnicode changed its API
        !            96:          <CS14>          7/1/97        DSH             SC, DFA complier, requires parameters in functions. #pragma'd
        !            97:                                                                        them out to eliminate C warnings.
        !            98:          <CS13>         6/30/97        msd             Remove unused parameter warnings in FallbackProc by commenting
        !            99:                                                                        out unused parameter names.
        !           100:          <CS12>         6/26/97        DSH             FallbackProc declare variables before useage for SC,
        !           101:                                                                        MockConverters no longer static for DFA.
        !           102:          <CS11>         6/25/97        msd             In function InitStaticUnicodeConverter, the variable fsVars was
        !           103:                                                                        being used before being initialized.
        !           104:          <CS10>         6/24/97        DSH             Runtime checks to call through CFM or static linked routines.
        !           105:           <CS9>         6/20/97        msd             Re-introduce fix from <CS7>. Fix another missing cast. Remove a
        !           106:                                                                        spurious semicolon.
        !           107:           <CS8>         6/18/97        djb             Add more ConversionContexts routines. Improved file mangling.
        !           108:           <CS7>         6/16/97        msd             Add a missing cast in GetFileIDString.
        !           109:           <CS6>         6/13/97        djb             Added support for long filenames. Switched to
        !           110:                                                                        ConvertUnicodeToHFSName, ConvertHFSNameToUnicode, and
        !           111:                                                                        CompareUnicodeNames.
        !           112:           <CS5>          6/4/97        djb             Use system script instead of macRoman.
        !           113:           <CS4>         5/19/97        djb             Add call to LockMappingTable so tables won't move!
        !           114:           <CS3>          5/9/97        djb             Include HFSInstrumentation.h
        !           115:           <CS2>          5/7/97        djb             Add summary traces. Add FastSimpleCompareStrings routine.
        !           116:           <CS1>         4/24/97        djb             first checked in
        !           117:          <HFS5>         3/27/97        djb             Add calls to real Unicode conversion routines.
        !           118:          <HFS4>          2/6/97        msd             Add conditional code to use real Unicode comparison routines
        !           119:                                                                        (default to off).
        !           120:          <HFS3>          1/6/97        djb             Fix HFSUnicodeCompare - the final comparison of length1 and
        !           121:                                                                        length2 was backwards.
        !           122:          <HFS2>        12/12/96        msd             Use precompiled headers.
        !           123:          <HFS1>        12/12/96        msd             first checked in
        !           124: 
        !           125: */
        !           126: 
        !           127: #include "../../hfs_macos_defs.h"
        !           128: #include "UCStringCompareData.h"
        !           129: 
        !           130: #include "../headers/FileMgrInternal.h"
        !           131: #include "../headers/HFSUnicodeWrappers.h"
        !           132: 
        !           133: #include "ConvertUTF.h"
        !           134: 
        !           135: enum {
        !           136:        kMinFileExtensionChars = 1,             // does not include dot
        !           137:        kMaxFileExtensionChars = 5              // does not include dot
        !           138: };
        !           139: 
        !           140: #define kASCIIPiSymbol                         0xB9
        !           141: #define kASCIIMicroSign                                0xB5
        !           142: #define kASCIIGreekDelta                       0xC6
        !           143: 
        !           144: 
        !           145: #define Is7BitASCII(c)                         ( (c) >= 0x20 && (c) <= 0x7F )
        !           146: 
        !           147: #define        IsSpecialASCIIChar(c)           ( (c) == (UInt8) kASCIIMicroSign || (c) == (UInt8) kASCIIPiSymbol || (c) == (UInt8) kASCIIGreekDelta )
        !           148: 
        !           149: // Note:       '�' has two Unicode representations 0x00B5 (micro sign) and 0x03BC (greek)
        !           150: //                     '�' has two Unicode representations 0x2206 (increment) and 0x0394 (greek)
        !           151: #define        IsSpecialUnicodeChar(c)         ( (c) == 0x00B5 || (c) == 0x03BC || (c) == 0x03C0 || (c) == 0x2206 || (c) == 0x0394 )
        !           152: 
        !           153: #define IsHexDigit(c)                          ( ((c) >= (UInt8) '0' && (c) <= (UInt8) '9') || ((c) >= (UInt8) 'A' && (c) <= (UInt8) 'F') )
        !           154: 
        !           155: 
        !           156: static void    GetFilenameExtension( ItemCount length, ConstUniCharArrayPtr unicodeStr, Str15 extStr );
        !           157: 
        !           158: static void    GetFileIDString( HFSCatalogNodeID fileID, Str15 fileIDStr );
        !           159: 
        !           160: static void AppendPascalString( ConstStr15Param src, Str31 dst );
        !           161: 
        !           162: static UInt32 HexStringToInteger( UInt32 length, const UInt8 *hexStr );
        !           163: 
        !           164: 
        !           165: 
        !           166: //
        !           167: // Get filename extension (if any) as a pascal string
        !           168: //
        !           169: #if TARGET_API_MAC_OS8
        !           170: static void
        !           171: GetFilenameExtension( ItemCount length, ConstUniCharArrayPtr unicodeStr, Str15 extStr )
        !           172: {
        !           173:        UInt32  i;
        !           174:        UniChar c;
        !           175:        UInt16  extChars;                       // number of extension characters (excluding the dot)
        !           176:        UInt16  maxExtChars;
        !           177:        Boolean foundExtension;
        !           178: 
        !           179: 
        !           180:        extStr[0] = (UInt8) 0;          // assume there's no extension
        !           181: 
        !           182:        if ( length < 3 )
        !           183:                return;                                 // sorry, "x.y" is smallest possible extension  
        !           184:        
        !           185:        if ( length < (kMaxFileExtensionChars + 2) )
        !           186:                maxExtChars = length - 2;       // we need at least one prefix character and dot
        !           187:        else
        !           188:                maxExtChars = kMaxFileExtensionChars;
        !           189: 
        !           190:        i = length;
        !           191:        extChars = 0;
        !           192:        foundExtension = false;
        !           193: 
        !           194:        while ( extChars <= maxExtChars )
        !           195:        {
        !           196:                c = unicodeStr[--i];
        !           197: 
        !           198:                if ( c == (UniChar) '.' )               // look for leading dot
        !           199:                {
        !           200:                        if ( extChars > 0 )                     // cannot end with a dot
        !           201:                                foundExtension = true;
        !           202:                        break;
        !           203:                }
        !           204: 
        !           205:                if ( Is7BitASCII(c) || IsSpecialUnicodeChar(c) )
        !           206:                        ++extChars;
        !           207:                else
        !           208:                        break;
        !           209:        }
        !           210:        
        !           211:        // if we found one then copy it
        !           212:        if ( foundExtension )
        !           213:        {
        !           214:                UInt8 *extStrPtr = extStr;
        !           215:                const UniChar *unicodeStrPtr = &unicodeStr[i];  // point to dot char
        !           216:                
        !           217:                *(extStrPtr++) = extChars + 1;          // set length to extension chars plus dot
        !           218: 
        !           219:                for ( i = 0; i <= extChars; ++i )
        !           220:                {
        !           221:                        c = *(unicodeStrPtr++);
        !           222:                        
        !           223:                        // map any special characters
        !           224:                        switch (c)
        !           225:                        {
        !           226:                                case 0x00B5:                    // micro sign
        !           227:                                case 0x03BC:                    // greek mu
        !           228:                                        c = (UniChar) '�';
        !           229:                                        break;
        !           230: 
        !           231:                                case 0x03C0:                    // greek pi
        !           232:                                        c = (UniChar) '�';
        !           233:                                        break;
        !           234: 
        !           235:                                case 0x2206:                    // increment sign
        !           236:                                case 0x0394:                    // greek capital delta
        !           237:                                        c = (UniChar) '�';
        !           238:                                        break;
        !           239:                        }
        !           240: 
        !           241:                        *(extStrPtr++) = (UInt8) c;             // copy/convert to ascii
        !           242:                }
        !           243:        }
        !           244: 
        !           245: } // end GetFilenameExtension
        !           246: #endif /* TARGET_API_MAC_OS8 */
        !           247: 
        !           248: 
        !           249: //
        !           250: // Count filename extension characters (if any)
        !           251: //
        !           252: static UInt32
        !           253: CountFilenameExtensionChars( const unsigned char * filename, UInt32    length )
        !           254: {
        !           255:        UInt32  i;
        !           256:        UniChar c;
        !           257:        UInt32  extChars;                       // number of extension characters (excluding the dot)
        !           258:        UInt16  maxExtChars;
        !           259:        Boolean foundExtension;
        !           260: 
        !           261: 
        !           262:     if (length == kUndefinedStrLen)
        !           263:                length = strlen(filename);
        !           264: 
        !           265:        if ( length < 3 )
        !           266:                return 0;                                       // sorry, "x.y" is smallest possible extension  
        !           267:        
        !           268:        if ( length < (kMaxFileExtensionChars + 2) )
        !           269:                maxExtChars = length - 2;       // we need at least on prefix character and dot
        !           270:        else
        !           271:                maxExtChars = kMaxFileExtensionChars;
        !           272: 
        !           273:        extChars = 0;                           // assume there's no extension
        !           274:        i = length - 1;                         // index to last ascii character
        !           275:        foundExtension = false;
        !           276: 
        !           277:        while ( extChars <= maxExtChars )
        !           278:        {
        !           279:                c = filename[i--];
        !           280: 
        !           281:                if ( c == (UInt8) '.' )         // look for leading dot
        !           282:                {
        !           283:                        if ( extChars > 0 )                     // cannot end with a dot
        !           284:                                return (extChars);
        !           285: 
        !           286:                        break;
        !           287:                }
        !           288: 
        !           289:                if ( Is7BitASCII(c) || IsSpecialASCIIChar(c) )
        !           290:                        ++extChars;
        !           291:                else
        !           292:                        break;
        !           293:        }
        !           294:        
        !           295:        return 0;
        !           296: 
        !           297: } // end CountFilenameExtensionChars
        !           298: 
        !           299: 
        !           300: //
        !           301: // Convert file ID into a hexidecimal string with no leading zeros
        !           302: //
        !           303: #if TARGET_API_MAC_OS8
        !           304: static void
        !           305: GetFileIDString( HFSCatalogNodeID fileID, Str15 fileIDStr )
        !           306: {
        !           307:        SInt32  i, b;
        !           308:        static UInt8 *translate = (UInt8 *) "0123456789ABCDEF";
        !           309:        UInt8   c;
        !           310:        
        !           311:        fileIDStr[1] = '#';
        !           312: 
        !           313:        for ( i = 1, b = 28; b >= 0; b -= 4 )
        !           314:        {
        !           315:                c = *(translate + ((fileID >> b) & 0x0000000F));
        !           316:                
        !           317:                // if its not a leading zero add it to our string
        !           318:                if ( (c != (UInt8) '0') || (i > 1) || (b == 0) )
        !           319:                        fileIDStr[++i] = c;
        !           320:        }
        !           321: 
        !           322:        fileIDStr[0] = (UInt8) i;
        !           323: 
        !           324: } // end GetFileIDString
        !           325: #endif /* TARGET_API_MAC_OS8 */
        !           326: 
        !           327: 
        !           328: //
        !           329: // Append a suffix to a pascal string
        !           330: //
        !           331: #if TARGET_API_MAC_OS8
        !           332: static void
        !           333: AppendPascalString( ConstStr15Param src, Str31 dst )
        !           334: {
        !           335:        UInt32  i, j;
        !           336:        UInt32  srcLen;
        !           337:        
        !           338:        srcLen = StrLength(src);
        !           339:        
        !           340:        if ( (srcLen + StrLength(dst)) > 31 )   // safety net
        !           341:                return;
        !           342:        
        !           343:        i = dst[0] + 1;         // get end of dst
        !           344:        
        !           345:        for (j = 1; j <= srcLen; ++j)
        !           346:                dst[i++] = src[j];
        !           347:                
        !           348:        dst[0] += srcLen;
        !           349: 
        !           350: } // end AppendPascalString
        !           351: #endif /* TARGET_API_MAC_OS8 */
        !           352: 
        !           353: 
        !           354: HFSCatalogNodeID
        !           355: GetEmbeddedFileID(const unsigned char * filename, UInt32 length, UInt32 *prefixLength)
        !           356: {
        !           357:        short   extChars;
        !           358:        short   i;
        !           359:        UInt8   c;                      // current character in filename
        !           360: 
        !           361:        *prefixLength = 0;
        !           362: 
        !           363:        if ( filename == NULL )
        !           364:                return 0;
        !           365: 
        !           366:     if (length == kUndefinedStrLen)
        !           367:                length = strlen(filename);
        !           368: 
        !           369:        if ( length < 4 )
        !           370:                return 0;               // too small to have a file ID
        !           371: 
        !           372:        if ( length >= 6 )      // big enough for a file ID (#10) and an extension (.x) ?
        !           373:                extChars = CountFilenameExtensionChars(filename, length);
        !           374:        else
        !           375:                extChars = 0;
        !           376:        
        !           377:        if ( extChars > 0 )
        !           378:                length -= (extChars + 1);       // skip dot plus extension characters
        !           379: 
        !           380:        // scan for file id digits...
        !           381:        for ( i = length - 1; i >= 0; --i)
        !           382:        {
        !           383:                c = filename[i];
        !           384: 
        !           385:                if ( c == '#' )         // look for file ID marker
        !           386:                {
        !           387:                        if ( (length - i) < 3 )
        !           388:                                break;          // too small to be a file ID
        !           389: 
        !           390:                        *prefixLength = i;
        !           391:                        return HexStringToInteger(length - i - 1, &filename[i+1]);
        !           392:                }
        !           393: 
        !           394:                if ( !IsHexDigit(c) )
        !           395:                        break;                  // file ID string must have hex digits  
        !           396:        }
        !           397: 
        !           398:        return 0;
        !           399: 
        !           400: } // end GetEmbeddedFileID
        !           401: 
        !           402: 
        !           403: //_______________________________________________________________________
        !           404: 
        !           405: static UInt32
        !           406: HexStringToInteger (UInt32 length, const UInt8 *hexStr)
        !           407: {
        !           408:        UInt32          value;  // decimal value represented by the string
        !           409:        short           i;
        !           410:        UInt8           c;              // next character in buffer
        !           411:        const UInt8     *p;             // pointer to character string
        !           412: 
        !           413:        value = 0;
        !           414:        p = hexStr;
        !           415: 
        !           416:        for ( i = 0; i < length; ++i )
        !           417:        {
        !           418:                c = *p++;
        !           419: 
        !           420:                if (c >= '0' && c <= '9')
        !           421:                {
        !           422:                        value = value << 4;
        !           423:                        value += (UInt32) c - (UInt32) '0';
        !           424:                }
        !           425:                else if (c >= 'A' && c <= 'F')
        !           426:                {
        !           427:                        value = value << 4;
        !           428:                        value += 10 + ((unsigned int) c - (unsigned int) 'A');
        !           429:                }
        !           430:                else
        !           431:                {
        !           432:                        return 0;       // oops, how did this character get in here?
        !           433:                }
        !           434:        }
        !           435: 
        !           436:        return value;
        !           437: 
        !           438: } // end HexStringToInteger
        !           439: 
        !           440: 
        !           441: //_______________________________________________________________________
        !           442: //
        !           443: //     Routine:        FastRelString
        !           444: //
        !           445: //     Output:         returns -1 if str1 < str2
        !           446: //                             returns  1 if str1 > str2
        !           447: //                             return   0 if equal
        !           448: //
        !           449: //_______________________________________________________________________
        !           450: 
        !           451: extern unsigned short gCompareTable[];
        !           452: 
        !           453: SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 )
        !           454: {
        !           455:        UInt16*                 compareTable;
        !           456:        SInt32                  bestGuess;
        !           457:        UInt8                   length, length2;
        !           458:        UInt8                   delta;
        !           459: 
        !           460:        delta = 0;
        !           461:        length = *(str1++);
        !           462:        length2 = *(str2++);
        !           463: 
        !           464:        if (length == length2)
        !           465:                bestGuess = 0;
        !           466:        else if (length < length2)
        !           467:        {
        !           468:                bestGuess = -1;
        !           469:                delta = length2 - length;
        !           470:        }
        !           471:        else
        !           472:        {
        !           473:                bestGuess = 1;
        !           474:                length = length2;
        !           475:        }
        !           476: 
        !           477:        compareTable = (UInt16*) gCompareTable;
        !           478: 
        !           479:        while (length--)
        !           480:        {
        !           481:                UInt8   aChar, bChar;
        !           482: 
        !           483:                aChar = *(str1++);
        !           484:                bChar = *(str2++);
        !           485:                
        !           486:                if (aChar != bChar)             //      If they don't match exacly, do case conversion
        !           487:                {       
        !           488:                        UInt16  aSortWord, bSortWord;
        !           489: 
        !           490:                        aSortWord = compareTable[aChar];
        !           491:                        if (bChar == 0 && delta == 1) {
        !           492:                                bChar = *(str2++);      /* skip over embedded null */
        !           493:                                bestGuess = 0;
        !           494:                        }
        !           495:                        bSortWord = compareTable[bChar];
        !           496: 
        !           497:                        if (aSortWord > bSortWord)
        !           498:                                return 1;
        !           499: 
        !           500:                        if (aSortWord < bSortWord)
        !           501:                                return -1;
        !           502:                }
        !           503:                
        !           504:                //      If characters match exactly, then go on to next character immediately without
        !           505:                //      doing any extra work.
        !           506:        }
        !           507:        
        !           508:        //      if you got to here, then return bestGuess
        !           509:        return bestGuess;
        !           510: }      
        !           511: 
        !           512: 
        !           513: 
        !           514: //
        !           515: //     FastUnicodeCompare - Compare two Unicode strings; produce a relative ordering
        !           516: //
        !           517: //         IF                          RESULT
        !           518: //     --------------------------
        !           519: //     str1 < str2             =>      -1
        !           520: //     str1 = str2             =>       0
        !           521: //     str1 > str2             =>      +1
        !           522: //
        !           523: //     The lower case table starts with 256 entries (one for each of the upper bytes
        !           524: //     of the original Unicode char).  If that entry is zero, then all characters with
        !           525: //     that upper byte are already case folded.  If the entry is non-zero, then it is
        !           526: //     the _index_ (not byte offset) of the start of the sub-table for the characters
        !           527: //     with that upper byte.  All ignorable characters are folded to the value zero.
        !           528: //
        !           529: //     In pseudocode:
        !           530: //
        !           531: //             Let c = source Unicode character
        !           532: //             Let table[] = lower case table
        !           533: //
        !           534: //             lower = table[highbyte(c)]
        !           535: //             if (lower == 0)
        !           536: //                     lower = c
        !           537: //             else
        !           538: //                     lower = table[lower+lowbyte(c)]
        !           539: //
        !           540: //             if (lower == 0)
        !           541: //                     ignore this character
        !           542: //
        !           543: //     To handle ignorable characters, we now need a loop to find the next valid character.
        !           544: //     Also, we can't pre-compute the number of characters to compare; the string length might
        !           545: //     be larger than the number of non-ignorable characters.  Further, we must be able to handle
        !           546: //     ignorable characters at any point in the string, including as the first or last characters.
        !           547: //     We use a zero value as a sentinel to detect both end-of-string and ignorable characters.
        !           548: //     Since the File Manager doesn't prevent the NUL character (value zero) as part of a filename,
        !           549: //     the case mapping table is assumed to map u+0000 to some non-zero value (like 0xFFFF, which is
        !           550: //     an invalid Unicode character).
        !           551: //
        !           552: //     Pseudocode:
        !           553: //
        !           554: //             while (1) {
        !           555: //                     c1 = GetNextValidChar(str1)                     //      returns zero if at end of string
        !           556: //                     c2 = GetNextValidChar(str2)
        !           557: //
        !           558: //                     if (c1 != c2) break                                     //      found a difference
        !           559: //
        !           560: //                     if (c1 == 0)                                            //      reached end of string on both strings at once?
        !           561: //                             return 0;                                               //      yes, so strings are equal
        !           562: //             }
        !           563: //
        !           564: //             // When we get here, c1 != c2.  So, we just need to determine which one is less.
        !           565: //             if (c1 < c2)
        !           566: //                     return -1;
        !           567: //             else
        !           568: //                     return 1;
        !           569: //
        !           570: 
        !           571: extern UInt16 gLowerCaseTable[];
        !           572: extern UInt16 gLatinCaseFold[];
        !           573: 
        !           574: SInt32 FastUnicodeCompare ( register ConstUniCharArrayPtr str1, register ItemCount length1,
        !           575:                                                        register ConstUniCharArrayPtr str2, register ItemCount length2)
        !           576: {
        !           577:        register UInt16         c1,c2;
        !           578:        register UInt16         temp;
        !           579:        register UInt16*        lowerCaseTable;
        !           580: 
        !           581:        lowerCaseTable = (UInt16*) gLowerCaseTable;
        !           582: 
        !           583:        while (1) {
        !           584:                /* Set default values for c1, c2 in case there are no more valid chars */
        !           585:                c1 = 0;
        !           586:                c2 = 0;
        !           587:                
        !           588:                /* Find next non-ignorable char from str1, or zero if no more */
        !           589:                while (length1 && c1 == 0) {
        !           590:                        c1 = *(str1++);
        !           591:                        --length1;
        !           592:                        /* check for basic latin first */
        !           593:                        if (c1 < 0x0100) {
        !           594:                                c1 = gLatinCaseFold[c1];
        !           595:                                break;
        !           596:                        }
        !           597:                        /* case fold if neccessary */
        !           598:                        if ((temp = lowerCaseTable[c1>>8]) != 0)
        !           599:                                c1 = lowerCaseTable[temp + (c1 & 0x00FF)];
        !           600:                }
        !           601:                
        !           602:                
        !           603:                /* Find next non-ignorable char from str2, or zero if no more */
        !           604:                while (length2 && c2 == 0) {
        !           605:                        c2 = *(str2++);
        !           606:                        --length2;
        !           607:                        /* check for basic latin first */
        !           608:                        if (c2 < 0x0100) {
        !           609:                                if ((c2 = gLatinCaseFold[c2]) != 0)
        !           610:                                        break;
        !           611:                                else
        !           612:                                        continue; /* ignore this character */
        !           613:                        }
        !           614:                        /* case fold if neccessary */
        !           615:                        if ((temp = lowerCaseTable[c2>>8]) != 0)
        !           616:                                c2 = lowerCaseTable[temp + (c2 & 0x00FF)];
        !           617:                }
        !           618:                
        !           619:                if (c1 != c2)           //      found a difference, so stop looping
        !           620:                        break;
        !           621:                
        !           622:                if (c1 == 0)            //      did we reach the end of both strings at the same time?
        !           623:                        return 0;               //      yes, so strings are equal
        !           624:        }
        !           625:        
        !           626:        if (c1 < c2)
        !           627:                return -1;
        !           628:        else
        !           629:                return 1;
        !           630: }
        !           631: 
        !           632: 
        !           633: OSErr
        !           634: ConvertUTF8ToUnicode(ByteCount srcLen, const unsigned char* srcStr, ByteCount maxDstLen,
        !           635:                                         ByteCount *actualDstLen, UniCharArrayPtr dstStr)
        !           636: {
        !           637:        ConversionResult result;
        !           638:        UTF8* sourceStart;
        !           639:        UTF8* sourceEnd;
        !           640:        UTF16* targetStart;
        !           641:        UTF16* targetEnd;
        !           642: 
        !           643:        sourceStart = (UTF8*) srcStr;
        !           644:        sourceEnd = sourceStart + srcLen;
        !           645:        targetStart = (UTF16*) dstStr;
        !           646:        targetEnd = targetStart + maxDstLen/2;
        !           647: 
        !           648:        result = ConvertUTF8toUTF16 (&sourceStart, sourceEnd, &targetStart, targetEnd);
        !           649:        
        !           650:        *actualDstLen = (targetStart - dstStr) * sizeof(UniChar);
        !           651:        
        !           652:        if (result == targetExhausted)
        !           653:                return kTECOutputBufferFullStatus;
        !           654:        else if (result == sourceExhausted)
        !           655:                return kTextMalformedInputErr;
        !           656: 
        !           657:        return noErr;
        !           658: }
        !           659: 
        !           660: 
        !           661: OSErr
        !           662: ConvertUnicodeToUTF8(ByteCount srcLen, ConstUniCharArrayPtr srcStr, ByteCount maxDstLen,
        !           663:                                         ByteCount *actualDstLen, unsigned char* dstStr)
        !           664: {
        !           665:        ConversionResult result;
        !           666:        UTF16* sourceStart;
        !           667:        UTF16* sourceEnd;
        !           668:        UTF8* targetStart;
        !           669:        UTF8* targetEnd;
        !           670:        ByteCount outputLength;
        !           671: 
        !           672:        sourceStart = (UTF16*) srcStr;
        !           673:        sourceEnd = (UTF16*) ((char*) srcStr + srcLen);
        !           674:        targetStart = (UTF8*) dstStr;
        !           675:        targetEnd = targetStart + maxDstLen;
        !           676:        
        !           677:        result = ConvertUTF16toUTF8 (&sourceStart, sourceEnd, &targetStart, targetEnd);
        !           678:        
        !           679:        *actualDstLen = outputLength = targetStart - dstStr;
        !           680: 
        !           681:        if (result == targetExhausted)
        !           682:                return kTECOutputBufferFullStatus;
        !           683:        else if (result == sourceExhausted)
        !           684:                return kTECPartialCharErr;
        !           685: 
        !           686:        if (outputLength >= maxDstLen)
        !           687:                return kTECOutputBufferFullStatus;
        !           688:                
        !           689:        dstStr[outputLength] = 0;       /* also add null termination */
        !           690: 
        !           691:        return noErr;
        !           692: }
        !           693: 

unix.superglobalmegacorp.com

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