Changeset 3515
- Timestamp:
- 12/31/06 21:49:52 (2 years ago)
- Files:
-
- trunk/Additions/NSAttributedStringAdditions.m (modified) (4 diffs)
- trunk/Additions/NSStringAdditions.h (modified) (1 diff)
- trunk/Additions/NSStringAdditions.m (modified) (1 diff)
- trunk/Chat Core.exp (modified) (1 diff)
- trunk/Chat Core/MVIRCChatConnection.h (modified) (1 diff)
- trunk/Chat Core/MVIRCChatConnection.m (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/Additions/NSAttributedStringAdditions.m
r3457 r3515 244 244 end = i; 245 245 j = ++i; 246 for( ; i < length && bytes[i] != '\006' ; i++ ) ; 246 247 for( ; i < length && bytes[i] != '\006' ; i++ ); 247 248 if( i >= length ) break; 248 249 if( i == j ) continue; 250 249 251 if( bytes[j++] == 'E' ) { 250 252 NSString *encodingStr = [[NSString allocWithZone:nil] initWithBytes:&(bytes[j]) length:(i-j) encoding:NSASCIIStringEncoding]; … … 294 296 if( newEncoding && newEncoding != currentEncoding ) { 295 297 if( ( end - start ) > 0 ) { 296 NSData *subdata = [data subdataWithRange:NSMakeRange( start, end-start)];298 NSData *subdata = [data subdataWithRange:NSMakeRange( start, ( end - start ) )]; 297 299 if( currentEncoding != NSUTF8StringEncoding ) { 298 300 NSString *tempStr = [[NSString allocWithZone:nil] initWithData:subdata encoding:currentEncoding]; 299 // I'd check for nil, except only UTF-8 could fail since the others all300 // define values for all bytes 0-255301 subdata = [tempStr dataUsingEncoding:NSUTF8StringEncoding];301 NSData *tempData = [tempStr dataUsingEncoding:NSUTF8StringEncoding]; 302 if( tempData ) subdata = tempData; 303 [tempStr release]; 302 304 } 303 305 … … 314 316 if( [newData length] > 0 || currentEncoding != encoding ) { 315 317 if( start < length ) { 316 NSData *subdata = [data subdataWithRange:NSMakeRange( start, length-start)];318 NSData *subdata = [data subdataWithRange:NSMakeRange( start, ( length - start) )]; 317 319 if( currentEncoding != NSUTF8StringEncoding ) { 318 320 NSString *tempStr = [[NSString allocWithZone:nil] initWithData:subdata encoding:currentEncoding]; 319 subdata = [tempStr dataUsingEncoding:NSUTF8StringEncoding]; 321 NSData *tempData = [tempStr dataUsingEncoding:NSUTF8StringEncoding]; 322 if( tempData ) subdata = tempData; 323 [tempStr release]; 320 324 } 321 325 … … 327 331 } 328 332 329 NSString *message = [[[NSString allocWithZone:nil] initWithData:data encoding:encoding] autorelease]; 333 BOOL validUTF8 = isValidUTF8( [data bytes], [data length] ); 334 NSString *message = [[[NSString allocWithZone:nil] initWithBytes:[data bytes] length:[data length] encoding:( validUTF8 ? NSUTF8StringEncoding : encoding )] autorelease]; 330 335 if( ! message ) { 331 336 [self release]; trunk/Additions/NSStringAdditions.h
r3500 r3515 1 BOOL isValidUTF8( const char *s, unsigned len ); 2 1 3 @interface NSString (NSStringAdditions) 2 4 + (NSString *) locallyUniqueString; trunk/Additions/NSStringAdditions.m
r3500 r3515 1 1 #import "NSStringAdditions.h" 2 2 #include <sys/time.h> 3 4 #define is7Bit(ch) (((ch) & 0x80) == 0) 5 #define isUTF8Tupel(ch) (((ch) & 0xE0) == 0xC0) 6 #define isUTF8LongTupel(ch) (((ch) & 0xFE) == 0xC0) 7 #define isUTF8Triple(ch) (((ch) & 0xF0) == 0xE0) 8 #define isUTF8LongTriple(ch1,ch2) (((ch1) & 0xFF) == 0xE0 && ((ch2) & 0xE0) == 0x80) 9 #define isUTF8Quartet(ch) (((ch) & 0xF8) == 0xF0) 10 #define isUTF8LongQuartet(ch1,ch2) (((ch1) & 0xFF) == 0xF0 && ((ch2) & 0xF0) == 0x80) 11 #define isUTF8Quintet(ch) (((ch) & 0xFC) == 0xF8) 12 #define isUTF8LongQuintet(ch1,ch2) (((ch1) & 0xFF) == 0xF8 && ((ch2) & 0xF8) == 0x80) 13 #define isUTF8Sextet(ch) (((ch) & 0xFE) == 0xFC) 14 #define isUTF8LongSextet(ch1,ch2) (((ch1) & 0xFF) == 0xFC && ((ch2) & 0xFC) == 0x80) 15 #define isUTF8Cont(ch) (((ch) & 0xC0) == 0x80) 16 17 BOOL isValidUTF8( const char *s, unsigned len ) { 18 for( unsigned i = 0; i < len; ++i ) { 19 const unsigned char ch = s[i]; 20 21 if( is7Bit( ch ) ) 22 continue; 23 24 if( isUTF8Tupel( ch ) ) { 25 if( len - i < 1 ) // too short 26 return NO; 27 if( isUTF8LongTupel( ch ) ) // not minimally encoded 28 return NO; 29 if( ! isUTF8Cont( s[i + 1] ) ) 30 return NO; 31 i += 1; 32 } else if( isUTF8Triple( ch ) ) { 33 if( len - i < 2 ) // too short 34 return NO; 35 if( isUTF8LongTriple( ch, s[i + 1] ) ) // not minimally encoded 36 return NO; 37 if( ! isUTF8Cont( s[i + 2] ) ) 38 return NO; 39 i += 2; 40 } else if( isUTF8Quartet( ch ) ) { 41 if( len - i < 3 ) // too short 42 return NO; 43 if( isUTF8LongQuartet( ch, s[i + 1] ) ) // not minimally encoded 44 return NO; 45 if( ! isUTF8Cont( s[i + 2] ) || ! isUTF8Cont( s[i + 3] ) ) 46 return NO; 47 i += 3; 48 } else if( isUTF8Quintet( ch ) ) { 49 if( len - i < 4 ) // too short 50 return NO; 51 if( isUTF8LongQuintet( ch, s[i + 1] ) ) // not minimally encoded 52 return NO; 53 if( ! isUTF8Cont( s[i + 2] ) || ! isUTF8Cont( s[i + 3] ) || ! isUTF8Cont( s[i + 4] ) ) 54 return NO; 55 i += 4; 56 } else if( isUTF8Sextet( ch ) ) { 57 if( len - i < 5 ) // too short 58 return NO; 59 if( isUTF8LongSextet( ch, s[i + 1] ) ) // not minimally encoded 60 return NO; 61 if( ! isUTF8Cont( s[i + 2] ) || ! isUTF8Cont( s[i + 3] ) || ! isUTF8Cont( s[i + 4] ) || ! isUTF8Cont( s[i + 5] ) ) 62 return NO; 63 i += 5; 64 } else return NO; 65 } 66 67 return YES; 68 } 69 70 #undef is7Bit 71 #undef isUTF8Tupel 72 #undef isUTF8LongTupel 73 #undef isUTF8Triple 74 #undef isUTF8LongTriple 75 #undef isUTF8Quartet 76 #undef isUTF8LongQuartet 77 #undef isUTF8Quintet 78 #undef isUTF8LongQuintet 79 #undef isUTF8Sextet 80 #undef isUTF8LongSextet 81 #undef isUTF8Cont 3 82 4 83 @implementation NSString (NSStringAdditions) trunk/Chat Core.exp
r3512 r3515 1 1 .objc_class_name_MVChatConnection 2 .objc_class_name_MVChatPluginManager 2 3 .objc_class_name_MVChatRoom 3 4 .objc_class_name_MVChatUser 4 5 .objc_class_name_MVChatUserWatchRule 6 .objc_class_name_MVDownloadFileTransfer 5 7 .objc_class_name_MVFileTransfer 6 .objc_class_name_MVDownloadFileTransfer7 8 .objc_class_name_MVUploadFileTransfer 8 .objc_class_name_MVChatPluginManager 9 _MVChatConnectionWillConnectNotification 9 _MVChatConnectionChatRoomListUpdatedNotification 10 10 _MVChatConnectionDidConnectNotification 11 _MVChatConnectionDidDisconnectNotification 11 12 _MVChatConnectionDidNotConnectNotification 12 _MVChatConnectionWillDisconnectNotification 13 _MVChatConnectionDidDisconnectNotification 13 _MVChatConnectionErrorDomain 14 14 _MVChatConnectionErrorNotification 15 _MVChatConnectionGotBeepNotification 16 _MVChatConnectionGotPrivateMessageNotification 17 _MVChatConnectionGotRawMessageNotification 18 _MVChatConnectionNeedCertificatePasswordNotification 15 19 _MVChatConnectionNeedNicknamePasswordNotification 16 _MVChatConnectionNeedCertificatePasswordNotification17 20 _MVChatConnectionNeedPublicKeyVerificationNotification 18 _MVChatConnectionGotBeepNotification19 _MVChatConnectionGotRawMessageNotification20 _MVChatConnectionGotPrivateMessageNotification21 _MVChatConnectionChatRoomListUpdatedNotification22 _MVChatConnectionSelfAwayStatusChangedNotification23 _MVChatConnectionWatchedUserOnlineNotification24 _MVChatConnectionWatchedUserOfflineNotification25 21 _MVChatConnectionNicknameAcceptedNotification 26 22 _MVChatConnectionNicknameRejectedNotification 23 _MVChatConnectionSelfAwayStatusChangedNotification 24 _MVChatConnectionSubcodeReplyNotification 27 25 _MVChatConnectionSubcodeRequestNotification 28 _MVChatConnectionSubcodeReplyNotification 29 _MVChatConnectionErrorDomain 26 _MVChatConnectionWatchedUserOfflineNotification 27 _MVChatConnectionWatchedUserOnlineNotification 28 _MVChatConnectionWillConnectNotification 29 _MVChatConnectionWillDisconnectNotification 30 _MVChatPluginManagerDidReloadPluginsNotification 31 _MVChatPluginManagerWillReloadPluginsNotification 32 _MVChatRoomAttributeUpdatedNotification 33 _MVChatRoomBannedUsersSyncedNotification 34 _MVChatRoomGotMessageNotification 35 _MVChatRoomInvitedNotification 30 36 _MVChatRoomJoinedNotification 31 _MVChatRoomPartedNotification32 37 _MVChatRoomKickedNotification 33 _MVChatRoomInvitedNotification 34 _MVChatRoomMemberQuietedFeature 35 _MVChatRoomMemberVoicedFeature 38 _MVChatRoomMemberAdministratorFeature 39 _MVChatRoomMemberFounderFeature 36 40 _MVChatRoomMemberHalfOperatorFeature 37 41 _MVChatRoomMemberOperatorFeature 38 _MVChatRoomMemberAdministratorFeature 39 _MVChatRoomMemberFounderFeature 42 _MVChatRoomMemberQuietedFeature 40 43 _MVChatRoomMemberUsersSyncedNotification 41 _MVChatRoomBannedUsersSyncedNotification 44 _MVChatRoomMemberVoicedFeature 45 _MVChatRoomModesChangedNotification 46 _MVChatRoomPartedNotification 47 _MVChatRoomTopicChangedNotification 48 _MVChatRoomUserBanRemovedNotification 49 _MVChatRoomUserBannedNotification 42 50 _MVChatRoomUserJoinedNotification 51 _MVChatRoomUserKickedNotification 52 _MVChatRoomUserModeChangedNotification 43 53 _MVChatRoomUserPartedNotification 44 _MVChatRoomUserKickedNotification 45 _MVChatRoomUserBannedNotification 46 _MVChatRoomUserBanRemovedNotification 47 _MVChatRoomUserModeChangedNotification 48 _MVChatRoomGotMessageNotification 49 _MVChatRoomTopicChangedNotification 50 _MVChatRoomModesChangedNotification 51 _MVChatRoomAttributeUpdatedNotification 54 _MVChatUserAttributeUpdatedNotification 55 _MVChatUserAwayStatusMessageChangedNotification 56 _MVChatUserBanAuthorAttribute 57 _MVChatUserBanDateAttribute 58 _MVChatUserBanServerAttribute 59 _MVChatUserClientInfoAttribute 60 _MVChatUserDeviceInfoAttribute 61 _MVChatUserDigitalSignatureAttribute 62 _MVChatUserExtensionAttribute 63 _MVChatUserGeoLocationAttribute 64 _MVChatUserIdleTimeUpdatedNotification 65 _MVChatUserInformationUpdatedNotification 52 66 _MVChatUserKnownRoomsAttribute 67 _MVChatUserLocalTimeAttribute 68 _MVChatUserModeChangedNotification 69 _MVChatUserMoodAttribute 70 _MVChatUserNicknameChangedNotification 53 71 _MVChatUserPictureAttribute 54 72 _MVChatUserPingAttribute 55 _MVChatUserLocalTimeAttribute 56 _MVChatUserClientInfoAttribute 73 _MVChatUserPreferredContactMethodsAttribute 74 _MVChatUserPreferredLanguageAttribute 75 _MVChatUserPublicKeyAttribute 76 _MVChatUserServerDigitalSignatureAttribute 77 _MVChatUserServerPublicKeyAttribute 78 _MVChatUserServiceAttribute 79 _MVChatUserStatusChangedNotification 80 _MVChatUserStatusMessageAttribute 81 _MVChatUserTimezoneAttribute 57 82 _MVChatUserVCardAttribute 58 _MVChatUserServiceAttribute59 _MVChatUserMoodAttribute60 _MVChatUserStatusMessageAttribute61 _MVChatUserPreferredLanguageAttribute62 _MVChatUserPreferredContactMethodsAttribute63 _MVChatUserTimezoneAttribute64 _MVChatUserGeoLocationAttribute65 _MVChatUserDeviceInfoAttribute66 _MVChatUserExtensionAttribute67 _MVChatUserPublicKeyAttribute68 _MVChatUserServerPublicKeyAttribute69 _MVChatUserDigitalSignatureAttribute70 _MVChatUserBanServerAttribute71 _MVChatUserBanAuthorAttribute72 _MVChatUserBanDateAttribute73 _MVChatUserServerDigitalSignatureAttribute74 _MVChatUserNicknameChangedNotification75 _MVChatUserStatusChangedNotification76 _MVChatUserAwayStatusMessageChangedNotification77 _MVChatUserIdleTimeUpdatedNotification78 _MVChatUserModeChangedNotification79 _MVChatUserInformationUpdatedNotification80 _MVChatUserAttributeUpdatedNotification81 83 _MVChatUserWatchRuleMatchedNotification 82 84 _MVChatUserWatchRuleRemovedMatchedUserNotification 83 85 _MVDownloadFileTransferOfferNotification 86 _MVFileTransferErrorDomain 87 _MVFileTransferErrorOccurredNotification 88 _MVFileTransferFinishedNotification 84 89 _MVFileTransferStartedNotification 85 _MVFileTransferFinishedNotification 86 _MVFileTransferErrorOccurredNotification 87 _MVFileTransferErrorDomain 88 _MVChatPluginManagerWillReloadPluginsNotification 89 _MVChatPluginManagerDidReloadPluginsNotification 90 _NSChatCTCPTwoFormatType 90 91 _NSChatWindowsIRCFormatType 91 _ NSChatCTCPTwoFormatType92 _isValidUTF8 trunk/Chat Core/MVIRCChatConnection.h
r3498 r3515 67 67 - (void) _resetSupportedFeatures; 68 68 69 - (NSString *) _newStringWithBytes:(const char *) bytes length:(unsigned) length; 69 70 - (NSString *) _stringFromPossibleData:(id) input; 70 71 @end trunk/Chat Core/MVIRCChatConnection.m
r3507 r3515 26 26 #define JVMaximumISONCommandLength 450 27 27 #define JVMaximumMembersForWhoRequest 100 28 #define JVFallbackEncoding NSISOLatin1StringEncoding 28 29 29 30 static const NSStringEncoding supportedEncodings[] = { … … 746 747 747 748 - (void) socket:(AsyncSocket *) sock didReadData:(NSData *) data withTag:(long) tag { 748 NSString *rawString = [[NSString allocWithZone:nil] initWithData:data encoding:[self encoding]]; 749 if( ! rawString ) rawString = [[NSString allocWithZone:nil] initWithData:data encoding:NSISOLatin1StringEncoding]; 749 NSString *rawString = [self _newStringWithBytes:[data bytes] length:[data length]]; 750 750 751 751 const char *line = (const char *)[data bytes]; … … 827 827 currentParameter = line; 828 828 while( notEndOfLine() && *line != ' ' ) line++; 829 param = [[NSString allocWithZone:nil] initWithBytes:currentParameter length:(line - currentParameter) encoding:[self encoding]]; 830 if( ! param ) param = [[NSString allocWithZone:nil] initWithBytes:currentParameter length:(line - currentParameter) encoding:NSISOLatin1StringEncoding]; 829 param = [self _newStringWithBytes:currentParameter length:(line - currentParameter)]; 831 830 checkAndMarkIfDone(); 832 831 if( ! done ) line++; … … 855 854 856 855 if( [self respondsToSelector:selector] ) { 857 NSString *senderString = nil; 858 if( sender && senderLength ) { 859 senderString = [[NSString allocWithZone:nil] initWithBytes:sender length:senderLength encoding:[self encoding]]; 860 if( ! senderString ) senderString = [[NSString allocWithZone:nil] initWithBytes:sender length:senderLength encoding:NSISOLatin1StringEncoding]; 861 } 856 NSString *senderString = [self _newStringWithBytes:sender length:senderLength]; 862 857 863 858 MVChatUser *chatUser = nil; … … 867 862 chatUser = [self chatUserWithUniqueIdentifier:senderString]; 868 863 if( ! [chatUser address] && host && hostLength ) { 869 NSString *hostString = [[NSString allocWithZone:nil] initWithBytes:host length:hostLength encoding:[self encoding]]; 870 if( ! hostString ) hostString = [[NSString allocWithZone:nil] initWithBytes:host length:hostLength encoding:NSISOLatin1StringEncoding]; 864 NSString *hostString = [self _newStringWithBytes:host length:hostLength]; 871 865 [chatUser _setAddress:hostString]; 872 866 [hostString release]; … … 874 868 875 869 if( ! [chatUser username] ) { 876 NSString *userString = [[NSString allocWithZone:nil] initWithBytes:user length:userLength encoding:[self encoding]]; 877 if( ! userString ) userString = [[NSString allocWithZone:nil] initWithBytes:user length:userLength encoding:NSISOLatin1StringEncoding]; 870 NSString *userString = [self _newStringWithBytes:user length:userLength]; 878 871 [chatUser _setUsername:userString]; 879 872 [userString release]; … … 1254 1247 #pragma mark - 1255 1248 1249 - (NSString *) _newStringWithBytes:(const char *) bytes length:(unsigned) length { 1250 if( bytes && length ) { 1251 BOOL validUTF8 = isValidUTF8( bytes, length ); 1252 NSStringEncoding encoding = ( [self encoding] != NSUTF8StringEncoding ? [self encoding] : JVFallbackEncoding ); 1253 NSString *ret = [[NSString allocWithZone:nil] initWithBytes:bytes length:length encoding:( validUTF8 ? NSUTF8StringEncoding : encoding )]; 1254 if( ! ret && encoding != JVFallbackEncoding ) ret = [[NSString allocWithZone:nil] initWithBytes:bytes length:length encoding:JVFallbackEncoding]; 1255 return ret; 1256 } 1257 1258 if( ! length ) return @""; 1259 return nil; 1260 } 1261 1256 1262 - (NSString *) _stringFromPossibleData:(id) input { 1257 if( [input isKindOfClass:[NSData class]] ) { 1258 NSString *ret = [[[NSString allocWithZone:nil] initWithData:input encoding:[self encoding]] autorelease]; 1259 if( ret ) return ret; 1260 return [[[NSString allocWithZone:nil] initWithData:input encoding:NSISOLatin1StringEncoding] autorelease]; 1261 } 1263 if( [input isKindOfClass:[NSData class]] ) 1264 return [[self _newStringWithBytes:[input bytes] length:[input length]] autorelease]; 1262 1265 return input; 1263 1266 } … … 1505 1508 [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadWithName:MVChatConnectionGotPrivateMessageNotification object:sender userInfo:[NSDictionary dictionaryWithObjectsAndKeys:msgData, @"message", [NSString locallyUniqueString], @"identifier", [NSNumber numberWithBool:YES], @"notice", nil]]; 1506 1509 if( [[sender nickname] isEqualToString:@"NickServ"] ) { 1507 NSString *msg = [ [NSString allocWithZone:nil] initWithData:msgData encoding:[self encoding]];1508 if( ! msg ) msg = [[NSString allocWithZone:nil] initWithData:msgData encoding:NSISOLatin1StringEncoding]; 1510 NSString *msg = [self _newStringWithBytes:[msgData bytes] length:[msgData length]]; 1511 1509 1512 if( [msg rangeOfString:@"NickServ"].location != NSNotFound && [msg rangeOfString:@"IDENTIFY"].location != NSNotFound ) { 1510 1513 if( ! [self nicknamePassword] ) { … … 1516 1519 [[self localUser] _setIdentified:NO]; 1517 1520 } 1521 1518 1522 [msg release]; 1519 1523 } … … 1534 1538 1535 1539 while( line != end && *line != ' ' ) line++; 1536 NSString *command = [[NSString allocWithZone:nil] initWithBytes:current length:(line - current) encoding:[self encoding]]; 1537 if( ! command ) command = [[NSString allocWithZone:nil] initWithBytes:current length:(line - current) encoding:NSISOLatin1StringEncoding]; 1538 1540 1541 NSString *command = [self _newStringWithBytes:current length:(line - current)]; 1539 1542 NSMutableData *arguments = nil; 1540 1543 if( line != end ) { … … 1596 1599 if( [arguments length] < 100 ) [sender sendSubcodeReply:command withArguments:arguments]; 1597 1600 } else if( [command caseInsensitiveCompare:@"DCC"] == NSOrderedSame ) { 1598 NSString *msg = [[NSString allocWithZone:nil] initWithData:arguments encoding:[self encoding]]; 1599 if( ! msg ) msg = [[NSString allocWithZone:nil] initWithData:arguments encoding:NSISOLatin1StringEncoding]; 1600 1601 NSString *msg = [self _newStringWithBytes:[arguments bytes] length:[arguments length]]; 1601 1602 NSString *subCommand = nil; 1602 1603 NSString *fileName = nil;
