#include "botan-1.6/include/hex.h"
#include "botan-1.6/include/bit_ops.h"
#include "botan-1.6/include/parsing.h"
#include "botan-1.6/include/charset.h"
#include <algorithm>
namespace Enctain {
namespace Botan {
Hex_Encoder::Hex_Encoder(bool breaks, u32bit length, Case c) :
casing(c), line_length(breaks ? length : 0)
{
in.create(64);
out.create(2*in.size());
counter = position = 0;
}
Hex_Encoder::Hex_Encoder(Case c) : casing(c), line_length(0)
{
in.create(64);
out.create(2*in.size());
counter = position = 0;
}
void Hex_Encoder::encode(byte in, byte out[2], Hex_Encoder::Case casing)
{
const byte* BIN_TO_HEX = ((casing == Uppercase) ? BIN_TO_HEX_UPPER :
BIN_TO_HEX_LOWER);
out[0] = BIN_TO_HEX[((in >> 4) & 0x0F)];
out[1] = BIN_TO_HEX[((in ) & 0x0F)];
}
void Hex_Encoder::encode_and_send(const byte block[], u32bit length)
{
for(u32bit j = 0; j != length; ++j)
encode(block[j], out + 2*j, casing);
if(line_length == 0)
send(out, 2*length);
else
{
u32bit remaining = 2*length, offset = 0;
while(remaining)
{
u32bit sent = std::min(line_length - counter, remaining);
send(out + offset, sent);
counter += sent;
remaining -= sent;
offset += sent;
if(counter == line_length)
{
send('\n');
counter = 0;
}
}
}
}
void Hex_Encoder::write(const byte input[], u32bit length)
{
in.copy(position, input, length);
if(position + length >= in.size())
{
encode_and_send(in, in.size());
input += (in.size() - position);
length -= (in.size() - position);
while(length >= in.size())
{
encode_and_send(input, in.size());
input += in.size();
length -= in.size();
}
in.copy(input, length);
position = 0;
}
position += length;
}
void Hex_Encoder::end_msg()
{
encode_and_send(in, position);
if(counter && line_length)
send('\n');
counter = position = 0;
}
Hex_Decoder::Hex_Decoder(Decoder_Checking c) : checking(c)
{
in.create(64);
out.create(in.size() / 2);
position = 0;
}
bool Hex_Decoder::is_valid(byte in)
{
return (HEX_TO_BIN[in] != 0x80);
}
void Hex_Decoder::handle_bad_char(byte c)
{
if(checking == NONE)
return;
if((checking == IGNORE_WS) && Charset::is_space(c))
return;
throw Decoding_Error("Hex_Decoder: Invalid hex character: " +
to_string(c));
}
byte Hex_Decoder::decode(const byte hex[2])
{
return (byte)((HEX_TO_BIN[hex[0]] << 4) | HEX_TO_BIN[hex[1]]);
}
void Hex_Decoder::decode_and_send(const byte block[], u32bit length)
{
for(u32bit j = 0; j != length / 2; ++j)
out[j] = decode(block + 2*j);
send(out, length / 2);
}
void Hex_Decoder::write(const byte input[], u32bit length)
{
for(u32bit j = 0; j != length; ++j)
{
if(is_valid(input[j]))
in[position++] = input[j];
else
handle_bad_char(input[j]);
if(position == in.size())
{
decode_and_send(in, in.size());
position = 0;
}
}
}
void Hex_Decoder::end_msg()
{
decode_and_send(in, position);
position = 0;
}
}
}