enh: unit test and optimization for base58
This commit is contained in:
parent
a34402a11f
commit
6ac6e8f2bd
|
@ -22,6 +22,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TBASE_MAX_ILEN 4096
|
||||||
|
#define TBASE_MAX_OLEN 5653
|
||||||
|
|
||||||
uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen);
|
uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen);
|
||||||
char *base58_encode(const uint8_t *value, int32_t vlen);
|
char *base58_encode(const uint8_t *value, int32_t vlen);
|
||||||
|
|
||||||
|
|
|
@ -18,24 +18,29 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define BASE_BUF_SIZE 256
|
#define TBASE_BUF_SIZE 256
|
||||||
static const char *basis_58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
static const char *basis_58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||||
|
|
||||||
char *base58_encode(const uint8_t *value, int32_t vlen) {
|
char *base58_encode(const uint8_t *value, int32_t vlen) {
|
||||||
const uint8_t *pb = value;
|
const uint8_t *pb = value;
|
||||||
const uint8_t *pe = pb + vlen;
|
const uint8_t *pe = pb + vlen;
|
||||||
uint8_t buf[BASE_BUF_SIZE] = {0};
|
uint8_t buf[TBASE_BUF_SIZE] = {0};
|
||||||
uint8_t *pbuf = &buf[0];
|
uint8_t *pbuf = &buf[0];
|
||||||
bool bfree = false;
|
bool bfree = false;
|
||||||
int32_t nz = 0, size = 0, len = 0;
|
int32_t nz = 0, size = 0, len = 0;
|
||||||
|
|
||||||
|
if (vlen > TBASE_MAX_ILEN) {
|
||||||
|
terrno = TSDB_CODE_INVALID_PARA;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
while (pb != pe && *pb == 0) {
|
while (pb != pe && *pb == 0) {
|
||||||
++pb;
|
++pb;
|
||||||
++nz;
|
++nz;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (pe - pb) * 69 / 50 + 1;
|
size = (pe - pb) * 69 / 50 + 1;
|
||||||
if (size > BASE_BUF_SIZE) {
|
if (size > TBASE_BUF_SIZE) {
|
||||||
if (!(pbuf = taosMemoryCalloc(1, size))) {
|
if (!(pbuf = taosMemoryCalloc(1, size))) {
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -47,7 +52,7 @@ char *base58_encode(const uint8_t *value, int32_t vlen) {
|
||||||
int32_t num = *pb;
|
int32_t num = *pb;
|
||||||
int32_t i = 0;
|
int32_t i = 0;
|
||||||
for (int32_t j = (int32_t)size - 1; (num != 0 || i < len) && j >= 0; --j, ++i) {
|
for (int32_t j = (int32_t)size - 1; (num != 0 || i < len) && j >= 0; --j, ++i) {
|
||||||
num += ((int32_t)buf[j]) << 8;
|
num += ((int32_t)pbuf[j]) << 8;
|
||||||
pbuf[j] = num % 58;
|
pbuf[j] = num % 58;
|
||||||
num /= 58;
|
num /= 58;
|
||||||
}
|
}
|
||||||
|
@ -57,7 +62,7 @@ char *base58_encode(const uint8_t *value, int32_t vlen) {
|
||||||
|
|
||||||
const uint8_t *pi = pbuf + (size - len);
|
const uint8_t *pi = pbuf + (size - len);
|
||||||
while (pi != pbuf + size && *pi == 0) ++pi;
|
while (pi != pbuf + size && *pi == 0) ++pi;
|
||||||
uint8_t *result = taosMemoryCalloc(1, size + 1);
|
uint8_t *result = taosMemoryCalloc(1, nz + (pbuf + size - pi) + 1);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
if (bfree) taosMemoryFree(pbuf);
|
if (bfree) taosMemoryFree(pbuf);
|
||||||
|
@ -83,11 +88,23 @@ static const signed char index_58[256] = {
|
||||||
|
|
||||||
uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen) {
|
uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen) {
|
||||||
const char *pe = value + inlen;
|
const char *pe = value + inlen;
|
||||||
uint8_t buf[BASE_BUF_SIZE] = {0};
|
uint8_t buf[TBASE_BUF_SIZE] = {0};
|
||||||
uint8_t *pbuf = &buf[0];
|
uint8_t *pbuf = &buf[0];
|
||||||
bool bfree = false;
|
bool bfree = false;
|
||||||
int32_t nz = 0, size = 0, len = 0;
|
int32_t nz = 0, size = 0, len = 0;
|
||||||
|
|
||||||
|
if (inlen > TBASE_MAX_OLEN) {
|
||||||
|
terrno = TSDB_CODE_INVALID_PARA;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t i = 0; i < inlen; ++i) {
|
||||||
|
if (value[i] == 0) {
|
||||||
|
terrno = TSDB_CODE_INVALID_PARA;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (*value && isspace(*value)) ++value;
|
while (*value && isspace(*value)) ++value;
|
||||||
while (*value == '1') {
|
while (*value == '1') {
|
||||||
++nz;
|
++nz;
|
||||||
|
@ -95,7 +112,7 @@ uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size = (int32_t)(pe - value) * 733 / 1000 + 1;
|
size = (int32_t)(pe - value) * 733 / 1000 + 1;
|
||||||
if (size > BASE_BUF_SIZE) {
|
if (size > TBASE_BUF_SIZE) {
|
||||||
if (!(pbuf = taosMemoryCalloc(1, size))) {
|
if (!(pbuf = taosMemoryCalloc(1, size))) {
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -106,6 +123,7 @@ uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen) {
|
||||||
while (*value && !isspace(*value)) {
|
while (*value && !isspace(*value)) {
|
||||||
int32_t num = index_58[(uint8_t)*value];
|
int32_t num = index_58[(uint8_t)*value];
|
||||||
if (num == -1) {
|
if (num == -1) {
|
||||||
|
terrno = TSDB_CODE_INVALID_PARA;
|
||||||
if (bfree) taosMemoryFree(pbuf);
|
if (bfree) taosMemoryFree(pbuf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +145,7 @@ uint8_t *base58_decode(const char *value, size_t inlen, int32_t *outlen) {
|
||||||
const uint8_t *it = pbuf + (size - len);
|
const uint8_t *it = pbuf + (size - len);
|
||||||
while (it != pbuf + size && *it == 0) ++it;
|
while (it != pbuf + size && *it == 0) ++it;
|
||||||
|
|
||||||
uint8_t *result = taosMemoryCalloc(1, size + 1);
|
uint8_t *result = taosMemoryCalloc(1, inlen + 1);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
if (bfree) taosMemoryFree(pbuf);
|
if (bfree) taosMemoryFree(pbuf);
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
|
|
@ -100,3 +100,11 @@ add_test(
|
||||||
NAME talgoTest
|
NAME talgoTest
|
||||||
COMMAND talgoTest
|
COMMAND talgoTest
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# tbaseCodecTest
|
||||||
|
add_executable(tbaseCodecTest "tbaseCodecTest.cpp")
|
||||||
|
target_link_libraries(tbaseCodecTest os util common gtest_main)
|
||||||
|
add_test(
|
||||||
|
NAME tbaseCodecTest
|
||||||
|
COMMAND tbaseCodecTest
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "os.h"
|
||||||
|
#include "taos.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
#include "tbase58.h"
|
||||||
|
#include "tbase64.h"
|
||||||
|
#include "tglobal.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkBase58Codec(uint8_t *pRaw, int32_t rawLen, int32_t index) {
|
||||||
|
char *pEnc = base58_encode((const uint8_t *)pRaw, rawLen);
|
||||||
|
ASSERT_NE(nullptr, pEnc);
|
||||||
|
|
||||||
|
int32_t encLen = strlen(pEnc);
|
||||||
|
std::cout << "index:" << index << ", encLen is " << encLen << std::endl;
|
||||||
|
int32_t decLen = 0;
|
||||||
|
char *pDec = (char *)base58_decode((const char *)pEnc, encLen, &decLen);
|
||||||
|
std::cout << "index:" << index << ", decLen is " << decLen << std::endl;
|
||||||
|
ASSERT_NE(nullptr, pDec);
|
||||||
|
ASSERT_EQ(rawLen, decLen);
|
||||||
|
ASSERT_LE(rawLen, encLen);
|
||||||
|
ASSERT_EQ(0, strncmp((char *)pRaw, pDec, rawLen));
|
||||||
|
taosMemoryFreeClear(pDec);
|
||||||
|
taosMemoryFreeClear(pEnc);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TD_BASE_CODEC_TEST, tbase58_test) {
|
||||||
|
const int32_t TEST_LEN_MAX = TBASE_MAX_ILEN;
|
||||||
|
const int32_t TEST_LEN_STEP = 10;
|
||||||
|
int32_t rawLen = 0;
|
||||||
|
uint8_t *pRaw = NULL;
|
||||||
|
|
||||||
|
pRaw = (uint8_t *)taosMemoryCalloc(1, TEST_LEN_MAX);
|
||||||
|
ASSERT_NE(nullptr, pRaw);
|
||||||
|
|
||||||
|
// 1. normal case
|
||||||
|
// string blend with char and '\0'
|
||||||
|
rawLen = TEST_LEN_MAX;
|
||||||
|
for (int32_t i = 0; i < TEST_LEN_MAX; i += 1000) {
|
||||||
|
checkBase58Codec(pRaw, rawLen, i);
|
||||||
|
pRaw[i] = i & 127;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string without '\0'
|
||||||
|
for (int32_t i = 0; i < TEST_LEN_MAX; ++i) {
|
||||||
|
pRaw[i] = i & 127;
|
||||||
|
}
|
||||||
|
checkBase58Codec(pRaw, TEST_LEN_MAX, 0);
|
||||||
|
for (int32_t i = 0; i < TEST_LEN_MAX; i += 1000) {
|
||||||
|
rawLen = i;
|
||||||
|
checkBase58Codec(pRaw, rawLen, i);
|
||||||
|
}
|
||||||
|
taosMemoryFreeClear(pRaw);
|
||||||
|
ASSERT_EQ(nullptr, pRaw);
|
||||||
|
|
||||||
|
// 2. overflow case
|
||||||
|
char tmp[1];
|
||||||
|
char *pEnc = base58_encode((const uint8_t *)tmp, TBASE_MAX_ILEN + 1);
|
||||||
|
ASSERT_EQ(nullptr, pEnc);
|
||||||
|
char *pDec = (char *)base58_decode((const char *)tmp, TBASE_MAX_OLEN + 1, NULL);
|
||||||
|
ASSERT_EQ(nullptr, pDec);
|
||||||
|
|
||||||
|
taosMemoryFreeClear(pRaw);
|
||||||
|
ASSERT_EQ(nullptr, pRaw);
|
||||||
|
}
|
Loading…
Reference in New Issue