From f8ac003bbfe11956578dd2189827686c27374d06 Mon Sep 17 00:00:00 2001 From: Maciej Jurczak Date: Thu, 25 Jun 2020 22:52:38 +0200 Subject: [PATCH 1/4] base64: Fixed decode buffer size estimation Fixed required result buffer size underestimation in base64_estimate_decode_size() function. --- sys/include/base64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/include/base64.h b/sys/include/base64.h index c34534059f10..4509c9d28e5a 100644 --- a/sys/include/base64.h +++ b/sys/include/base64.h @@ -41,7 +41,7 @@ extern "C" { */ static inline size_t base64_estimate_decode_size(size_t base64_in_size) { - return ((base64_in_size / 4) * 3); + return (((base64_in_size + 3) / 4) * 3); } /** From 3c7fd0cdc93c1a1be1ccdc394b5bd8d8aef7a303 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 Jun 2020 16:26:50 +0200 Subject: [PATCH 2/4] sys/base64: Use void pointer for buffers in API This is a non-breaking change, as `unsigned char *` can implicitly be converted to `void *`. --- sys/base64/base64.c | 54 ++++++++++++++++++++++++-------------------- sys/include/base64.h | 6 ++--- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/sys/base64/base64.c b/sys/base64/base64.c index 0f1b90075a9e..7f53e2d6c562 100644 --- a/sys/base64/base64.c +++ b/sys/base64/base64.c @@ -19,6 +19,8 @@ */ #include +#include + #include "base64.h" #include "kernel_defines.h" @@ -35,7 +37,7 @@ /* * returns the corresponding ascii symbol value for the given base64 code */ -static char getsymbol(unsigned char code, bool urlsafe) +static char getsymbol(uint8_t code, bool urlsafe) { if (!IS_ACTIVE(MODULE_BASE64URL)) { urlsafe = false; @@ -73,10 +75,11 @@ static char getsymbol(unsigned char code, bool urlsafe) } static int base64_encode_base(const void *data_in, size_t data_in_size, - unsigned char *base64_out, size_t *base64_out_size, + void *base64_out, size_t *base64_out_size, bool urlsafe) { - const unsigned char *in = data_in; + const uint8_t *in = data_in; + uint8_t *out = base64_out; size_t required_size = base64_estimate_encode_size(data_in_size); if (data_in == NULL) { @@ -93,45 +96,45 @@ static int base64_encode_base(const void *data_in, size_t data_in_size, return BASE64_ERROR_BUFFER_OUT_SIZE; } - if (base64_out == NULL) { + if (out == NULL) { return BASE64_ERROR_BUFFER_OUT; } int iterate_base64_buffer = 0; - unsigned char nNum = 0; + uint8_t n_num = 0; int nLst = 0; int njump = 0; for (int i = 0; i < (int)(data_in_size); ++i) { - unsigned char tmpval; + uint8_t tmpval; njump++; tmpval = *(in + i); - nNum = (tmpval >> (2 * njump)); + n_num = (tmpval >> (2 * njump)); if (njump == 4) { - nNum = nLst << (8 - 2 * njump); + n_num = nLst << (8 - 2 * njump); njump = 0; nLst = 0; --i; } else { - nNum += nLst << (8 - 2 * njump); + n_num += nLst << (8 - 2 * njump); nLst = tmpval & ((1 << njump * 2) - 1); } - base64_out[iterate_base64_buffer++] = getsymbol(nNum, urlsafe); + out[iterate_base64_buffer++] = getsymbol(n_num, urlsafe); } /* The last character is not finished yet */ njump++; - nNum = nLst << (8 - 2 * njump); - base64_out[iterate_base64_buffer++] = getsymbol(nNum, urlsafe); + n_num = nLst << (8 - 2 * njump); + out[iterate_base64_buffer++] = getsymbol(n_num, urlsafe); /* if required we append '=' for the required dividability */ while (iterate_base64_buffer % 4) { - base64_out[iterate_base64_buffer++] = '='; + out[iterate_base64_buffer++] = '='; } *base64_out_size = iterate_base64_buffer; @@ -140,14 +143,14 @@ static int base64_encode_base(const void *data_in, size_t data_in_size, } int base64_encode(const void *data_in, size_t data_in_size, - unsigned char *base64_out, size_t *base64_out_size) + void *base64_out, size_t *base64_out_size) { return base64_encode_base(data_in, data_in_size, base64_out, base64_out_size, false); } #if IS_ACTIVE(MODULE_BASE64URL) int base64url_encode(const void *data_in, size_t data_in_size, - unsigned char *base64_out, size_t *base64_out_size) + void *base64_out, size_t *base64_out_size) { return base64_encode_base(data_in, data_in_size, base64_out, base64_out_size, true); } @@ -156,7 +159,7 @@ int base64url_encode(const void *data_in, size_t data_in_size, /* * returns the corresponding base64 code for the given ascii symbol */ -static int getcode(char symbol) +static uint8_t getcode(char symbol) { if (symbol == '/') { return BASE64_SLASH; @@ -200,13 +203,14 @@ static int getcode(char symbol) return BASE64_NOT_DEFINED; } -int base64_decode(const unsigned char *base64_in, size_t base64_in_size, +int base64_decode(const void *base64_in, size_t base64_in_size, void *data_out, size_t *data_out_size) { - unsigned char *out = data_out; + uint8_t *out = data_out; + const uint8_t *in = base64_in; size_t required_size = base64_estimate_decode_size(base64_in_size); - if (base64_in == NULL) { + if (in == NULL) { return BASE64_ERROR_DATA_IN; } @@ -229,14 +233,14 @@ int base64_decode(const unsigned char *base64_in, size_t base64_in_size, } int iterate_data_buffer = 0; - unsigned char nNum = 0; - int nLst = getcode(base64_in[0]) << 2; + uint8_t n_num = 0; + int nLst = getcode(in[0]) << 2; int code = 0; int mask = 2; for (int i = 1; i < (int)(base64_in_size); i++) { - code = getcode(base64_in[i]); + code = getcode(in[i]); if (code == BASE64_NOT_DEFINED || code == BASE64_EQUALS) { continue; @@ -244,16 +248,16 @@ int base64_decode(const unsigned char *base64_in, size_t base64_in_size, int nm = (0xFF << (2 * mask)); - nNum = nLst + ((code & (0xFF & nm)) >> (2 * mask)); + n_num = nLst + ((code & (0xFF & nm)) >> (2 * mask)); nLst = (code & (0xFF & ~nm)) << (8 - (2 * mask)); - (mask != 3) ? out[iterate_data_buffer++] = nNum : nNum; + (mask != 3) ? out[iterate_data_buffer++] = n_num : n_num; (mask == 0) ? mask = 3 : mask--; } if (code == BASE64_EQUALS) { /* add the last character to the data_out buffer */ - out[iterate_data_buffer] = nNum; + out[iterate_data_buffer] = n_num; } *data_out_size = iterate_data_buffer; diff --git a/sys/include/base64.h b/sys/include/base64.h index 4509c9d28e5a..493779776585 100644 --- a/sys/include/base64.h +++ b/sys/include/base64.h @@ -74,7 +74,7 @@ static inline size_t base64_estimate_encode_size(size_t data_in_size) BASE64_ERROR_DATA_IN if `data_in` equals NULL. */ int base64_encode(const void *data_in, size_t data_in_size, - unsigned char *base64_out, size_t *base64_out_size); + void *base64_out, size_t *base64_out_size); /** * @brief Encodes a given datum to base64 with URL and Filename Safe Alphabet @@ -100,7 +100,7 @@ int base64_encode(const void *data_in, size_t data_in_size, BASE64_ERROR_DATA_IN if `data_in` equals NULL. */ int base64url_encode(const void *data_in, size_t data_in_size, - unsigned char *base64_out, size_t *base64_out_size); + void *base64_out, size_t *base64_out_size); /** * @brief Decodes a given base64 string and save the result to the given destination. @@ -120,7 +120,7 @@ int base64url_encode(const void *data_in, size_t data_in_size, BASE64_ERROR_DATA_IN if `base64_in` equals NULL, BASE64_ERROR_DATA_IN_SIZE if `base64_in_size` is between 1 and 4. */ -int base64_decode(const unsigned char *base64_in, size_t base64_in_size, +int base64_decode(const void *base64_in, size_t base64_in_size, void *data_out, size_t *data_out_size); #ifdef __cplusplus From e3ea4943af4c5acfde3e68fb00fda2728e722b0d Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 Jun 2020 16:29:54 +0200 Subject: [PATCH 3/4] tests: Add benchmark for sys/base64 --- tests/bench_sys_base64/Makefile | 7 ++ tests/bench_sys_base64/main.c | 99 ++++++++++++++++++++++++++ tests/bench_sys_base64/tests/01-run.py | 21 ++++++ 3 files changed, 127 insertions(+) create mode 100644 tests/bench_sys_base64/Makefile create mode 100644 tests/bench_sys_base64/main.c create mode 100755 tests/bench_sys_base64/tests/01-run.py diff --git a/tests/bench_sys_base64/Makefile b/tests/bench_sys_base64/Makefile new file mode 100644 index 000000000000..98993c7b3c69 --- /dev/null +++ b/tests/bench_sys_base64/Makefile @@ -0,0 +1,7 @@ +include ../Makefile.tests_common + +USEMODULE += base64 +USEMODULE += fmt +USEMODULE += xtimer + +include $(RIOTBASE)/Makefile.include diff --git a/tests/bench_sys_base64/main.c b/tests/bench_sys_base64/main.c new file mode 100644 index 000000000000..3c33a7301a9e --- /dev/null +++ b/tests/bench_sys_base64/main.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Benchmark for the base64 lib + * + * @author Marian Buschsieweke + * + * @} + */ + +#include +#include + +#include "base64.h" +#include "fmt.h" +#include "xtimer.h" + +#define MIN(a, b) (a < b) ? a : b + +static char buf[128]; + +static const char input[96] = "This is an extremely, enormously, greatly, " + "immensely, tremendously, remarkably lengthy " + "sentence!"; +static const char base64[128] = +"VGhpcyBpcyBhbiBleHRyZW1lbHksIGVub3Jtb3VzbHksIGdyZWF0bHksIGltbWVuc2VseSwgdHJl" +"bWVuZG91c2x5LCByZW1hcmthYmx5IGxlbmd0aHkgc2VudGVuY2Uh"; + +int main(void) { + uint32_t start, stop; + size_t size; + + /* We don't want check return value in the benchmark loop, so we just do + * a simple self test now. */ + print_str("Verifying that base64 encoding works for benchmark input: "); + size = sizeof(buf); + if ((BASE64_SUCCESS != base64_encode(input, sizeof(input), buf, &size)) || + (size != sizeof(buf)) || + (0 != memcmp(base64, buf, sizeof(base64)))) + { + print_str("FAIL\nGot: \""); + print(buf, MIN(size, sizeof(base64))); + print_str("\"\nExpected: \""); + print(base64, sizeof(base64)); + print_str("\"\n"); + } + else { + print_str("OK\n"); + } + + print_str("Verifying that base64 decoding works for benchmark input: "); + size = sizeof(buf); + if ((BASE64_SUCCESS != base64_decode(base64, sizeof(base64), buf, &size)) || + (size != sizeof(input)) || + (0 != memcmp(input, buf, sizeof(input)))) + { + print_str("FAIL\nGot: \""); + print(buf, MIN(size, sizeof(input))); + print_str("\"\nExpected: \""); + print(input, sizeof(input)); + print_str("\"\n"); + } + else { + print_str("OK\n"); + } + + start = xtimer_now_usec(); + for (unsigned i = 0; i < 10000; i++) { + size = sizeof(buf); + base64_encode(input, sizeof(input), buf, &size); + } + stop = xtimer_now_usec(); + + print_str("Encoding 10.000 x 96 bytes (128 bytes in base64): "); + print_u32_dec(stop - start); + print_str(" µs\n"); + + start = xtimer_now_usec(); + for (unsigned i = 0; i < 10000; i++) { + size = sizeof(buf); + base64_decode(base64, sizeof(base64), buf, &size); + } + stop = xtimer_now_usec(); + + print_str("Decoding 10.000 x 96 bytes (128 bytes in base64): "); + print_u32_dec(stop - start); + print_str(" µs\n"); + return 0; +} diff --git a/tests/bench_sys_base64/tests/01-run.py b/tests/bench_sys_base64/tests/01-run.py new file mode 100755 index 000000000000..7fa6c23f3ca9 --- /dev/null +++ b/tests/bench_sys_base64/tests/01-run.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact("Verifying that base64 encoding works for benchmark input: OK\r\n") + child.expect_exact("Verifying that base64 decoding works for benchmark input: OK\r\n") + child.expect(r"Encoding 10\.000 x 96 bytes \(128 bytes in base64\): [0-9]+ µs\r\n") + child.expect(r"Decoding 10\.000 x 96 bytes \(128 bytes in base64\): [0-9]+ µs\r\n") + + +if __name__ == "__main__": + sys.exit(run(testfunc)) From 4e6ec3493fbbff1f3e26bdb7dd10dbb5cdfe7582 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Tue, 30 Jun 2020 17:09:01 +0200 Subject: [PATCH 4/4] tests/unittests: Extend & clean up base64 tests - Added unit test for `base64_estimate_{de,en}code_size()` - Mark constant stuff as `const` - Use `memcmp()` for comparing memory - Do not use variable size arrays - Various code style issue --- tests/unittests/tests-base64/tests-base64.c | 241 +++++++++++--------- 1 file changed, 128 insertions(+), 113 deletions(-) diff --git a/tests/unittests/tests-base64/tests-base64.c b/tests/unittests/tests-base64/tests-base64.c index 153ba2385f97..573686d4d06c 100644 --- a/tests/unittests/tests-base64/tests-base64.c +++ b/tests/unittests/tests-base64/tests-base64.c @@ -20,16 +20,17 @@ static void test_base64_01_encode_string(void) { - unsigned char data_in[] = "Hello RIOT this is a base64 test!\n" - "This should work as intended."; + static const char data_in[] = "Hello RIOT this is a base64 test!\n" + "This should work as intended."; - unsigned char expected_encoding[] = "SGVsbG8gUklPVCB0aGlzIGlzIGEgYmFzZTY0IHR" - "lc3QhClRoaXMgc2hvdWxkIHdvcmsgYXMgaW50ZW5kZWQu"; + static const char expected_encoding[] = + "SGVsbG8gUklPVCB0aGlzIGlzIGEgYmFzZTY0IHR" + "lc3QhClRoaXMgc2hvdWxkIHdvcmsgYXMgaW50ZW5kZWQu"; - size_t data_in_size = strlen((char *)data_in); + size_t data_in_size = strlen(data_in); size_t base64_out_size = 0; - unsigned char base64_out[ strlen((char *)expected_encoding) ]; + char base64_out[sizeof(expected_encoding)]; /* * @Note: @@ -46,34 +47,34 @@ static void test_base64_01_encode_string(void) TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)base64_out_size; ++i) { - TEST_ASSERT_MESSAGE(base64_out[i] == expected_encoding[i], \ - "encoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(expected_encoding, base64_out, + base64_out_size)), + "encoding failed!(produced unexpected output)"); #if (TEST_BASE64_SHOW_OUTPUT == 1) puts("Test 01 Encoded:"); - for (int i = 0; i < (int)base64_out_size; ++i) { + for (size_t i = 0; i < base64_out_size; ++i) { printf("%c", base64_out[i]); } - printf("\nFrom:\n%s\n", (char *)data_in); + printf("\nFrom:\n%s\n", data_in); #endif } static void test_base64_02_decode_base64(void) { - unsigned char encoded_base64[] = "SGVsbG8gUklPVCB0aGlzIGlzIGEgYmFzZTY0IHRlc3Q" - "hClRoaXMgc2hvdWxkIHdvcmsgYXMgaW50ZW5kZWQu"; + static const char encoded_base64[] = + "SGVsbG8gUklPVCB0aGlzIGlzIGEgYmFzZTY0IHRlc3Q" + "hClRoaXMgc2hvdWxkIHdvcmsgYXMgaW50ZW5kZWQu"; - unsigned char expected_string[] = "Hello RIOT this is a base64 test!\n" - "This should work as intended."; + static const char expected_string[] = "Hello RIOT this is a base64 test!\n" + "This should work as intended."; - size_t base64_size = strlen((char *)encoded_base64); + size_t base64_size = strlen(encoded_base64); size_t data_out_size = 0; - unsigned char data_out[ strlen((char *)expected_string) ]; + unsigned char data_out[sizeof(expected_string)]; int ret = base64_decode(encoded_base64, base64_size, NULL, &data_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); @@ -84,51 +85,49 @@ static void test_base64_02_decode_base64(void) ret = base64_decode(encoded_base64, base64_size, data_out, &data_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)data_out_size; ++i) { - TEST_ASSERT_MESSAGE(data_out[i] == expected_string[i], \ - "decoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(expected_string, data_out, + data_out_size)), + "decoding failed!(produced unexpected output)"); #if (TEST_BASE64_SHOW_OUTPUT == 1) puts("Test 02 Decoded:"); - for (int i = 0; i < (int)data_out_size; ++i) { + for (size_t i = 0; i < data_out_size; ++i) { printf("%c", data_out[i]); } - printf("\nFrom:\n%s\n", (char *)encoded_base64); + printf("\nFrom:\n%s\n", encoded_base64); #endif } static void test_base64_03_single_character(void) { size_t element_size = 1; - unsigned char element[] = "1"; + static const char element[] = "1"; - size_t elementDecodeSize = 3; - unsigned char elementDecode[3]; + unsigned char element_decode[3]; + size_t element_decode_size = sizeof(element_decode); - size_t element_base64_out_size = 10; unsigned char element_base64_out[10]; + size_t element_base64_out_size = sizeof(element_base64_out); - int ret = base64_encode(element, element_size, \ + int ret = base64_encode(element, element_size, element_base64_out, &element_base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - ret = base64_decode(element_base64_out, element_base64_out_size, \ - elementDecode, &elementDecodeSize); + ret = base64_decode(element_base64_out, element_base64_out_size, + element_decode, &element_decode_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)elementDecodeSize; ++i) { - TEST_ASSERT_MESSAGE(element[i] == elementDecode[i], \ - "decoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(element, element_decode, + element_decode_size)), + "encoding failed!(produced unexpected output)"); } static void test_base64_04_free_conversion(void) { size_t elements = 255; - unsigned char elm[elements]; + char elm[elements]; size_t elem_base64_out_size = 0; unsigned char elm_base64_out[((elements / 3) * 4) + (elements / 10)]; @@ -137,7 +136,7 @@ static void test_base64_04_free_conversion(void) unsigned char elem_base64_out_decoded[ elements + 10 ]; /* fill some values */ - for (int i = 0; i < (int)elements; ++i) { + for (size_t i = 0; i < elements; ++i) { elm[i] = i; } @@ -147,33 +146,33 @@ static void test_base64_04_free_conversion(void) ret = base64_encode(elm, elements, elm_base64_out, &elem_base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - ret = base64_decode(elm_base64_out, elem_base64_out_size, \ + ret = base64_decode(elm_base64_out, elem_base64_out_size, NULL, &elem_base64_out_decoded_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); - ret = base64_decode(elm_base64_out, elem_base64_out_size, \ + ret = base64_decode(elm_base64_out, elem_base64_out_size, elem_base64_out_decoded, &elem_base64_out_decoded_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)elements; ++i) { - TEST_ASSERT_MESSAGE(elem_base64_out_decoded[i] == elm[i], \ - "decoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(elem_base64_out_decoded, elm, + elements)), + "decoding failed!(produced unexpected output)"); } static void test_base64_05_decode_larger(void) { - unsigned char decodeit[] = "SG93IG11Y2ggd29vZCB3b3VsZCBhIHdvb2RjaHVjayBjaHVj" - "awppZiBhIHdvb2RjaHVjayBjb3VsZCBjaHVjayB3b29kPwpI" - "ZSB3b3VsZCBjaHVjaywgaGUgd291bGQsIGFzIG11Y2ggYXMg" - "aGUgY291bGQsCmFuZCBjaHVjayBhcyBtdWNoIHdvb2QgYXMg" - "YSB3b29kY2h1Y2sgd291bGQKaWYgYSB3b29kY2h1Y2sgY291" - "bGQgY2h1Y2sgd29vZC4=="; + static const char decodeit[] = + "SG93IG11Y2ggd29vZCB3b3VsZCBhIHdvb2RjaHVjayBjaHVj" + "awppZiBhIHdvb2RjaHVjayBjb3VsZCBjaHVjayB3b29kPwpI" + "ZSB3b3VsZCBjaHVjaywgaGUgd291bGQsIGFzIG11Y2ggYXMg" + "aGUgY291bGQsCmFuZCBjaHVjayBhcyBtdWNoIHdvb2QgYXMg" + "YSB3b29kY2h1Y2sgd291bGQKaWYgYSB3b29kY2h1Y2sgY291" + "bGQgY2h1Y2sgd29vZC4=="; size_t data_size = 199; - unsigned char data[data_size]; + char data[data_size]; - size_t decodeit_size = strlen((char *)decodeit); + size_t decodeit_size = strlen(decodeit); int ret = base64_decode(decodeit, decodeit_size, data, &data_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); @@ -181,11 +180,11 @@ static void test_base64_05_decode_larger(void) #if (TEST_BASE64_SHOW_OUTPUT == 1) puts("Test 05 Decoded:"); - for (int i = 0; i < (int)data_size; ++i) { + for (size_t i = 0; i < data_size; ++i) { printf("%c", data[i]); } - printf("\nFrom:\n%s\n", (char *)decodeit); + printf("\nFrom:\n%s\n", decodeit); #endif } @@ -202,25 +201,26 @@ static void test_base64_06_stream_encode(void) * */ - unsigned char stream_encode[] = "Peter Piper picked a peck of pickled peppers." - "\nA peck of pickled peppers Peter Piper picked." - "\nIf Peter Piper picked a peck of pickled peppers," - "\nWhere's the peck of pickled peppers Peter Piper picked?"; + static const char stream_encode[] = + "Peter Piper picked a peck of pickled peppers.\n" + "A peck of pickled peppers Peter Piper picked.\n" + "If Peter Piper picked a peck of pickled peppers,\n" + "Where's the peck of pickled peppers Peter Piper picked?"; /* required output size +2 extra bytes */ size_t encoded_size = 264 + 2; /* cppcheck-suppress unassignedVariable * (reason: the above array is used/assigned in base64_encode() using its pointer) */ - unsigned char encode_result[encoded_size]; + char encode_result[encoded_size]; - int remain = strlen((char *)stream_encode); + int remain = strlen(stream_encode); int out_iter = 0; int ret = BASE64_SUCCESS; for (int i = 3; i < remain; (i += 3)) { size_t size_used = encoded_size - out_iter; - ret = base64_encode(stream_encode + (strlen((char *)stream_encode) - remain), \ + ret = base64_encode(stream_encode + (strlen(stream_encode) - remain), i, encode_result + out_iter, &size_used); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); @@ -230,7 +230,7 @@ static void test_base64_06_stream_encode(void) /* this final chunk we want to encode and append is prime to 3 */ size_t finish = encoded_size - out_iter; - ret = base64_encode(stream_encode + (strlen((char *)stream_encode) - remain), \ + ret = base64_encode(stream_encode + (strlen(stream_encode) - remain), remain, encode_result + out_iter, &finish); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); @@ -238,11 +238,11 @@ static void test_base64_06_stream_encode(void) out_iter += finish; puts("Test 06 Encoded:"); - for (int i = 0; i < (int)out_iter; ++i) { + for (size_t i = 0; i < out_iter; ++i) { printf("%c", encode_result[i]); } - printf("\nFrom:\n%s\n", (char *)stream_encode); + printf("\nFrom:\n%s\n", stream_encode); #endif } @@ -255,21 +255,22 @@ static void test_base64_07_stream_decode(void) * The chunks passed to decode MUST be dividable by 4. */ - unsigned char encoded[] = "UGV0ZXIgUGlwZXIgcGlja2VkIGEgcGVjayBvZiBwaWNrbGVkIH" - "BlcHBlcnMuCkEgcGVjayBvZiBwaWNrbGVkIHBlcHBlcnMgUGV0" - "ZXIgUGlwZXIgcGlja2VkLgpJZiBQZXRlciBQaXBlciBwaWNrZW" - "QgYSBwZWNrIG9mIHBpY2tsZWQgcGVwcGVycywKV2hlcmUncyB0" - "aGUgcGVjayBvZiBwaWNrbGVkIHBlcHBlcnMgUGV0ZXIgUGlwZX" - "IgcGlja2VkPw=="; + static const char encoded[] = + "UGV0ZXIgUGlwZXIgcGlja2VkIGEgcGVjayBvZiBwaWNrbGVkIH" + "BlcHBlcnMuCkEgcGVjayBvZiBwaWNrbGVkIHBlcHBlcnMgUGV0" + "ZXIgUGlwZXIgcGlja2VkLgpJZiBQZXRlciBQaXBlciBwaWNrZW" + "QgYSBwZWNrIG9mIHBpY2tsZWQgcGVwcGVycywKV2hlcmUncyB0" + "aGUgcGVjayBvZiBwaWNrbGVkIHBlcHBlcnMgUGV0ZXIgUGlwZX" + "IgcGlja2VkPw=="; /* required output size +2 extra bytes */ size_t decoded_size = 196 + 2; /* cppcheck-suppress unassignedVariable * (reason: the above array is used/assigned in base64_decode() using its pointer) */ - unsigned char stream_decoded[decoded_size]; + char stream_decoded[decoded_size]; - size_t encoded_size = strlen((char *)encoded); + size_t encoded_size = strlen(encoded); int remain = encoded_size; int out_iter = 0; @@ -277,7 +278,7 @@ static void test_base64_07_stream_decode(void) for (int i = 4; i < remain; (i += 4)) { size_t size_used = decoded_size - out_iter; - ret = base64_decode(encoded + (encoded_size - remain), \ + ret = base64_decode(encoded + (encoded_size - remain), i, stream_decoded + out_iter, &size_used); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); @@ -286,7 +287,7 @@ static void test_base64_07_stream_decode(void) } size_t finish = decoded_size - out_iter; - ret = base64_decode(encoded + (encoded_size - remain), \ + ret = base64_decode(encoded + (encoded_size - remain), remain, stream_decoded + out_iter, &finish); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); @@ -294,38 +295,35 @@ static void test_base64_07_stream_decode(void) out_iter += finish; puts("Test 07 Decoded:"); - for (int i = 0; i < (int)out_iter; ++i) { + for (size_t i = 0; i < out_iter; ++i) { printf("%c", stream_decoded[i]); } - printf("\nFrom:\n%s\n", (char *)encoded); + printf("\nFrom:\n%s\n", encoded); #endif } static void test_base64_08_encode_16_bytes(void) { - /* FIXME: init as enum here and below required, - * to fix folding-constant compiler error on OS X - */ - enum { buffer_size = 16 }; - unsigned char buffer[buffer_size]; - for (int i = 0; i < buffer_size; ++i) { + unsigned char buffer[16]; + size_t buffer_size = sizeof(buffer); + for (size_t i = 0; i < buffer_size; ++i) { buffer[i] = 'a'; } - enum { expected_out_size = 24 }; + char element_base64_out[24]; + size_t expected_out_size = sizeof(element_base64_out); size_t element_base64_out_size = expected_out_size; - unsigned char element_base64_out[expected_out_size]; size_t required_out_size = 0; - int ret = base64_encode(buffer, buffer_size, \ + int ret = base64_encode(buffer, buffer_size, element_base64_out, &required_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); TEST_ASSERT_EQUAL_INT(required_out_size, expected_out_size); - ret = base64_encode(buffer, buffer_size, \ - element_base64_out, &element_base64_out_size); + ret = base64_encode(buffer, buffer_size, + element_base64_out, &element_base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); TEST_ASSERT_EQUAL_INT(expected_out_size, element_base64_out_size); @@ -345,22 +343,22 @@ static void test_base64_09_encode_size_determination(void) // test 20 bytes input, expected 28 bytes output size_t required_out_size = 0; - int ret = base64_encode(buffer, buffer_size, \ + int ret = base64_encode(buffer, buffer_size, element_base64_out, &required_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); TEST_ASSERT_EQUAL_INT(required_out_size, expected_out_size); - ret = base64_encode(buffer, buffer_size, \ - element_base64_out, &element_base64_out_size); + ret = base64_encode(buffer, buffer_size, + element_base64_out, &element_base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); TEST_ASSERT_EQUAL_INT(expected_out_size, element_base64_out_size); // test 19 bytes input, expected 28 bytes output required_out_size = 0; - ret = base64_encode(buffer, 19, \ - element_base64_out, &required_out_size); + ret = base64_encode(buffer, 19, + element_base64_out, &required_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); TEST_ASSERT_EQUAL_INT(required_out_size, expected_out_size); @@ -368,8 +366,8 @@ static void test_base64_09_encode_size_determination(void) // test 18 bytes input, expected 24 bytes output expected_out_size = 24; required_out_size = 0; - ret = base64_encode(buffer, 18, \ - element_base64_out, &required_out_size); + ret = base64_encode(buffer, 18, + element_base64_out, &required_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); TEST_ASSERT_EQUAL_INT(required_out_size, expected_out_size); @@ -377,8 +375,8 @@ static void test_base64_09_encode_size_determination(void) // test 17 bytes input, expected 24 bytes output expected_out_size = 24; required_out_size = 0; - ret = base64_encode(buffer, 17, \ - element_base64_out, &required_out_size); + ret = base64_encode(buffer, 17, + element_base64_out, &required_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); TEST_ASSERT_EQUAL_INT(required_out_size, expected_out_size); @@ -416,7 +414,7 @@ static void test_base64_11_urlsafe_encode_int(void) unsigned char expected_encoding[] = "-RAAAA=="; size_t base64_out_size = 0; - unsigned char base64_out[ strlen((char *)expected_encoding) ]; + char base64_out[sizeof(expected_encoding)]; /* * @Note: @@ -425,23 +423,22 @@ static void test_base64_11_urlsafe_encode_int(void) * This size is a lower bound estimation, * thus it can require few more bytes then the actual used size for the output. */ - int ret = base64url_encode((void *)&data_in, sizeof(data_in), NULL, &base64_out_size); + int ret = base64url_encode(&data_in, sizeof(data_in), NULL, &base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); - ret = base64url_encode((void *)&data_in, sizeof(data_in), base64_out, &base64_out_size); + ret = base64url_encode(&data_in, sizeof(data_in), base64_out, &base64_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)base64_out_size; ++i) { - TEST_ASSERT_MESSAGE(base64_out[i] == expected_encoding[i], \ - "encoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(expected_encoding, base64_out, + base64_out_size)), + "encoding failed!(produced unexpected output)"); #if (TEST_BASE64_SHOW_OUTPUT == 1) puts("Test 11 Encoded:"); - for (int i = 0; i < (int)base64_out_size; ++i) { + for (size_t i = 0; i < base64_out_size; ++i) { printf("%c", base64_out[i]); } @@ -451,13 +448,13 @@ static void test_base64_11_urlsafe_encode_int(void) static void test_base64_12_urlsafe_decode_int(void) { - unsigned char encoded_base64[] = "_____wAA=="; - unsigned char expected[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0}; + static const char encoded_base64[] = "_____wAA=="; + static const uint8_t expected[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0}; - size_t base64_size = strlen((char *)encoded_base64); + size_t base64_size = strlen(encoded_base64); size_t data_out_size = 0; - unsigned char data_out[ sizeof(expected) ]; + unsigned char data_out[sizeof(expected)]; int ret = base64_decode(encoded_base64, base64_size, NULL, &data_out_size); TEST_ASSERT_EQUAL_INT(BASE64_ERROR_BUFFER_OUT_SIZE, ret); @@ -468,22 +465,39 @@ static void test_base64_12_urlsafe_decode_int(void) ret = base64_decode(encoded_base64, base64_size, data_out, &data_out_size); TEST_ASSERT_EQUAL_INT(BASE64_SUCCESS, ret); - for (int i = 0; i < (int)data_out_size; ++i) { - TEST_ASSERT_MESSAGE(data_out[i] == expected[i], \ - "decoding failed!(produced unexpected output)"); - } + TEST_ASSERT_MESSAGE((0 == memcmp(expected, data_out, data_out_size)), + "decoding failed!(produced unexpected output)"); #if (TEST_BASE64_SHOW_OUTPUT == 1) puts("Test 11 Decoded:"); - for (int i = 0; i < (int)data_out_size; ++i) { + for (size_t i = 0; i < data_out_size; ++i) { printf("%x", data_out[i]); } - printf("\nFrom:\n%x\n", (char *)encoded_base64); + printf("\nFrom:\n%s\n", encoded_base64); #endif } +static void test_base64_13_size_estimation(void) { + size_t expected = 0; + for (size_t i = 0; i < 33; i += 3) { + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_encode_size(i + 0)); + expected += 4; + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_encode_size(i + 1)); + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_encode_size(i + 2)); + } + + expected = 0; + for (size_t i = 0; i < 44; i += 4) { + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_decode_size(i + 0)); + expected += 3; + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_decode_size(i + 1)); + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_decode_size(i + 2)); + TEST_ASSERT_EQUAL_INT(expected, base64_estimate_decode_size(i + 3)); + } +} + Test *tests_base64_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { @@ -500,6 +514,7 @@ Test *tests_base64_tests(void) new_TestFixture(test_base64_10_decode_empty), new_TestFixture(test_base64_11_urlsafe_encode_int), new_TestFixture(test_base64_12_urlsafe_decode_int), + new_TestFixture(test_base64_13_size_estimation), }; EMB_UNIT_TESTCALLER(base64_tests, NULL, NULL, fixtures);