//
// Base32Decoder.cpp
//
// Library: Foundation
// Package: Streams
// Module:  Base32
//
// Copyright (c) 2004-2025, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier:	BSL-1.0
//


#include "Poco/Base32Decoder.h"
#include "Poco/Base32Encoder.h"
#include "Poco/Exception.h"
#include <cstring>


namespace Poco {


const unsigned char Base32DecoderBuf::REVERSE_DEFAULT_ENCODING[256] = 
{
	/* 00 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 08 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 10 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 18 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 20 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 28 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 30 */ 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 
	/* 38 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 
	/* 40 */ 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 
	/* 48 */ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 
	/* 50 */ 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 
	/* 58 */ 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 60 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 68 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 70 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 78 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 80 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 88 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 90 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 98 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};


const unsigned char Base32DecoderBuf::REVERSE_HEX_ENCODING[256] = 
{
	/* 00 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 08 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 10 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 18 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 20 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 28 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 30 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
	/* 38 */ 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 
	/* 40 */ 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 
	/* 48 */ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
	/* 50 */ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0xFF, 
	/* 58 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 60 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 68 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 70 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 78 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 80 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 88 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 90 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 98 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};


const unsigned char Base32DecoderBuf::REVERSE_CROCKFORD_ENCODING[256] = 
{
	/* 00 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 08 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 10 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 18 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 20 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 28 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 30 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
	/* 38 */ 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 
	/* 40 */ 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 
	/* 48 */ 0x11, 0x01, 0x12, 0x13, 0x01, 0x14, 0x15, 0x00, 
	/* 50 */ 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C, 
	/* 58 */ 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 60 */ 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 
	/* 68 */ 0x11, 0x01, 0x12, 0x13, 0x01, 0x14, 0x15, 0x00, 
	/* 70 */ 0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C, 
	/* 78 */ 0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 80 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 88 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 90 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* 98 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* A8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* B8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* C8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* D8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* E8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
	/* F8 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};


Base32DecoderBuf::Base32DecoderBuf(std::istream& istr, int options):
	_groupLength(0),
	_groupIndex(0),
	_buf(*istr.rdbuf()),
	_encoding(encoding(options))
{
}


Base32DecoderBuf::~Base32DecoderBuf()
{
}


int Base32DecoderBuf::readFromDevice()
{
	if (_groupIndex < _groupLength)
	{
		return _group[_groupIndex++];
	}
	else
	{
		unsigned char buffer[8];
		std::memset(buffer, '=', sizeof(buffer));
		int c;

		// per RFC-4648, Section 6, permissible block lengths are:
		// 2, 4, 5, 7, and 8 bytes. Any other length is malformed.
		//
		do 
		{
			if ((c = readOne()) == -1) return -1;
			buffer[0] = (unsigned char) c;
			if (_encoding[buffer[0]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) throw DataFormatException();
			buffer[1] = (unsigned char) c;
			if (_encoding[buffer[1]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) break;
			buffer[2] = (unsigned char) c;
			if (_encoding[buffer[2]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) throw DataFormatException();
			buffer[3] = (unsigned char) c;
			if (_encoding[buffer[3]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) break;
			buffer[4] = (unsigned char) c;
			if (_encoding[buffer[4]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) break;
			buffer[5] = (unsigned char) c;
			if (_encoding[buffer[5]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) throw DataFormatException();
			buffer[6] = (unsigned char) c;
			if (_encoding[buffer[6]] == 0xFF) throw DataFormatException();
			if ((c = readOne()) == -1) break;
			buffer[7] = (unsigned char) c;
			if (_encoding[buffer[7]] == 0xFF) throw DataFormatException();
		} 
		while (false);

		_group[0] = (_encoding[buffer[0]] << 3) | (_encoding[buffer[1]] >> 2);
		_group[1] = ((_encoding[buffer[1]] & 0x03) << 6) | (_encoding[buffer[2]] << 1) | (_encoding[buffer[3]] >> 4);
		_group[2] = ((_encoding[buffer[3]] & 0x0F) << 4) | (_encoding[buffer[4]] >> 1);
		_group[3] = ((_encoding[buffer[4]] & 0x01) << 7) | (_encoding[buffer[5]] << 2) | (_encoding[buffer[6]] >> 3);
		_group[4] = ((_encoding[buffer[6]] & 0x07) << 5) | _encoding[buffer[7]];

		if (buffer[2] == '=')
			_groupLength = 1;
		else if (buffer[4] == '=')
			_groupLength = 2;
		else if (buffer[5] == '=')
			_groupLength = 3;
		else if (buffer[7] == '=')
			_groupLength = 4;
		else
			_groupLength = 5;
		_groupIndex = 1;
		return _group[0];
	}
}


int Base32DecoderBuf::readOne()
{
	int ch = _buf.sbumpc();
	return ch;
}


const unsigned char* Base32DecoderBuf::encoding(int options)
{
	if ((options & BASE32_USE_HEX_ALPHABET) != 0)
		return REVERSE_HEX_ENCODING;
	else if ((options & BASE32_USE_CROCKFORD_ALPHABET) != 0)
		return REVERSE_CROCKFORD_ENCODING;
	else
		return REVERSE_DEFAULT_ENCODING;
}


Base32DecoderIOS::Base32DecoderIOS(std::istream& istr, int options): _buf(istr, options)
{
	poco_ios_init(&_buf);
}


Base32DecoderIOS::~Base32DecoderIOS()
{
}


Base32DecoderBuf* Base32DecoderIOS::rdbuf()
{
	return &_buf;
}


Base32Decoder::Base32Decoder(std::istream& istr, int options): Base32DecoderIOS(istr, options), std::istream(&_buf)
{
}


Base32Decoder::~Base32Decoder()
{
}


} // namespace Poco
