|
|
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.