Tidied decoding of data.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@8142 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2000-11-17 13:27:22 +00:00
parent 13a505f5ad
commit 999cd23cc9
4 changed files with 565 additions and 346 deletions

View file

@ -31,6 +31,28 @@
</desc>
</method>
<method type="GSMimeCodingContext*">
<sel>contextFor:</sel>
<arg type="NSDictionary*">headerInfo</arg>
<desc>
Return a coding context object to be used for decoding data
according to the scheme specified in the header.
<p>
The default implementation supports the following transfer
encodings specified in either a <code>transfer-encoding</code>
of <code>content-transfer-encoding</code> header -
</p>
<list>
<item>base64</item>
<item>quoted-printable</item>
<item>binary</item>
<item>7bit</item>
<item>8bit</item>
<item>chunked (for HTTP/1.1)</item>
</list>
</desc>
</method>
<method type="BOOL">
<sel>decodeData:</sel>
<arg type="NSData*">sourceData</arg>
@ -39,7 +61,7 @@
<sel>intoData:</sel>
<arg type="NSMutableData*">destinationData</arg>
<sel>withContext:</sel>
<arg type="GSMimeEncodingContext*">ctxt</arg>
<arg type="GSMimeCodingContext*">ctxt</arg>
<desc>
<p>
Decodes the raw data from the specified range in the source

View file

@ -34,15 +34,16 @@
<h2>Methods </h2>
<ul>
<li><a href ="GSMimeParser.html#method-0">+mimeParser</a>
<li><a href ="GSMimeParser.html#method-1">-decodeData:fromRange:intoData:withContext:</a>
<li><a href ="GSMimeParser.html#method-2">-document</a>
<li><a href ="GSMimeParser.html#method-3">-parse:</a>
<li><a href ="GSMimeParser.html#method-4">-parseHeader:</a>
<li><a href ="GSMimeParser.html#method-5">-parsingHeaders</a>
<li><a href ="GSMimeParser.html#method-6">-scanHeader:named:inTo:</a>
<li><a href ="GSMimeParser.html#method-7">-scanSpace:</a>
<li><a href ="GSMimeParser.html#method-8">-scanSpecial:</a>
<li><a href ="GSMimeParser.html#method-9">-scanToken:</a>
<li><a href ="GSMimeParser.html#method-1">-contextFor:</a>
<li><a href ="GSMimeParser.html#method-2">-decodeData:fromRange:intoData:withContext:</a>
<li><a href ="GSMimeParser.html#method-3">-document</a>
<li><a href ="GSMimeParser.html#method-4">-parse:</a>
<li><a href ="GSMimeParser.html#method-5">-parseHeader:</a>
<li><a href ="GSMimeParser.html#method-6">-parsingHeaders</a>
<li><a href ="GSMimeParser.html#method-7">-scanHeader:named:inTo:</a>
<li><a href ="GSMimeParser.html#method-8">-scanSpace:</a>
<li><a href ="GSMimeParser.html#method-9">-scanSpecial:</a>
<li><a href ="GSMimeParser.html#method-10">-scanToken:</a>
</ul>
<hr><h2>Class Methods </h2>
<h3><a name ="method-0">mimeParser</a></h3>
@ -52,8 +53,31 @@
<hr>
<hr><h2>Instances Methods </h2>
<h3><a name ="method-1">decodeData:fromRange:intoData:withContext:</a></h3>
- (BOOL) <b>decodeData:</b> (NSData*)sourceData <b>fromRange:</b> (NSRange)aRange <b>intoData:</b> (NSMutableData*)destinationData <b>withContext:</b> (GSMimeEncodingContext*)ctxt;<br>
<h3><a name ="method-1">contextFor:</a></h3>
- (GSMimeCodingContext*) <b>contextFor:</b> (NSDictionary*)headerInfo;<br>
Return a coding context object to be used for decoding data
according to the scheme specified in the header.
<p>
The default implementation supports the following transfer
encodings specified in either a <code>transfer-encoding</code>
of <code>content-transfer-encoding</code> header -
</p>
<ul>
<li>base64
<li>quoted-printable
<li>binary
<li>7bit
<li>8bit
<li>chunked (for HTTP/1.1)
</ul>
<hr>
<h3><a name ="method-2">decodeData:fromRange:intoData:withContext:</a></h3>
- (BOOL) <b>decodeData:</b> (NSData*)sourceData <b>fromRange:</b> (NSRange)aRange <b>intoData:</b> (NSMutableData*)destinationData <b>withContext:</b> (GSMimeCodingContext*)ctxt;<br>
<p>
@ -81,13 +105,13 @@
<hr>
<h3><a name ="method-2">document</a></h3>
<h3><a name ="method-3">document</a></h3>
- (GSMimeDocument*) <b>document</b>;<br>
Returns the object into which raw mime data is being parsed.
<hr>
<h3><a name ="method-3">parse:</a></h3>
<h3><a name ="method-4">parse:</a></h3>
- (BOOL) <b>parse:</b> (NSData*)rawData;<br>
This method is called repeatedly to pass raw mime data into
@ -96,7 +120,7 @@
all the available information.
<hr>
<h3><a name ="method-4">parseHeader:</a></h3>
<h3><a name ="method-5">parseHeader:</a></h3>
- (BOOL) <b>parseHeader:</b> (NSString*)aRawHeader;<br>
<p>
@ -144,7 +168,7 @@
<hr>
<h3><a name ="method-5">parsingHeaders</a></h3>
<h3><a name ="method-6">parsingHeaders</a></h3>
- (BOOL) <b>parsingHeaders</b>;<br>
Returns YES if the parser is expecting to read mime headers,
@ -153,7 +177,7 @@
the mime message (or has been passed all data).
<hr>
<h3><a name ="method-6">scanHeader:named:inTo:</a></h3>
<h3><a name ="method-7">scanHeader:named:inTo:</a></h3>
- (BOOL) <b>scanHeader:</b> (NSScanner*)aScanner <b>named:</b> (NSString*)aName <b>inTo:</b> (NSMutableDictionary*)info;<br>
<p>
@ -260,7 +284,7 @@
<hr>
<h3><a name ="method-7">scanSpace:</a></h3>
<h3><a name ="method-8">scanSpace:</a></h3>
- (BOOL) <b>scanSpace:</b> (NSScanner*)aScanner;<br>
A convenience method to scan past any whitespace in the scanner
@ -268,7 +292,7 @@
comes after it. Returns YES if any space was read, NO otherwise.
<hr>
<h3><a name ="method-8">scanSpecial:</a></h3>
<h3><a name ="method-9">scanSpecial:</a></h3>
- (NSString*) <b>scanSpecial:</b> (NSScanner*)aScanner;<br>
A convenience method to use a scanner (that is set up to scan a
@ -278,7 +302,7 @@
will contain a single space character.
<hr>
<h3><a name ="method-9">scanToken:</a></h3>
<h3><a name ="method-10">scanToken:</a></h3>
- (NSString*) <b>scanToken:</b> (NSScanner*)aScanner;<br>
A convenience method to use a scanner (that is set up to scan a

View file

@ -39,28 +39,16 @@
@class NSString;
@class NSMutableString;
typedef enum {
GSMimeEncodingBase64,
GSMimeEncodingQuotedPrintable,
GSMimeEncodingSevenBit,
GSMimeEncodingEightBit,
GSMimeEncodingBinary,
GSMimeEncodingChunked, // HTTP/1.1 chunked transfer
GSMimeEncodingUnknown
} GSMimeEncoding;
/*
* A trivial class for mantaining state while decoding/encoding data.
* Each encoding type requires its own subclass.
*/
@interface GSMimeEncodingContext : NSObject
@interface GSMimeCodingContext : NSObject
{
@public
GSMimeEncoding type; /* The encoding type to be used. */
unsigned char buf[8]; /* Temporary data storage area. */
int pos; /* Context position count. */
BOOL foot; /* Reading footer near end of data. */
BOOL atEnd; /* Flag to say that data has ended. */
BOOL atEnd; /* Flag to say that data has ended. */
}
- (BOOL) atEnd;
- (void) setAtEnd: (BOOL)flag;
@end
@interface GSMimeDocument : NSObject
@ -96,15 +84,16 @@ typedef enum {
NSData *boundary;
GSMimeDocument *document;
GSMimeParser *child;
GSMimeEncodingContext *context;
GSMimeCodingContext *context;
}
+ (GSMimeParser*) mimeParser;
- (GSMimeCodingContext*) contextFor: (NSDictionary*)headerInfo;
- (BOOL) decodeData: (NSData*)sData
fromRange: (NSRange)aRange
intoData: (NSMutableData*)dData
withContext: (GSMimeEncodingContext*)ctxt;
withContext: (GSMimeCodingContext*)ctxt;
- (GSMimeDocument*) document;
- (BOOL) parse: (NSData*)input;
- (BOOL) parseHeader: (NSString*)aRawHeader;

View file

@ -189,9 +189,105 @@ parseCharacterSet(NSString *token)
return NSASCIIStringEncoding;
}
@implementation GSMimeEncodingContext
@implementation GSMimeCodingContext
- (BOOL) atEnd
{
return atEnd;
}
- (id) copyWithZone: (NSZone*)z
{
return RETAIN(self);
}
- (void) setAtEnd: (BOOL)flag
{
atEnd = flag;
}
@end
@interface GSMimeBase64DecoderContext : GSMimeCodingContext
{
@public
unsigned char buf[4];
unsigned pos;
}
@end
@implementation GSMimeBase64DecoderContext
@end
@interface GSMimeQuotedDecoderContext : GSMimeCodingContext
{
@public
unsigned char buf[4];
unsigned pos;
}
@end
@implementation GSMimeQuotedDecoderContext
@end
@interface GSMimeChunkedDecoderContext : GSMimeCodingContext
{
@public
unsigned char buf[8];
unsigned pos;
enum {
ChunkSize, // Reading chunk size
ChunkExt, // Reading cjhunk extensions
ChunkEol1, // Reading end of line after size;ext
ChunkData, // Reading chunk data
ChunkEol2, // Reading end of line after data
ChunkFoot, // Reading chunk footer after newline
ChunkFootA // Reading chunk footer
} state;
NSMutableData *data;
}
@end
@implementation GSMimeChunkedDecoderContext
- (void) dealloc
{
RELEASE(data);
[super dealloc];
}
- (id) init
{
self = [super init];
if (self != nil)
{
data = [NSMutableData new];
}
return self;
}
@end
@interface GSMimeBinaryDecoderContext : GSMimeCodingContext
@end
@implementation GSMimeBinaryDecoderContext
- (id) autorelease
{
return self;
}
- (id) copyWithZone: (NSZone*)z
{
return self;
}
- (void) dealloc
{
NSLog(@"Error - attempt to deallocate GSMimeBinaryDecoderContext");
}
- (id) retain
{
return self;
}
- (void) release
{
}
@end
@interface GSMimeParser (Private)
- (BOOL) _decodeBody: (NSData*)data;
@ -216,10 +312,66 @@ parseCharacterSet(NSString *token)
[super dealloc];
}
- (GSMimeCodingContext*) contextFor: (NSDictionary*)info
{
NSString *name;
NSString *value;
static GSMimeCodingContext *defaultContext = nil;
if (defaultContext == nil)
{
defaultContext = [GSMimeBinaryDecoderContext new];
}
if (info == nil)
{
NSLog(@"contextFor: - nil header ... assumed binary encoding");
return defaultContext;
}
name = [info objectForKey: @"Name"];
if ([name isEqualToString: @"content-transfer-encoding"] == YES
|| [name isEqualToString: @"transfer-encoding"] == YES)
{
value = [info objectForKey: @"Value"];
if ([value length] == 0)
{
NSLog(@"Bad value for %@ header - assume binary encoding", name);
return defaultContext;
}
if ([value isEqualToString: @"base64"] == YES)
{
return AUTORELEASE([GSMimeBase64DecoderContext new]);
}
else if ([value isEqualToString: @"quoted-printable"] == YES)
{
return AUTORELEASE([GSMimeQuotedDecoderContext new]);
}
else if ([value isEqualToString: @"binary"] == YES)
{
return defaultContext;
}
else if ([value characterAtIndex: 0] == '7')
{
return defaultContext;
}
else if ([value characterAtIndex: 0] == '8')
{
return defaultContext;
}
else if ([value isEqualToString: @"chunked"] == YES)
{
return AUTORELEASE([GSMimeChunkedDecoderContext new]);
}
}
NSLog(@"contextFor: - unknown header (%@) ... assumed binary encoding", name);
return defaultContext;
}
- (BOOL) decodeData: (NSData*)sData
fromRange: (NSRange)aRange
intoData: (NSMutableData*)dData
withContext: (GSMimeEncodingContext*)ctxt
withContext: (GSMimeCodingContext*)con
{
unsigned size = [dData length];
unsigned len = [sData length];
@ -227,22 +379,15 @@ parseCharacterSet(NSString *token)
unsigned char *dst;
const char *src;
const char *end;
Class ccls;
if (dData == nil || ctxt == nil)
if (dData == nil || [con isKindOfClass: [GSMimeCodingContext class]] == NO)
{
[NSException raise: NSInvalidArgumentException
format: @"Bad data or context"];
format: @"Bad destination data for decode"];
}
GS_RANGE_CHECK(aRange, len);
/*
* A nil data item as input represents end of data.
*/
if (sData == nil)
{
ctxt->atEnd = YES;
}
/*
* Get pointers into source data buffer.
*/
@ -250,278 +395,353 @@ parseCharacterSet(NSString *token)
src += aRange.location;
end = src + aRange.length;
switch (ctxt->type)
ccls = [con class];
if (ccls == [GSMimeBase64DecoderContext class])
{
case GSMimeEncodingBase64:
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (3 * (end + 8 - src))/4];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
GSMimeBase64DecoderContext *ctxt;
/*
* Now decode data into buffer, keeping count and temporary
* data in context.
*/
while (src < end)
{
int cc = *src++;
ctxt = (GSMimeBase64DecoderContext*)con;
if (isupper(cc))
{
cc -= 'A';
}
else if (islower(cc))
{
cc = cc - 'a' + 26;
}
else if (isdigit(cc))
{
cc = cc - '0' + 52;
}
else if (cc == '+')
{
cc = 62;
}
else if (cc == '/')
{
cc = 63;
}
else if (cc == '=')
{
ctxt->atEnd = YES;
cc = -1;
}
else if (cc == '-')
{
ctxt->atEnd = YES;
break;
}
else
{
cc = -1; /* ignore */
}
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (3 * (end + 8 - src))/4];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
if (cc >= 0)
{
ctxt->buf[ctxt->pos++] = cc;
if (ctxt->pos == 4)
/*
* Now decode data into buffer, keeping count and temporary
* data in context.
*/
while (src < end)
{
int cc = *src++;
if (isupper(cc))
{
cc -= 'A';
}
else if (islower(cc))
{
cc = cc - 'a' + 26;
}
else if (isdigit(cc))
{
cc = cc - '0' + 52;
}
else if (cc == '+')
{
cc = 62;
}
else if (cc == '/')
{
cc = 63;
}
else if (cc == '=')
{
[ctxt setAtEnd: YES];
cc = -1;
}
else if (cc == '-')
{
[ctxt setAtEnd: YES];
break;
}
else
{
cc = -1; /* ignore */
}
if (cc >= 0)
{
ctxt->buf[ctxt->pos++] = cc;
if (ctxt->pos == 4)
{
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
dst += 3;
}
}
}
/*
* Odd characters at end of decoded data need to be added separately.
*/
if ([ctxt atEnd] == YES && ctxt->pos > 0)
{
unsigned len = ctxt->pos - 1;;
while (ctxt->pos < 4)
{
ctxt->buf[ctxt->pos++] = '\0';
}
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
size += len;
}
[dData setLength: size + dst - beg];
}
else if (ccls == [GSMimeQuotedDecoderContext class])
{
GSMimeQuotedDecoderContext *ctxt;
ctxt = (GSMimeQuotedDecoderContext*)con;
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
while (src < end)
{
if (ctxt->pos > 0)
{
if ((*src == '\n') || (*src == '\r'))
{
ctxt->pos = 0;
}
else
{
ctxt->buf[ctxt->pos++] = '=';
if (ctxt->pos == 3)
{
int c;
int val;
ctxt->pos = 0;
c = ctxt->buf[1];
val = isdigit(c) ? (c - '0') : (c - 55);
val *= 0x10;
c = ctxt->buf[2];
val += isdigit(c) ? (c - '0') : (c - 55);
*dst++ = val;
}
}
}
else if (*src == '=')
{
ctxt->buf[ctxt->pos++] = '=';
}
else
{
*dst++ = *src;
}
src++;
}
[dData setLength: size + dst - beg];
}
else if (ccls == [GSMimeChunkedDecoderContext class])
{
GSMimeChunkedDecoderContext *ctxt;
const char *footers = src;
ctxt = (GSMimeChunkedDecoderContext*)con;
dst = beg = 0;
while ([ctxt atEnd] == NO && src < end)
{
switch (ctxt->state)
{
case ChunkSize:
if (isxdigit(*src) && ctxt->pos < sizeof(ctxt->buf))
{
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
dst += 3;
ctxt->buf[ctxt->pos++] = *src;
}
}
}
/*
* Odd characters at end of decoded data need to be added separately.
*/
if (ctxt->atEnd == YES && ctxt->pos > 0)
{
unsigned len = ctxt->pos - 1;;
while (ctxt->pos < 4)
{
ctxt->buf[ctxt->pos++] = '\0';
}
ctxt->pos = 0;
decodebase64(dst, ctxt->buf);
size += len;
}
[dData setLength: size + dst - beg];
break;
case GSMimeEncodingQuotedPrintable:
/*
* Expand destination data buffer to have capacity to handle info.
*/
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
while (src < end)
{
if (ctxt->pos > 0)
{
if ((*src == '\n') || (*src == '\r'))
else if (*src == ';')
{
ctxt->pos = 0;
ctxt->state = ChunkExt;
}
else
else if (*src == '\r')
{
ctxt->buf[ctxt->pos++] = '=';
if (ctxt->pos == 3)
{
int c;
int val;
ctxt->pos = 0;
c = ctxt->buf[1];
val = isdigit(c) ? (c - '0') : (c - 55);
val *= 0x10;
c = ctxt->buf[2];
val += isdigit(c) ? (c - '0') : (c - 55);
*dst++ = val;
}
ctxt->state = ChunkEol1;
}
}
else if (*src == '=')
{
ctxt->buf[ctxt->pos++] = '=';
}
else
{
*dst++ = *src;
}
src++;
}
[dData setLength: size + dst - beg];
break;
case GSMimeEncodingChunked:
while (ctxt->atEnd == NO && src < end)
{
/*
* If we are reading a chunk footer, look for a blank line
* that terminates it.
*/
if (ctxt->foot == YES)
{
if (*src == '\r')
else if (*src == '\n')
{
src++;
ctxt->state = ChunkData;
}
else if (*src != '\n' || ctxt->buf[0] != '\n')
src++;
if (ctxt->state != ChunkSize)
{
ctxt->buf[0] = *src++;
}
else
{
ctxt->foot = NO;
ctxt->atEnd = YES;
src++;
break;
}
continue;
}
/*
* Keep track of chunk size in the context.
* A negative 'pos' indicates that we are reading the chunk size.
* A positive 'pos' indicates that we are reading the chunk itsself.
*/
if (ctxt->pos <= 0)
{
BOOL foundChunkSize = NO;
/*
* If we have a negative 'pos', convert it to a positive
* count of bytes read for the chunk size.
*/
if (ctxt->pos < 0)
{
ctxt->pos = -ctxt->pos;
}
while (src < end)
{
if (isxdigit(*src))
{
ctxt->buf[ctxt->pos++] = *src++;
if (ctxt->pos == sizeof(ctxt->buf))
{
NSLog(@"Bad chunk size field");
ctxt->pos = 0;
}
}
else
{
if (*src == '\r')
{
src++;
}
if (*src == '\n')
{
src++;
}
foundChunkSize = YES;
break;
}
}
if (foundChunkSize == YES)
{
int size = 0;
int val = 0;
int index;
for (index = 0; index < ctxt->pos; index++)
{
size *= 16;
val *= 16;
if (isdigit(ctxt->buf[index]))
{
size += ctxt->buf[index] - '0';
val += ctxt->buf[index] - '0';
}
else if (isupper(ctxt->buf[index]))
{
size += ctxt->buf[index] - 'A' + 10;
val += ctxt->buf[index] - 'A' + 10;
}
else
{
size += ctxt->buf[index] - 'a' + 10;
val += ctxt->buf[index] - 'a' + 10;
}
}
ctxt->pos = size;
ctxt->pos = val;
/*
* Check to see if this is the terminator for the
* document content.
* If we have read a chunk already, make sure that our
* destination size is updated correctly before growing
* the buffer for another chunk.
*/
if (ctxt->pos == 0)
{
ctxt->foot = YES;
ctxt->buf[0] = src[-1]; // last char read
}
size += (dst - beg);
[dData setLength: size + val];
dst = (unsigned char*)[dData mutableBytes];
dst += size;
beg = dst;
}
else
{
ctxt->pos = -ctxt->pos;
}
}
if (ctxt->pos > 0)
{
/*
* Expand destination data buffer to have capacity to
* handle remainder of chunk.
*/
[dData setLength: size + ctxt->pos];
dst = (unsigned char*)[dData mutableBytes];
beg = dst;
/*
* Read the specified chunk length (excluding carriage returns)
*/
while (ctxt->pos > 0 && src < end)
{
if (*src != '\r')
{
*dst++ = *src;
ctxt->pos--;
}
src++;
}
[dData setLength: size + dst - beg];
}
}
break;
break;
default:
NSLog(@"Content encoding %d not known - assume binary", ctxt->type);
case GSMimeEncodingBinary:
case GSMimeEncodingSevenBit:
case GSMimeEncodingEightBit:
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
memcpy(&dst[size], src, (end - src));
[dData setLength: size + end - src];
break;
case ChunkExt:
if (*src == '\r')
{
ctxt->state = ChunkEol1;
}
else if (*src == '\n')
{
ctxt->state = ChunkData;
}
src++;
break;
case ChunkEol1:
if (*src == '\n')
{
ctxt->state = ChunkData;
}
src++;
break;
case ChunkData:
/*
* If the pos is non-zero, we have a data chunk to read.
* otherwise, what we actually want it to read footers.
*/
if (ctxt->pos > 0)
{
*dst++ = *src++;
if (--ctxt->pos == 0)
{
ctxt->state = ChunkEol2;
}
}
else
{
footers = src; // Record start position.
ctxt->state = ChunkFoot;
}
break;
case ChunkEol2:
if (*src == '\n')
{
ctxt->state = ChunkSize;
}
src++;
break;
case ChunkFoot:
if (*src == '\r')
{
src++;
}
else if (*src == '\n')
{
[ctxt setAtEnd: YES];
}
else
{
ctxt->state = ChunkFootA;
}
break;
case ChunkFootA:
if (*src == '\n')
{
ctxt->state = ChunkFootA;
}
src++;
break;
}
}
if (ctxt->state == ChunkFoot || ctxt->state == ChunkFootA)
{
[ctxt->data appendBytes: footers length: src - footers];
if ([ctxt atEnd] == YES)
{
NSMutableData *old;
/*
* Pretend we are back parsing the original headers ...
*/
old = data;
data = ctxt->data;
bytes = (unsigned char*)[data mutableBytes];
dataEnd = [data length];
inBody = NO;
/*
* Duplicate the normal header parsing process for our footers.
*/
while (inBody == NO)
{
if ([self _unfoldHeader] == NO)
{
break;
}
if (inBody == NO)
{
NSString *header;
header = [self _decodeHeader];
if (header == nil)
{
break;
}
if ([self parseHeader: header] == NO)
{
break;
}
}
}
/*
* restore original data.
*/
ctxt->data = data;
data = old;
bytes = (unsigned char*)[data mutableBytes];
dataEnd = [data length];
inBody = YES;
}
}
/*
* Append any data.
*/
[dData setLength: size + dst - beg];
}
else
{
/*
* Assume binary (no) decoding required.
*/
[dData setLength: size + (end - src)];
dst = (unsigned char*)[dData mutableBytes];
memcpy(&dst[size], src, (end - src));
[dData setLength: size + end - src];
}
/*
* A nil data item as input represents end of data.
*/
if (sData == nil)
{
[con setAtEnd: YES];
}
return YES;
@ -548,7 +768,7 @@ parseCharacterSet(NSString *token)
{
data = [[NSMutableData alloc] init];
document = [[GSMimeDocument alloc] init];
context = [[GSMimeEncodingContext alloc] init];
context = [[GSMimeCodingContext alloc] init];
}
return self;
}
@ -710,55 +930,6 @@ parseCharacterSet(NSString *token)
}
[document deleteHeaderNamed: name]; // Should be unique
}
else if ([name isEqualToString: @"content-transfer-encoding"] == YES
|| [name isEqualToString: @"transfer-encoding"] == YES)
{
BOOL supported = NO;
value = [info objectForKey: @"Value"];
if ([value length] == 0)
{
NSLog(@"Bad value for %@ header", name);
return NO;
}
if ([value isEqualToString: @"quoted-printable"] == YES)
{
context->type = GSMimeEncodingQuotedPrintable;
supported = YES;
}
else if ([value isEqualToString: @"base64"] == YES)
{
context->type = GSMimeEncodingBase64;
supported = YES;
}
else if ([value isEqualToString: @"binary"] == YES)
{
context->type = GSMimeEncodingBinary;
supported = YES;
}
else if ([value characterAtIndex: 0] == '7')
{
context->type = GSMimeEncodingSevenBit;
supported = YES;
}
else if ([value characterAtIndex: 0] == '8')
{
context->type = GSMimeEncodingEightBit;
supported = YES;
}
else if ([value isEqualToString: @"chunked"] == YES)
{
context->type = GSMimeEncodingChunked;
supported = YES;
}
if (supported == NO)
{
context->type = GSMimeEncodingBinary;
NSLog(@"Unsupported/unknown content-transfer-encoding");
return NO;
}
[document deleteHeaderNamed: name]; // Should be unique
}
else if ([name isEqualToString: @"content-type"] == YES)
{
NSString *type;
@ -1320,7 +1491,7 @@ parseCharacterSet(NSString *token)
}
else
{
if (context->atEnd == YES)
if ([context atEnd] == YES)
{
if ([d length] > 0)
{
@ -1334,7 +1505,7 @@ parseCharacterSet(NSString *token)
intoData: data
withContext: context];
if (context->atEnd == YES)
if ([context atEnd] == YES)
{
/*
* If no content type is supplied, we assume text.
@ -1533,7 +1704,8 @@ parseCharacterSet(NSString *token)
*/
if (lineEnd == lineStart)
{
unsigned lengthRemaining;
unsigned lengthRemaining;
NSDictionary *hdr;
/*
* Overwrite the header data with the body, ready to start
@ -1551,7 +1723,19 @@ parseCharacterSet(NSString *token)
lineStart = 0;
lineEnd = 0;
input = 0;
inBody = YES; /* At end of headers. */
/*
* At end of headers - set up context for decoding data.
*/
inBody = YES;
DESTROY(context);
hdr = [document headerNamed: @"content-transfer-encoding"];
if (hdr == nil)
{
hdr = [document headerNamed: @"transfer-encoding"];
}
context = [self contextFor: hdr];
RETAIN(context);
}
}
}