This is NSData+MIME.m in view mode; [Download] [Up]
//---------------------------------------------------------------------------------------
// NSData+MIME.m created by erik on Sun 12-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: NSData+MIME.m,v 1.7 1998/09/28 12:28:38 erik Exp $
//---------------------------------------------------------------------------------------
#import "Utilities.h"
#import "NSCharacterSet+MIME.h"
#import "NSData+MIME.h"
#import "NSString+MIME.h"
//---------------------------------------------------------------------------------------
// Mother's little helpers
//---------------------------------------------------------------------------------------
typedef unsigned char byte;
static char basishex[] =
"0123456789ABCDEF";
static byte indexhex[128] = {
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99, 99,99,99,99,
99,10,11,12, 13,14,15,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
99,10,11,12, 13,14,15,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99
};
static __inline__ void encode2bytehex(unsigned int value, char *buffer)
{
buffer[0] = basishex[value/16];
buffer[1] = basishex[value%16];
}
static __inline__ unsigned int decode2bytehex(const char *p)
{
return indexhex[(int)*p] * 16 + indexhex[(int)*(p+1)];
}
static byte basis64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static byte index64[128] = {
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,99, 99,99,99,99,
99,99,99,99, 99,99,99,99, 99,99,99,62, 99,99,99,63,
52,53,54,55, 56,57,58,59, 60,61,99,99, 99,99,99,99,
99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,99, 99,99,99,99,
99,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,99, 99,99,99,99
};
static __inline__ byte char64(byte c)
{
return (c > 127) ? 99 : index64[(int)c];
}
static __inline__ byte invchar64(byte b)
{
return basis64[(int)b];
}
//---------------------------------------------------------------------------------------
// constants
//---------------------------------------------------------------------------------------
NSString *MIME7BitContentTransferEncoding = @"7bit";
NSString *MIME8BitContentTransferEncoding = @"8bit";
NSString *MIMEBinaryContentTransferEncoding = @"binary";
NSString *MIMEQuotedPrintableContentTransferEncoding = @"quoted-printable";
NSString *MIMEBase64ContentTransferEncoding = @"base64";
//---------------------------------------------------------------------------------------
@implementation NSData(MIMEExtensions_Alexandra)
//---------------------------------------------------------------------------------------
- (NSData *)decodeContentWithTransferEncoding:(NSString *)encodingName
{
encodingName = [encodingName lowercaseString];
if([encodingName isEqualToString:MIME7BitContentTransferEncoding])
return self;
if([encodingName isEqualToString:MIME8BitContentTransferEncoding])
return self;
if([encodingName isEqualToString:MIMEBinaryContentTransferEncoding])
return self;
if([encodingName isEqualToString:MIMEQuotedPrintableContentTransferEncoding])
return [self decodeQuotedPrintable];
if([encodingName isEqualToString:MIMEBase64ContentTransferEncoding])
return [self decodeBase64];
[NSException raise:NSInvalidArgumentException format:@"unknown content transfer encoding; found '%@'", encodingName];
return nil;
}
//---------------------------------------------------------------------------------------
// DECODING SCHEMES
//---------------------------------------------------------------------------------------
- (NSData *)decodeQuotedPrintable;
{
NSMutableData *decodedData;
const char *source, *endOfSource;
char *dest;
source = [self bytes];
endOfSource = source + [self length];
decodedData = [NSMutableData dataWithLength:[self length]];
dest = [decodedData mutableBytes];
while(source < endOfSource)
{
if(*source == EQUALS)
{
source += 1;
if(iscrlf(*source) || iswhitespace(*source))
{
while(iswhitespace(*source))
source += 1;
if(*source == CR) // this is not exactly according
source += 1; // to rfc1521 but it does decode
if(*source == LF) // it properly while offering
source += 1; // some robustness...
}
else
{
if(isxdigit(*source) && isxdigit(*(source+1)))
{
*dest++ = decode2bytehex(source);
source += 2;
}
}
}
else
{
*dest ++ = *source++;
}
}
[decodedData setLength:(unsigned int)((void *)dest - [decodedData mutableBytes])];
return decodedData;
}
- (NSData *)decodeQuotedPrintable1522;
{
NSMutableData *decodedData;
const char *source, *endOfSource;
char *dest;
source = [self bytes];
endOfSource = source + [self length];
decodedData = [NSMutableData dataWithLength:[self length]];
dest = [decodedData mutableBytes];
while(source < endOfSource)
{
unsigned char c = *source++;
if((c == EQUALS) && isxdigit(*(source)) && isxdigit(*(source+1)))
{
c = decode2bytehex(source);
source += 2;
}
else if(c == UNDERSCORE)
{
c = SPACE;
}
*dest++ = c;
}
[decodedData setLength:(unsigned int)((void *)dest - [decodedData mutableBytes])];
return decodedData;
}
- (NSData *)decodeBase64;
{
NSMutableData *decodedData;
const byte *source, *endOfSource;
byte *dest, groupv[4], c, b;
int groupc = 0;
BOOL groupHadPadding = NO;
source = [self bytes];
endOfSource = source + [self length];
decodedData = [NSMutableData dataWithLength:[self length]];
dest = [decodedData mutableBytes];
while(source < endOfSource)
{
c = *source++;
if((b = char64(c)) != 99)
{
groupv[groupc++] = b;
}
else if(c == EQUALS)
{
if(groupc > 1)
{
groupv[groupc++] = 127;
groupHadPadding = YES;
}
}
if(groupc == 4)
{
groupc = 0;
*dest++ = (groupv[0]<<2) | ((groupv[1]&0x30)>>4);
if(groupv[2] != 127)
{
*dest++ = ((groupv[1]&0xF) << 4) | ((groupv[2]&0x3C) >> 2);
if(groupv[3] != 127)
*dest++ = ((groupv[2]&0x03) << 6) | groupv[3];
}
if(groupHadPadding)
break;
}
}
if(groupc != 0)
LOG(@"MIME Decoder: premature end of base64 encoded data");
[decodedData setLength:(unsigned int)((void *)dest - [decodedData mutableBytes])];
return decodedData;
}
//---------------------------------------------------------------------------------------
// ENCODING SCHEMES
//---------------------------------------------------------------------------------------
- (NSData *)encodeQuotedPrintable;
{
[NSException raise:NSInternalInconsistencyException format:@"NSData+Mime: -encodeQuotedPrintable not implemented yet."];
return nil;
}
- (NSData *)encodeQuotedPrintable1522;
{
return [self encodeQuotedPrintable1522MustEscapeCharactersInString:nil];
}
- (NSData *)encodeQuotedPrintable1522MustEscapeCharactersInString:(NSString *)escChars;
{
NSMutableCharacterSet *tempCharacterSet;
NSCharacterSet *literalChars;
NSMutableData *buffer;
unsigned int length;
const byte *source, *chunkStart, *endOfSource;
char escValue[3] = "=00", underscore = '_';
if(escChars != nil)
{
tempCharacterSet = [[NSCharacterSet MIME1522DefaultLiteralCharacterSet] mutableCopy];
[tempCharacterSet removeCharactersInString:escChars];
literalChars = [[tempCharacterSet copy] autorelease];
[tempCharacterSet release];
}
else
{
literalChars = [NSCharacterSet MIME1522DefaultLiteralCharacterSet];
}
length = [self length];
buffer = [[[NSMutableData alloc] initWithCapacity:length + length / 10] autorelease];
chunkStart = source = [self bytes];
endOfSource = source + length;
while(source < endOfSource)
{
if([literalChars characterIsMember:(unichar)(*source)] == NO)
{
if((length = (source - chunkStart)) > 0)
[buffer appendBytes:chunkStart length:length];
if(*source == SPACE)
{
[buffer appendBytes:&underscore length:1];
}
else
{
encode2bytehex(*source, &escValue[1]);
[buffer appendBytes:escValue length:3];
}
chunkStart = source + 1;
}
source += 1;
}
[buffer appendBytes:chunkStart length:(source - chunkStart)];
return buffer;
}
- (NSData *)encodeBase64;
{
return [self encodeBase64WithLineLength:76 andNewlineAtEnd:YES];
}
- (NSData *)encodeBase64WithLineLength:(unsigned int)lineLength andNewlineAtEnd:(BOOL)endWithNL;
{
NSMutableData *encodedData;
const byte *source, *endOfSource;
byte *dest, groupv[4], b;
int i, bytec = 0, groupc = 0;
unsigned int numgroups, groupsPerLine, dataLength;
source = [self bytes];
endOfSource = source + [self length];
numgroups = udivroundup([self length], 3);
groupsPerLine = lineLength / 4;
if(groupsPerLine == 0)
[NSException raise:NSInvalidArgumentException format:@"line length must be > 3"];
if((lineLength % 4) != 0)
LOG(@"MIME Encoder: rounded down line length for base64 encoding.");
dataLength = numgroups * 4;
if(lineLength > 0)
dataLength += udivroundup(numgroups, groupsPerLine) * 2;
encodedData = [NSMutableData dataWithLength:dataLength];
dest = [encodedData mutableBytes];
while(source < endOfSource)
{
b = *source++;
switch(bytec++)
{
case 0:
groupv[0] = (b & 0xFC) >> 2;
groupv[1] = (b & 0x03) << 4;
break;
case 1:
groupv[1] |= (b & 0xF0) >> 4;
groupv[2] = (b & 0x0F) << 2;
break;
case 2:
groupv[2] |= (b & 0xC0) >> 6;
groupv[3] = (b & 0x3F);
break;
}
if((bytec == 3) || (source == endOfSource))
{
for(i = 0; i < bytec + 1; i++)
*dest++ = invchar64(groupv[i]);
for(; i < 4; i++)
*dest++ = EQUALS;
bytec = 0;
groupc += 1;
if(((groupc % groupsPerLine) == 0) || ((source == endOfSource) && (endWithNL == YES)))
{
*dest++ = CR;
*dest++ = LF;
}
}
}
[encodedData setLength:(unsigned int)((void *)dest - [encodedData mutableBytes])];
return encodedData;
}
//---------------------------------------------------------------------------------------
@end
//---------------------------------------------------------------------------------------
#if 0
static void appendchars(NSMutableString *buffer, const char *p, unsigned int l)
{
NSString *s = [[NSString alloc] initWithData:[NSData dataWithBytes:p length:l] encoding:NSISOLatin1StringEncoding];
[buffer appendString:s];
[s release];
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.