fix base64

This commit is contained in:
tqcq 2024-03-23 12:24:13 +08:00
parent f0f8d77937
commit 5274aca7fd
6 changed files with 127 additions and 92 deletions

View File

@ -1,25 +0,0 @@
/**
* @file : sequence_checker
* @created : Saturday Feb 03, 2024 13:32:22 CST
* @license : MIT
**/
#pragma once
#ifndef SLED_SEQUENCE_CHECKER_H
#define SLED_SEQUENCE_CHECKER_H
namespace sled {
class SequenceChecker : public internal::SequenceCheckerImpl {
public:
enum InitialState : bool {
kDetached = false,
kAttached = true,
};
explicit SequenceChecker(InitialState initial_state = kAttached) : Impl(initial_state) {}
};
}// namespace sled
#endif// SLED_SEQUENCE_CHECKER_H

View File

@ -38,6 +38,7 @@
#include "sled/strings/utils.h" #include "sled/strings/utils.h"
// synchorization // synchorization
#include "seld/synchronization/sequence_checker.h"
#include "sled/synchronization/event.h" #include "sled/synchronization/event.h"
#include "sled/synchronization/mutex.h" #include "sled/synchronization/mutex.h"
#include "sled/synchronization/one_time_event.h" #include "sled/synchronization/one_time_event.h"

View File

@ -9,6 +9,7 @@
#define SLED_STRINGS_BASE64_H #define SLED_STRINGS_BASE64_H
#include "sled/status_or.h" #include "sled/status_or.h"
#include <string.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -16,13 +17,44 @@ namespace sled {
class Base64 { class Base64 {
public: public:
static std::string Encode(const uint8_t *const ptr, size_t len); static size_t DecodedLength(const char *base64_data, size_t base64_len);
static std::string Encode(const std::vector<unsigned char> &data); static std::string Encode(const uint8_t *ptr, size_t len);
static std::string Encode(const std::string &data); static StatusOr<std::string> Decode(const uint8_t *ptr, size_t len);
static std::string Encode(const char *const data);
static StatusOr<std::string> Decode(const std::string &base64); // EncodedLength
static StatusOr<std::string> Decode(const std::vector<unsigned char> &base64); static inline size_t EncodedLength(size_t data_len) { return (data_len + 2) / 3 * 4; }
static StatusOr<std::string> Decode(const uint8_t *const ptr, size_t len);
static inline size_t DecodedLength(const std::string &str) { return DecodedLength(str.data(), str.size()); }
static inline size_t DecodedLength(const char *base64_str) { return DecodedLength(base64_str, strlen(base64_str)); }
// Encode
static inline std::string Encode(const std::vector<unsigned char> &data)
{
return Encode(data.data(), data.size());
}
static inline std::string Encode(const std::string &data) { return Encode((uint8_t *) data.data(), data.size()); }
static inline std::string Encode(const char *const data) { return Encode((uint8_t *) data, strlen(data)); }
// Decode
static inline StatusOr<std::string> Decode(const char *ptr, size_t len)
{
return Decode((const uint8_t *) ptr, len);
}
static inline StatusOr<std::string> Decode(const char *ptr) { return Decode(ptr, strlen(ptr)); }
static inline StatusOr<std::string> Decode(const std::string &base64)
{
return Decode(base64.data(), base64.size());
}
static inline StatusOr<std::string> Decode(const std::vector<unsigned char> &base64)
{
return Decode(base64.data(), base64.size());
}
}; };
}// namespace sled }// namespace sled

View File

@ -4,6 +4,7 @@
#include <array> #include <array>
#include <fmt/format.h> #include <fmt/format.h>
#include <sstream> #include <sstream>
#include <string.h>
namespace sled { namespace sled {
const char kBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const char kBase64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@ -17,38 +18,43 @@ IsBase64(char c)
return isalnum(c) || c == '+' || c == '/'; return isalnum(c) || c == '+' || c == '/';
} }
std::string size_t
Base64::Encode(const uint8_t *const ptr, size_t len) Base64::DecodedLength(const char *base64_data, size_t base64_len)
{ {
auto data = (unsigned char *) (ptr); if (base64_len <= 0) { return 0; }
return Encode(std::vector<unsigned char>(data, data + len)); /**
* The number of padding characters at the end of the base64 data
* is the number of '=' characters at the end of the base64 data.
**/
if (base64_data) {
size_t padding = (4 - (base64_len % 4)) % 4;
while (base64_data[--base64_len] == '=') { ++padding; }
return ((base64_len + 3) / 4) * 3 - ((5 + padding * 6) / 8);
} else {
return base64_len / 4 * 3 + ((base64_len % 4) * 6 + 5) / 8;
}
} }
std::string std::string
Base64::Encode(const std::string &input) Base64::Encode(const uint8_t *ptr, size_t len)
{
return Encode((uint8_t *) input.data(), input.length());
}
std::string
Base64::Encode(const char *const data)
{ {
return Encode((uint8_t *) data, strlen(data)); // std::stringstream ss;
} std::string result(EncodedLength(len), 0);
int write_idx = 0;
std::string
Base64::Encode(const std::vector<unsigned char> &data)
{
std::stringstream ss;
int value = 0; int value = 0;
int value_bits = 0; int value_bits = 0;
for (unsigned char c : data) { while (len > 0) {
value = (value << 8) + c; value = (value << 8) + *ptr;
value_bits += 8; value_bits += 8;
while (value_bits >= 6) { while (value_bits >= 6) {
value_bits -= 6; value_bits -= 6;
ss << kBase64Chars[(value >> value_bits) & 0x3F]; // ss << kBase64Chars[(value >> value_bits) & 0x3F];
result[write_idx++] = kBase64Chars[(value >> value_bits) & 0x3F];
} }
++ptr;
--len;
} }
/** /**
@ -56,31 +62,40 @@ Base64::Encode(const std::vector<unsigned char> &data)
* 2 -> 4 -> (8 - value_bits - 2) * 2 -> 4 -> (8 - value_bits - 2)
* 4 -> 2 -> (8 - value_bits - 2) * 4 -> 2 -> (8 - value_bits - 2)
**/ **/
if (value_bits > 0) { ss << kBase64Chars[((value << 8) >> (value_bits + 2)) & 0x3F]; } if (value_bits > 0) {
while (ss.str().size() % 4) { ss << '='; } result[write_idx++] = kBase64Chars[(value << (6 - value_bits)) & 0x3F];
// ss << kBase64Chars[((value << 8) >> (value_bits + 2)) & 0x3F];
}
// while (ss.str().size() % 4) { ss << '='; }
while (write_idx % 4) { result[write_idx++] = '='; }
return ss.str(); // return ss.str();
return std::move(result);
} }
StatusOr<std::string> StatusOr<std::string>
Base64::Decode(const std::string &input) Base64::Decode(const uint8_t *ptr, size_t len)
{ {
CallOnce(once_flag, [&] { CallOnce(once_flag, [&] {
std::fill(kInvBase64Chars.begin(), kInvBase64Chars.end(), -1); std::fill(kInvBase64Chars.begin(), kInvBase64Chars.end(), -1);
for (int i = 0; kBase64Chars[i]; i++) { kInvBase64Chars[kBase64Chars[i]] = i; } for (int i = 0; kBase64Chars[i]; i++) { kInvBase64Chars[kBase64Chars[i]] = i; }
}); });
std::stringstream ss; int write_idx = 0;
std::string data(DecodedLength((char *) ptr, len), 0);
// std::stringstream ss;
int value = 0; int value = 0;
int value_bits = 0; int value_bits = 0;
int index = 0; int index = 0;
for (unsigned char c : input) { for (int i = 0; i < len; i++) {
char c = ptr[i];
if (-1 != kInvBase64Chars[c]) { if (-1 != kInvBase64Chars[c]) {
// valid base64 character // valid base64 character
value = (value << 6) | kInvBase64Chars[c]; value = (value << 6) | kInvBase64Chars[c];
value_bits += 6; value_bits += 6;
if (value_bits >= 8) { if (value_bits >= 8) {
ss << char((value >> (value_bits - 8)) & 0xFF); data[write_idx++] = (value >> (value_bits - 8)) & 0xFF;
// ss << char((value >> (value_bits - 8)) & 0xFF);
value_bits -= 8; value_bits -= 8;
} }
} else if (c == '=') { } else if (c == '=') {
@ -93,19 +108,9 @@ Base64::Decode(const std::string &input)
} }
++index; ++index;
} }
while (write_idx < data.size()) data.pop_back();
return make_status_or<std::string>(ss.str()); return make_status_or<std::string>(data);
} }
StatusOr<std::string>
Base64::Decode(const std::vector<unsigned char> &base64)
{
return Decode(std::string(base64.begin(), base64.end()));
}
StatusOr<std::string>
Base64::Decode(const uint8_t *const ptr, size_t len)
{
return Decode(std::string((char *) ptr, len));
}
}// namespace sled }// namespace sled

View File

@ -38,5 +38,5 @@ Base64Decode(benchmark::State &state)
} }
} }
BENCHMARK(Base64Encode)->RangeMultiplier(10)->Range(10, 1000000); BENCHMARK(Base64Encode)->RangeMultiplier(100)->Range(10, 100000);
BENCHMARK(Base64Decode)->RangeMultiplier(10)->Range(10, 1000000); BENCHMARK(Base64Decode)->RangeMultiplier(100)->Range(10, 100000);

View File

@ -1,25 +1,47 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <sled/strings/base64.h> #include <sled/strings/base64.h>
#define TEST_ENCODE_DECODE(base64, text) \ TEST(Base64, EncodedLength)
do { \
EXPECT_EQ(sled::Base64::Encode(text), std::string(base64)); \
auto res = sled::Base64::Decode(base64); \
EXPECT_TRUE(res.ok()); \
EXPECT_EQ(res.value(), text); \
} while (0)
TEST(Base64, Encode) { EXPECT_EQ("aGVsbG8gd29ybGQK", sled::Base64::Encode("hello world\n")); }
TEST(Base64, Decode) { EXPECT_EQ("hello world\n", sled::Base64::Decode("aGVsbG8gd29ybGQK").value()); }
TEST(Base64, EncodeAndDecode)
{ {
TEST_ENCODE_DECODE("aGVsbG8gd29ybGQK", "hello world\n"); EXPECT_EQ(0, sled::Base64::EncodedLength(0));
TEST_ENCODE_DECODE("U2VuZCByZWluZm9yY2VtZW50cwo=", "Send reinforcements\n"); EXPECT_EQ(4, sled::Base64::EncodedLength(1));
TEST_ENCODE_DECODE("", ""); EXPECT_EQ(4, sled::Base64::EncodedLength(2));
TEST_ENCODE_DECODE("IA==", " "); EXPECT_EQ(4, sled::Base64::EncodedLength(3));
TEST_ENCODE_DECODE("AA==", std::string("\0", 1)); EXPECT_EQ(8, sled::Base64::EncodedLength(4));
TEST_ENCODE_DECODE("AAA=", std::string("\0\0", 2)); EXPECT_EQ(8, sled::Base64::EncodedLength(5));
TEST_ENCODE_DECODE("AAAA", std::string("\0\0\0", 3)); EXPECT_EQ(8, sled::Base64::EncodedLength(6));
EXPECT_EQ(12, sled::Base64::EncodedLength(7));
}
TEST(Base64, DecodedLength)
{
EXPECT_EQ(0, sled::Base64::DecodedLength(nullptr, 0));
EXPECT_EQ(1, sled::Base64::DecodedLength(nullptr, 1));
EXPECT_EQ(2, sled::Base64::DecodedLength(nullptr, 2));
EXPECT_EQ(2, sled::Base64::DecodedLength(nullptr, 3));
EXPECT_EQ(3, sled::Base64::DecodedLength(nullptr, 4));
EXPECT_EQ(0, sled::Base64::DecodedLength("", 0));
}
TEST(Base64, Encode)
{
EXPECT_EQ("aGVsbG8gd29ybGQK", sled::Base64::Encode("hello world\n"));
EXPECT_EQ("U2VuZCByZWluZm9yY2VtZW50cwo=", sled::Base64::Encode("Send reinforcements\n"));
EXPECT_EQ("", sled::Base64::Encode(""));
EXPECT_EQ("IA==", sled::Base64::Encode(" "));
EXPECT_EQ("AA==", sled::Base64::Encode(std::string("\0", 1)));
EXPECT_EQ("AAA=", sled::Base64::Encode(std::string("\0\0", 2)));
EXPECT_EQ("AAAA", sled::Base64::Encode(std::string("\0\0\0", 3)));
}
TEST(Base64, Decode)
{
EXPECT_EQ("hello world\n", sled::Base64::Decode("aGVsbG8gd29ybGQK").value());
EXPECT_EQ("Send reinforcements\n", sled::Base64::Decode("U2VuZCByZWluZm9yY2VtZW50cwo=").value());
EXPECT_EQ("", sled::Base64::Decode("").value());
EXPECT_EQ(" ", sled::Base64::Decode("IA==").value());
EXPECT_EQ(std::string("\0", 1), sled::Base64::Decode("AA==").value());
EXPECT_EQ(std::string("\0\0", 2), sled::Base64::Decode("AAA=").value());
EXPECT_EQ(std::string("\0\0\0", 3), sled::Base64::Decode("AAAA").value());
} }