mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-10-23 19:08:10 +08:00
feat(util): Add base64 codec to util
This commit is contained in:
46
components/util/include/esp_base64.h
Normal file
46
components/util/include/esp_base64.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief encode a base64-formatted buffer
|
||||||
|
*
|
||||||
|
* @param p_src input encoded data buffer pointer
|
||||||
|
* @param slen input data length by bytes
|
||||||
|
* @param p_dst output buffer pointer
|
||||||
|
* @param dlen output buffer length by bytes
|
||||||
|
*
|
||||||
|
* @return the result
|
||||||
|
* 0 : Success
|
||||||
|
* -ENOBUFS : output buffer it not enough
|
||||||
|
*/
|
||||||
|
int esp_base64_encode(const void *p_src, uint32_t slen, void *p_dst, uint32_t dlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief decode a base64-formatted buffer
|
||||||
|
*
|
||||||
|
* @param p_src input encoded data buffer pointer
|
||||||
|
* @param slen input data length by bytes
|
||||||
|
* @param p_dst output buffer pointer
|
||||||
|
* @param dlen output buffer length by bytes
|
||||||
|
*
|
||||||
|
* @return the result
|
||||||
|
* 0 : Success
|
||||||
|
* -EINVAL : input parameter invalid
|
||||||
|
* -ENOBUFS : output buffer it not enough
|
||||||
|
*/
|
||||||
|
int esp_base64_decode(const void *p_src, uint32_t slen, void *p_dst, uint32_t dlen);
|
201
components/util/src/base64.c
Normal file
201
components/util/src/base64.c
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_base64.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
|
||||||
|
typedef union _cache {
|
||||||
|
uint32_t u32d;
|
||||||
|
uint8_t u8d[4];
|
||||||
|
} cache_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use 4-byte align look-up table to speed up loading data
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const uint32_t s_base64_enc_lut[16] = {
|
||||||
|
0x44434241, 0x48474645, 0x4c4b4a49, 0x504f4e4d,
|
||||||
|
0x54535251, 0x58575655, 0x62615a59, 0x66656463,
|
||||||
|
0x6a696867, 0x6e6d6c6b, 0x7271706f, 0x76757473,
|
||||||
|
0x7a797877, 0x33323130, 0x37363534, 0x2f2b3938
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t s_base64_dec_lut[32] = {
|
||||||
|
0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
|
||||||
|
0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f,
|
||||||
|
0x7f7f7f7f, 0x7f7f7f7f, 0x3e7f7f7f, 0x3f7f7f7f,
|
||||||
|
0x37363534, 0x3b3a3938, 0x7f7f3d3c, 0x7f7f407f,
|
||||||
|
0x0201007f, 0x06050403, 0x0a090807, 0x0e0d0c0b,
|
||||||
|
0x1211100f, 0x16151413, 0x7f191817, 0x7f7f7f7f,
|
||||||
|
0x1c1b1a7f, 0x201f1e1d, 0x24232221, 0x28272625,
|
||||||
|
0x2c2b2a29, 0x302f2e2d, 0x7f333231, 0x7f7f7f7f
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline uint8_t __map_base64_enc_data(uint8_t index)
|
||||||
|
{
|
||||||
|
cache_t tmp;
|
||||||
|
uint8_t num = index / 4;
|
||||||
|
uint8_t off = index % 4;
|
||||||
|
tmp.u32d = s_base64_enc_lut[num];
|
||||||
|
|
||||||
|
return tmp.u8d[off];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t __map_base64_dec_data(uint8_t index)
|
||||||
|
{
|
||||||
|
cache_t tmp;
|
||||||
|
uint8_t num = index / 4;
|
||||||
|
uint8_t off = index % 4;
|
||||||
|
tmp.u32d = s_base64_dec_lut[num];
|
||||||
|
|
||||||
|
return tmp.u8d[off];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode a buffer into base64 format
|
||||||
|
*/
|
||||||
|
int esp_base64_encode(const void *p_src, uint32_t slen, void *p_dst, uint32_t dlen)
|
||||||
|
{
|
||||||
|
uint32_t i, n;
|
||||||
|
uint32_t C1, C2, C3;
|
||||||
|
uint8_t *p;
|
||||||
|
uint8_t *dst = (uint8_t *)p_dst;
|
||||||
|
const uint8_t *src = (const uint8_t *)p_src;
|
||||||
|
|
||||||
|
assert(p_dst);
|
||||||
|
assert(dlen);
|
||||||
|
assert(p_src);
|
||||||
|
assert(slen);
|
||||||
|
|
||||||
|
n = slen / 3 + (slen % 3 != 0);
|
||||||
|
n *= 4;
|
||||||
|
|
||||||
|
if (dlen < (n + 1))
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
n = (slen / 3) * 3;
|
||||||
|
|
||||||
|
for (i = 0, p = dst; i < n; i += 3) {
|
||||||
|
C1 = *src++;
|
||||||
|
C2 = *src++;
|
||||||
|
C3 = *src++;
|
||||||
|
|
||||||
|
*p++ = __map_base64_enc_data((C1 >> 2) & 0x3F);
|
||||||
|
*p++ = __map_base64_enc_data((((C1 & 3) << 4) + (C2 >> 4)) & 0x3F);
|
||||||
|
*p++ = __map_base64_enc_data((((C2 & 15) << 2) + (C3 >> 6)) & 0x3F);
|
||||||
|
*p++ = __map_base64_enc_data(C3 & 0x3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < slen) {
|
||||||
|
C1 = *src++;
|
||||||
|
C2 = ((i + 1) < slen) ? *src++ : 0;
|
||||||
|
|
||||||
|
*p++ = __map_base64_enc_data((C1 >> 2) & 0x3F);
|
||||||
|
*p++ = __map_base64_enc_data((((C1 & 3) << 4) + (C2 >> 4)) & 0x3F);
|
||||||
|
|
||||||
|
if ((i + 1) < slen)
|
||||||
|
*p++ = __map_base64_enc_data(((C2 & 15) << 2) & 0x3F);
|
||||||
|
else
|
||||||
|
*p++ = '=';
|
||||||
|
|
||||||
|
*p++ = '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return p - dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decode a base64-formatted buffer
|
||||||
|
*/
|
||||||
|
int esp_base64_decode(const void *p_src, uint32_t slen, void *p_dst, uint32_t dlen)
|
||||||
|
{
|
||||||
|
uint32_t i, n;
|
||||||
|
uint32_t j, x;
|
||||||
|
uint8_t *p;
|
||||||
|
uint8_t *dst = (uint8_t *)p_dst;
|
||||||
|
const uint8_t *src = (const uint8_t *)p_src;
|
||||||
|
|
||||||
|
assert(p_dst);
|
||||||
|
assert(dlen);
|
||||||
|
assert(p_src);
|
||||||
|
assert(slen);
|
||||||
|
|
||||||
|
/* First pass: check for validity and get output length */
|
||||||
|
for (i = n = j = 0; i < slen; i++) {
|
||||||
|
/* Skip spaces before checking for EOL */
|
||||||
|
x = 0;
|
||||||
|
while (i < slen && src[i] == ' ') {
|
||||||
|
++i;
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spaces at end of buffer are OK */
|
||||||
|
if (i == slen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((slen - i ) >= 2 && src[i] == '\r' && src[i + 1] == '\n')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (src[i] == '\n')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Space inside a line is an error */
|
||||||
|
if (x != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (src[i] == '=' && ++j > 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (src[i] > 127 || __map_base64_dec_data(src[i]) == 127)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (__map_base64_dec_data(src[i]) < 64 && j != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( n == 0 )
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
|
||||||
|
n -= j;
|
||||||
|
|
||||||
|
if (dlen < n )
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
|
||||||
|
if (*src == '\r' || *src == '\n' || *src == ' ')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
j -= (__map_base64_dec_data(*src) == 64);
|
||||||
|
x = (x << 6) | (__map_base64_dec_data(*src) & 0x3F);
|
||||||
|
|
||||||
|
if (++n == 4) {
|
||||||
|
n = 0;
|
||||||
|
if (j > 0)
|
||||||
|
*p++ = (uint8_t)(x >> 16);
|
||||||
|
if (j > 1)
|
||||||
|
*p++ = (uint8_t)(x >> 8);
|
||||||
|
if (j > 2)
|
||||||
|
*p++ = (uint8_t)(x >> 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - dst;
|
||||||
|
}
|
5
components/util/test/component.mk
Normal file
5
components/util/test/component.mk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#
|
||||||
|
#Component Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
77
components/util/test/test_base64.c
Normal file
77
components/util/test/test_base64.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "esp_base64.h"
|
||||||
|
#include "unity.h"
|
||||||
|
|
||||||
|
#define TEST_BASE64_COUNT 4096
|
||||||
|
#define TEST_BASE64_DEBUG 1
|
||||||
|
|
||||||
|
static unsigned char base64_test_dec[] =
|
||||||
|
{
|
||||||
|
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
|
||||||
|
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
|
||||||
|
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
|
||||||
|
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
|
||||||
|
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
|
||||||
|
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
|
||||||
|
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
|
||||||
|
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char base64_test_enc[] =
|
||||||
|
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
|
||||||
|
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
|
||||||
|
|
||||||
|
TEST_CASE("Test base64 codec", "[base64]")
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
uint32_t encode_time = 0, decode_time = 0;
|
||||||
|
unsigned char buffer[128];
|
||||||
|
|
||||||
|
extern uint32_t esp_get_time(void);
|
||||||
|
|
||||||
|
for (int i = 0; i < TEST_BASE64_COUNT; i++) {
|
||||||
|
uint32_t tmp = esp_get_time();
|
||||||
|
|
||||||
|
ret = esp_base64_encode(base64_test_dec, sizeof(base64_test_dec), buffer, sizeof(buffer));
|
||||||
|
TEST_ASSERT_TRUE(ret > 0);
|
||||||
|
|
||||||
|
encode_time += esp_get_time() - tmp;
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(memcmp(base64_test_enc, buffer, ret) == 0);
|
||||||
|
|
||||||
|
tmp = esp_get_time();
|
||||||
|
|
||||||
|
ret = esp_base64_decode(base64_test_enc, sizeof(base64_test_enc) - 1, buffer, sizeof(buffer));
|
||||||
|
TEST_ASSERT_TRUE(ret > 0);
|
||||||
|
|
||||||
|
decode_time += esp_get_time() - tmp;
|
||||||
|
|
||||||
|
TEST_ASSERT_TRUE(memcmp(base64_test_dec, buffer, ret) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TEST_BASE64_DEBUG
|
||||||
|
printf("base64 test cost time totally encode %u us and decode %u us, once cost is about encode %u us and decode %u us\n",
|
||||||
|
encode_time, decode_time, encode_time / TEST_BASE64_COUNT, decode_time / TEST_BASE64_COUNT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// align: base64 test cost time totally encode 100921 us and decode 549040 us,
|
||||||
|
// once cost is about encode 29 us and decode 133 us
|
||||||
|
|
||||||
|
// no align : base64 test cost time totally encode 640726 us and decode 1601834 us,
|
||||||
|
// once cost is about encode 156 us and decode 391 us
|
Reference in New Issue
Block a user