Fixes/comments for guessBestEncoding (#304)

* tests: add case for getRecommendedEncoding

* vmime: avoid integer multiply wraparound in wordEncoder::guessBestEncoding

If the input string is 42949673 characters long or larger, there will
be integer overflow on 32-bit platforms when multiplying by 100.
Switch that one computation to floating point.

* vmime: update comment in wordEncoder::guessBestEncoding
This commit is contained in:
Jan Engelhardt 2024-05-21 15:47:05 +02:00 committed by GitHub
parent 97d15b8cd7
commit b447adbe37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 27 additions and 4 deletions

View File

@ -302,14 +302,16 @@ wordEncoder::Encoding wordEncoder::guessBestEncoding(
}
}
// Use Base64 if more than 40% non-ASCII, or Quoted-Printable else (default)
// Base64 would be more space-efficient when the ASCII content is
// below 83.33%, but QP has a legibility arugment going for it, so we
// picked 60%.
const size_t asciiCount =
utility::stringUtils::countASCIIchars(buffer.begin(), buffer.end());
const size_t asciiPercent =
buffer.length() == 0 ? 100 : (100 * asciiCount) / buffer.length();
const double asciiPercent =
buffer.length() == 0 ? 100 : static_cast<double>(asciiCount) / buffer.length();
if (asciiPercent < 60) {
if (asciiPercent < 0.60) {
return ENCODING_B64;
} else {
return ENCODING_QP;

View File

@ -32,6 +32,7 @@ VMIME_TEST_SUITE_BEGIN(textTest)
VMIME_TEST_LIST_BEGIN
VMIME_TEST(testConstructors)
VMIME_TEST(testCopy)
VMIME_TEST(testRecommendedEncoding)
VMIME_TEST(testNewFromString)
VMIME_TEST(testDisplayForm)
VMIME_TEST(testParse)
@ -155,6 +156,17 @@ VMIME_TEST_SUITE_BEGIN(textTest)
VASSERT("copyFrom", t1 == t2);
}
void testRecommendedEncoding() {
vmime::encoding enc;
VASSERT_TRUE("1.1", vmime::charset("iso8859-1").getRecommendedEncoding(enc));
VASSERT_TRUE("1.2", enc.getName() == vmime::encodingTypes::QUOTED_PRINTABLE);
VASSERT_TRUE("1.2", vmime::charset("iso8859-2").getRecommendedEncoding(enc));
VASSERT_TRUE("1.3", enc.getName() == vmime::encodingTypes::QUOTED_PRINTABLE);
VASSERT_FALSE("1.3", vmime::charset(vmime::charsets::UTF_8).getRecommendedEncoding(enc));
}
void testNewFromString() {
vmime::string s1 = "only ASCII characters";

View File

@ -36,6 +36,7 @@ VMIME_TEST_SUITE_BEGIN(wordEncoderTest)
VMIME_TEST(testIsEncodingNeeded_specialChars)
VMIME_TEST(testGuessBestEncoding_QP)
VMIME_TEST(testGuessBestEncoding_B64)
VMIME_TEST(testGuessBestEncoding_size)
VMIME_TEST(testEncodeQP_RFC2047)
VMIME_TEST_LIST_END
@ -159,6 +160,14 @@ VMIME_TEST_SUITE_BEGIN(wordEncoderTest)
);
}
void testGuessBestEncoding_size() {
std::string i(42949673, 'a');
auto enc = vmime::wordEncoder::guessBestEncoding(i, vmime::charset("utf-8"));
VASSERT_EQ("1", enc, vmime::wordEncoder::ENCODING_QP);
}
void testEncodeQP_RFC2047() {
// When Quoted-Printable is used, it should be RFC-2047 QP encoding