File 15-vmime-wrongly-padded-B64-words.diff of Package libvmime_zarafa7
---
src/word.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++---------------
vmime/word.hpp | 23 ++++++++++++++++++++-
2 files changed, 67 insertions(+), 16 deletions(-)
Index: vmime/src/word.cpp
===================================================================
--- vmime.orig/src/word.cpp
+++ vmime/src/word.cpp
@@ -64,8 +64,7 @@ word::word(const string& buffer, const c
ref <word> 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;
@@ -121,7 +120,7 @@ ref <word> word::parseNext(const string&
if (!unencoded.empty())
{
- if (prevIsEncoded)
+ if (state->prevIsEncoded && !state->isFirst)
unencoded = whiteSpaces + unencoded;
ref <word> w = vmime::create <word>(unencoded, charset(charsets::US_ASCII));
@@ -130,8 +129,8 @@ ref <word> word::parseNext(const string&
if (newPosition)
*newPosition = pos;
- if (isEncoded)
- *isEncoded = false;
+ state->prevIsEncoded = false;
+ state->isFirst = false;
return (w);
}
@@ -182,13 +181,13 @@ ref <word> word::parseNext(const string&
pos += 2; // ?=
ref <word> w = vmime::create <word>();
- 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);
}
@@ -196,7 +195,7 @@ ref <word> word::parseNext(const string&
++pos;
}
- if (startPos != end && !isFirst && prevIsEncoded)
+ if (startPos != end && !state->isFirst && state->prevIsEncoded)
unencoded += whiteSpaces;
if (startPos != end)
@@ -211,8 +210,8 @@ ref <word> word::parseNext(const string&
if (newPosition)
*newPosition = end;
- if (isEncoded)
- *isEncoded = false;
+ state->prevIsEncoded = false;
+ state->isFirst = false;
return (w);
}
@@ -229,9 +228,9 @@ const std::vector <ref <word> > word::pa
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)
@@ -244,6 +243,14 @@ const std::vector <ref <word> > word::pa
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] == '?')
{
@@ -290,12 +297,20 @@ void word::parse(const string& buffer, c
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;
@@ -306,6 +321,21 @@ void word::parse(const string& buffer, c
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;
}
}
Index: vmime/vmime/word.hpp
===================================================================
--- vmime.orig/vmime/word.hpp
+++ vmime/vmime/word.hpp
@@ -125,6 +125,20 @@ public:
bool prevWordIsEncoded;
bool lastCharIsSpace;
};
+
+ class parserState
+ {
+ public:
+
+ parserState()
+ : prevIsEncoded(false), isFirst(true)
+ {
+ }
+
+ bool prevIsEncoded;
+ bool isFirst;
+ std::string undecodedBytes;
+ };
#endif
@@ -134,13 +148,20 @@ public:
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 <ref <const component> > getChildComponents() const;
private:
- static 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);
+ static ref <word> parseNext(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition, parserState* state);
static const std::vector <ref <word> > parseMultiple(const string& buffer, const string::size_type position, const string::size_type end, string::size_type* newPosition);