Mercurial > libbase64
changeset 24:90760aa2e7ed
base64: support binary data
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 26 Mar 2020 08:41:12 +0100 |
parents | fe5437c0fa3d |
children | 3172e43c9b43 |
files | base64.c base64.h test/base64.c |
diffstat | 3 files changed, 72 insertions(+), 71 deletions(-) [+] |
line wrap: on
line diff
--- a/base64.c Wed Mar 25 16:54:36 2020 +0100 +++ b/base64.c Thu Mar 26 08:41:12 2020 +0100 @@ -79,19 +79,24 @@ } size_t -b64_encode(const char src[], char dst[], size_t dstsz) +b64_encode(const char src[], size_t srcsz, char dst[], size_t dstsz) { assert(src); assert(dst); + if (srcsz == 0) + srcsz = strlen(src); + size_t nwritten = 0; - while (*src && dstsz) { + while (srcsz && dstsz) { char inputbuf[3] = { 0 }; int count = 0; - while (*src && count < 3) + while (srcsz && count < 3) { inputbuf[count++] = *src++; + --srcsz; + } if (dstsz < 4) { errno = ERANGE; @@ -129,25 +134,29 @@ } size_t -b64_decode(const char src[], char dst[], size_t dstsz) +b64_decode(const char src[], size_t srcsz, char dst[], size_t dstsz) { assert(src); assert(dst); + if (srcsz == 0) + srcsz = strlen(src); + size_t nwritten = 0; - while (*src && dstsz) { + while (srcsz && dstsz) { signed char inputbuf[4] = { -1, -1, -1, -1 }; int parsed = 0, required = 1; - for (; *src && parsed < 4; parsed++) { + for (; srcsz && parsed < 4; parsed++) { /* '=' is only allowed in last 2 characters. */ if ((*src == '=' && parsed <= 1) || !b64_isvalid(*src)) goto eilseq; if (b64_isbase64(*src)) inputbuf[parsed] = b64_rlookup(*src); - src++; + ++src; + --srcsz; } if (required >= dstsz)
--- a/base64.h Wed Mar 25 16:54:36 2020 +0100 +++ b/base64.h Thu Mar 26 08:41:12 2020 +0100 @@ -34,49 +34,6 @@ #endif /** - * \page Base64 Base64 - * \brief Base64 encoding and decoding. - * - * The C functions does not allocate memory by itself and therefore user must - * repeat the calls to the functions until all data has been processed. - * - * ## Encoding - * - * You can encode like this: - * - * ```c - * const char *data = "hello"; - * char tmpbuf[5]; - * - * // Note: data will be incremented, use a temporary variable if you need to - * // reuse it - * while (b64_encode_step(&data, tmpbuf)) - * printf("%s", tmpbuf); - * - * printf("\n"); - * ``` - * - * ## Decoding - * - * And you can decode like this: - * - * ```c - * const char *data = "aGVsbG8="; - * char tmpbuf[4]; - * - * // Note: data will be incremented, use a temporary variable if you need to - * // reuse it - * while (b64_decode_step(&data, tmpbuf)) - * printf("%s", tmpbuf); - * - * printf("\n"); - * - * if (errno != 0) - * perror("invalid sequence"); - * ``` - */ - -/** * Check if the character is a %base64 character, A-Za-z0-9 and +/. * * \param ch the character to test @@ -156,16 +113,21 @@ * This function will write at most dstsz bytes into the buffer, including the * NUL terminator. * + * If srcsz is 0 then strlen(src) is called to determine the number of bytes in + * src. Note that binary data may contain embedded 0 and therefore specifying + * the source size would be required in that case. + * * \pre src != NULL * \pre dst != NULL * \param src the source to encode + * \param srcsz the source size or 0 to read until NUL terminator * \param dst the destination buffer * \param dstsz the destination size * \return The number of bytes written or -1 on error and sets errno. * \see \ref b64_encode_length */ size_t -b64_encode(const char src[], char dst[], size_t dstsz); +b64_encode(const char src[], size_t srcsz, char dst[], size_t dstsz); /** * Decode the given src into the destination buffer. @@ -173,16 +135,20 @@ * This function will write at most dstsz bytes into the buffer, including the * NUL terminator. * + * If srcsz is 0 then strlen(src) is called to determine the number of bytes in + * src. + * * \pre src != NULL * \pre dst != NULL * \param src the source to encode + * \param srcsz the source size or 0 to read until NUL terminator * \param dst the destination buffer * \param dstsz the destination size * \return The number of bytes written or -1 on error and sets errno. * \see \ref b64_decode_length */ size_t -b64_decode(const char src[], char dst[], size_t dstsz); +b64_decode(const char src[], size_t srcsz, char dst[], size_t dstsz); #if defined(__cplusplus) }
--- a/test/base64.c Wed Mar 25 16:54:36 2020 +0100 +++ b/test/base64.c Thu Mar 26 08:41:12 2020 +0100 @@ -175,31 +175,43 @@ char buffer[BUFSIZ]; size_t r; - r = b64_encode("a", buffer, sizeof (buffer)); + r = b64_encode("a", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 4U); GREATEST_ASSERT_STR_EQ(buffer, "YQ=="); - r = b64_encode("ab", buffer, sizeof (buffer)); + r = b64_encode("ab", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 4U); GREATEST_ASSERT_STR_EQ(buffer, "YWI="); - r = b64_encode("abc", buffer, sizeof (buffer)); + r = b64_encode("abc", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 4U); GREATEST_ASSERT_STR_EQ(buffer, "YWJj"); - r = b64_encode("hello", buffer, sizeof (buffer)); + r = b64_encode("hello", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 8U); GREATEST_ASSERT_STR_EQ(buffer, "aGVsbG8="); - r = b64_encode("this is a long sentence", buffer, sizeof (buffer)); + r = b64_encode("this is a long sentence", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 32U); GREATEST_ASSERT_STR_EQ(buffer, "dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U="); GREATEST_PASS(); } GREATEST_TEST +test_b64_encode_binary(void) +{ + char buffer[BUFSIZ]; + size_t r; + + r = b64_encode("a\0bc", 4, buffer, sizeof (buffer)); + GREATEST_ASSERT_EQ(r, 8U); + GREATEST_ASSERT_STR_EQ(buffer, "YQBiYw=="); + GREATEST_PASS(); +} + +GREATEST_TEST test_b64_encode_toosmall(void) { char buffer[10]; size_t r; - r = b64_encode("hello world", buffer, sizeof (buffer)); + r = b64_encode("hello world", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, ERANGE); GREATEST_PASS(); @@ -208,6 +220,7 @@ GREATEST_SUITE(suite_b64_encode) { GREATEST_RUN_TEST(test_b64_encode_basic); + GREATEST_RUN_TEST(test_b64_encode_binary); GREATEST_RUN_TEST(test_b64_encode_toosmall); } @@ -265,49 +278,61 @@ char buffer[BUFSIZ]; size_t r; - r = b64_decode("YQ==", buffer, sizeof (buffer)); + r = b64_decode("YQ==", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 1U); GREATEST_ASSERT_STR_EQ(buffer, "a"); - r = b64_decode("YWI=", buffer, sizeof (buffer)); + r = b64_decode("YWI=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 2U); GREATEST_ASSERT_STR_EQ(buffer, "ab"); - r = b64_decode("YWJj", buffer, sizeof (buffer)); + r = b64_decode("YWJj", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 3U); GREATEST_ASSERT_STR_EQ(buffer, "abc"); - r = b64_decode("aGVsbG8=", buffer, sizeof (buffer)); + r = b64_decode("aGVsbG8=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 5U); GREATEST_ASSERT_STR_EQ(buffer, "hello"); - r = b64_decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=", buffer, sizeof (buffer)); + r = b64_decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 23U); GREATEST_ASSERT_STR_EQ(buffer, "this is a long sentence"); - r = b64_decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=", buffer, sizeof (buffer)); + r = b64_decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, 26U); GREATEST_ASSERT_STR_EQ(buffer, "Welcome to our server dude"); GREATEST_PASS(); } GREATEST_TEST +test_b64_decode_sized(void) +{ + char buffer[BUFSIZ]; + size_t r; + + r = b64_decode("YQ== ", 4, buffer, sizeof (buffer)); + GREATEST_ASSERT_EQ(r, 1U); + GREATEST_ASSERT_STR_EQ(buffer, "a"); + GREATEST_PASS(); +} + +GREATEST_TEST test_b64_decode_invalid(void) { char buffer[BUFSIZ]; size_t r; - r = b64_decode("YW=", buffer, sizeof (buffer)); + r = b64_decode("YW=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); - r = b64_decode("?!", buffer, sizeof (buffer)); + r = b64_decode("?!", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); - r = b64_decode("=ABC", buffer, sizeof (buffer)); + r = b64_decode("=ABC", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); - r = b64_decode("A=BC", buffer, sizeof (buffer)); + r = b64_decode("A=BC", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); - r = b64_decode("==BC", buffer, sizeof (buffer)); + r = b64_decode("==BC", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); - r = b64_decode("AB=C", buffer, sizeof (buffer)); + r = b64_decode("AB=C", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, EILSEQ); GREATEST_PASS(); @@ -319,7 +344,7 @@ char buffer[10]; size_t r; - r = b64_decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=", buffer, sizeof (buffer)); + r = b64_decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=", 0, buffer, sizeof (buffer)); GREATEST_ASSERT_EQ(r, (size_t)-1); GREATEST_ASSERT_EQ(errno, ERANGE); GREATEST_PASS(); @@ -328,6 +353,7 @@ GREATEST_SUITE(suite_b64_decode) { GREATEST_RUN_TEST(test_b64_decode_basic); + GREATEST_RUN_TEST(test_b64_decode_sized); GREATEST_RUN_TEST(test_b64_decode_invalid); GREATEST_RUN_TEST(test_b64_decode_toosmall); }