aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--src/text.cpp3
-rw-r--r--src/word.cpp19
-rw-r--r--tests/parser/textTest.cpp26
-rw-r--r--vmime/word.hpp18
5 files changed, 63 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 026dda5e..c251dd09 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,10 @@
VERSION 0.8.2cvs
================
+2007-11-20 Vincent Richard <[email protected]>
+
+ * text, word: fixed incorrect white-space between words.
+
2007-07-09 Vincent Richard <[email protected]>
* IMAPUtils.cpp: fixed bug in modified UTF-7 encoding (IMAP).
diff --git a/src/text.cpp b/src/text.cpp
index 7386a698..c6b20c52 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -335,11 +335,12 @@ void text::encodeAndFold(utility::outputStream& os, const string::size_type maxL
const string::size_type firstLineOffset, string::size_type* lastLineLength, const int flags) const
{
string::size_type curLineLength = firstLineOffset;
+ word::generatorState state;
for (int wi = 0 ; wi < getWordCount() ; ++wi)
{
getWordAt(wi)->generate(os, maxLineLength, curLineLength,
- &curLineLength, flags, (wi == 0));
+ &curLineLength, flags, &state);
}
if (lastLineLength)
diff --git a/src/word.cpp b/src/word.cpp
index a33ab2ca..5c83ef98 100644
--- a/src/word.cpp
+++ b/src/word.cpp
@@ -309,16 +309,21 @@ void word::parse(const string& buffer, const string::size_type position,
void word::generate(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos) const
{
- generate(os, maxLineLength, curLinePos, newLinePos, 0, true);
+ generate(os, maxLineLength, curLinePos, newLinePos, 0, NULL);
}
void word::generate(utility::outputStream& os, const string::size_type maxLineLength,
const string::size_type curLinePos, string::size_type* newLinePos, const int flags,
- const bool isFirstWord) const
+ generatorState* state) const
{
string::size_type curLineLength = curLinePos;
+ generatorState defaultGeneratorState;
+
+ if (state == NULL)
+ state = &defaultGeneratorState;
+
// Calculate the number of ASCII chars to check whether encoding is needed
// and _which_ encoding to use.
const string::size_type asciiCount =
@@ -374,7 +379,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe
// we write the full line no matter of the max line length...
if (!newLine && p != end && lastWSpos == end &&
- !isFirstWord && curLineStart == m_buffer.begin())
+ !state->isFirstWord && curLineStart == m_buffer.begin())
{
// Here, we are continuing on the line of previous encoded
// word, but there is not even enough space to put the
@@ -428,7 +433,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe
// last white-space.
#if 1
- if (curLineLength != 1 && !isFirstWord)
+ if (curLineLength != NEW_LINE_SEQUENCE_LENGTH && !state->isFirstWord && state->prevWordIsEncoded)
os << " "; // Separate from previous word
#endif
@@ -521,7 +526,7 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe
}
// Encode and fold input buffer
- if (curLineLength != 1 && !isFirstWord)
+ if (!startNewLine && !state->isFirstWord && state->prevWordIsEncoded)
{
os << " "; // Separate from previous word
++curLineLength;
@@ -554,11 +559,15 @@ void word::generate(utility::outputStream& os, const string::size_type maxLineLe
// End of the encoded word
os << wordEnd;
+
+ state->prevWordIsEncoded = true;
}
}
if (newLinePos)
*newLinePos = curLineLength;
+
+ state->isFirstWord = false;
}
diff --git a/tests/parser/textTest.cpp b/tests/parser/textTest.cpp
index 28a72150..e63dd4c8 100644
--- a/tests/parser/textTest.cpp
+++ b/tests/parser/textTest.cpp
@@ -41,6 +41,7 @@ VMIME_TEST_SUITE_BEGIN
VMIME_TEST(testWordConstructors)
VMIME_TEST(testWordParse)
VMIME_TEST(testWordGenerate)
+ VMIME_TEST(testWordGenerateSpace)
VMIME_TEST(testWordGenerateMultiBytes)
VMIME_TEST_LIST_END
@@ -269,6 +270,31 @@ VMIME_TEST_SUITE_BEGIN
vmime::word("\xf1\xf2\xf3\xf4\xf5", vmime::charset("foo")).generate());
}
+ void testWordGenerateSpace()
+ {
+ // No white-space between an unencoded word and a encoded one
+ VASSERT_EQ("1", "Bonjour =?utf-8?Q?Fran=C3=A7ois?=",
+ vmime::text::newFromString("Bonjour Fran\xc3\xa7ois",
+ vmime::charset("utf-8"))->generate());
+
+ // White-space between two encoded words
+ vmime::text txt;
+ txt.appendWord(vmime::create <vmime::word>("\xc3\x89t\xc3\xa9", "utf-8"));
+ txt.appendWord(vmime::create <vmime::word>("Fran\xc3\xa7ois", "utf-8"));
+
+ const vmime::string decoded = "\xc3\x89t\xc3\xa9""Fran\xc3\xa7ois";
+ const vmime::string encoded = "=?utf-8?B?w4l0w6k=?= =?utf-8?Q?Fran=C3=A7ois?=";
+
+ // -- test encoding
+ VASSERT_EQ("2", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("3", decoded, txt2.getWholeBuffer());
+ }
+
void testWordGenerateMultiBytes()
{
// Ensure we don't encode a non-integral number of characters
diff --git a/vmime/word.hpp b/vmime/word.hpp
index 6f6c2798..d4bddc16 100644
--- a/vmime/word.hpp
+++ b/vmime/word.hpp
@@ -109,13 +109,29 @@ public:
ref <component> clone() const;
+#ifndef VMIME_BUILDING_DOC
+ class generatorState
+ {
+ public:
+
+ generatorState()
+ : isFirstWord(true), prevWordIsEncoded(false)
+ {
+ }
+
+ bool isFirstWord;
+ bool prevWordIsEncoded;
+ };
+#endif
+
+
using component::parse;
using component::generate;
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 generate(utility::outputStream& os, const string::size_type maxLineLength, const string::size_type curLinePos, string::size_type* newLinePos, const int flags, const bool isFirstWord) const;
+ 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;