use crate::error::{
decode_buffer_smaller_than_ecc, decode_buffer_too_big, decode_buffer_wrong_size, invalid_bits,
invalid_ecc_len, too_many_errors, HumancodeError,
};
use crate::smallbytebuf::SmallByteBuf;
use crate::EncodedChunk;
use core::fmt::{Debug, Formatter};
use libzbase32::low_level_decode::{
character_to_quintet, is_last_quintet_valid, quintets_to_octets, required_octets_buffer_len,
};
use libzbase32::low_level_encode::required_quintets_buffer_len;
use libzbase32::ZBase32Error;
use reed_solomon_32::decoder as reed_solomoon_decoder;
pub const CHUNK_DECODER_0: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_0, 0);
pub const CHUNK_DECODER_1: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_1, 1);
pub const CHUNK_DECODER_2: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_2, 2);
pub const CHUNK_DECODER_3: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_3, 3);
pub const CHUNK_DECODER_4: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_4, 4);
pub const CHUNK_DECODER_5: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_5, 5);
pub const CHUNK_DECODER_6: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_6, 6);
pub const CHUNK_DECODER_7: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_7, 7);
pub const CHUNK_DECODER_8: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_8, 8);
pub const CHUNK_DECODER_9: ChunkDecoder = ChunkDecoder::new(&reed_solomoon_decoder::DECODER_9, 9);
pub const CHUNK_DECODER_10: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_10, 10);
pub const CHUNK_DECODER_11: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_11, 11);
pub const CHUNK_DECODER_12: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_12, 12);
pub const CHUNK_DECODER_13: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_13, 13);
pub const CHUNK_DECODER_14: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_14, 14);
pub const CHUNK_DECODER_15: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_15, 15);
pub const CHUNK_DECODER_16: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_16, 16);
pub const CHUNK_DECODER_17: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_17, 17);
pub const CHUNK_DECODER_18: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_18, 18);
pub const CHUNK_DECODER_19: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_19, 19);
pub const CHUNK_DECODER_20: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_20, 20);
pub const CHUNK_DECODER_21: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_21, 21);
pub const CHUNK_DECODER_22: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_22, 22);
pub const CHUNK_DECODER_23: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_23, 23);
pub const CHUNK_DECODER_24: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_24, 24);
pub const CHUNK_DECODER_25: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_25, 25);
pub const CHUNK_DECODER_26: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_26, 26);
pub const CHUNK_DECODER_27: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_27, 27);
pub const CHUNK_DECODER_28: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_28, 28);
pub const CHUNK_DECODER_29: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_29, 29);
pub const CHUNK_DECODER_30: ChunkDecoder =
ChunkDecoder::new(&reed_solomoon_decoder::DECODER_30, 30);
#[derive(Copy, Clone)]
pub struct DecodedChunk {
buf: SmallByteBuf<19>,
}
impl DecodedChunk {
pub fn as_bytes(&self) -> &[u8] {
self.buf.as_bytes()
}
}
impl AsRef<[u8]> for DecodedChunk {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Debug for DecodedChunk {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.as_bytes())
}
}
#[derive(Debug)]
pub struct ChunkDecoder {
rs_decoder: &'static reed_solomoon_decoder::Decoder,
ecc: u8,
}
impl ChunkDecoder {
const fn new(rs_decoder: &'static reed_solomoon_decoder::Decoder, ecc: u8) -> ChunkDecoder {
ChunkDecoder { rs_decoder, ecc }
}
pub fn decode_chunk(
&self,
encoded_data: &str,
bits: u8,
) -> Result<(DecodedChunk, Option<EncodedChunk>), HumancodeError> {
if bits == 0 || bits > 150 {
return Err(invalid_bits());
}
fn convert_encoded_data_to_quintets(
bits: u8,
num_quintets: usize,
encoded_data: &str,
) -> Result<(SmallByteBuf<31>, SmallByteBuf<31>), HumancodeError> {
let mut out_buffer = [0u8; 31];
let mut out_idx = 0;
let mut erase_pos = [0u8; 31];
let mut erase_pos_size = 0;
for &x in encoded_data.as_bytes().iter() {
if x == b'-' {
continue;
}
if out_idx >= out_buffer.len() {
return Err(decode_buffer_too_big());
}
match character_to_quintet(x) {
Ok(x) => {
if out_idx + 1 == num_quintets && !is_last_quintet_valid(bits as u64, x) {
erase_pos[erase_pos_size] = out_idx as u8;
erase_pos_size += 1;
} else {
out_buffer[out_idx] = x;
}
}
Err(ZBase32Error::InputError(_)) => {
erase_pos[erase_pos_size] = out_idx as u8;
erase_pos_size += 1;
}
Err(ZBase32Error::UsageError(_)) => {
unreachable!("This shouldn't be possible")
}
};
out_idx += 1;
}
Ok((
SmallByteBuf::new(out_buffer, out_idx as u8),
SmallByteBuf::new(erase_pos, erase_pos_size as u8),
))
}
let num_quintets = required_quintets_buffer_len(bits as u64)
.expect("required_quintets_buffer_len() failed - which shouldn't be possible");
let (quintet_buffer, erase_pos) =
convert_encoded_data_to_quintets(bits, num_quintets, encoded_data)?;
if quintet_buffer.len() <= self.ecc as usize {
return Err(decode_buffer_smaller_than_ecc());
}
if quintet_buffer.len() - self.ecc as usize != num_quintets {
return Err(decode_buffer_wrong_size());
}
let (out, err_count) = match self
.rs_decoder
.correct_err_count(quintet_buffer.as_bytes(), Some(erase_pos.as_bytes()))
{
Ok(r) => r,
Err(_) => return Err(too_many_errors()),
};
let corrected_chunk = if err_count > 0 || erase_pos.len() > 0 {
Some(EncodedChunk::from_quintet_buffer(&out))
} else {
None
};
let decoded_data_len = required_octets_buffer_len(bits as u64)
.expect("required_octets_buffer_len() failed - which shouldn't be possible");
let mut decoded_chunk = DecodedChunk {
buf: SmallByteBuf::new([0u8; 19], decoded_data_len as u8),
};
if err_count > 0 || erase_pos.len() > 0 {
let final_data_quintet = out.data()[out.data().len() - 1];
if !is_last_quintet_valid(bits as u64, final_data_quintet) {
return Err(too_many_errors());
}
}
quintets_to_octets(out.data(), decoded_chunk.buf.as_mut_bytes(), bits as u64)
.expect("quintets_to_octets() failed - which shouldn't be possible");
Ok((decoded_chunk, corrected_chunk))
}
}
pub fn decode_chunk(
encoded_data: &str,
ecc: u8,
bits: u8,
) -> Result<(DecodedChunk, Option<EncodedChunk>), HumancodeError> {
match ecc {
0 => CHUNK_DECODER_0.decode_chunk(encoded_data, bits),
1 => CHUNK_DECODER_1.decode_chunk(encoded_data, bits),
2 => CHUNK_DECODER_2.decode_chunk(encoded_data, bits),
3 => CHUNK_DECODER_3.decode_chunk(encoded_data, bits),
4 => CHUNK_DECODER_4.decode_chunk(encoded_data, bits),
5 => CHUNK_DECODER_5.decode_chunk(encoded_data, bits),
6 => CHUNK_DECODER_6.decode_chunk(encoded_data, bits),
7 => CHUNK_DECODER_7.decode_chunk(encoded_data, bits),
8 => CHUNK_DECODER_8.decode_chunk(encoded_data, bits),
9 => CHUNK_DECODER_9.decode_chunk(encoded_data, bits),
10 => CHUNK_DECODER_10.decode_chunk(encoded_data, bits),
11 => CHUNK_DECODER_11.decode_chunk(encoded_data, bits),
12 => CHUNK_DECODER_12.decode_chunk(encoded_data, bits),
13 => CHUNK_DECODER_13.decode_chunk(encoded_data, bits),
14 => CHUNK_DECODER_14.decode_chunk(encoded_data, bits),
15 => CHUNK_DECODER_15.decode_chunk(encoded_data, bits),
16 => CHUNK_DECODER_16.decode_chunk(encoded_data, bits),
17 => CHUNK_DECODER_17.decode_chunk(encoded_data, bits),
18 => CHUNK_DECODER_18.decode_chunk(encoded_data, bits),
19 => CHUNK_DECODER_19.decode_chunk(encoded_data, bits),
20 => CHUNK_DECODER_20.decode_chunk(encoded_data, bits),
21 => CHUNK_DECODER_21.decode_chunk(encoded_data, bits),
22 => CHUNK_DECODER_22.decode_chunk(encoded_data, bits),
23 => CHUNK_DECODER_23.decode_chunk(encoded_data, bits),
24 => CHUNK_DECODER_24.decode_chunk(encoded_data, bits),
25 => CHUNK_DECODER_25.decode_chunk(encoded_data, bits),
26 => CHUNK_DECODER_26.decode_chunk(encoded_data, bits),
27 => CHUNK_DECODER_27.decode_chunk(encoded_data, bits),
28 => CHUNK_DECODER_28.decode_chunk(encoded_data, bits),
29 => CHUNK_DECODER_29.decode_chunk(encoded_data, bits),
30 => CHUNK_DECODER_30.decode_chunk(encoded_data, bits),
_ => Err(invalid_ecc_len()),
}
}