This is NSString+MIME.m in view mode; [Download] [Up]
//--------------------------------------------------------------------------------------- // NSString+MIME.m created by erik on Wed 08-Jan-1997 // This code is part of the Alexandra Newsreader Project. For copyright details see // GNU public license version 2 or above. No warranties implied. Use at own risk. // More information can be found at <http://www.object-factory.com/Alexandra>. // @(#)$Id: NSString+MIME.m,v 1.7 1998/10/22 14:27:24 erik Exp $ //--------------------------------------------------------------------------------------- #import "Utilities.h" #import "NSData+MIME.h" #import "NSString+MIME.h" //--------------------------------------------------------------------------------------- // Constants //--------------------------------------------------------------------------------------- NSString *MIMEFormatException = @"MIMEFormatException"; NSString *MIMEAsciiStringEncoding = @"us-ascii"; NSString *MIMELatin1StringEncoding = @"iso-8859-1"; NSString *MIMELatin2StringEncoding = @"iso-8859-2"; NSString *MIME2022JPStringEncoding = @"iso-2022"; //--------------------------------------------------------------------------------------- @implementation NSString(MIMEExtensions_Alexandra) //--------------------------------------------------------------------------------------- + (NSString *)stringWithData:(NSData *)data MIMEEncoding:(NSString *)encodingName { return [[[NSString alloc] initWithData:data MIMEEncoding:encodingName] autorelease]; } + (NSString *)stringWithBytes:(const void *)buffer length:(unsigned int)length MIMEEncoding:(NSString *)encodingName; { return [self stringWithData:[NSData dataWithBytes:buffer length:length] MIMEEncoding:encodingName]; } //--------------------------------------------------------------------------------------- // Converting to/from byte representations //--------------------------------------------------------------------------------------- - initWithData:(NSData *)buffer MIMEEncoding:(NSString *)encodingName; { NSStringEncoding encoding; encodingName = [encodingName lowercaseString]; if((encoding = [NSString stringEncodingForMIMEEncoding:encodingName]) == 0) encoding = NSASCIIStringEncoding; // hope that NSString does something reasonable return [self initWithData:buffer encoding:encoding]; } - (NSData *)dataUsingMIMEEncoding:(NSString *)encodingName { NSStringEncoding encoding; encodingName = [encodingName lowercaseString]; if((encoding = [NSString stringEncodingForMIMEEncoding:encodingName]) == 0) return nil; return [self dataUsingEncoding:encoding]; } //--------------------------------------------------------------------------------------- // NSStringEncoding vs. MIME Encoding //--------------------------------------------------------------------------------------- - (NSString *)recommendedMIMEEncoding; { if([self canBeConvertedToEncoding:NSASCIIStringEncoding]) return MIMEAsciiStringEncoding; if([self canBeConvertedToEncoding:NSISOLatin1StringEncoding]) return MIMELatin1StringEncoding; #ifndef LITTLE_FOUNDATION if([self canBeConvertedToEncoding:NSISOLatin2StringEncoding]) return MIMELatin2StringEncoding; if([self canBeConvertedToEncoding:NSISO2022JPStringEncoding]) return MIME2022JPStringEncoding; #endif return nil; } + (NSStringEncoding)stringEncodingForMIMEEncoding:(NSString *)encoding; { static NSMutableDictionary *table = nil; if(table == nil) { table = [NSMutableDictionary dictionary]; [table setObject:[NSNumber numberWithUnsignedInt:NSASCIIStringEncoding] forKey:MIMEAsciiStringEncoding]; [table setObject:[NSNumber numberWithUnsignedInt:NSISOLatin1StringEncoding] forKey:MIMELatin1StringEncoding]; #ifndef LITTLE_FOUNDATION [table setObject:[NSNumber numberWithUnsignedInt:NSISOLatin2StringEncoding] forKey:MIMELatin2StringEncoding]; [table setObject:[NSNumber numberWithUnsignedInt:NSISO2022JPStringEncoding] forKey:MIME2022JPStringEncoding]; #endif table = [table copy]; } return [[table objectForKey:[encoding lowercaseString]] unsignedIntValue]; } //--------------------------------------------------------------------------------------- // RFC1522 Encoding/Decoding //--------------------------------------------------------------------------------------- - initWithMIMEHeaderFieldData:(NSData *)value; { NSMutableString *dest; const char *source, *endOfSource, *vstart, *buffer; unsigned int length; dest = [[NSMutableString alloc] init]; buffer = [value bytes]; length = [value length]; vstart = buffer; endOfSource = (const char *)buffer + length; for(source = buffer; source < endOfSource; source++) { if((*source == EQUALS) && (source < endOfSource - 1) &&(*(source + 1) == QMARK)) { const char *p, *q, *pmax, *qmarkp[4]; char transferEncoding; int qmarks = 0, len; NSStringEncoding stringEncoding; NSString *charset, *text, *tmp; NSData *textBuffer = nil; pmax = source + umin(endOfSource - (char *)source, 76); for(p=source+1; p<pmax-1 && qmarks<4; p++) { if(*p == QMARK) { if(*(p - 1) == QMARK) break; qmarkp[qmarks] = p; qmarks += 1; } else if(*p == SPACE) break; } if((qmarks < 4) || (*(qmarkp[3] + 1) != EQUALS)) { tmp = [NSString stringWithFormat:@"MIME Decoder: '=?' didn't introducde RFC1522 word in '%@'", [NSString stringWithCString:buffer length:length]]; LOG(tmp); continue; } q = qmarkp[2] + 1; len = qmarkp[3] - q; transferEncoding = tolower(*(qmarkp[1]+1)); if(transferEncoding == 'q') textBuffer = [[NSData dataWithBytes:(void *)q length:len] decodeQuotedPrintable1522]; else if(transferEncoding == 'b') textBuffer = [[NSData dataWithBytes:(void *)q length:len] decodeBase64]; if(textBuffer != nil) { q = qmarkp[0] + 1; len = qmarkp[1] - q; charset = [[NSString stringWithCString:q length:len] lowercaseString]; if((stringEncoding = [NSString stringEncodingForMIMEEncoding:charset]) == 0) stringEncoding = NSASCIIStringEncoding; text = [[NSString alloc] initWithData:textBuffer encoding:stringEncoding]; if(vstart != source) [dest appendString:[NSString stringWithBytes:vstart length:source - vstart MIMEEncoding:MIMELatin1StringEncoding]]; [dest appendString:text]; [text release]; vstart = qmarkp[3] + 2; source = vstart - 1; // will be incremented by loop! } } } if(vstart != source) [dest appendString:[NSString stringWithBytes:vstart length:source - vstart MIMEEncoding:MIMELatin1StringEncoding]]; self = [self initWithString:dest]; [dest release]; return self; } - (NSData *)dataForMIMEHeaderField; { NSCharacterSet *spaceCharacterSet; NSMutableData *buffer; NSScanner *scanner; NSMutableString *text; NSString *currentEncoding, *nextEncoding, *word, *spaces; spaceCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@" "]; buffer = [NSMutableData data]; scanner = [NSScanner scannerWithString:self]; [scanner setCharactersToBeSkipped:nil]; text = [NSMutableString string]; currentEncoding = nil; do { if([scanner scanCharactersFromSet:spaceCharacterSet intoString:&spaces] == NO) spaces = @""; if([scanner scanUpToCharactersFromSet:spaceCharacterSet intoString:&word] == NO) word = nil; nextEncoding = [word recommendedMIMEEncoding]; if((nextEncoding != currentEncoding) || ([text length] + [word length] + 7 + [currentEncoding length] > 75) || (word == nil)) { if([text length] > 0) { if(currentEncoding != MIMEAsciiStringEncoding) [buffer appendData:[text dataByWrappingInHeaderFieldWord]]; else [buffer appendData:[text dataUsingEncoding:NSASCIIStringEncoding]]; } [buffer appendData:[spaces dataUsingEncoding:NSASCIIStringEncoding]]; currentEncoding = nextEncoding; text = [[word mutableCopy] autorelease]; } else { [text appendString:spaces]; [text appendString:word]; } } while([text length] > 0); return buffer; } - (NSData *)dataByWrappingInHeaderFieldWord; { NSMutableData *buffer; NSData *stringData, *b64TransferData, *qpTransferData, *transferData; NSString *characterSetName; unsigned int b64Length, qpLength; characterSetName = [self recommendedMIMEEncoding]; stringData = [self dataUsingMIMEEncoding:characterSetName]; b64TransferData = [stringData encodeBase64WithLineLength:UINT_MAX-3 andNewlineAtEnd:NO]; qpTransferData = [stringData encodeQuotedPrintable1522]; b64Length = [b64TransferData length]; qpLength = [qpTransferData length]; if((qpLength < 6) || (qpLength < [stringData length] * 3/2) || (qpLength <= b64Length)) transferData = qpTransferData; else transferData = b64TransferData; if([transferData length] + 7 + [characterSetName length] > 75) [NSException raise:NSInvalidArgumentException format:@"Encoding of this string results in a MIME word which exceeds the maximum length of 75 characters. Try to split it into multiple words and make sure that idividual components are separated by whitespaces."]; buffer = [NSMutableData data]; [buffer appendData:[[NSString stringWithFormat:@"=?%@?%@?", characterSetName, (transferData == qpTransferData) ? @"Q" : @"B"] dataUsingEncoding:NSASCIIStringEncoding]]; [buffer appendData:transferData]; [buffer appendData:[@"?=" dataUsingEncoding:NSASCIIStringEncoding]]; return buffer; } - (NSData *)dataForHeaderFieldBody; { return [self dataUsingMIMEEncoding:MIMEAsciiStringEncoding]; } //--------------------------------------------------------------------------------------- @end //---------------------------------------------------------------------------------------
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.