diff --git a/tests/main.c b/tests/main.c index 2cbdcaf..4d55e3f 100644 --- a/tests/main.c +++ b/tests/main.c @@ -37,6 +37,26 @@ static MunitResult test_hex_to_base64(const MunitParameter params[], return MUNIT_OK; } +static MunitResult test_base64_decode(const MunitParameter params[], + void *data) { + (void)params; + (void)data; + + const char *input = "TWFu"; + unsigned char buf[512] = {0}; + size_t len = base64_to_bytes(buf, input); + assert_string_equal((char *)buf, "Man"); + assert_size(len, ==, 3); + + const char *input2 = "WUVMTE9XIFNVQk1BUklORQ=="; + memset(buf, 0, 512); + len = base64_to_bytes(buf, input2); + assert_string_equal((char *)buf, "YELLOW SUBMARINE"); + assert_size(len, ==, 18); // the 2 = create two bytes of padding at the end + + return MUNIT_OK; +} + static MunitResult test_frequency_score(const MunitParameter params[], void *data) { (void)params; @@ -73,6 +93,8 @@ static MunitTest test_suite_tests[] = { NULL}, {"/hex_to_base64", test_hex_to_base64, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, + {"/base64_decode", test_base64_decode, NULL, NULL, MUNIT_TEST_OPTION_NONE, + NULL}, {"/frequency_score", test_frequency_score, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, {"/hamming", test_hamming, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL}, diff --git a/utils.c b/utils.c index d4aef38..3d53b69 100644 --- a/utils.c +++ b/utils.c @@ -36,10 +36,10 @@ size_t hex_to_bytes(unsigned char *out, const char hex[static 1]) { return strlen(hex) / 2 + strlen(hex) % 2; } -char *bytes_to_base64(char *out, const unsigned char in[static 1], size_t len) { - static const char base64_table[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char *bytes_to_base64(char *out, const unsigned char in[static 1], size_t len) { for (size_t i = 0; i < len - 2; i += 3) { size_t j = i / 3 * 4; out[j] = base64_table[in[i] >> 2]; @@ -50,6 +50,42 @@ char *bytes_to_base64(char *out, const unsigned char in[static 1], size_t len) { return out; } +size_t base64_to_bytes(unsigned char *out, const char *in) { + char decoding_table[256] = {0}; + for (size_t i = 0; i < 64; ++i) { + decoding_table[(unsigned char)base64_table[i]] = i; + } + + size_t in_length = strlen(in); + if (in_length % 4 != 0) { + return 0; + } + + size_t i = 0; + for (size_t j = 0; j < in_length - 3;) { + unsigned char sextet1 = + in[j] == '=' ? 0 : decoding_table[(unsigned char)in[j]]; + unsigned char sextet2 = + in[j + 1] == '=' ? 0 : decoding_table[(unsigned char)in[j + 1]]; + unsigned char sextet3 = + in[j + 2] == '=' ? 0 : decoding_table[(unsigned char)in[j + 2]]; + unsigned char sextet4 = + in[j + 3] == '=' ? 0 : decoding_table[(unsigned char)in[j + 3]]; + + out[i] = sextet1 << 2; + out[i] += sextet2 >> 4; + out[i + 1] = sextet2 << 4; + out[i + 1] += sextet3 >> 2; + out[i + 2] = sextet3 << 6; + out[i + 2] += sextet4; + + j += 4; + i += 3; + } + + return i; +} + double frequency_score(const char *buf, size_t len) { static const double english_freqs[27] = { 0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015, // A-G diff --git a/utils.h b/utils.h index 4cb4d2a..9b3faec 100644 --- a/utils.h +++ b/utils.h @@ -6,6 +6,7 @@ unsigned char hex_to_byte(const char c); size_t hex_to_bytes(unsigned char *out, const char hex[static 1]); char *bytes_to_base64(char *out, const unsigned char in[static 1], size_t len); +size_t base64_to_bytes(unsigned char *out, const char *in); double frequency_score(const char *buf, size_t len); unsigned int hamming(const char *s1, const char *s2);