/* NSCharacterSet.m Character set holder object. Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. Author: Adam Fedor Date: Apr 1995 This file is part of the mySTEP Library and is provided under the terms of the GNU Library General Public License. */ #import #import #import #import #import #import #import #import "NSPrivate.h" // A simple array for caching standard bitmap sets static NSCharacterSet *cache_set[12]; static NSLock *__cacheLock = nil; static NSString *__charSetPath /*= @"CS"*/; @interface NSBitmapCharSet : NSCharacterSet { char data[BITMAP_SIZE]; } - (id) initWithBitmap:(NSData *)bitmap; @end @interface NSMutableBitmapCharSet : NSMutableCharacterSet { char data[BITMAP_SIZE]; } - (id) initWithBitmap:(NSData *)bitmap; @end //***************************************************************************** // // NSCharacterSet // //***************************************************************************** @implementation NSCharacterSet + (id) allocWithZone:(NSZone *) z { // Provide a default object for alloc return NSAllocateObject([NSBitmapCharSet self], 0, z); } + (NSCharacterSet *) _bitmapForSet:(NSString *)setname number:(int)number { NSCharacterSet *set=nil; // Creating standard character sets NSString *systemPath; NSAssert(number >= 0 && number < sizeof(cache_set)/sizeof(cache_set[0]), @"NSCharacterSet cache is too small"); #if 0 NSLog(@"NSCharacterSet _bitmapForSet:%@", setname); #endif if(!__cacheLock) __cacheLock = [NSLock new]; #if 0 NSLog(@"NSCharacterSet: __cacheLock lock"); #endif [__cacheLock lock]; if (cache_set[number] == nil) { NS_DURING // Search the system path { NSBundle *bundle=[NSBundle bundleForClass:[self class]]; #if 0 NSLog(@"a"); #endif systemPath = [bundle pathForResource:setname ofType:@"charSet" inDirectory:__charSetPath]; #if 0 NSLog(@"b path=%@", systemPath); #endif if(systemPath != nil && [systemPath length] != 0) { // Load the character set file NS_DURING #if 0 NSLog(@"c"); #endif set = [self characterSetWithBitmapRepresentation: [NSData dataWithContentsOfFile: systemPath]]; NS_HANDLER NSLog(@"Unable to read NSCharacterSet file %@", systemPath); set=nil; NS_ENDHANDLER } if(!set) { // If we didn't load a set then raise an exception [NSException raise:NSGenericException format:@"Could not find bitmap file %@ at %@ [%@ - %@]", setname, systemPath, [[NSBundle bundleForClass:[self class]] bundlePath], __charSetPath]; } else cache_set[number] = [set retain]; // else cache the set } NS_HANDLER [__cacheLock unlock]; [localException raise]; set=nil; NS_ENDHANDLER } else set = cache_set[number]; // fetch from cache #if 0 NSLog(@"d"); #endif [__cacheLock unlock]; #if 0 NSLog(@"e"); #endif return set; } + (id) alphanumericCharacterSet { return [self _bitmapForSet:@"alphanum" number: 0]; } + (id) controlCharacterSet { return [self _bitmapForSet:@"control" number: 1]; } + (id) decimalDigitCharacterSet { return [self _bitmapForSet:@"decimal" number: 2]; } + (id) decomposableCharacterSet { NSLog(@"Warning: Decomposable set not yet fully specified"); return [self _bitmapForSet:@"decomposable" number: 3]; } + (id) illegalCharacterSet { NSLog(@"Warning: Illegal set not yet fully specified\n"); return [self _bitmapForSet:@"illegal" number: 4]; } + (id) letterCharacterSet { return [self _bitmapForSet:@"letterchar" number: 5]; } + (id) lowercaseLetterCharacterSet { return [self _bitmapForSet:@"lowercase" number: 6]; } + (id) newlineCharacterSet { #if 1 fprintf(stderr, "newlineCharacterSet\n"); #endif // return [self characterSetWithCharactersInString:@"\n\r"]; // makes some problem // return [self _bitmapForSet:@"newline" number: 11]; static NSCharacterSet *nl; // cache if(!nl) nl=[[self characterSetWithCharactersInString:@"\n\r"] retain]; // should also include \U0085 return nl; } + (id) nonBaseCharacterSet { return [self _bitmapForSet:@"nonbase" number: 7]; } + (id) punctuationCharacterSet; { return NIMP; } + (id) symbolCharacterSet; { return NIMP; } + (id) capitalizedLetterCharacterSet; { return NIMP; } + (id) uppercaseLetterCharacterSet { return [self _bitmapForSet:@"uppercase" number: 8]; } + (id) whitespaceAndNewlineCharacterSet { return [self _bitmapForSet:@"whitespaceandnl" number: 9]; } + (id) whitespaceCharacterSet { return [self _bitmapForSet:@"whitespace" number: 10]; } // Creating custom character sets + (id) characterSetWithBitmapRepresentation:(NSData *)data { return [[[NSBitmapCharSet alloc] initWithBitmap:data] autorelease]; } + (id) characterSetWithCharactersInString:(NSString *)aString { int i, length; NSMutableData *bitmap = [NSMutableData dataWithLength:BITMAP_SIZE]; char *bytes = [bitmap mutableBytes]; if (!aString) [NSException raise:NSInvalidArgumentException format:@"Creating character set with nil string"]; length = [aString length]; for (i = 0; i < length; i++) { unichar letter = [aString characterAtIndex:i]; if (letter >= UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified string exceeds character set"]; SETBIT(bytes[letter/8], letter%8); } return [self characterSetWithBitmapRepresentation:bitmap]; } + (id) characterSetWithRange:(NSRange)aRange { int i; NSMutableData *bitmap = [NSMutableData dataWithLength:BITMAP_SIZE]; char *bytes = (char *)[bitmap mutableBytes]; if (NSMaxRange(aRange) > UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified range exceeds character set"]; for (i = aRange.location; i < NSMaxRange(aRange); i++) SETBIT(bytes[i/8], i % 8); return [self characterSetWithBitmapRepresentation:bitmap]; } + (id) characterSetWithContentsOfFile: (NSString *)aFile { if ([@"bitmap" isEqual: [aFile pathExtension]]) { NSData *bitmap = [NSData dataWithContentsOfFile: aFile]; return [self characterSetWithBitmapRepresentation: bitmap]; } return nil; } - (NSData *) bitmapRepresentation { SUBCLASS return nil; } - (BOOL) characterIsMember:(unichar)aCharacter { SUBCLASS return NO; } - (void) encodeWithCoder: (NSCoder*)aCoder { SUBCLASS } - (id) initWithCoder: (NSCoder*)aCoder { SUBCLASS return nil; } - (BOOL) isEqual: (id)anObject { if (anObject == self) return YES; if ([anObject isKindOfClass:[NSCharacterSet class]]) { int i; for (i = 0; i <= 0xffff; i++) // FIXME: we should directly compare the bytes by memcmp() if ([self characterIsMember: (unichar)i] != [anObject characterIsMember: (unichar)i]) return NO; return YES; } return NO; } - (BOOL) hasMemberInPlane:(unsigned char) plane; { NIMP; return NO; } - (NSCharacterSet *) invertedSet { NSMutableData *bitmap =[[[self bitmapRepresentation] mutableCopy] autorelease]; int i, length = [bitmap length]; char *bytes = [bitmap mutableBytes]; for (i = 0; i < length; i++) bytes[i] = ~bytes[i]; return [[self class] characterSetWithBitmapRepresentation:bitmap]; } - (BOOL) isSupersetOfSet:(NSCharacterSet *) other; { NIMP; return NO; } - (BOOL) longCharacterIsMember:(UTF32Char) aCharacter; { NIMP; return NO; } // NSCopying, NSMutableCopying - (id) copyWithZone:(NSZone *) zone { return [self retain]; } // if immutable - (id) mutableCopyWithZone:(NSZone *) zone { return [[NSMutableBitmapCharSet allocWithZone:zone] initWithBitmap:[self bitmapRepresentation]]; } @end /* NSMutableCharacterSet */ @implementation NSMutableCharacterSet + (id) allocWithZone:(NSZone *) z { // Provide a default object for allocation return NSAllocateObject([NSMutableBitmapCharSet self], 0, z); } + (NSCharacterSet *) characterSetWithBitmapRepresentation:(NSData *)data { // Override this from NSCharacterSet to create the correct class return [[[NSMutableBitmapCharSet alloc] initWithBitmap:data] autorelease]; } - (id) copyWithZone:(NSZone *) zone { // make immutable copy return [[NSBitmapCharSet alloc] initWithBitmap:[self bitmapRepresentation]]; } - (id) mutableCopyWithZone:(NSZone *) zone { return [[NSMutableBitmapCharSet alloc] initWithBitmap:[self bitmapRepresentation]]; } @end /* NSCharacterSet */ //***************************************************************************** // // NSBitmapCharSet // //***************************************************************************** @implementation NSBitmapCharSet - (id) init { return [self initWithBitmap:NULL]; } - (id) initWithBitmap:(NSData *)bitmap { // Designated initializer if((self=[super init])) { [bitmap getBytes:data length:BITMAP_SIZE]; } return self; } - (NSData *) bitmapRepresentation { return [NSData dataWithBytes:data length:BITMAP_SIZE]; } - (BOOL) characterIsMember:(unichar)aCharacter { return ISSET(data[aCharacter/8], aCharacter%8); } - (void) encodeWithCoder: (NSCoder*)aCoder { [aCoder encodeObject: [self bitmapRepresentation]]; } - (id) initWithCoder: (NSCoder*)aCoder { NSData *rep; #if 0 NSLog(@"%@ initWithCoder:%@", self, aCoder); #endif if([aCoder allowsKeyedCoding]) { [self autorelease]; return [[isa characterSetWithCharactersInString:[aCoder decodeObjectForKey:@"NSString"]] copy]; } rep=[aCoder decodeObject]; self = [self initWithBitmap: rep]; return self; } @end /* NSBitmapCharSet */ //***************************************************************************** // // NSMutableBitmapCharSet // //***************************************************************************** @implementation NSMutableBitmapCharSet - (id) init { return [self initWithBitmap:NULL]; } - (id) initWithBitmap:(NSData *)bitmap { // Designated initializer if((self=[super init])) { [bitmap getBytes:data length:BITMAP_SIZE]; } return self; } - (void) encodeWithCoder:(NSCoder*)aCoder { [aCoder encodeObject: [self bitmapRepresentation]]; } - (id) initWithCoder:(NSCoder*)aCoder { NSData *rep; #if 0 NSLog(@"%@ initWithCoder:%@", self, aCoder); #endif if([aCoder allowsKeyedCoding]) { [self autorelease]; return [[isa characterSetWithCharactersInString:[aCoder decodeObjectForKey:@"NSString"]] mutableCopy]; } rep=[aCoder decodeObject]; self = [self initWithBitmap: rep]; return self; } - (NSData *) bitmapRepresentation // Need to implement the next two { // methods just like NSBitmapCharSet return [NSData dataWithBytes:data length:BITMAP_SIZE]; } - (BOOL) characterIsMember:(unichar)aCharacter { return ISSET(data[aCharacter/8], aCharacter%8); } - (void) addCharactersInRange:(NSRange)aRange { int i; if (NSMaxRange(aRange) > UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified range exceeds character set"]; for (i = aRange.location; i < NSMaxRange(aRange); i++) SETBIT(data[i/8], i % 8); } - (void) addCharactersInString:(NSString *)aString { int i, length; if (!aString) [NSException raise:NSInvalidArgumentException format:@"Adding characters from nil string"]; length = [aString length]; for (i = 0; i < length; i++) { unichar letter = [aString characterAtIndex:i]; if (letter >= UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified string exceeds character set"]; SETBIT(data[letter/8], letter%8); } } - (void) formUnionWithCharacterSet:(NSCharacterSet *)otherSet { int i; const char *other_bytes = [[otherSet bitmapRepresentation] bytes]; for (i = 0; i < BITMAP_SIZE; i++) data[i] = (data[i] || other_bytes[i]); } - (void) formIntersectionWithCharacterSet:(NSCharacterSet *)otherSet { int i; const char *other_bytes = [[otherSet bitmapRepresentation] bytes]; for (i = 0; i < BITMAP_SIZE; i++) data[i] = (data[i] && other_bytes[i]); } - (void) removeCharactersInRange:(NSRange)aRange { int i; if (NSMaxRange(aRange) > UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified range exceeds character set"]; for (i=aRange.location; i < NSMaxRange(aRange); i++) CLRBIT(data[i/8], i % 8); } - (void) removeCharactersInString:(NSString *)aString { int i, length; if (!aString) [NSException raise:NSInvalidArgumentException format:@"Removing characters from nil string"]; length = [aString length]; for (i = 0; i < length; i++) { unichar letter = [aString characterAtIndex:i]; if (letter >= UNICODE_SIZE) [NSException raise:NSInvalidArgumentException format:@"Specified string exceeds character set"]; CLRBIT(data[letter/8], letter%8); } } - (void) invert { int i; for (i = 0; i < BITMAP_SIZE; i++) data[i] = ~data[i]; } @end /* NSMutableBitmapCharSet */