changeset 19:436f5c3243bf

Add C implementation While here, update years
author David Demelier <markand@malikania.fr>
date Fri, 24 Jan 2020 13:57:48 +0100
parents bdc4fde21426
children 26eacf43ea9e
files CMakeLists.txt INSTALL.md LICENSE.md README.md base64.c base64.h base64.hpp doc/mainpage.cpp test/base64++.cpp test/base64.cpp test/main.cpp
diffstat 11 files changed, 818 insertions(+), 236 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Oct 05 19:32:09 2018 +0200
+++ b/CMakeLists.txt	Fri Jan 24 13:57:48 2020 +0100
@@ -17,11 +17,14 @@
 #
 
 cmake_minimum_required(VERSION 3.5)
-project(base64 CXX)
+project(base64)
 
 set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED On)
 
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED On)
+
 set(BASE64_VERSION_MAJOR "2")
 set(BASE64_VERSION_MINOR "0")
 set(BASE64_VERSION_PATCH "0")
@@ -31,19 +34,30 @@
 find_package(Boost REQUIRED unit_test_framework)
 
 enable_testing()
+
+# C code.
 add_executable(
 	base64
-	${base64_SOURCE_DIR}/base64.hpp
-	${base64_SOURCE_DIR}/test/main.cpp
-	${base64_SOURCE_DIR}/INSTALL.md
-	${base64_SOURCE_DIR}/LICENSE.md
-	${base64_SOURCE_DIR}/README.md
+	${base64_SOURCE_DIR}/base64.h
+	${base64_SOURCE_DIR}/base64.c
+	${base64_SOURCE_DIR}/test/base64.cpp
 )
 target_link_libraries(base64 Boost::unit_test_framework)
 target_include_directories(base64 PRIVATE ${base64_SOURCE_DIR})
 target_compile_definitions(base64 PRIVATE BOOST_TEST_DYN_LINK)
 add_test(NAME base64 COMMAND base64)
 
+# C++ code.
+add_executable(
+	base64++
+	${base64_SOURCE_DIR}/base64.hpp
+	${base64_SOURCE_DIR}/test/base64++.cpp
+)
+target_link_libraries(base64++ Boost::unit_test_framework)
+target_include_directories(base64++ PRIVATE ${base64_SOURCE_DIR})
+target_compile_definitions(base64++ PRIVATE BOOST_TEST_DYN_LINK)
+add_test(NAME base64++ COMMAND base64++)
+
 if (DOXYGEN_FOUND)
 	set(DOXYGEN_PROJECT_NAME base64)
 	set(DOXYGEN_PROJECT_NUMBER ${BASE64_VERSION})
@@ -56,8 +70,7 @@
 		doxygen
 		${base64_SOURCE_DIR}/doc/mainpage.cpp
 		${base64_SOURCE_DIR}/base64.hpp
+		${base64_SOURCE_DIR}/base64.h
 		WORKING_DIRECTORY ${base64_SOURCE_DIR}
 	)
-
-	add_dependencies(base64 doxygen)
 endif ()
--- a/INSTALL.md	Fri Oct 05 19:32:09 2018 +0200
+++ b/INSTALL.md	Fri Jan 24 13:57:48 2020 +0100
@@ -1,12 +1,18 @@
-libbase64++ -- installation instructions
-========================================
+libbase64 -- installation instructions
+======================================
 
 Requirements
 ------------
 
-  - C++17.
+- C++17.
+- C99.
 
-Installation
-------------
+Installation (C++ variant)
+--------------------------
 
 Just copy the file base64.hpp and add it to your project.
+
+Installation (C variant)
+------------------------
+
+Copy base64.h and base64.c to your project.
--- a/LICENSE.md	Fri Oct 05 19:32:09 2018 +0200
+++ b/LICENSE.md	Fri Jan 24 13:57:48 2020 +0100
@@ -1,5 +1,5 @@
-libbase64++ -- license
-======================
+libbase64 -- license
+====================
 
 Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
 
--- a/README.md	Fri Oct 05 19:32:09 2018 +0200
+++ b/README.md	Fri Jan 24 13:57:48 2020 +0100
@@ -1,7 +1,7 @@
-libbase64++ -- Base64 encoding and decoding
-===========================================
+libbase64 -- Base64 encoding and decoding
+=========================================
 
 Introduction
 ------------
 
-Base64 encoding and decoding easily in C++17.
+Base64 encoding and decoding easily in C++17 or C99.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base64.c	Fri Jan 24 13:57:48 2020 +0100
@@ -0,0 +1,134 @@
+/*
+ * base64.h -- base64 encoding and decoding
+ *
+ * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "base64.h"
+
+static bool
+invalid(void)
+{
+	errno = EILSEQ;
+	return false;
+}
+
+bool
+b64_isbase64(unsigned char ch)
+{
+	return isalnum(ch) || ch == '+' || ch == '/';
+}
+
+bool
+b64_isvalid(unsigned char ch)
+{
+	return b64_isbase64(ch) || ch == '=';
+}
+
+unsigned char
+b64_lookup(unsigned char value)
+{
+	assert(value < 64);
+
+	static const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+	return table[value];
+}
+
+unsigned char
+b64_rlookup(unsigned char ch)
+{
+	assert(b64_isbase64(ch));
+
+	if (ch >= '0' && ch <= '9')
+		return ch + 4;
+	if (ch >= 'A' && ch <= 'Z')
+		return ch - 65;
+	if (ch >= 'a' && ch <= 'z')
+		return ch - 71;
+
+	return ch == '+' ? 62U : 63U;
+}
+
+bool
+b64_encode_step(const char **pch, char *output)
+{
+	assert(pch);
+	assert(output);
+
+	if (!**pch)
+		return false;
+
+	char inputbuf[3] = { 0 };
+	int count = 0;
+
+	output[0] = output[1] = output[2] = output[3] = output[4] = 0;
+
+	while (**pch && count < 3)
+		inputbuf[count++] = *(*pch)++;
+
+	output[0] = b64_lookup(inputbuf[0] >> 2 & 0x3f);
+	output[1] = b64_lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f));
+	output[2] = (count < 2) ? '=' : b64_lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03));
+	output[3] = (count < 3) ? '=' : b64_lookup(inputbuf[2] & 0x3f);
+
+	return count > 0;
+}
+
+bool
+b64_decode_step(const char **pch, char *output)
+{
+	assert(pch);
+	assert(output);
+
+	if (!**pch)
+		return false;
+
+	char inputbuf[4] = { -1, -1, -1, -1 };
+	int count = 0;
+
+	errno = output[0] = output[1] = output[2] = output[3] = 0;
+
+	for (; **pch && count < 4; count++) {
+		// Check if the character is valid and get its value.
+		if ((**pch == '=' && count <= 1) || !b64_isvalid(**pch))
+			return invalid();
+		if (b64_isbase64(**pch))
+			inputbuf[count] = b64_rlookup(**pch);
+
+		(*pch)++;
+	}
+
+	if (count != 4)
+		return invalid();
+
+	output[0] = ((inputbuf[0] << 2) & 0xfc) | ((inputbuf[1] >> 4) & 0x03);
+
+	if (inputbuf[2] != -1)
+		output[1] = ((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f);
+	if (inputbuf[3] != -1) {
+		// "XY=Z" is not allowed.
+		if (inputbuf[2] == -1)
+			return invalid();
+
+		output[2] = ((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f);
+	}
+
+	return count > 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/base64.h	Fri Jan 24 13:57:48 2020 +0100
@@ -0,0 +1,165 @@
+/*
+ * base64.h -- base64 encoding and decoding
+ *
+ * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+/**
+ * \file base64.h
+ * \brief Base64 encoding and decoding.
+ * \author David Demelier <markand@malikania.fr>
+ * \version 2.0.0-dev
+ */
+
+#include <stdbool.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#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:
+ *
+ * ```
+ * 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
+ * \return true if valid
+ */
+bool
+b64_isbase64(unsigned char ch);
+
+/**
+ * Check if the given character is a valid character in %base64 string,
+ * including '='.
+ *
+ * \param ch the character
+ * \return true if the character is valid
+ */
+bool
+b64_isvalid(unsigned char ch);
+
+/**
+ * Get the %base64 character from the 6-bits value.
+ *
+ * \pre value must be valid (< 64)
+ * \param value the value
+ * \return the %base64 character for value
+ */
+unsigned char
+b64_lookup(unsigned char value);
+
+/**
+ * Get the integer value from the %base64 character.
+ *
+ * \pre is_base64(ch)
+ * \param ch the %base64 character
+ * \return the integer value for the %base64 character ch
+ * ````
+ * auto b64 = base64::rlookup('D') // 3
+ * ````
+ */
+unsigned char
+b64_rlookup(unsigned char ch);
+
+/**
+ * Encode some piece of data into the given output.
+ *
+ * The pointer pch will be incremented after the last character that was
+ * treated for input, user is responsible to call this function until the whole
+ * string was encoded.
+ *
+ * The parameter output will be filled with four characters plus the nul
+ * terminator and must have enough room to store them. This function will
+ * append a nul terminator.
+ *
+ * \pre pch != NULL
+ * \pre output != NULL and must have at least five bytes available
+ * \param pch pointer to pointer to char to consume
+ * \param output output string
+ * \return true if the string was fully consumed
+ */
+bool
+b64_encode_step(const char **pch, char *output);
+
+/**
+ * Encode some data into the given output.
+ *
+ * Similar to b64_encode_step, this function requires successive call until the
+ * input string has been consumed.
+ *
+ * The parameter output will be filled with at most three characters plus the
+ * nul terminator and must have enough room to store them. This function will
+ * append a nul terminator.
+ *
+ * In case of invalid sequence, errno is set and the function returns false.
+ *
+ * \pre pch != NULL
+ * \pre output != NULL and must have at least four bytes available
+ * \param pch pointer to pointer to char to consume
+ * \param output output string
+ * \return true if the string was fully consumed
+ */
+bool
+b64_decode_step(const char **pch, char *output);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // !BASE64_H
--- a/base64.hpp	Fri Oct 05 19:32:09 2018 +0200
+++ b/base64.hpp	Fri Jan 24 13:57:48 2020 +0100
@@ -1,7 +1,7 @@
 /*
  * base64.hpp -- base64 encoding and decoding
  *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
--- a/doc/mainpage.cpp	Fri Oct 05 19:32:09 2018 +0200
+++ b/doc/mainpage.cpp	Fri Jan 24 13:57:48 2020 +0100
@@ -5,23 +5,45 @@
  *
  * ## Introduction
  *
- * This code allows you to encode and decode %base64 data in C++ as easy as
- * possible.
+ * This code allows you to encode and decode %base64 data in C or C++ as easy
+ * as possible.
  *
- * ## Installation
+ * ## Usage (C++ variant)
  *
- * Just copy the file base64.hpp and add it to your project.
+ * Just copy the file base64.hpp and add it to your project. It does not depend
+ * on the C files.
  *
- * ## Overview
+ * ### Overview
  *
- * ````
+ * ```
  * #include "base64.hpp"
  *
- * int main(void)
+ * int main()
  * {
  * 	base64::encode("Hello World!");
- *
- * 	return 0;
  * }
- * ````
+ * ```
+ *
+ * ## Usage (C variant)
+ *
+ * Copy the base64.h and base64.c files into your projects.
+ *
+ * ### Overview
+ *
+ * ```
+ * #include "base64.p"
+ *
+ * int
+ * main(void)
+ * {
+ * 	const char *str = "Hello World!");
+ * 	const char *p = str;
+ * 	char buffer[5];
+ *
+ * 	while (b64_encode_step(&p, buffer))
+ * 		printf("%s", buffer);
+ *
+ * 	printf("\n");
+ * }
+ * ```
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/base64++.cpp	Fri Jan 24 13:57:48 2020 +0100
@@ -0,0 +1,207 @@
+/*
+ * base64++.cpp -- main test file for base64 (C++ version)
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "libbase64"
+#include <boost/test/unit_test.hpp>
+
+#include <base64.hpp>
+
+BOOST_AUTO_TEST_CASE(lookup)
+{
+	BOOST_TEST(base64::lookup(0b000000) == 'A');
+	BOOST_TEST(base64::lookup(0b000001) == 'B');
+	BOOST_TEST(base64::lookup(0b000010) == 'C');
+	BOOST_TEST(base64::lookup(0b000011) == 'D');
+	BOOST_TEST(base64::lookup(0b000100) == 'E');
+	BOOST_TEST(base64::lookup(0b000101) == 'F');
+	BOOST_TEST(base64::lookup(0b000110) == 'G');
+	BOOST_TEST(base64::lookup(0b000111) == 'H');
+	BOOST_TEST(base64::lookup(0b001000) == 'I');
+	BOOST_TEST(base64::lookup(0b001001) == 'J');
+	BOOST_TEST(base64::lookup(0b001010) == 'K');
+	BOOST_TEST(base64::lookup(0b001011) == 'L');
+	BOOST_TEST(base64::lookup(0b001100) == 'M');
+	BOOST_TEST(base64::lookup(0b001101) == 'N');
+	BOOST_TEST(base64::lookup(0b001110) == 'O');
+	BOOST_TEST(base64::lookup(0b001111) == 'P');
+	BOOST_TEST(base64::lookup(0b010000) == 'Q');
+	BOOST_TEST(base64::lookup(0b010001) == 'R');
+	BOOST_TEST(base64::lookup(0b010010) == 'S');
+	BOOST_TEST(base64::lookup(0b010011) == 'T');
+	BOOST_TEST(base64::lookup(0b010100) == 'U');
+	BOOST_TEST(base64::lookup(0b010101) == 'V');
+	BOOST_TEST(base64::lookup(0b010110) == 'W');
+	BOOST_TEST(base64::lookup(0b010111) == 'X');
+	BOOST_TEST(base64::lookup(0b011000) == 'Y');
+	BOOST_TEST(base64::lookup(0b011001) == 'Z');
+	BOOST_TEST(base64::lookup(0b011010) == 'a');
+	BOOST_TEST(base64::lookup(0b011011) == 'b');
+	BOOST_TEST(base64::lookup(0b011100) == 'c');
+	BOOST_TEST(base64::lookup(0b011101) == 'd');
+	BOOST_TEST(base64::lookup(0b011110) == 'e');
+	BOOST_TEST(base64::lookup(0b011111) == 'f');
+	BOOST_TEST(base64::lookup(0b100000) == 'g');
+	BOOST_TEST(base64::lookup(0b100001) == 'h');
+	BOOST_TEST(base64::lookup(0b100010) == 'i');
+	BOOST_TEST(base64::lookup(0b100011) == 'j');
+	BOOST_TEST(base64::lookup(0b100100) == 'k');
+	BOOST_TEST(base64::lookup(0b100101) == 'l');
+	BOOST_TEST(base64::lookup(0b100110) == 'm');
+	BOOST_TEST(base64::lookup(0b100111) == 'n');
+	BOOST_TEST(base64::lookup(0b101000) == 'o');
+	BOOST_TEST(base64::lookup(0b101001) == 'p');
+	BOOST_TEST(base64::lookup(0b101010) == 'q');
+	BOOST_TEST(base64::lookup(0b101011) == 'r');
+	BOOST_TEST(base64::lookup(0b101100) == 's');
+	BOOST_TEST(base64::lookup(0b101101) == 't');
+	BOOST_TEST(base64::lookup(0b101110) == 'u');
+	BOOST_TEST(base64::lookup(0b101111) == 'v');
+	BOOST_TEST(base64::lookup(0b110000) == 'w');
+	BOOST_TEST(base64::lookup(0b110001) == 'x');
+	BOOST_TEST(base64::lookup(0b110010) == 'y');
+	BOOST_TEST(base64::lookup(0b110011) == 'z');
+	BOOST_TEST(base64::lookup(0b110100) == '0');
+	BOOST_TEST(base64::lookup(0b110101) == '1');
+	BOOST_TEST(base64::lookup(0b110110) == '2');
+	BOOST_TEST(base64::lookup(0b110111) == '3');
+	BOOST_TEST(base64::lookup(0b111000) == '4');
+	BOOST_TEST(base64::lookup(0b111001) == '5');
+	BOOST_TEST(base64::lookup(0b111010) == '6');
+	BOOST_TEST(base64::lookup(0b111011) == '7');
+	BOOST_TEST(base64::lookup(0b111100) == '8');
+	BOOST_TEST(base64::lookup(0b111101) == '9');
+	BOOST_TEST(base64::lookup(0b111110) == '+');
+	BOOST_TEST(base64::lookup(0b111111) == '/');
+}
+
+BOOST_AUTO_TEST_CASE(rlookup)
+{
+	BOOST_TEST(base64::rlookup('A') == 0b000000U);
+	BOOST_TEST(base64::rlookup('B') == 0b000001U);
+	BOOST_TEST(base64::rlookup('C') == 0b000010U);
+	BOOST_TEST(base64::rlookup('D') == 0b000011U);
+	BOOST_TEST(base64::rlookup('E') == 0b000100U);
+	BOOST_TEST(base64::rlookup('F') == 0b000101U);
+	BOOST_TEST(base64::rlookup('G') == 0b000110U);
+	BOOST_TEST(base64::rlookup('H') == 0b000111U);
+	BOOST_TEST(base64::rlookup('I') == 0b001000U);
+	BOOST_TEST(base64::rlookup('J') == 0b001001U);
+	BOOST_TEST(base64::rlookup('K') == 0b001010U);
+	BOOST_TEST(base64::rlookup('L') == 0b001011U);
+	BOOST_TEST(base64::rlookup('M') == 0b001100U);
+	BOOST_TEST(base64::rlookup('N') == 0b001101U);
+	BOOST_TEST(base64::rlookup('O') == 0b001110U);
+	BOOST_TEST(base64::rlookup('P') == 0b001111U);
+	BOOST_TEST(base64::rlookup('Q') == 0b010000U);
+	BOOST_TEST(base64::rlookup('R') == 0b010001U);
+	BOOST_TEST(base64::rlookup('S') == 0b010010U);
+	BOOST_TEST(base64::rlookup('T') == 0b010011U);
+	BOOST_TEST(base64::rlookup('U') == 0b010100U);
+	BOOST_TEST(base64::rlookup('V') == 0b010101U);
+	BOOST_TEST(base64::rlookup('W') == 0b010110U);
+	BOOST_TEST(base64::rlookup('X') == 0b010111U);
+	BOOST_TEST(base64::rlookup('Y') == 0b011000U);
+	BOOST_TEST(base64::rlookup('Z') == 0b011001U);
+	BOOST_TEST(base64::rlookup('a') == 0b011010U);
+	BOOST_TEST(base64::rlookup('b') == 0b011011U);
+	BOOST_TEST(base64::rlookup('c') == 0b011100U);
+	BOOST_TEST(base64::rlookup('d') == 0b011101U);
+	BOOST_TEST(base64::rlookup('e') == 0b011110U);
+	BOOST_TEST(base64::rlookup('f') == 0b011111U);
+	BOOST_TEST(base64::rlookup('g') == 0b100000U);
+	BOOST_TEST(base64::rlookup('h') == 0b100001U);
+	BOOST_TEST(base64::rlookup('i') == 0b100010U);
+	BOOST_TEST(base64::rlookup('j') == 0b100011U);
+	BOOST_TEST(base64::rlookup('k') == 0b100100U);
+	BOOST_TEST(base64::rlookup('l') == 0b100101U);
+	BOOST_TEST(base64::rlookup('m') == 0b100110U);
+	BOOST_TEST(base64::rlookup('n') == 0b100111U);
+	BOOST_TEST(base64::rlookup('o') == 0b101000U);
+	BOOST_TEST(base64::rlookup('p') == 0b101001U);
+	BOOST_TEST(base64::rlookup('q') == 0b101010U);
+	BOOST_TEST(base64::rlookup('r') == 0b101011U);
+	BOOST_TEST(base64::rlookup('s') == 0b101100U);
+	BOOST_TEST(base64::rlookup('t') == 0b101101U);
+	BOOST_TEST(base64::rlookup('u') == 0b101110U);
+	BOOST_TEST(base64::rlookup('v') == 0b101111U);
+	BOOST_TEST(base64::rlookup('w') == 0b110000U);
+	BOOST_TEST(base64::rlookup('x') == 0b110001U);
+	BOOST_TEST(base64::rlookup('y') == 0b110010U);
+	BOOST_TEST(base64::rlookup('z') == 0b110011U);
+	BOOST_TEST(base64::rlookup('0') == 0b110100U);
+	BOOST_TEST(base64::rlookup('1') == 0b110101U);
+	BOOST_TEST(base64::rlookup('2') == 0b110110U);
+	BOOST_TEST(base64::rlookup('3') == 0b110111U);
+	BOOST_TEST(base64::rlookup('4') == 0b111000U);
+	BOOST_TEST(base64::rlookup('5') == 0b111001U);
+	BOOST_TEST(base64::rlookup('6') == 0b111010U);
+	BOOST_TEST(base64::rlookup('7') == 0b111011U);
+	BOOST_TEST(base64::rlookup('8') == 0b111100U);
+	BOOST_TEST(base64::rlookup('9') == 0b111101U);
+	BOOST_TEST(base64::rlookup('+') == 0b111110U);
+	BOOST_TEST(base64::rlookup('/') == 0b111111U);
+}
+
+BOOST_AUTO_TEST_CASE(encode)
+{
+	BOOST_TEST(base64::encode("a") == "YQ==");
+	BOOST_TEST(base64::encode("ab") == "YWI=");
+	BOOST_TEST(base64::encode("abc") == "YWJj");
+	BOOST_TEST(base64::encode("hello") == "aGVsbG8=");
+	BOOST_TEST(base64::encode("this is a long sentence") == "dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=");
+}
+
+BOOST_AUTO_TEST_CASE(decode)
+{
+	BOOST_TEST(base64::decode("YQ==") == "a");
+	BOOST_TEST(base64::decode("YWI=") == "ab");
+	BOOST_TEST(base64::decode("YWJj") == "abc");
+	BOOST_TEST(base64::decode("aGVsbG8=") == "hello");
+	BOOST_TEST(base64::decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=") == "this is a long sentence");
+	BOOST_TEST(base64::decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=") == "Welcome to our server dude");
+}
+
+BOOST_AUTO_TEST_CASE(truncated)
+{
+	BOOST_REQUIRE_THROW(base64::decode("YW="), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	BOOST_REQUIRE_THROW(base64::decode("?!"), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(wrong1)
+{
+	BOOST_REQUIRE_THROW(base64::decode("=ABC"), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(wrong2)
+{
+	BOOST_REQUIRE_THROW(base64::decode("A=BC"), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(wrong3)
+{
+	BOOST_REQUIRE_THROW(base64::decode("==BC"), std::invalid_argument);
+}
+
+BOOST_AUTO_TEST_CASE(wrong4)
+{
+	BOOST_REQUIRE_THROW(base64::decode("AB=C"), std::invalid_argument);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/base64.cpp	Fri Jan 24 13:57:48 2020 +0100
@@ -0,0 +1,242 @@
+/*
+ * base64.cpp -- main test file for base64 (C version)
+ *
+ * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define BOOST_TEST_MODULE "libbase64"
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+
+#include <base64.h>
+
+namespace {
+
+auto do_encode(const char *str) -> std::string
+{
+	std::string ret;
+	char buf[5];
+
+	while (b64_encode_step(&str, buf))
+		ret += buf;
+
+	return ret;
+}
+
+auto do_decode(const char *str) -> std::string
+{
+	std::string ret;
+	char buf[5];
+
+	while (b64_decode_step(&str, buf))
+		ret += buf;
+
+	return ret;
+}
+
+
+BOOST_AUTO_TEST_CASE(lookup)
+{
+	BOOST_TEST(b64_lookup(0b000000) == 'A');
+	BOOST_TEST(b64_lookup(0b000001) == 'B');
+	BOOST_TEST(b64_lookup(0b000010) == 'C');
+	BOOST_TEST(b64_lookup(0b000011) == 'D');
+	BOOST_TEST(b64_lookup(0b000100) == 'E');
+	BOOST_TEST(b64_lookup(0b000101) == 'F');
+	BOOST_TEST(b64_lookup(0b000110) == 'G');
+	BOOST_TEST(b64_lookup(0b000111) == 'H');
+	BOOST_TEST(b64_lookup(0b001000) == 'I');
+	BOOST_TEST(b64_lookup(0b001001) == 'J');
+	BOOST_TEST(b64_lookup(0b001010) == 'K');
+	BOOST_TEST(b64_lookup(0b001011) == 'L');
+	BOOST_TEST(b64_lookup(0b001100) == 'M');
+	BOOST_TEST(b64_lookup(0b001101) == 'N');
+	BOOST_TEST(b64_lookup(0b001110) == 'O');
+	BOOST_TEST(b64_lookup(0b001111) == 'P');
+	BOOST_TEST(b64_lookup(0b010000) == 'Q');
+	BOOST_TEST(b64_lookup(0b010001) == 'R');
+	BOOST_TEST(b64_lookup(0b010010) == 'S');
+	BOOST_TEST(b64_lookup(0b010011) == 'T');
+	BOOST_TEST(b64_lookup(0b010100) == 'U');
+	BOOST_TEST(b64_lookup(0b010101) == 'V');
+	BOOST_TEST(b64_lookup(0b010110) == 'W');
+	BOOST_TEST(b64_lookup(0b010111) == 'X');
+	BOOST_TEST(b64_lookup(0b011000) == 'Y');
+	BOOST_TEST(b64_lookup(0b011001) == 'Z');
+	BOOST_TEST(b64_lookup(0b011010) == 'a');
+	BOOST_TEST(b64_lookup(0b011011) == 'b');
+	BOOST_TEST(b64_lookup(0b011100) == 'c');
+	BOOST_TEST(b64_lookup(0b011101) == 'd');
+	BOOST_TEST(b64_lookup(0b011110) == 'e');
+	BOOST_TEST(b64_lookup(0b011111) == 'f');
+	BOOST_TEST(b64_lookup(0b100000) == 'g');
+	BOOST_TEST(b64_lookup(0b100001) == 'h');
+	BOOST_TEST(b64_lookup(0b100010) == 'i');
+	BOOST_TEST(b64_lookup(0b100011) == 'j');
+	BOOST_TEST(b64_lookup(0b100100) == 'k');
+	BOOST_TEST(b64_lookup(0b100101) == 'l');
+	BOOST_TEST(b64_lookup(0b100110) == 'm');
+	BOOST_TEST(b64_lookup(0b100111) == 'n');
+	BOOST_TEST(b64_lookup(0b101000) == 'o');
+	BOOST_TEST(b64_lookup(0b101001) == 'p');
+	BOOST_TEST(b64_lookup(0b101010) == 'q');
+	BOOST_TEST(b64_lookup(0b101011) == 'r');
+	BOOST_TEST(b64_lookup(0b101100) == 's');
+	BOOST_TEST(b64_lookup(0b101101) == 't');
+	BOOST_TEST(b64_lookup(0b101110) == 'u');
+	BOOST_TEST(b64_lookup(0b101111) == 'v');
+	BOOST_TEST(b64_lookup(0b110000) == 'w');
+	BOOST_TEST(b64_lookup(0b110001) == 'x');
+	BOOST_TEST(b64_lookup(0b110010) == 'y');
+	BOOST_TEST(b64_lookup(0b110011) == 'z');
+	BOOST_TEST(b64_lookup(0b110100) == '0');
+	BOOST_TEST(b64_lookup(0b110101) == '1');
+	BOOST_TEST(b64_lookup(0b110110) == '2');
+	BOOST_TEST(b64_lookup(0b110111) == '3');
+	BOOST_TEST(b64_lookup(0b111000) == '4');
+	BOOST_TEST(b64_lookup(0b111001) == '5');
+	BOOST_TEST(b64_lookup(0b111010) == '6');
+	BOOST_TEST(b64_lookup(0b111011) == '7');
+	BOOST_TEST(b64_lookup(0b111100) == '8');
+	BOOST_TEST(b64_lookup(0b111101) == '9');
+	BOOST_TEST(b64_lookup(0b111110) == '+');
+	BOOST_TEST(b64_lookup(0b111111) == '/');
+}
+
+BOOST_AUTO_TEST_CASE(rlookup)
+{
+	BOOST_TEST(b64_rlookup('A') == 0b000000U);
+	BOOST_TEST(b64_rlookup('B') == 0b000001U);
+	BOOST_TEST(b64_rlookup('C') == 0b000010U);
+	BOOST_TEST(b64_rlookup('D') == 0b000011U);
+	BOOST_TEST(b64_rlookup('E') == 0b000100U);
+	BOOST_TEST(b64_rlookup('F') == 0b000101U);
+	BOOST_TEST(b64_rlookup('G') == 0b000110U);
+	BOOST_TEST(b64_rlookup('H') == 0b000111U);
+	BOOST_TEST(b64_rlookup('I') == 0b001000U);
+	BOOST_TEST(b64_rlookup('J') == 0b001001U);
+	BOOST_TEST(b64_rlookup('K') == 0b001010U);
+	BOOST_TEST(b64_rlookup('L') == 0b001011U);
+	BOOST_TEST(b64_rlookup('M') == 0b001100U);
+	BOOST_TEST(b64_rlookup('N') == 0b001101U);
+	BOOST_TEST(b64_rlookup('O') == 0b001110U);
+	BOOST_TEST(b64_rlookup('P') == 0b001111U);
+	BOOST_TEST(b64_rlookup('Q') == 0b010000U);
+	BOOST_TEST(b64_rlookup('R') == 0b010001U);
+	BOOST_TEST(b64_rlookup('S') == 0b010010U);
+	BOOST_TEST(b64_rlookup('T') == 0b010011U);
+	BOOST_TEST(b64_rlookup('U') == 0b010100U);
+	BOOST_TEST(b64_rlookup('V') == 0b010101U);
+	BOOST_TEST(b64_rlookup('W') == 0b010110U);
+	BOOST_TEST(b64_rlookup('X') == 0b010111U);
+	BOOST_TEST(b64_rlookup('Y') == 0b011000U);
+	BOOST_TEST(b64_rlookup('Z') == 0b011001U);
+	BOOST_TEST(b64_rlookup('a') == 0b011010U);
+	BOOST_TEST(b64_rlookup('b') == 0b011011U);
+	BOOST_TEST(b64_rlookup('c') == 0b011100U);
+	BOOST_TEST(b64_rlookup('d') == 0b011101U);
+	BOOST_TEST(b64_rlookup('e') == 0b011110U);
+	BOOST_TEST(b64_rlookup('f') == 0b011111U);
+	BOOST_TEST(b64_rlookup('g') == 0b100000U);
+	BOOST_TEST(b64_rlookup('h') == 0b100001U);
+	BOOST_TEST(b64_rlookup('i') == 0b100010U);
+	BOOST_TEST(b64_rlookup('j') == 0b100011U);
+	BOOST_TEST(b64_rlookup('k') == 0b100100U);
+	BOOST_TEST(b64_rlookup('l') == 0b100101U);
+	BOOST_TEST(b64_rlookup('m') == 0b100110U);
+	BOOST_TEST(b64_rlookup('n') == 0b100111U);
+	BOOST_TEST(b64_rlookup('o') == 0b101000U);
+	BOOST_TEST(b64_rlookup('p') == 0b101001U);
+	BOOST_TEST(b64_rlookup('q') == 0b101010U);
+	BOOST_TEST(b64_rlookup('r') == 0b101011U);
+	BOOST_TEST(b64_rlookup('s') == 0b101100U);
+	BOOST_TEST(b64_rlookup('t') == 0b101101U);
+	BOOST_TEST(b64_rlookup('u') == 0b101110U);
+	BOOST_TEST(b64_rlookup('v') == 0b101111U);
+	BOOST_TEST(b64_rlookup('w') == 0b110000U);
+	BOOST_TEST(b64_rlookup('x') == 0b110001U);
+	BOOST_TEST(b64_rlookup('y') == 0b110010U);
+	BOOST_TEST(b64_rlookup('z') == 0b110011U);
+	BOOST_TEST(b64_rlookup('0') == 0b110100U);
+	BOOST_TEST(b64_rlookup('1') == 0b110101U);
+	BOOST_TEST(b64_rlookup('2') == 0b110110U);
+	BOOST_TEST(b64_rlookup('3') == 0b110111U);
+	BOOST_TEST(b64_rlookup('4') == 0b111000U);
+	BOOST_TEST(b64_rlookup('5') == 0b111001U);
+	BOOST_TEST(b64_rlookup('6') == 0b111010U);
+	BOOST_TEST(b64_rlookup('7') == 0b111011U);
+	BOOST_TEST(b64_rlookup('8') == 0b111100U);
+	BOOST_TEST(b64_rlookup('9') == 0b111101U);
+	BOOST_TEST(b64_rlookup('+') == 0b111110U);
+	BOOST_TEST(b64_rlookup('/') == 0b111111U);
+}
+
+BOOST_AUTO_TEST_CASE(encode)
+{
+	BOOST_TEST(do_encode("a") == "YQ==");
+	BOOST_TEST(do_encode("ab") == "YWI=");
+	BOOST_TEST(do_encode("abc") == "YWJj");
+	BOOST_TEST(do_encode("hello") == "aGVsbG8=");
+	BOOST_TEST(do_encode("this is a long sentence") == "dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=");
+}
+
+BOOST_AUTO_TEST_CASE(decode)
+{
+	BOOST_TEST(do_decode("YQ==") == "a");
+	BOOST_TEST(do_decode("YWI=") == "ab");
+	BOOST_TEST(do_decode("YWJj") == "abc");
+	BOOST_TEST(do_decode("aGVsbG8=") == "hello");
+	BOOST_TEST(do_decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=") == "this is a long sentence");
+	BOOST_TEST(do_decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=") == "Welcome to our server dude");
+}
+
+BOOST_AUTO_TEST_CASE(truncated)
+{
+	BOOST_TEST(do_decode("YW=").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+BOOST_AUTO_TEST_CASE(invalid)
+{
+	BOOST_TEST(do_decode("?!").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+BOOST_AUTO_TEST_CASE(wrong1)
+{
+	BOOST_TEST(do_decode("=ABC").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+BOOST_AUTO_TEST_CASE(wrong2)
+{
+	BOOST_TEST(do_decode("A=BC").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+BOOST_AUTO_TEST_CASE(wrong3)
+{
+	BOOST_TEST(do_decode("==BC").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+BOOST_AUTO_TEST_CASE(wrong4)
+{
+	BOOST_TEST(do_decode("AB=C").empty());
+	BOOST_TEST(errno == EILSEQ);
+}
+
+} // !namespace
--- a/test/main.cpp	Fri Oct 05 19:32:09 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-/*
- * main.cpp -- main test file for base64
- *
- * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#define BOOST_TEST_MODULE "libbase64"
-#include <boost/test/unit_test.hpp>
-
-#include <base64.hpp>
-
-BOOST_AUTO_TEST_CASE(lookup)
-{
-	BOOST_TEST(base64::lookup(0b000000) == 'A');
-	BOOST_TEST(base64::lookup(0b000001) == 'B');
-	BOOST_TEST(base64::lookup(0b000010) == 'C');
-	BOOST_TEST(base64::lookup(0b000011) == 'D');
-	BOOST_TEST(base64::lookup(0b000100) == 'E');
-	BOOST_TEST(base64::lookup(0b000101) == 'F');
-	BOOST_TEST(base64::lookup(0b000110) == 'G');
-	BOOST_TEST(base64::lookup(0b000111) == 'H');
-	BOOST_TEST(base64::lookup(0b001000) == 'I');
-	BOOST_TEST(base64::lookup(0b001001) == 'J');
-	BOOST_TEST(base64::lookup(0b001010) == 'K');
-	BOOST_TEST(base64::lookup(0b001011) == 'L');
-	BOOST_TEST(base64::lookup(0b001100) == 'M');
-	BOOST_TEST(base64::lookup(0b001101) == 'N');
-	BOOST_TEST(base64::lookup(0b001110) == 'O');
-	BOOST_TEST(base64::lookup(0b001111) == 'P');
-	BOOST_TEST(base64::lookup(0b010000) == 'Q');
-	BOOST_TEST(base64::lookup(0b010001) == 'R');
-	BOOST_TEST(base64::lookup(0b010010) == 'S');
-	BOOST_TEST(base64::lookup(0b010011) == 'T');
-	BOOST_TEST(base64::lookup(0b010100) == 'U');
-	BOOST_TEST(base64::lookup(0b010101) == 'V');
-	BOOST_TEST(base64::lookup(0b010110) == 'W');
-	BOOST_TEST(base64::lookup(0b010111) == 'X');
-	BOOST_TEST(base64::lookup(0b011000) == 'Y');
-	BOOST_TEST(base64::lookup(0b011001) == 'Z');
-	BOOST_TEST(base64::lookup(0b011010) == 'a');
-	BOOST_TEST(base64::lookup(0b011011) == 'b');
-	BOOST_TEST(base64::lookup(0b011100) == 'c');
-	BOOST_TEST(base64::lookup(0b011101) == 'd');
-	BOOST_TEST(base64::lookup(0b011110) == 'e');
-	BOOST_TEST(base64::lookup(0b011111) == 'f');
-	BOOST_TEST(base64::lookup(0b100000) == 'g');
-	BOOST_TEST(base64::lookup(0b100001) == 'h');
-	BOOST_TEST(base64::lookup(0b100010) == 'i');
-	BOOST_TEST(base64::lookup(0b100011) == 'j');
-	BOOST_TEST(base64::lookup(0b100100) == 'k');
-	BOOST_TEST(base64::lookup(0b100101) == 'l');
-	BOOST_TEST(base64::lookup(0b100110) == 'm');
-	BOOST_TEST(base64::lookup(0b100111) == 'n');
-	BOOST_TEST(base64::lookup(0b101000) == 'o');
-	BOOST_TEST(base64::lookup(0b101001) == 'p');
-	BOOST_TEST(base64::lookup(0b101010) == 'q');
-	BOOST_TEST(base64::lookup(0b101011) == 'r');
-	BOOST_TEST(base64::lookup(0b101100) == 's');
-	BOOST_TEST(base64::lookup(0b101101) == 't');
-	BOOST_TEST(base64::lookup(0b101110) == 'u');
-	BOOST_TEST(base64::lookup(0b101111) == 'v');
-	BOOST_TEST(base64::lookup(0b110000) == 'w');
-	BOOST_TEST(base64::lookup(0b110001) == 'x');
-	BOOST_TEST(base64::lookup(0b110010) == 'y');
-	BOOST_TEST(base64::lookup(0b110011) == 'z');
-	BOOST_TEST(base64::lookup(0b110100) == '0');
-	BOOST_TEST(base64::lookup(0b110101) == '1');
-	BOOST_TEST(base64::lookup(0b110110) == '2');
-	BOOST_TEST(base64::lookup(0b110111) == '3');
-	BOOST_TEST(base64::lookup(0b111000) == '4');
-	BOOST_TEST(base64::lookup(0b111001) == '5');
-	BOOST_TEST(base64::lookup(0b111010) == '6');
-	BOOST_TEST(base64::lookup(0b111011) == '7');
-	BOOST_TEST(base64::lookup(0b111100) == '8');
-	BOOST_TEST(base64::lookup(0b111101) == '9');
-	BOOST_TEST(base64::lookup(0b111110) == '+');
-	BOOST_TEST(base64::lookup(0b111111) == '/');
-}
-
-BOOST_AUTO_TEST_CASE(rlookup)
-{
-	BOOST_TEST(base64::rlookup('A') == 0b000000U);
-	BOOST_TEST(base64::rlookup('B') == 0b000001U);
-	BOOST_TEST(base64::rlookup('C') == 0b000010U);
-	BOOST_TEST(base64::rlookup('D') == 0b000011U);
-	BOOST_TEST(base64::rlookup('E') == 0b000100U);
-	BOOST_TEST(base64::rlookup('F') == 0b000101U);
-	BOOST_TEST(base64::rlookup('G') == 0b000110U);
-	BOOST_TEST(base64::rlookup('H') == 0b000111U);
-	BOOST_TEST(base64::rlookup('I') == 0b001000U);
-	BOOST_TEST(base64::rlookup('J') == 0b001001U);
-	BOOST_TEST(base64::rlookup('K') == 0b001010U);
-	BOOST_TEST(base64::rlookup('L') == 0b001011U);
-	BOOST_TEST(base64::rlookup('M') == 0b001100U);
-	BOOST_TEST(base64::rlookup('N') == 0b001101U);
-	BOOST_TEST(base64::rlookup('O') == 0b001110U);
-	BOOST_TEST(base64::rlookup('P') == 0b001111U);
-	BOOST_TEST(base64::rlookup('Q') == 0b010000U);
-	BOOST_TEST(base64::rlookup('R') == 0b010001U);
-	BOOST_TEST(base64::rlookup('S') == 0b010010U);
-	BOOST_TEST(base64::rlookup('T') == 0b010011U);
-	BOOST_TEST(base64::rlookup('U') == 0b010100U);
-	BOOST_TEST(base64::rlookup('V') == 0b010101U);
-	BOOST_TEST(base64::rlookup('W') == 0b010110U);
-	BOOST_TEST(base64::rlookup('X') == 0b010111U);
-	BOOST_TEST(base64::rlookup('Y') == 0b011000U);
-	BOOST_TEST(base64::rlookup('Z') == 0b011001U);
-	BOOST_TEST(base64::rlookup('a') == 0b011010U);
-	BOOST_TEST(base64::rlookup('b') == 0b011011U);
-	BOOST_TEST(base64::rlookup('c') == 0b011100U);
-	BOOST_TEST(base64::rlookup('d') == 0b011101U);
-	BOOST_TEST(base64::rlookup('e') == 0b011110U);
-	BOOST_TEST(base64::rlookup('f') == 0b011111U);
-	BOOST_TEST(base64::rlookup('g') == 0b100000U);
-	BOOST_TEST(base64::rlookup('h') == 0b100001U);
-	BOOST_TEST(base64::rlookup('i') == 0b100010U);
-	BOOST_TEST(base64::rlookup('j') == 0b100011U);
-	BOOST_TEST(base64::rlookup('k') == 0b100100U);
-	BOOST_TEST(base64::rlookup('l') == 0b100101U);
-	BOOST_TEST(base64::rlookup('m') == 0b100110U);
-	BOOST_TEST(base64::rlookup('n') == 0b100111U);
-	BOOST_TEST(base64::rlookup('o') == 0b101000U);
-	BOOST_TEST(base64::rlookup('p') == 0b101001U);
-	BOOST_TEST(base64::rlookup('q') == 0b101010U);
-	BOOST_TEST(base64::rlookup('r') == 0b101011U);
-	BOOST_TEST(base64::rlookup('s') == 0b101100U);
-	BOOST_TEST(base64::rlookup('t') == 0b101101U);
-	BOOST_TEST(base64::rlookup('u') == 0b101110U);
-	BOOST_TEST(base64::rlookup('v') == 0b101111U);
-	BOOST_TEST(base64::rlookup('w') == 0b110000U);
-	BOOST_TEST(base64::rlookup('x') == 0b110001U);
-	BOOST_TEST(base64::rlookup('y') == 0b110010U);
-	BOOST_TEST(base64::rlookup('z') == 0b110011U);
-	BOOST_TEST(base64::rlookup('0') == 0b110100U);
-	BOOST_TEST(base64::rlookup('1') == 0b110101U);
-	BOOST_TEST(base64::rlookup('2') == 0b110110U);
-	BOOST_TEST(base64::rlookup('3') == 0b110111U);
-	BOOST_TEST(base64::rlookup('4') == 0b111000U);
-	BOOST_TEST(base64::rlookup('5') == 0b111001U);
-	BOOST_TEST(base64::rlookup('6') == 0b111010U);
-	BOOST_TEST(base64::rlookup('7') == 0b111011U);
-	BOOST_TEST(base64::rlookup('8') == 0b111100U);
-	BOOST_TEST(base64::rlookup('9') == 0b111101U);
-	BOOST_TEST(base64::rlookup('+') == 0b111110U);
-	BOOST_TEST(base64::rlookup('/') == 0b111111U);
-}
-
-BOOST_AUTO_TEST_CASE(encode)
-{
-	BOOST_TEST(base64::encode("a") == "YQ==");
-	BOOST_TEST(base64::encode("ab") == "YWI=");
-	BOOST_TEST(base64::encode("abc") == "YWJj");
-	BOOST_TEST(base64::encode("hello") == "aGVsbG8=");
-	BOOST_TEST(base64::encode("this is a long sentence") == "dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=");
-}
-
-BOOST_AUTO_TEST_CASE(decode)
-{
-	BOOST_TEST(base64::decode("YQ==") == "a");
-	BOOST_TEST(base64::decode("YWI=") == "ab");
-	BOOST_TEST(base64::decode("YWJj") == "abc");
-	BOOST_TEST(base64::decode("aGVsbG8=") == "hello");
-	BOOST_TEST(base64::decode("dGhpcyBpcyBhIGxvbmcgc2VudGVuY2U=") == "this is a long sentence");
-	BOOST_TEST(base64::decode("V2VsY29tZSB0byBvdXIgc2VydmVyIGR1ZGU=") == "Welcome to our server dude");
-}
-
-BOOST_AUTO_TEST_CASE(truncated)
-{
-	BOOST_REQUIRE_THROW(base64::decode("YW="), std::invalid_argument);
-}
-
-BOOST_AUTO_TEST_CASE(invalid)
-{
-	BOOST_REQUIRE_THROW(base64::decode("?!"), std::invalid_argument);
-}
-
-BOOST_AUTO_TEST_CASE(wrong1)
-{
-	BOOST_REQUIRE_THROW(base64::decode("=ABC"), std::invalid_argument);
-}
-
-BOOST_AUTO_TEST_CASE(wrong2)
-{
-	BOOST_REQUIRE_THROW(base64::decode("A=BC"), std::invalid_argument);
-}
-
-BOOST_AUTO_TEST_CASE(wrong3)
-{
-	BOOST_REQUIRE_THROW(base64::decode("==BC"), std::invalid_argument);
-}
-
-BOOST_AUTO_TEST_CASE(wrong4)
-{
-	BOOST_REQUIRE_THROW(base64::decode("AB=C"), std::invalid_argument);
-}