diff --git a/ChangeLog b/ChangeLog index 4aa624fa7..37b141e5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2011-11-07 Richard Frith-Macdonald + + * Source/Additions/GSMime.m: ([+decodeBase64:]) tolerate missing + padding and also use of '-' and '_' rather than '+' and '/' as + permitted in the "URL and Filename safe" variation given in RFC 4648 + 2011-11-04 Richard Frith-Macdonald * Source/NSDate.m: ([-timeIntervalSinceDate:]) return NaN if other diff --git a/Source/Additions/GSMime.m b/Source/Additions/GSMime.m index 0a3171381..6a96954e2 100644 --- a/Source/Additions/GSMime.m +++ b/Source/Additions/GSMime.m @@ -4201,22 +4201,26 @@ appendString(NSMutableData *m, NSUInteger offset, NSUInteger fold, { c = 63; } + else if (c == '_') + { + c = 63; /* RFC 4648 permits '_' in URLs and filenames */ + } else if (c == '+') { c = 62; } + else if (c == '-') + { + c = 62; /* RFC 4648 permits '-' in URLs and filenames */ + } else if (c == '=') { c = -1; pad++; } - else if (c == '-') - { - break; /* end */ - } else { - c = -1; /* ignore */ + c = -1; /* Ignore ... non-standard but more tolerant */ } if (c >= 0) @@ -4231,6 +4235,15 @@ appendString(NSMutableData *m, NSUInteger offset, NSUInteger fold, } } + /* If length is not a multiple of four, treat it as if the missing + * bytes were the '=' characters normally used for padding. + * This is not allowed by the basic standards, but permitted in some + * variants of 6ase64 encoding, so we should tolerate it. + */ + if (length % 4 > 0) + { + pad += (4 - length % 4); + } if (pos > 0) { NSUInteger i; diff --git a/Tests/base/GSMime/general.m b/Tests/base/GSMime/general.m index 799af4776..7d948c4ee 100644 --- a/Tests/base/GSMime/general.m +++ b/Tests/base/GSMime/general.m @@ -65,11 +65,22 @@ exact(GSMimeParser **parserPointer, NSData *data) int main() { NSAutoreleasePool *arp = [NSAutoreleasePool new]; + NSData *cr; NSData *data; GSMimeParser *parser; GSMimeDocument *doc; GSMimeDocument *idoc; + cr = [NSData dataWithBytes: "\r" length: 1]; + + data = [NSData dataWithBytes: "DQ==" length: 4]; + PASS_EQUAL([GSMimeDocument decodeBase64: data], cr, + "decodeBase64 works for padded data"); + + data = [NSData dataWithBytes: "DQ" length: 2]; + PASS_EQUAL([GSMimeDocument decodeBase64: data], cr, + "decodeBase64 works for unpadded data"); + data = [NSData dataWithContentsOfFile: @"mime1.dat"]; idoc = exact(0, data); PASS_EQUAL([[[idoc content] objectAtIndex:0] content], @"a",