use crate::error_correction::{generate_ecc, interleave, DataBlock, ECCLevel};
use crate::types::{QRGenError, Version};
type DataBlockRow = (usize, usize, usize, usize);
pub(crate) static EC_BYTES_PER_BLOCK: [[usize; 4]; 44] = [
[7, 10, 13, 17],
[10, 16, 22, 28],
[15, 26, 18, 22],
[20, 18, 26, 16],
[26, 24, 18, 22],
[18, 16, 24, 28],
[20, 18, 18, 26],
[24, 22, 22, 26],
[30, 22, 20, 24],
[18, 26, 24, 28],
[20, 30, 28, 24],
[24, 22, 26, 28],
[26, 22, 24, 22],
[30, 24, 20, 24],
[22, 24, 30, 24],
[24, 28, 24, 30],
[28, 26, 28, 28],
[30, 26, 28, 28],
[28, 26, 26, 26],
[28, 26, 30, 28],
[28, 28, 30, 24],
[30, 28, 30, 30],
[30, 28, 30, 30],
[26, 28, 30, 30],
[28, 28, 28, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[30, 28, 30, 30],
[2, 0, 0, 0],
[5, 6, 0, 0],
[6, 8, 0, 0],
[8, 10, 14, 0],
];
pub(crate) static DATA_BYTES_PER_BLOCK: [[DataBlockRow; 4]; 44] = [
[(19, 1, 0, 0), (16, 1, 0, 0), (13, 1, 0, 0), (9, 1, 0, 0)],
[(34, 1, 0, 0), (28, 1, 0, 0), (22, 1, 0, 0), (16, 1, 0, 0)],
[(55, 1, 0, 0), (44, 1, 0, 0), (17, 2, 0, 0), (13, 2, 0, 0)],
[(80, 1, 0, 0), (32, 2, 0, 0), (24, 2, 0, 0), (9, 4, 0, 0)],
[(108, 1, 0, 0), (43, 2, 0, 0), (15, 2, 16, 2), (11, 2, 12, 2)],
[(68, 2, 0, 0), (27, 4, 0, 0), (19, 4, 0, 0), (15, 4, 0, 0)],
[(78, 2, 0, 0), (31, 4, 0, 0), (14, 2, 15, 4), (13, 4, 14, 1)],
[(97, 2, 0, 0), (38, 2, 39, 2), (18, 4, 19, 2), (14, 4, 15, 2)],
[(116, 2, 0, 0), (36, 3, 37, 2), (16, 4, 17, 4), (12, 4, 13, 4)],
[(68, 2, 69, 2), (43, 4, 44, 1), (19, 6, 20, 2), (15, 6, 16, 2)],
[(81, 4, 0, 0), (50, 1, 51, 4), (22, 4, 23, 4), (12, 3, 13, 8)],
[(92, 2, 93, 2), (36, 6, 37, 2), (20, 4, 21, 6), (14, 7, 15, 4)],
[(107, 4, 0, 0), (37, 8, 38, 1), (20, 8, 21, 4), (11, 12, 12, 4)],
[(115, 3, 116, 1), (40, 4, 41, 5), (16, 11, 17, 5), (12, 11, 13, 5)],
[(87, 5, 88, 1), (41, 5, 42, 5), (24, 5, 25, 7), (12, 11, 13, 7)],
[(98, 5, 99, 1), (45, 7, 46, 3), (19, 15, 20, 2), (15, 3, 16, 13)],
[(107, 1, 108, 5), (46, 10, 47, 1), (22, 1, 23, 15), (14, 2, 15, 17)],
[(120, 5, 121, 1), (43, 9, 44, 4), (22, 17, 23, 1), (14, 2, 15, 19)],
[(113, 3, 114, 4), (44, 3, 45, 11), (21, 17, 22, 4), (13, 9, 14, 16)],
[(107, 3, 108, 5), (41, 3, 42, 13), (24, 15, 25, 5), (15, 15, 16, 10)],
[(116, 4, 117, 4), (42, 17, 0, 0), (22, 17, 23, 6), (16, 19, 17, 6)],
[(111, 2, 112, 7), (46, 17, 0, 0), (24, 7, 25, 16), (13, 34, 0, 0)],
[(121, 4, 122, 5), (47, 4, 48, 14), (24, 11, 25, 14), (15, 16, 16, 14)],
[(117, 6, 118, 4), (45, 6, 46, 14), (24, 11, 25, 16), (16, 30, 17, 2)],
[(106, 8, 107, 4), (47, 8, 48, 13), (24, 7, 25, 22), (15, 22, 16, 13)],
[(114, 10, 115, 2), (46, 19, 47, 4), (22, 28, 23, 6), (16, 33, 17, 4)],
[(122, 8, 123, 4), (45, 22, 46, 3), (23, 8, 24, 26), (15, 12, 16, 28)],
[(117, 3, 118, 10), (45, 3, 46, 23), (24, 4, 25, 31), (15, 11, 16, 31)],
[(116, 7, 117, 7), (45, 21, 46, 7), (23, 1, 24, 37), (15, 19, 16, 26)],
[(115, 5, 116, 10), (47, 19, 48, 10), (24, 15, 25, 25), (15, 23, 16, 25)],
[(115, 13, 116, 3), (46, 2, 47, 29), (24, 42, 25, 1), (15, 23, 16, 28)],
[(115, 17, 0, 0), (46, 10, 47, 23), (24, 10, 25, 35), (15, 19, 16, 35)],
[(115, 17, 116, 1), (46, 14, 47, 21), (24, 29, 25, 19), (15, 11, 16, 46)],
[(115, 13, 116, 6), (46, 14, 47, 23), (24, 44, 25, 7), (16, 59, 17, 1)],
[(121, 12, 122, 7), (47, 12, 48, 26), (24, 39, 25, 14), (15, 22, 16, 41)],
[(121, 6, 122, 14), (47, 6, 48, 34), (24, 46, 25, 10), (15, 2, 16, 64)],
[(122, 17, 123, 4), (46, 29, 47, 14), (24, 49, 25, 10), (15, 24, 16, 46)],
[(122, 4, 123, 18), (46, 13, 47, 32), (24, 48, 25, 14), (15, 42, 16, 32)],
[(117, 20, 118, 4), (47, 40, 48, 7), (24, 43, 25, 22), (15, 10, 16, 67)],
[(118, 19, 119, 6), (47, 18, 48, 31), (24, 34, 25, 34), (15, 20, 16, 61)],
[(3, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
[(5, 1, 0, 0), (4, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
[(11, 1, 0, 0), (9, 1, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)],
[(16, 1, 0, 0), (14, 1, 0, 0), (10, 1, 0, 0), (0, 0, 0, 0)],
];
pub fn total_data_codewords(version: u8, ecc: ECCLevel) -> Result<usize, QRGenError> {
let (block_1_size, block_1_count, block_2_size, block_2_count) =
Version::Micro(i16::from(version)).fetch(ecc, &DATA_BYTES_PER_BLOCK)?;
Ok(block_1_size * block_1_count + block_2_size * block_2_count)
}
pub fn construct_codewords(
rawbits: &[u8],
version: u8,
ecc: ECCLevel,
) -> Result<(Vec<u8>, Vec<u8>), QRGenError> {
let ver = Version::Micro(i16::from(version));
let (block_1_size, block_1_count, block_2_size, block_2_count) =
ver.fetch(ecc, &DATA_BYTES_PER_BLOCK)?;
let ec_bytes = ver.fetch(ecc, &EC_BYTES_PER_BLOCK)?;
let total_size = total_data_codewords(version, ecc)?;
debug_assert_eq!(rawbits.len(), total_size);
let block_1_end = block_1_size * block_1_count;
let mut blocks: Vec<&[u8]> = Vec::new();
blocks.extend(rawbits[..block_1_end].chunks(block_1_size));
if block_2_size > 0 {
debug_assert_eq!(block_2_count as usize, rawbits[block_1_end..].len() / block_2_size);
blocks.extend(rawbits[block_1_end..].chunks(block_2_size));
}
let mut data_blocks = Vec::with_capacity(blocks.len());
for block in blocks {
let ecc_codewords = generate_ecc(block, ec_bytes);
data_blocks.push(DataBlock {
data: block.to_vec(),
ecc: ecc_codewords,
});
}
let interleaved = interleave(&data_blocks);
let data_len: usize = data_blocks.iter().map(|b| b.data.len()).sum();
let data = interleaved[..data_len].to_vec();
let ec = interleaved[data_len..].to_vec();
Ok((data, ec))
}