view C++/modules/Base64/base64.h @ 485:898d8b29a4f1

Switch to lowercase filenames
author David Demelier <markand@malikania.fr>
date Thu, 12 Nov 2015 21:53:36 +0100
parents C++/modules/Base64/Base64.h@3f29e6c05983
children
line wrap: on
line source

/*
 * Base64.h -- base64 encoding and decoding
 *
 * Copyright (c) 2013-2015 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 _BASE_64_H_
#define _BASE_64_H_

/**
 * @file Base64.h
 * @brief Base64 encoding and decoding
 */

#include <stdexcept>
#include <string>

namespace base64 {

/**
 * Get the base 64 character from the 6-bits value.
 *
 * @pre value must be valid
 * @param value the value
 */
unsigned char lookup(unsigned int value) noexcept;

/**
 * Get the integer value from the base 64 character.
 *
 * @pre ch must be a valid base 64 character but not '='
 * @param ch the base64 character
 */
unsigned int rlookup(unsigned char ch);

/**
 * Check if the given character is a valid base 64 character.
 *
 * @param char the character
 * @return true if the character is valid
 */
bool isValid(unsigned char) noexcept;

/**
 * Encode the input to the output. Requirements:
 *	InputIt	must be InputIterator
 *	OutputIt must be OutputIterator
 *
 * @param input the beginning
 * @param end the end of the data
 * @param output the output destination
 * @return output
 */
template <typename InputIt, typename OutputIt>
OutputIt encode(InputIt input, InputIt end, OutputIt output)
{
	while (input != end) {
		char inputbuf[3] = { 0, 0, 0 };
		int count;

		for (count = 0; count < 3 && input != end; ++count) {
			inputbuf[count] = *input++;
		}

		*output++ = lookup(inputbuf[0] >> 2 & 0x3f);
		*output++ = lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f));
		*output++ = (count < 2) ? '=' : lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03));
		*output++ = (count < 3) ? '=' : lookup(inputbuf[2] & 0x3f);
	}

	return output;
}

/**
 * Decode the input to the output. Requirements:
 *	InputIt must be InputIterator
 *	OutputIt must be OutputIterator
 *
 * @param input the beginning
 * @param end the end of the data
 * @param output the output destination
 * @return output
 * @throw std::invalid_argument on bad base64 string
 */
template <typename InputIt, typename OutputIt>
OutputIt decode(InputIt input, InputIt end, OutputIt output)
{
	while (input != end) {
		char inputbuf[4] = { -1, -1, -1, -1 };
		int count;

		for (count = 0; count < 4 && input != end; ++count) {
			if (*input != '=') {
				/* Check if the character is valid and get its value */
				if (isValid(*input)) {
					inputbuf[count] = rlookup(*input);
				} else {
					throw std::invalid_argument{"invalid base64 string"};
				}
			} else {
				/* A base 64 string cannot start with "=" or "==" */
				if (count == 0 || count == 1) {
					throw std::invalid_argument{"invalid or truncated base64 string"};
				}
			}
			
			input++;
		}

		if (count != 4) {
			throw std::invalid_argument("truncated string");
		}

		*output++ = static_cast<unsigned char>(((inputbuf[0] << 2) & 0xfc) | ((inputbuf[1] >> 4) & 0x03));

		if (inputbuf[2] != -1) {
			*output++ = static_cast<unsigned char>(((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f));
		}
		if (inputbuf[3] != -1) {
			/* "XY=Z" is not allowed */
			if (inputbuf[2] == -1) {
				throw std::invalid_argument{"invalid base64 string"};
			}

			*output++ = static_cast<unsigned char>(((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f));
		}
	}

	return output;
}

/**
 * Encode a string.
 *
 * @param input the input string
 * @return the base64 formatted string
 */
std::string encode(const std::string &input);

/**
 * Decode a string.
 *
 * @param input the base64 formatted string
 * @return the original string
 * @throw std::invalid_argument on bad base64 string
 */
std::string decode(const std::string &input);

} // !base64

#endif // !_BASE_64_H_