use crate::common::cpp_essentials::{DecoderResult, StructuredAppendInfo};
use crate::common::reedsolomon::{
get_predefined_genericgf, PredefinedGenericGF, ReedSolomonDecoder,
};
use crate::common::{
AIFlag, BitMatrix, BitSource, CharacterSet, ECIStringBuilder, Eci, Result, SymbologyIdentifier,
};
use crate::qrcode::cpp_port::bitmatrix_parser::{
ReadCodewords, ReadFormatInformation, ReadVersion,
};
use crate::qrcode::decoder::{DataBlock, ErrorCorrectionLevel, Mode, Version};
use crate::Exceptions;
pub fn CorrectErrors(codewordBytes: &mut [u8], numDataCodewords: u32) -> Result<bool> {
let mut codewordsInts = codewordBytes.iter().copied().map(|b| b as i32).collect();
let numECCodewords = ((codewordBytes.len() as u32) - numDataCodewords) as i32;
let rs = ReedSolomonDecoder::new(get_predefined_genericgf(
PredefinedGenericGF::QrCodeField256,
));
rs.decode(&mut codewordsInts, numECCodewords)?;
codewordBytes[..numDataCodewords as usize].copy_from_slice(
&codewordsInts[..numDataCodewords as usize]
.iter()
.copied()
.map(|i| i as u8)
.collect::<Vec<u8>>(),
);
Ok(true)
}
pub fn DecodeHanziSegment(
bits: &mut BitSource,
count: u32,
result: &mut ECIStringBuilder,
) -> Result<()> {
let mut count = count;
result.switch_encoding(CharacterSet::GB18030, false);
result.reserve(2 * count as usize);
while count > 0 {
let twoBytes = bits.readBits(13)?;
let mut assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
if assembledTwoBytes < 0x00A00 {
assembledTwoBytes += 0x0A1A1;
} else {
assembledTwoBytes += 0x0A6A1;
}
*result += ((assembledTwoBytes >> 8) & 0xFF) as u8;
*result += (assembledTwoBytes & 0xFF) as u8;
count -= 1;
}
Ok(())
}
pub fn DecodeKanjiSegment(
bits: &mut BitSource,
count: u32,
result: &mut ECIStringBuilder,
) -> Result<()> {
let mut count = count;
result.switch_encoding(CharacterSet::Shift_JIS, false);
result.reserve(2 * count as usize);
while count > 0 {
let twoBytes = bits.readBits(13)?;
let mut assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
if assembledTwoBytes < 0x01F00 {
assembledTwoBytes += 0x08140;
} else {
assembledTwoBytes += 0x0C140;
}
*result += (assembledTwoBytes >> 8) as u8;
*result += (assembledTwoBytes) as u8;
count -= 1;
}
Ok(())
}
pub fn DecodeByteSegment(
bits: &mut BitSource,
count: u32,
result: &mut ECIStringBuilder,
) -> Result<()> {
result.switch_encoding(CharacterSet::Unknown, false);
result.reserve(count as usize);
for _i in 0..count {
*result += (bits.readBits(8)?) as u8;
}
Ok(())
}
pub fn ToAlphaNumericChar(value: u32) -> Result<char> {
let value = value as usize;
const ALPHANUMERIC_CHARS: [char; 45] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
' ', '$', '%', '*', '+', '-', '.', '/', ':',
];
if value >= (ALPHANUMERIC_CHARS.len()) {
return Err(Exceptions::index_out_of_bounds_with(
"oAlphaNumericChar: out of range",
));
}
Ok(ALPHANUMERIC_CHARS[value])
}
pub fn DecodeAlphanumericSegment(
bits: &mut BitSource,
count: u32,
result: &mut ECIStringBuilder,
) -> Result<()> {
let mut count = count;
let mut buffer = String::new();
while count > 1 {
let nextTwoCharsBits = bits.readBits(11)?;
buffer.push(ToAlphaNumericChar(nextTwoCharsBits / 45)?);
buffer.push(ToAlphaNumericChar(nextTwoCharsBits % 45)?);
count -= 2;
}
if count == 1 {
buffer.push(ToAlphaNumericChar(bits.readBits(6)?)?);
}
if result.symbology.aiFlag != AIFlag::None {
for i in 0..buffer.len() {
if buffer
.chars()
.nth(i)
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
== '%'
{
if i < buffer.len() - 1
&& buffer
.chars()
.nth(i + 1)
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
== '%'
{
buffer.remove(i + 1);
} else {
buffer.replace_range(i..i, &char::from(0x1D).to_string());
}
}
}
}
result.switch_encoding(CharacterSet::ISO8859_1, false);
*result += buffer;
Ok(())
}
pub fn DecodeNumericSegment(
bits: &mut BitSource,
count: u32,
result: &mut ECIStringBuilder,
) -> Result<()> {
let mut count = count;
result.switch_encoding(CharacterSet::ISO8859_1, false);
result.reserve(count as usize);
while count > 0 {
let n = std::cmp::min(count, 3);
let nDigits = bits.readBits(1 + 3 * n as usize)?; result.append_string(&crate::common::cpp_essentials::util::ToString(
nDigits as usize,
n as usize,
)?);
count -= n;
}
Ok(())
}
pub fn ParseECIValue(bits: &mut BitSource) -> Result<Eci> {
let firstByte = bits.readBits(8)?;
if (firstByte & 0x80) == 0 {
return Ok(Eci::from(firstByte & 0x7F));
}
if (firstByte & 0xC0) == 0x80 {
let secondByte = bits.readBits(8)?;
return Ok(Eci::from(((firstByte & 0x3F) << 8) | secondByte));
}
if (firstByte & 0xE0) == 0xC0 {
let secondThirdBytes = bits.readBits(16)?;
return Ok(Eci::from(((firstByte & 0x1F) << 16) | secondThirdBytes));
}
Err(Exceptions::format_with("ParseECIValue: invalid value"))
}
pub fn IsEndOfStream(bits: &mut BitSource, version: &Version) -> Result<bool> {
let bitsRequired = Mode::get_terminator_bit_length(version); let bitsAvailable = std::cmp::min(bits.available(), bitsRequired as usize);
Ok(bitsAvailable == 0 || bits.peak_bits(bitsAvailable)? == 0)
}
pub fn DecodeBitStream(
bytes: &[u8],
version: &Version,
ecLevel: ErrorCorrectionLevel,
) -> Result<DecoderResult<bool>> {
let mut bits = BitSource::new(bytes.to_vec());
let mut result = ECIStringBuilder::default();
result.symbology = SymbologyIdentifier {
code: b'Q',
modifier: b'1',
eciModifierOffset: 1,
aiFlag: AIFlag::None,
}; let mut structuredAppend = StructuredAppendInfo::default();
let modeBitLength = Mode::get_codec_mode_bits_length(version);
let res = (|| {
while !IsEndOfStream(&mut bits, version)? {
let mode: Mode = if modeBitLength == 0 {
Mode::NUMERIC } else {
Mode::CodecModeForBits(
bits.readBits(modeBitLength as usize)?,
Some(version.isMicroQRCode()),
)?
};
match mode {
Mode::FNC1_FIRST_POSITION => {
result.symbology.modifier = b'3';
result.symbology.aiFlag = AIFlag::GS1; }
Mode::FNC1_SECOND_POSITION => {
if !result.is_empty() {
return Err(Exceptions::format_with("AIM Application Indicator (FNC1 in second position) at illegal position"));
}
result.symbology.modifier = b'5'; let appInd = bits.readBits(8)?;
if appInd < 100
{
result +=
crate::common::cpp_essentials::util::ToString(appInd as usize, 2)?;
} else if (165..=190).contains(&appInd) || (197..=222).contains(&appInd)
{
result += (appInd - 100) as u8;
} else {
return Err(Exceptions::format_with("Invalid AIM Application Indicator"));
}
result.symbology.aiFlag = AIFlag::AIM; }
Mode::STRUCTURED_APPEND => {
structuredAppend.index = bits.readBits(4)? as i32;
structuredAppend.count = bits.readBits(4)? as i32 + 1;
structuredAppend.id = (bits.readBits(8)?).to_string(); }
Mode::ECI => {
result.switch_encoding(ParseECIValue(&mut bits)?.into(), true);
}
Mode::HANZI => {
let subset = bits.readBits(4)?;
if subset != 1
{
return Err(Exceptions::format_with("Unsupported HANZI subset"));
}
let count = bits.readBits(mode.CharacterCountBits(version) as usize)?;
DecodeHanziSegment(&mut bits, count, &mut result)?;
}
_ => {
let count = bits.readBits(mode.CharacterCountBits(version) as usize)?;
match mode {
Mode::NUMERIC => DecodeNumericSegment(&mut bits, count, &mut result)?,
Mode::ALPHANUMERIC => {
DecodeAlphanumericSegment(&mut bits, count, &mut result)?
}
Mode::BYTE => DecodeByteSegment(&mut bits, count, &mut result)?,
Mode::KANJI => DecodeKanjiSegment(&mut bits, count, &mut result)?,
_ => return Err(Exceptions::format_with("Invalid CodecMode")), };
}
}
}
Ok(())
})();
Ok(DecoderResult::with_eci_string_builder(result)
.withError(res.err())
.withEcLevel(ecLevel.to_string())
.withVersionNumber(version.getVersionNumber())
.withStructuredAppend(structuredAppend))
}
pub fn Decode(bits: &BitMatrix) -> Result<DecoderResult<bool>> {
let Ok(pversion) = ReadVersion(bits) else {
return Err(Exceptions::format_with("Invalid version"));
};
let version = pversion;
let Ok(formatInfo) = ReadFormatInformation(bits, version.isMicroQRCode()) else {
return Err(Exceptions::format_with("Invalid format information"));
};
let codewords = ReadCodewords(bits, version, &formatInfo)?;
if codewords.is_empty() {
return Err(Exceptions::format_with("Failed to read codewords"));
}
let dataBlocks: Vec<DataBlock> =
DataBlock::getDataBlocks(&codewords, version, formatInfo.error_correction_level)?;
if dataBlocks.is_empty() {
return Err(Exceptions::format_with("Failed to get data blocks"));
}
let op = |totalBytes, dataBlock: &DataBlock| totalBytes + dataBlock.getNumDataCodewords();
let totalBytes = dataBlocks.iter().fold(0, op); let mut resultBytes = vec![0u8; totalBytes as usize];
let mut resultIterator = 0;
for dataBlock in dataBlocks.iter() {
let mut codewordBytes = dataBlock.getCodewords().to_vec();
let numDataCodewords = dataBlock.getNumDataCodewords() as usize;
if !CorrectErrors(&mut codewordBytes, numDataCodewords as u32)? {
return Err(Exceptions::CHECKSUM);
}
resultBytes[resultIterator..(resultIterator + numDataCodewords)]
.copy_from_slice(&codewordBytes[..numDataCodewords]);
resultIterator += numDataCodewords;
}
Ok(
DecodeBitStream(&resultBytes, version, formatInfo.error_correction_level)?
.withIsMirrored(formatInfo.isMirrored),
)
}