diff -urb libvmime-0.9.2-patched/src/word.cpp libvmime-0.9.2/src/word.cpp --- libvmime-0.9.2-patched/src/word.cpp 2015-01-16 15:04:04.124264216 +0100 +++ libvmime-0.9.2/src/word.cpp 2015-01-16 15:05:13.672262038 +0100 @@ -64,8 +64,7 @@ ref word::parseNext(const string& buffer, const string::size_type position, - const string::size_type end, string::size_type* newPosition, - bool prevIsEncoded, bool* isEncoded, bool isFirst) + const string::size_type end, string::size_type* newPosition, parserState* state) { string::size_type pos = position; @@ -120,7 +119,7 @@ if (!unencoded.empty()) { - if (prevIsEncoded) + if (state->prevIsEncoded && !state->isFirst) unencoded = whiteSpaces + unencoded; ref w = vmime::create (unencoded, charset(charsets::US_ASCII)); @@ -129,8 +128,8 @@ if (newPosition) *newPosition = pos; - if (isEncoded) - *isEncoded = false; + state->prevIsEncoded = false; + state->isFirst = false; return (w); } @@ -181,13 +180,13 @@ pos += 2; // ?= ref w = vmime::create (); - w->parse(buffer, wordStart, pos, NULL); + w->parseWithState(buffer, wordStart, pos, NULL, state); if (newPosition) *newPosition = pos; - if (isEncoded) - *isEncoded = true; + state->prevIsEncoded = true; + state->isFirst = false; return (w); } @@ -195,7 +194,7 @@ ++pos; } - if (startPos != end && !isFirst && prevIsEncoded) + if (startPos != end && !state->isFirst && state->prevIsEncoded) unencoded += whiteSpaces; if (startPos != end) @@ -210,8 +209,8 @@ if (newPosition) *newPosition = end; - if (isEncoded) - *isEncoded = false; + state->prevIsEncoded = false; + state->isFirst = false; return (w); } @@ -228,9 +227,9 @@ string::size_type pos = position; - bool prevIsEncoded = false; + parserState state; - while ((w = word::parseNext(buffer, pos, end, &pos, prevIsEncoded, &prevIsEncoded, (w == NULL))) != NULL) + while ((w = word::parseNext(buffer, pos, end, &pos, &state)) != NULL) res.push_back(w); if (newPosition) @@ -243,6 +242,14 @@ void word::parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition) { + parseWithState(buffer, position, end, newPosition, NULL); +} + + +void word::parseWithState + (const string& buffer, const size_t position, + const size_t end, size_t* newPosition, parserState* state) +{ if (position + 6 < end && // 6 = "=?(.+)?(.*)?=" buffer[position] == '=' && buffer[position + 1] == '?') { @@ -289,12 +296,20 @@ if (theEncoder) { // Decode text + string encodedBuffer(dataPos, dataEnd); string decodedBuffer; - utility::inputStreamStringAdapter ein(string(dataPos, dataEnd)); + + if (state && !state->undecodedBytes.empty()) + { + encodedBuffer = state->undecodedBytes + encodedBuffer; + state->undecodedBytes.clear(); + } + + utility::inputStreamStringAdapter ein(encodedBuffer); utility::outputStreamStringAdapter eout(decodedBuffer); - theEncoder->decode(ein, eout); + const size_t decodedLen = theEncoder->decode(ein, eout); delete (theEncoder); m_buffer = decodedBuffer; @@ -305,6 +320,21 @@ if (newPosition) *newPosition = (p - buffer.begin()); + // For Base64 encoding, ensure all bytes have been decoded. + // If there are remaining bytes, keep them for the next run. + // + // This allows decoding some insanities like: + // =?utf-8?B?5Lit5?= =?utf-8?B?paH?= + if (*encPos == 'B' || *encPos == 'b') + { + const size_t actualEncodedLen = encodedBuffer.length(); + const size_t theoricalEncodedLen = + ((decodedLen + ((decodedLen % 3) ? (3 - (decodedLen % 3)) : 0) ) / 3) * 4; + + if (state && actualEncodedLen != theoricalEncodedLen) + state->undecodedBytes.assign(dataPos + theoricalEncodedLen, dataEnd); + } + return; } } diff -urb libvmime-0.9.2-patched/vmime/word.hpp libvmime-0.9.2/vmime/word.hpp --- libvmime-0.9.2-patched/vmime/word.hpp 2015-01-16 15:04:04.128264216 +0100 +++ libvmime-0.9.2/vmime/word.hpp 2015-01-16 15:05:13.672262038 +0100 @@ -125,6 +125,20 @@ bool prevWordIsEncoded; bool lastCharIsSpace; }; + + class parserState + { + public: + + parserState() + : prevIsEncoded(false), isFirst(true) + { + } + + bool prevIsEncoded; + bool isFirst; + std::string undecodedBytes; + }; #endif @@ -134,13 +148,20 @@ void parse(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition = NULL); void generate(utility::outputStream& os, const string::size_type maxLineLength = lineLengthLimits::infinite, const string::size_type curLinePos = 0, string::size_type* newLinePos = NULL) const; + void parseWithState + (const string& buffer, + const size_t position, + const size_t end, + size_t* newPosition, + parserState* state); + void generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, generatorState* state) const; const std::vector > getChildComponents() const; private: - static ref parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, bool prevIsEncoded, bool* isEncoded, bool isFirst); + static ref parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, parserState* state); static const std::vector > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);