From 4d9c75119115a5654875aeb84375a515d0bd4d63 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Thu, 9 Feb 2017 15:54:09 -0800 Subject: [PATCH 1/8] introduce Base64::encode on string --- source/common/common/base64.cc | 81 ++++++++++++++++++++----------- source/common/common/base64.h | 17 +++++++ test/common/common/base64_test.cc | 22 +++++++++ 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index ac5ee3d6c0798..5acb0229aa0e2 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -68,6 +68,40 @@ std::string Base64::decode(const std::string& input) { return result; } +void Base64::encode_base(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret) { + switch (pos % 3) { + case 0: + ret.push_back(CHAR_TABLE[cur_char >> 2]); + next_c = (cur_char & 0x03) << 4; + break; + case 1: + ret.push_back(CHAR_TABLE[next_c | (cur_char >> 4)]); + next_c = (cur_char & 0x0f) << 2; + break; + case 2: + ret.push_back(CHAR_TABLE[next_c | (cur_char >> 6)]); + ret.push_back(CHAR_TABLE[cur_char & 0x3f]); + next_c = 0; + break; + } +} + +void Base64::encode_last(uint64_t pos, uint8_t last_char, std::string& ret) { + switch (pos % 3) { + case 1: + ret.push_back(CHAR_TABLE[last_char]); + ret.push_back('='); + ret.push_back('='); + break; + case 2: + ret.push_back(CHAR_TABLE[last_char]); + ret.push_back('='); + break; + default: + break; + } +} + std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { uint64_t output_length = (std::min(length, buffer.length()) + 2) / 3 * 4; std::string ret; @@ -83,22 +117,7 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { const uint8_t* slice_mem = static_cast(slice.mem_); for (uint64_t i = 0; i < slice.len_ && j < length; ++i, ++j) { - const uint8_t c = slice_mem[i]; - switch (j % 3) { - case 0: - ret.push_back(CHAR_TABLE[c >> 2]); - next_c = (c & 0x03) << 4; - break; - case 1: - ret.push_back(CHAR_TABLE[next_c | (c >> 4)]); - next_c = (c & 0x0f) << 2; - break; - case 2: - ret.push_back(CHAR_TABLE[next_c | (c >> 6)]); - ret.push_back(CHAR_TABLE[c & 0x3f]); - next_c = 0; - break; - } + encode_base(slice_mem[i], j, next_c, ret); } if (j == length) { @@ -106,19 +125,25 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { } } - switch (j % 3) { - case 1: - ret.push_back(CHAR_TABLE[next_c]); - ret.push_back('='); - ret.push_back('='); - break; - case 2: - ret.push_back(CHAR_TABLE[next_c]); - ret.push_back('='); - break; - default: - break; + encode_last(j, next_c, ret); + + return ret; +} + +std::string Base64::encode(const std::string& input) { + uint64_t output_length = (input.length() + 2) / 3 * 4; + std::string ret; + ret.reserve(output_length); + + uint64_t pos = 0; + uint8_t next_c = 0; + + for (size_t i = 0; i < input.length(); ++i) { + encode_base(input[i], pos, next_c, ret); + pos++; } + encode_last(pos, next_c, ret); + return ret; } diff --git a/source/common/common/base64.h b/source/common/common/base64.h index 69047f1c8cdc8..d87f005e8a72c 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -11,6 +11,12 @@ class Base64 { */ static std::string encode(const Buffer::Instance& buffer, uint64_t length); + /** + * Base64 encode an input string. + * @param input string to encode + */ + static std::string encode(const std::string& input); + /** * Base64 decode an input string. * @param input supplies the input to decode. @@ -19,4 +25,15 @@ class Base64 { * bytes. */ static std::string decode(const std::string& input); + +private: + /** + * Helper methods for encoding. + */ + static inline void encode_base(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, + std::string& ret); + /** + * Encode last characters if input string length is not divisible by 3. + */ + static inline void encode_last(uint64_t pos, uint8_t last_char, std::string& ret); }; diff --git a/test/common/common/base64_test.cc b/test/common/common/base64_test.cc index 1cebf7e0a5524..e667a9536637e 100644 --- a/test/common/common/base64_test.cc +++ b/test/common/common/base64_test.cc @@ -22,6 +22,16 @@ TEST(Base64Test, SingleSliceBufferEncode) { EXPECT_EQ("Zm8=", Base64::encode(buffer, 2)); } +TEST(Base64Test, EncodeString) { + EXPECT_EQ("", Base64::encode("")); + + std::string two_zero_bytes("\0\0", 2); + EXPECT_EQ("AAA=", Base64::encode(two_zero_bytes)); + + EXPECT_EQ("Zm9v", Base64::encode("foo")); + EXPECT_EQ("Zm8=", Base64::encode("fo")); +} + TEST(Base64Test, Decode) { EXPECT_EQ("", Base64::decode("")); EXPECT_EQ("foo", Base64::decode("Zm9v")); @@ -42,12 +52,24 @@ TEST(Base64Test, Decode) { EXPECT_FALSE(memcmp(test_string, Base64::decode(Base64::encode(buffer, 36)).data(), 36)); } + { + std::string test_string("\0\0\0\0als;jkopqitu[\0opbjlcxnb35g]b[\xaa\b\n", 36); + EXPECT_FALSE( + memcmp(test_string.data(), Base64::decode(Base64::encode(test_string)).data(), 36)); + } + { std::string test_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string decoded = Base64::decode(test_string); Buffer::OwnedImpl buffer(decoded); EXPECT_EQ(test_string, Base64::encode(buffer, decoded.length())); } + + { + std::string test_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::string decoded = Base64::decode(test_string); + EXPECT_EQ(test_string, Base64::encode(decoded)); + } } TEST(Base64Test, MultiSlicesBufferEncode) { From 4d5897ef05efd4418c9d18d08d70d4a74d32c803 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Thu, 9 Feb 2017 15:58:13 -0800 Subject: [PATCH 2/8] nit. --- source/common/common/base64.cc | 2 +- source/common/common/base64.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index 5acb0229aa0e2..cd2c8f73e24b1 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -104,8 +104,8 @@ void Base64::encode_last(uint64_t pos, uint8_t last_char, std::string& ret) { std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { uint64_t output_length = (std::min(length, buffer.length()) + 2) / 3 * 4; - std::string ret; ret.reserve(output_length); + std::string ret; uint64_t num_slices = buffer.getRawSlices(nullptr, 0); Buffer::RawSlice slices[num_slices]; diff --git a/source/common/common/base64.h b/source/common/common/base64.h index d87f005e8a72c..b0625a2be0b69 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -13,7 +13,7 @@ class Base64 { /** * Base64 encode an input string. - * @param input string to encode + * @param input string to encode. */ static std::string encode(const std::string& input); From 6a15e7dfbcb688772869b1789424548c021f8849 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Thu, 9 Feb 2017 16:00:59 -0800 Subject: [PATCH 3/8] move. --- source/common/common/base64.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index cd2c8f73e24b1..0313e43371dcd 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -132,8 +132,8 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { std::string Base64::encode(const std::string& input) { uint64_t output_length = (input.length() + 2) / 3 * 4; - std::string ret; ret.reserve(output_length); + std::string ret; uint64_t pos = 0; uint8_t next_c = 0; From 8bab524b48f9e8d7c38ccdbf818d1f1fe04b86f9 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Thu, 9 Feb 2017 16:17:16 -0800 Subject: [PATCH 4/8] boom --- source/common/common/base64.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index 0313e43371dcd..5acb0229aa0e2 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -104,8 +104,8 @@ void Base64::encode_last(uint64_t pos, uint8_t last_char, std::string& ret) { std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { uint64_t output_length = (std::min(length, buffer.length()) + 2) / 3 * 4; - ret.reserve(output_length); std::string ret; + ret.reserve(output_length); uint64_t num_slices = buffer.getRawSlices(nullptr, 0); Buffer::RawSlice slices[num_slices]; @@ -132,8 +132,8 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { std::string Base64::encode(const std::string& input) { uint64_t output_length = (input.length() + 2) / 3 * 4; - ret.reserve(output_length); std::string ret; + ret.reserve(output_length); uint64_t pos = 0; uint8_t next_c = 0; From b002b417fde3484606c71076abd11865e5a6af04 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Thu, 9 Feb 2017 19:51:48 -0800 Subject: [PATCH 5/8] addressed comments. --- source/common/common/base64.cc | 19 +++++++++---------- source/common/common/base64.h | 12 ++++++------ test/common/common/base64_test.cc | 20 ++++++++------------ 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/source/common/common/base64.cc b/source/common/common/base64.cc index 5acb0229aa0e2..b0e7ebcaad062 100644 --- a/source/common/common/base64.cc +++ b/source/common/common/base64.cc @@ -68,7 +68,7 @@ std::string Base64::decode(const std::string& input) { return result; } -void Base64::encode_base(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret) { +void Base64::encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret) { switch (pos % 3) { case 0: ret.push_back(CHAR_TABLE[cur_char >> 2]); @@ -86,7 +86,7 @@ void Base64::encode_base(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, } } -void Base64::encode_last(uint64_t pos, uint8_t last_char, std::string& ret) { +void Base64::encodeLast(uint64_t pos, uint8_t last_char, std::string& ret) { switch (pos % 3) { case 1: ret.push_back(CHAR_TABLE[last_char]); @@ -117,7 +117,7 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { const uint8_t* slice_mem = static_cast(slice.mem_); for (uint64_t i = 0; i < slice.len_ && j < length; ++i, ++j) { - encode_base(slice_mem[i], j, next_c, ret); + encodeBase(slice_mem[i], j, next_c, ret); } if (j == length) { @@ -125,25 +125,24 @@ std::string Base64::encode(const Buffer::Instance& buffer, uint64_t length) { } } - encode_last(j, next_c, ret); + encodeLast(j, next_c, ret); return ret; } -std::string Base64::encode(const std::string& input) { - uint64_t output_length = (input.length() + 2) / 3 * 4; +std::string Base64::encode(const char* input, uint64_t length) { + uint64_t output_length = (length + 2) / 3 * 4; std::string ret; ret.reserve(output_length); uint64_t pos = 0; uint8_t next_c = 0; - for (size_t i = 0; i < input.length(); ++i) { - encode_base(input[i], pos, next_c, ret); - pos++; + for (uint64_t i = 0; i < length; ++i) { + encodeBase(input[i], pos++, next_c, ret); } - encode_last(pos, next_c, ret); + encodeLast(pos, next_c, ret); return ret; } diff --git a/source/common/common/base64.h b/source/common/common/base64.h index b0625a2be0b69..7594dab6df443 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -12,10 +12,11 @@ class Base64 { static std::string encode(const Buffer::Instance& buffer, uint64_t length); /** - * Base64 encode an input string. - * @param input string to encode. + * Base64 encode an input char buffer with a given length. + * @param input char array to encode. + * @param length of the input array. */ - static std::string encode(const std::string& input); + static std::string encode(const char* input, uint64_t length); /** * Base64 decode an input string. @@ -30,10 +31,9 @@ class Base64 { /** * Helper methods for encoding. */ - static inline void encode_base(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, - std::string& ret); + static void encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret); /** * Encode last characters if input string length is not divisible by 3. */ - static inline void encode_last(uint64_t pos, uint8_t last_char, std::string& ret); + static void encodeLast(uint64_t pos, uint8_t last_char, std::string& ret); }; diff --git a/test/common/common/base64_test.cc b/test/common/common/base64_test.cc index e667a9536637e..9b6d5e76a2730 100644 --- a/test/common/common/base64_test.cc +++ b/test/common/common/base64_test.cc @@ -23,13 +23,10 @@ TEST(Base64Test, SingleSliceBufferEncode) { } TEST(Base64Test, EncodeString) { - EXPECT_EQ("", Base64::encode("")); - - std::string two_zero_bytes("\0\0", 2); - EXPECT_EQ("AAA=", Base64::encode(two_zero_bytes)); - - EXPECT_EQ("Zm9v", Base64::encode("foo")); - EXPECT_EQ("Zm8=", Base64::encode("fo")); + EXPECT_EQ("", Base64::encode("", 0)); + EXPECT_EQ("AAA=", Base64::encode("\0\0", 2)); + EXPECT_EQ("Zm9v", Base64::encode("foo", 3)); + EXPECT_EQ("Zm8=", Base64::encode("fo", 2)); } TEST(Base64Test, Decode) { @@ -53,9 +50,8 @@ TEST(Base64Test, Decode) { } { - std::string test_string("\0\0\0\0als;jkopqitu[\0opbjlcxnb35g]b[\xaa\b\n", 36); - EXPECT_FALSE( - memcmp(test_string.data(), Base64::decode(Base64::encode(test_string)).data(), 36)); + const char* test_string = "\0\0\0\0als;jkopqitu[\0opbjlcxnb35g]b[\xaa\b\n"; + EXPECT_FALSE(memcmp(test_string, Base64::decode(Base64::encode(test_string, 36)).data(), 36)); } { @@ -66,9 +62,9 @@ TEST(Base64Test, Decode) { } { - std::string test_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char* test_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string decoded = Base64::decode(test_string); - EXPECT_EQ(test_string, Base64::encode(decoded)); + EXPECT_EQ(test_string, Base64::encode(decoded.c_str(), decoded.length())); } } From 5abc15ff3aa5ae051dd664ba611538d10f46c9f5 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Sun, 12 Feb 2017 21:17:16 -0800 Subject: [PATCH 6/8] better comments on methods. --- source/common/common/base64.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/common/common/base64.h b/source/common/common/base64.h index 7594dab6df443..56489d4a649bf 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -29,11 +29,12 @@ class Base64 { private: /** - * Helper methods for encoding. + * Helper method for encoding. This is used to encode all of the characters from the input string. */ static void encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret); /** - * Encode last characters if input string length is not divisible by 3. + * Encode last characters. It appends '=' chars to the ret if input + * string length is not divisible by 3. */ static void encodeLast(uint64_t pos, uint8_t last_char, std::string& ret); }; From 5157dafe00f500e7b802508207fb3bc5c71d7497 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Mon, 13 Feb 2017 10:25:28 -0800 Subject: [PATCH 7/8] new line. --- source/common/common/base64.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/common/common/base64.h b/source/common/common/base64.h index 56489d4a649bf..966b93ef4fb94 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -32,6 +32,7 @@ class Base64 { * Helper method for encoding. This is used to encode all of the characters from the input string. */ static void encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret); + /** * Encode last characters. It appends '=' chars to the ret if input * string length is not divisible by 3. From d00a9ef6db88bdc3ae798df2de1914c5f8f6a432 Mon Sep 17 00:00:00 2001 From: Roman Dzhabarov Date: Mon, 13 Feb 2017 11:26:06 -0800 Subject: [PATCH 8/8] change --- source/common/common/base64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common/common/base64.h b/source/common/common/base64.h index 966b93ef4fb94..19b2fe30ca657 100644 --- a/source/common/common/base64.h +++ b/source/common/common/base64.h @@ -32,7 +32,7 @@ class Base64 { * Helper method for encoding. This is used to encode all of the characters from the input string. */ static void encodeBase(const uint8_t cur_char, uint64_t pos, uint8_t& next_c, std::string& ret); - + /** * Encode last characters. It appends '=' chars to the ret if input * string length is not divisible by 3.