diff options
author | Vincent Richard <[email protected]> | 2015-06-07 19:32:44 +0000 |
---|---|---|
committer | Vincent Richard <[email protected]> | 2015-06-07 19:32:44 +0000 |
commit | c446afddd4589c6c65c15f507c992215d9a1e00b (patch) | |
tree | 6be523af579412785f592a10a93039aeeaacb26b | |
parent | Fixed estimation of generated size when no re-encoding is needed. (diff) | |
download | vmime-c446afddd4589c6c65c15f507c992215d9a1e00b.tar.gz vmime-c446afddd4589c6c65c15f507c992215d9a1e00b.zip |
Estimate generated size of parameterized field.
-rw-r--r-- | src/vmime/parameter.cpp | 34 | ||||
-rw-r--r-- | src/vmime/parameter.hpp | 2 | ||||
-rw-r--r-- | src/vmime/parameterizedHeaderField.cpp | 15 | ||||
-rw-r--r-- | src/vmime/parameterizedHeaderField.hpp | 2 | ||||
-rw-r--r-- | tests/parser/parameterTest.cpp | 140 |
5 files changed, 193 insertions, 0 deletions
diff --git a/src/vmime/parameter.cpp b/src/vmime/parameter.cpp index 8773e857..bba43f50 100644 --- a/src/vmime/parameter.cpp +++ b/src/vmime/parameter.cpp @@ -604,6 +604,40 @@ void parameter::generateImpl } +size_t parameter::getGeneratedSize(const generationContext& ctx) +{ + const string& name = m_name; + const string& value = m_value->getBuffer(); + + const size_t bytesNeedingEncoding = + value.length() - utility::stringUtils::countASCIIchars(value.begin(), value.end()); + + const size_t valueLength = value.length(); + + // Compute generated length in the very worst case + + // Non-encoded parameter + value (worst case: quoting + QP) + size_t len = name.length() + 1 /* = */ + 2 /* "" */ + 7 /* =?...?Q?...?= */ + + m_value->getCharset().getName().length() + valueLength + bytesNeedingEncoding * 2 + 1 /* ; */; + + // Encoded parameter + value + const size_t maxEncodedValueLengthOnLine = + ctx.getMaxLineLength() - 2 /* CRLF */ - NEW_LINE_SEQUENCE_LENGTH + - name.length() - 5 /* *00*= */ - 1 /* ; */; + + const size_t encodedValueLength = (valueLength + bytesNeedingEncoding * 2) + + m_value->getCharset().getName().length() + m_value->getLanguage().length() + 2 /* 2 x ' */; + + const size_t numberOfSections = 1 /* worst case: generation starts at the end of a line */ + + std::max(size_t(1), encodedValueLength / maxEncodedValueLengthOnLine); + + len += numberOfSections * (name.length() + 5 /* *00*= */ + 1 /* ; */ + 2 /* CRLF */ + NEW_LINE_SEQUENCE_LENGTH) + encodedValueLength; + + return len; + +} + + const std::vector <shared_ptr <component> > parameter::getChildComponents() { std::vector <shared_ptr <component> > list; diff --git a/src/vmime/parameter.hpp b/src/vmime/parameter.hpp index d1e6ea72..92ac95d7 100644 --- a/src/vmime/parameter.hpp +++ b/src/vmime/parameter.hpp @@ -85,6 +85,8 @@ public: void copyFrom(const component& other); parameter& operator=(const parameter& other); + size_t getGeneratedSize(const generationContext& ctx); + const std::vector <shared_ptr <component> > getChildComponents(); /** Return the name of this parameter. diff --git a/src/vmime/parameterizedHeaderField.cpp b/src/vmime/parameterizedHeaderField.cpp index e2925d25..c299ff65 100644 --- a/src/vmime/parameterizedHeaderField.cpp +++ b/src/vmime/parameterizedHeaderField.cpp @@ -359,6 +359,21 @@ void parameterizedHeaderField::generateImpl } +size_t parameterizedHeaderField::getGeneratedSize(const generationContext& ctx) +{ + size_t size = headerField::getGeneratedSize(ctx); + + for (std::vector <shared_ptr <parameter> >::const_iterator + it = m_params.begin() ; it != m_params.end() ; ++it) + { + size += 2; // "; " + size += (*it)->getGeneratedSize(ctx); + } + + return size; +} + + void parameterizedHeaderField::copyFrom(const component& other) { headerField::copyFrom(other); diff --git a/src/vmime/parameterizedHeaderField.hpp b/src/vmime/parameterizedHeaderField.hpp index 526e8bcb..47c53562 100644 --- a/src/vmime/parameterizedHeaderField.hpp +++ b/src/vmime/parameterizedHeaderField.hpp @@ -179,6 +179,8 @@ public: */ const std::vector <shared_ptr <parameter> > getParameterList(); + size_t getGeneratedSize(const generationContext& ctx); + const std::vector <shared_ptr <component> > getChildComponents(); private: diff --git a/tests/parser/parameterTest.cpp b/tests/parser/parameterTest.cpp index 41af3fdd..0cf2099f 100644 --- a/tests/parser/parameterTest.cpp +++ b/tests/parser/parameterTest.cpp @@ -33,7 +33,9 @@ VMIME_TEST_SUITE_BEGIN(parameterTest) VMIME_TEST(testParse) VMIME_TEST(testParseRFC2231) VMIME_TEST(testGenerate) + VMIME_TEST(testGetGeneratedSize) VMIME_TEST(testGenerateRFC2231) + VMIME_TEST(testGetGeneratedSizeRFC2231) VMIME_TEST(testNonStandardEncodedParam) VMIME_TEST(testParseNonSignificantWS) VMIME_TEST(testEncodeTSpecials) @@ -76,6 +78,25 @@ VMIME_TEST_SUITE_BEGIN(parameterTest) }; + const vmime::string generateParameter + (const vmime::parameter& param, + const vmime::generationContext& ctx, + const vmime::size_t maxLineLength = 0) const + { + vmime::generationContext ctx2(ctx); + + if (maxLineLength != 0) + ctx2.setMaxLineLength(maxLineLength); + + std::ostringstream oss; + vmime::utility::outputStreamAdapter adapter(oss); + + param.generate(ctx2, adapter); + + return oss.str(); + } + + #define FIELD_VALUE(f) (f.getValue()->generate()) #define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate()) #define PARAM_NAME(p, n) (p.getParameterAt(n)->getName()) @@ -270,6 +291,20 @@ VMIME_TEST_SUITE_BEGIN(parameterTest) VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate()); } + void testGetGeneratedSize() + { + vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); + + vmime::parameter p1("param1", "value1"); + VASSERT("1", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + vmime::parameter p2a("param1", "value1a;value1b"); + VASSERT("2&", p2a.getGeneratedSize(ctx) >= generateParameter(p2a, ctx).length()); + + vmime::parameter p2b("param1", "va\\lue\"1"); + VASSERT("1", p2b.getGeneratedSize(ctx) >= generateParameter(p2b, ctx).length()); + } + void testGenerateRFC2231() { // Extended parameter with charset specifier @@ -403,6 +438,111 @@ VMIME_TEST_SUITE_BEGIN(parameterTest) p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)); } + void testGetGeneratedSizeRFC2231() + { + vmime::generationContext ctx(vmime::generationContext::getDefaultContext()); + + // Extended parameter with charset specifier + vmime::parameter p1( + "param1", + vmime::word("value 1\xe9", vmime::charset("charset")) + ); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("1.no-encoding", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("1.rfc2047", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("1.rfc2231", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("1.both", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length()); + + // Value that spans on multiple lines + vmime::parameter p2( + "param1", + vmime::word( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + vmime::charset("charset") + ) + ); + + ctx.setMaxLineLength(25); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("2.no-encoding", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("2.rfc2047", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("2.rfc2231", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("2.both", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length()); + + // Non-ASCII parameter value + vmime::parameter p3( + "param1", + vmime::word( + "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc", + vmime::charset("utf-8") + ) + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("3.no-encoding", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("3.rfc2047", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("3.rfc2231", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("3.both", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length()); + + // No encoding needed + vmime::parameter p4( + "param1", + vmime::word("va lue", vmime::charset("charset")) + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("4.no-encoding", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("4.rfc2047", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("4.rfc2231", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("4.both", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length()); + + // Language specification + vmime::parameter p5( + "param1", + vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us") + ); + + ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength()); + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING); + VASSERT("5.no-encoding", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY); + VASSERT("5.rfc2047", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY); + VASSERT("5.rfc2231", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + + ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047); + VASSERT("5.both", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length()); + } + void testNonStandardEncodedParam() { // This syntax is non-standard (expressly prohibited |