use crate::{
common::{
BitSource, CharacterSet, DecoderRXingResult, ECIStringBuilder, Eci, Result, StringUtils,
},
DecodingHintDictionary, Exceptions,
};
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
use crate::{DecodeHintType, DecodeHintValue};
use super::{ErrorCorrectionLevel, Mode, VersionRef};
const ALPHANUMERIC_CHARS: &str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
const GB2312_SUBSET: u32 = 1;
pub fn decode(
bytes: &[u8],
version: VersionRef,
ecLevel: ErrorCorrectionLevel,
hints: &DecodingHintDictionary,
) -> Result<DecoderRXingResult> {
let mut bits = BitSource::new(bytes.to_owned());
let mut result = ECIStringBuilder::with_capacity(50); let mut byteSegments = vec![vec![0u8; 0]; 0];
let mut symbolSequence = -1;
let mut parityData = -1;
let mut currentCharacterSetECI = None;
let mut fc1InEffect = false;
let mut hasFNC1first = false;
let mut hasFNC1second = false;
let mut mode;
loop {
if bits.available() < 4 {
mode = Mode::TERMINATOR;
} else {
mode = Mode::forBits(bits.readBits(4)? as u8)?; }
match mode {
Mode::TERMINATOR => {}
Mode::FNC1_FIRST_POSITION => {
hasFNC1first = true; fc1InEffect = true;
}
Mode::FNC1_SECOND_POSITION => {
hasFNC1second = true; fc1InEffect = true;
}
Mode::STRUCTURED_APPEND => {
if bits.available() < 16 {
return Err(Exceptions::format_with(format!(
"Mode::Structured append expected bits.available() < 16, found bits of {}",
bits.available()
)));
}
symbolSequence = bits.readBits(8)? as i32;
parityData = bits.readBits(8)? as i32;
}
Mode::ECI => {
let value = parseECIValue(&mut bits)?;
currentCharacterSetECI = CharacterSet::from(value).into(); if currentCharacterSetECI.is_none() {
return Err(Exceptions::format_with(format!(
"Value of {value} not valid"
)));
}
}
Mode::HANZI => {
let subset = bits.readBits(4)?;
let countHanzi =
bits.readBits(mode.getCharacterCountBits(version) as usize)? as usize;
if subset == GB2312_SUBSET {
decodeHanziSegment(&mut bits, &mut result, countHanzi)?;
}
}
_ => {
let count = bits.readBits(mode.getCharacterCountBits(version) as usize)? as usize;
match mode {
Mode::NUMERIC => decodeNumericSegment(&mut bits, &mut result, count)?,
Mode::ALPHANUMERIC => {
decodeAlphanumericSegment(&mut bits, &mut result, count, fc1InEffect)?
}
Mode::BYTE => decodeByteSegment(
&mut bits,
&mut result,
count,
currentCharacterSetECI,
&mut byteSegments,
hints,
)?,
Mode::KANJI => decodeKanjiSegment(
&mut bits,
&mut result,
count,
currentCharacterSetECI,
hints,
)?,
_ => return Err(Exceptions::FORMAT),
}
}
}
if mode == Mode::TERMINATOR {
break;
}
}
let symbologyModifier = get_symbology_identifier(
currentCharacterSetECI.is_some(),
hasFNC1first,
hasFNC1second,
);
Ok(DecoderRXingResult::with_all(
bytes.to_owned(),
result.build_result().to_string(),
byteSegments.to_vec(),
format!("{}", u8::from(ecLevel)),
symbolSequence,
parityData,
symbologyModifier,
String::default(),
false,
))
}
fn get_symbology_identifier(has_charset: bool, hasFNC1first: bool, hasFNC1second: bool) -> u32 {
if has_charset {
if hasFNC1first {
4
} else if hasFNC1second {
6
} else {
2
}
} else if hasFNC1first {
3
} else if hasFNC1second {
5
} else {
1
}
}
fn decodeHanziSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
count: usize,
) -> Result<()> {
if count * 13 > bits.available() {
return Err(Exceptions::FORMAT);
}
let mut buffer = vec![0u8; 2 * count];
let mut offset = 0;
let mut count = count;
while count > 0 {
let twoBytes = bits.readBits(13)?;
let mut assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060);
if assembledTwoBytes < 0x00A00 {
assembledTwoBytes += 0x0A1A1;
} else {
assembledTwoBytes += 0x0A6A1;
}
buffer[offset] = (assembledTwoBytes >> 8) as u8;
buffer[offset + 1] = assembledTwoBytes as u8;
offset += 2;
count -= 1;
}
result.append_eci(Eci::GB18030);
result.append_bytes(&buffer);
Ok(())
}
fn decodeKanjiSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
count: usize,
currentCharacterSetECI: Option<CharacterSet>,
hints: &DecodingHintDictionary,
) -> Result<()> {
if count * 13 > bits.available() {
return Err(Exceptions::FORMAT);
}
let mut buffer = vec![0u8; 2 * count];
let mut offset = 0;
let mut count = count;
while count > 0 {
let twoBytes = bits.readBits(13)?;
let mut assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0);
if assembledTwoBytes < 0x01F00 {
assembledTwoBytes += 0x08140;
} else {
assembledTwoBytes += 0x0C140;
}
buffer[offset] = (assembledTwoBytes >> 8) as u8;
buffer[offset + 1] = assembledTwoBytes as u8;
offset += 2;
count -= 1;
}
#[cfg(not(feature = "allow_forced_iso_ied_18004_compliance"))]
let encoder = {
let _ = currentCharacterSetECI;
let _ = hints;
CharacterSet::Shift_JIS
};
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
let encoder = if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) =
hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT)
{
currentCharacterSetECI.unwrap_or(CharacterSet::ISO8859_1)
} else {
CharacterSet::Shift_JIS
};
result.append_eci(Eci::from(encoder));
result.append_bytes(&buffer);
Ok(())
}
fn decodeByteSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
count: usize,
currentCharacterSetECI: Option<CharacterSet>,
byteSegments: &mut Vec<Vec<u8>>,
hints: &DecodingHintDictionary,
) -> Result<()> {
if 8 * count > bits.available() {
return Err(Exceptions::FORMAT);
}
let mut readBytes = vec![0u8; count];
for byte in readBytes.iter_mut().take(count) {
*byte = bits.readBits(8)? as u8;
}
let encoding = if currentCharacterSetECI.is_none() {
{
#[cfg(not(feature = "allow_forced_iso_ied_18004_compliance"))]
StringUtils::guessCharset(&readBytes, hints).ok_or(Exceptions::ILLEGAL_STATE)?
}
#[cfg(feature = "allow_forced_iso_ied_18004_compliance")]
if let Some(DecodeHintValue::QrAssumeSpecConformInput(true)) =
hints.get(&DecodeHintType::QR_ASSUME_SPEC_CONFORM_INPUT)
{
CharacterSet::ISO8859_1
} else {
StringUtils::guessCharset(&readBytes, hints).ok_or(Exceptions::ILLEGAL_STATE)?
}
} else {
currentCharacterSetECI.ok_or(Exceptions::ILLEGAL_STATE)?
};
result.append_eci(Eci::from(encoding));
result.append_bytes(&readBytes);
byteSegments.push(readBytes);
Ok(())
}
fn toAlphaNumericChar(value: u32) -> Result<char> {
if value as usize >= ALPHANUMERIC_CHARS.len() {
return Err(Exceptions::FORMAT);
}
ALPHANUMERIC_CHARS
.chars()
.nth(value as usize)
.ok_or(Exceptions::FORMAT)
}
fn decodeAlphanumericSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
count: usize,
fc1InEffect: bool,
) -> Result<()> {
let mut r_hld = String::with_capacity(count);
let start = 0;
let mut count = count;
while count > 1 {
if bits.available() < 11 {
return Err(Exceptions::FORMAT);
}
let nextTwoCharsBits = bits.readBits(11)?;
r_hld.push(toAlphaNumericChar(nextTwoCharsBits / 45)?);
r_hld.push(toAlphaNumericChar(nextTwoCharsBits % 45)?);
count -= 2;
}
if count == 1 {
if bits.available() < 6 {
return Err(Exceptions::FORMAT);
}
r_hld.push(toAlphaNumericChar(bits.readBits(6)?)?);
}
if fc1InEffect {
for i in start..r_hld.len() {
if r_hld
.chars()
.nth(i)
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
== '%'
{
if i < result.len() - 1
&& r_hld
.chars()
.nth(i + 1)
.ok_or(Exceptions::INDEX_OUT_OF_BOUNDS)?
== '%'
{
r_hld.remove(i + 1);
} else {
r_hld.replace_range(i..i + 1, "\u{1D}");
}
}
}
}
result.append_eci(Eci::ISO8859_1);
result.append_string(&r_hld);
Ok(())
}
fn decodeNumericSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
count: usize,
) -> Result<()> {
result.append_eci(Eci::ISO8859_1);
let mut count = count;
while count >= 3 {
if bits.available() < 10 {
return Err(Exceptions::FORMAT);
}
let threeDigitsBits = bits.readBits(10)?;
if threeDigitsBits >= 1000 {
return Err(Exceptions::FORMAT);
}
result.append_char(toAlphaNumericChar(threeDigitsBits / 100)?);
result.append_char(toAlphaNumericChar((threeDigitsBits / 10) % 10)?);
result.append_char(toAlphaNumericChar(threeDigitsBits % 10)?);
count -= 3;
}
if count == 2 {
if bits.available() < 7 {
return Err(Exceptions::FORMAT);
}
let twoDigitsBits = bits.readBits(7)?;
if twoDigitsBits >= 100 {
return Err(Exceptions::FORMAT);
}
result.append_char(toAlphaNumericChar(twoDigitsBits / 10)?);
result.append_char(toAlphaNumericChar(twoDigitsBits % 10)?);
} else if count == 1 {
if bits.available() < 4 {
return Err(Exceptions::FORMAT);
}
let digitBits = bits.readBits(4)?;
if digitBits >= 10 {
return Err(Exceptions::FORMAT);
}
result.append_char(toAlphaNumericChar(digitBits)?);
}
Ok(())
}
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)
}