[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/wravery/cppgraphqlgen/next/src/Base64.cpp [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "graphqlservice/internal/Base64.h"

#include 
#include 
#include 

namespace graphql::internal {

std::uint8_t Base64::verifyFromBase64(char ch)
{
	const std::uint8_t result = fromBase64(ch);

	if ((result & 0xC0) != 0)
	{
		throw std::logic_error { "invalid character in base64 encoded string" };
	}

	return result;
}

std::vector Base64::fromBase64(std::string_view encoded)
{
	std::vector result;

	if (encoded.empty())
	{
		return result;
	}

	result.reserve((encoded.size() + (encoded.size() % 4)) * 3 / 4);

	// First decode all of the full unpadded segments 24 bits at a time
	while (encoded.size() >= 4 && encoded[3] != padding)
	{
		const uint32_t segment = (static_cast(verifyFromBase64(encoded[0])) > 8));
		result.emplace_back(static_cast(segment & 0xFF));

		encoded = encoded.substr(4);
	}

	// Get any leftover partial segment with 2 or 3 non-padding characters
	if (encoded.size() > 1)
	{
		const bool triplet = (encoded.size() > 2 && padding != encoded[2]);
		const std::uint8_t tail = (triplet ? verifyFromBase64(encoded[2]) : 0);
		const uint16_t segment = (static_cast(verifyFromBase64(encoded[0]))  2);

		if (triplet)
		{
			if (tail & 0x3)
			{
				throw std::logic_error { "invalid padding at the end of a base64 encoded string" };
			}

			result.emplace_back(static_cast((segment & 0xFF00) >> 8));
			result.emplace_back(static_cast(segment & 0xFF));

			encoded = encoded.substr(3);
		}
		else
		{
			if (segment & 0xFF)
			{
				throw std::logic_error { "invalid padding at the end of a base64 encoded string" };
			}

			result.emplace_back(static_cast((segment & 0xFF00) >> 8));

			encoded = encoded.substr(2);
		}
	}

	// Make sure anything that's left is 0 - 2 characters of padding
	if ((encoded.size() > 0 && padding != encoded[0])
		|| (encoded.size() > 1 && padding != encoded[1]) || encoded.size() > 2)
	{
		throw std::logic_error { "invalid padding at the end of a base64 encoded string" };
	}

	return result;
}

char Base64::verifyToBase64(std::uint8_t i)
{
	unsigned char result = toBase64(i);

	if (result == padding)
	{
		throw std::logic_error { "invalid 6-bit value" };
	}

	return result;
}

std::string Base64::toBase64(const std::vector& bytes)
{
	std::string result;

	if (bytes.empty())
	{
		return result;
	}

	std::size_t count = bytes.size();
	const std::uint8_t* data = bytes.data();

	result.reserve((count + (count % 3)) * 4 / 3);

	// First encode all of the full unpadded segments 24 bits at a time
	while (count >= 3)
	{
		const uint32_t segment = (static_cast(data[0])  18)),
			verifyToBase64(static_cast((segment & 0x3F000) >> 12)),
			verifyToBase64(static_cast((segment & 0xFC0) >> 6)),
			verifyToBase64(static_cast(segment & 0x3F)) });

		data += 3;
		count -= 3;
	}

	// Get any leftover partial segment with 1 or 2 bytes
	if (count > 0)
	{
		const bool pair = (count > 1);
		const uint16_t segment =
			(static_cast(data[0]) > 10)),
			verifyToBase64(static_cast((segment & 0x3F0) >> 4)),
			(pair ? verifyToBase64(static_cast((segment & 0xF) = 4 && maybeEncoded[3] != padding)
	{
		const auto a = fromBase64(maybeEncoded[0]);
		const auto b = fromBase64(maybeEncoded[1]);
		const auto c = fromBase64(maybeEncoded[2]);
		const auto d = fromBase64(maybeEncoded[3]);

		if (((a | b | c | d) & 0xC0) != 0)
		{
			// Invalid Base64 characters
			return Comparison::InvalidBase64;
		}

		if (Comparison::EqualTo == result)
		{
			const uint32_t segment = (static_cast(a) > 8),
				static_cast(segment & 0xFF) };

			for (auto value : decoded)
			{
				if (itr == itrEnd)
				{
					result = Comparison::LessThan;
					break;
				}

				if (*itr != value)
				{
					result = *itr < value ? Comparison::LessThan : Comparison::GreaterThan;
					break;
				}

				++itr;
			}
		}

		maybeEncoded = maybeEncoded.substr(4);
	}

	// Compare any leftover partial segment with 2 or 3 non-padding characters
	if (maybeEncoded.size() > 1)
	{
		const bool triplet = (maybeEncoded.size() > 2 && padding != maybeEncoded[2]);
		const auto a = fromBase64(maybeEncoded[0]);
		const auto b = fromBase64(maybeEncoded[1]);
		const auto c = triplet ? fromBase64(maybeEncoded[2]) : std::uint8_t {};

		if (((a | b | c) & 0xC0) != 0 || (c & 0x3) != 0)
		{
			// Invalid Base64 characters or padding
			return Comparison::InvalidBase64;
		}

		const uint16_t segment = (static_cast(a)  2);
		const std::array decoded { static_cast((segment & 0xFF00) >> 8),
			static_cast(segment & 0xFF) };

		if (triplet)
		{
			if (Comparison::EqualTo == result)
			{
				for (auto value : decoded)
				{
					if (itr == itrEnd)
					{
						result = Comparison::LessThan;
						break;
					}

					if (*itr != value)
					{
						result = *itr < value ? Comparison::LessThan : Comparison::GreaterThan;
						break;
					}

					++itr;
				}
			}

			maybeEncoded = maybeEncoded.substr(3);
		}
		else
		{
			if (decoded[1] != 0)
			{
				// Invalid padding
				return Comparison::InvalidBase64;
			}

			if (Comparison::EqualTo == result)
			{
				if (itr == itrEnd)
				{
					result = Comparison::LessThan;
				}
				else if (*itr != decoded[0])
				{
					result = *itr < decoded[0] ? Comparison::LessThan : Comparison::GreaterThan;
				}

				++itr;
			}

			maybeEncoded = maybeEncoded.substr(2);
		}
	}

	// Make sure anything that's left is 0 - 2 characters of padding
	if ((maybeEncoded.size() > 0 && padding != maybeEncoded[0])
		|| (maybeEncoded.size() > 1 && padding != maybeEncoded[1]) || maybeEncoded.size() > 2)
	{
		return Comparison::InvalidBase64;
	}

	if (Comparison::EqualTo == result)
	{
		// We should reach the end of the byte vector
		if (itr != itrEnd)
		{
			result = Comparison::GreaterThan;
		}
	}

	return result;
}

bool Base64::validateBase64(std::string_view maybeEncoded) noexcept
{
	if (maybeEncoded.empty())
	{
		return true;
	}

	// First decode and compare all of the full unpadded segments 24 bits at a time
	while (maybeEncoded.size() >= 4 && maybeEncoded[3] != padding)
	{
		const auto a = fromBase64(maybeEncoded[0]);
		const auto b = fromBase64(maybeEncoded[1]);
		const auto c = fromBase64(maybeEncoded[2]);
		const auto d = fromBase64(maybeEncoded[3]);

		if (((a | b | c | d) & 0xC0) != 0)
		{
			// Invalid Base64 characters
			return false;
		}

		maybeEncoded = maybeEncoded.substr(4);
	}

	// Compare any leftover partial segment with 2 or 3 non-padding characters
	if (maybeEncoded.size() > 1)
	{
		const bool triplet = (maybeEncoded.size() > 2 && padding != maybeEncoded[2]);
		const auto a = fromBase64(maybeEncoded[0]);
		const auto b = fromBase64(maybeEncoded[1]);
		const auto c = triplet ? fromBase64(maybeEncoded[2]) : std::uint8_t {};

		if (((a | b | c) & 0xC0) != 0 || (c & 0x3) != 0)
		{
			// Invalid Base64 characters or padding
			return false;
		}

		if (triplet)
		{
			maybeEncoded = maybeEncoded.substr(3);
		}
		else
		{
			const uint16_t segment = (static_cast(a)  2);

			if ((segment & 0xFF) != 0)
			{
				// Invalid padding
				return false;
			}

			maybeEncoded = maybeEncoded.substr(2);
		}
	}

	// Make sure anything that's left is 0 - 2 characters of padding
	if ((maybeEncoded.size() > 0 && padding != maybeEncoded[0])
		|| (maybeEncoded.size() > 1 && padding != maybeEncoded[1]) || maybeEncoded.size() > 2)
	{
		return false;
	}

	return true;
}

} // namespace graphql::internal

Web Proxy Viewer  |  New URL  |  Original Page