use crate::{
common::{BitSource, CharacterSet, DecoderRXingResult, ECIStringBuilder, Eci, Result},
Exceptions,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Mode {
PAD_ENCODE, ASCII_ENCODE,
C40_ENCODE,
TEXT_ENCODE,
ANSIX12_ENCODE,
EDIFACT_ENCODE,
BASE256_ENCODE,
ECI_ENCODE,
}
const C40_BASIC_SET_CHARS: [char; 40] = [
'*', '*', '*', ' ', '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',
];
const C40_SHIFT2_SET_CHARS: [char; 27] = [
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=',
'>', '?', '@', '[', '\\', ']', '^', '_',
];
const TEXT_BASIC_SET_CHARS: [char; 40] = [
'*', '*', '*', ' ', '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',
];
const TEXT_SHIFT2_SET_CHARS: [char; 27] = C40_SHIFT2_SET_CHARS;
const TEXT_SHIFT3_SET_CHARS: [char; 32] = [
'`',
'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',
'{',
'|',
'}',
'~',
127 as char,
];
const INSERT_STRING_CONST: &str = "\u{001E}\u{0004}";
const VALUE_236: &str = "[)>\u{001E}05\u{001D}";
const VALUE_237: &str = "[)>\u{001E}06\u{001D}";
pub fn decode(bytes: &[u8], is_flipped: bool) -> Result<DecoderRXingResult> {
let mut bits = BitSource::new(bytes.to_vec());
let mut result = ECIStringBuilder::with_capacity(100);
let mut resultTrailer = String::new();
let mut byteSegments = Vec::new(); let mut mode = Mode::ASCII_ENCODE;
let mut fnc1Positions = Vec::new();
let symbologyModifier;
let mut isECIencoded = false;
let mut known_eci = true;
let mut is_gs1 = false;
loop {
match mode {
Mode::ASCII_ENCODE => {
mode = decodeAsciiSegment(
&mut bits,
&mut result,
&mut resultTrailer,
&mut fnc1Positions,
&mut is_gs1,
)?
}
Mode::C40_ENCODE => {
decodeC40Segment(&mut bits, &mut result, &mut fnc1Positions)?;
mode = Mode::ASCII_ENCODE;
}
Mode::TEXT_ENCODE => {
decodeTextSegment(&mut bits, &mut result, &mut fnc1Positions)?;
mode = Mode::ASCII_ENCODE;
}
Mode::ANSIX12_ENCODE => {
decodeAnsiX12Segment(&mut bits, &mut result)?;
mode = Mode::ASCII_ENCODE;
}
Mode::EDIFACT_ENCODE => {
decodeEdifactSegment(&mut bits, &mut result)?;
mode = Mode::ASCII_ENCODE;
}
Mode::BASE256_ENCODE => {
decodeBase256Segment(&mut bits, &mut result, &mut byteSegments)?;
mode = Mode::ASCII_ENCODE;
}
Mode::ECI_ENCODE => {
known_eci &= decodeECISegment(&mut bits, &mut result)?;
isECIencoded = true; mode = Mode::ASCII_ENCODE;
}
_ => return Err(Exceptions::FORMAT),
}
if !(mode != Mode::PAD_ENCODE && bits.available() > 0) {
break;
}
} if !resultTrailer.is_empty() {
result.appendCharacters(&resultTrailer);
}
if isECIencoded && known_eci {
if fnc1Positions.contains(&0) || fnc1Positions.contains(&4) {
symbologyModifier = 5;
} else if fnc1Positions.contains(&1) || fnc1Positions.contains(&5) {
symbologyModifier = 6;
} else {
symbologyModifier = 4;
}
} else if fnc1Positions.contains(&0) || fnc1Positions.contains(&4) {
symbologyModifier = 2;
} else if fnc1Positions.contains(&1) || fnc1Positions.contains(&5) {
symbologyModifier = 3;
} else {
symbologyModifier = 1;
}
let mut result = DecoderRXingResult::with_symbology(
bytes.to_vec(),
result.build_result().to_string(),
byteSegments,
String::new(),
symbologyModifier,
);
if is_gs1 {
result.setContentType(String::from("GS1"));
}
if !known_eci {
result.setContentType(String::from("UnknownECI"));
}
if is_flipped {
result.setIsMirrored(is_flipped);
}
Ok(result)
}
fn decodeAsciiSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
resultTrailer: &mut String,
fnc1positions: &mut Vec<usize>,
is_gs1: &mut bool,
) -> Result<Mode> {
let mut upperShift = false;
let mut firstFNC1Position = 1;
let mut firstCodeword = true;
let mut sai = StructuredAppendInfo::default();
loop {
let mut oneByte = bits.readBits(8)?;
match oneByte {
0 => return Err(Exceptions::FORMAT),
1..=128 => {
if upperShift {
oneByte += 128;
}
result.append_char(char::from_u32(oneByte - 1).ok_or(Exceptions::PARSE)?);
return Ok(Mode::ASCII_ENCODE);
}
129 => return Ok(Mode::PAD_ENCODE), 130..=229 => {
let value = oneByte - 130;
if value < 10 {
result.append_char('0');
}
result.append_string(&format!("{value}"));
}
230 =>
{
return Ok(Mode::C40_ENCODE)
}
231 =>
{
return Ok(Mode::BASE256_ENCODE)
}
232 => {
if bits.getByteOffset() == firstFNC1Position {
*is_gs1 = true;
}
else if bits.getByteOffset() == firstFNC1Position + 1 {
}
else {
result.append_char(29 as char);
}
fnc1positions.push(result.len());
}
233 =>
{
if !firstCodeword
{
return Err(Exceptions::format_with(
"structured append tag must be first code word",
));
}
parse_structured_append(bits, &mut sai)?;
firstFNC1Position = 5;
}
234 =>
{}
235 =>
{
upperShift = true
}
236 => {
result.append_string(VALUE_236);
resultTrailer.replace_range(0..0, INSERT_STRING_CONST);
}
237 => {
result.append_string(VALUE_237);
resultTrailer.replace_range(0..0, INSERT_STRING_CONST);
}
238 =>
{
return Ok(Mode::ANSIX12_ENCODE)
}
239 =>
{
return Ok(Mode::TEXT_ENCODE)
}
240 =>
{
return Ok(Mode::EDIFACT_ENCODE)
}
241 =>
{
return Ok(Mode::ECI_ENCODE)
}
_ => {
if oneByte != 254 || bits.available() != 0 {
return Err(Exceptions::FORMAT);
}
}
}
if bits.available() == 0 {
break;
}
firstCodeword = false;
} Ok(Mode::ASCII_ENCODE)
}
fn decodeC40Segment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
fnc1positions: &mut Vec<usize>,
) -> Result<()> {
let mut upperShift = false;
let mut cValues = [0; 3];
let mut shift = 0;
loop {
if bits.available() == 8 {
return Ok(());
}
let firstByte = bits.readBits(8)?;
if firstByte == 254 {
return Ok(());
}
parseTwoBytes(firstByte, bits.readBits(8)?, &mut cValues);
for cValue in cValues {
match shift {
0 => {
if cValue < 3 {
shift = cValue + 1;
} else if cValue < C40_BASIC_SET_CHARS.len() as u32 {
let c40char = C40_BASIC_SET_CHARS[cValue as usize];
if upperShift {
result.append_char(
char::from_u32(c40char as u32 + 128).ok_or(Exceptions::PARSE)?,
);
upperShift = false;
} else {
result.append_char(c40char);
}
} else {
return Err(Exceptions::FORMAT);
}
}
1 => {
if upperShift {
result.append_char(char::from_u32(cValue + 128).ok_or(Exceptions::PARSE)?);
upperShift = false;
} else {
result.append_char(char::from_u32(cValue).ok_or(Exceptions::PARSE)?);
}
shift = 0;
}
2 => {
if cValue < C40_SHIFT2_SET_CHARS.len() as u32 {
let c40char = C40_SHIFT2_SET_CHARS[cValue as usize];
if upperShift {
result.append_char(
char::from_u32(c40char as u32 + 128).ok_or(Exceptions::PARSE)?,
);
upperShift = false;
} else {
result.append_char(c40char);
}
} else {
match cValue {
27 => {
fnc1positions.push(result.len());
result.append_char(29 as char); }
30 =>
{
upperShift = true
}
_ => return Err(Exceptions::FORMAT),
}
}
shift = 0;
}
3 => {
if upperShift {
result.append_char(char::from_u32(cValue + 224).ok_or(Exceptions::PARSE)?);
upperShift = false;
} else {
result.append_char(char::from_u32(cValue + 96).ok_or(Exceptions::PARSE)?);
}
shift = 0;
}
_ => return Err(Exceptions::FORMAT),
}
}
if bits.available() == 0 {
break;
}
} Ok(())
}
fn decodeTextSegment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
fnc1positions: &mut Vec<usize>,
) -> Result<()> {
let mut upperShift = false;
let mut cValues = [0; 3]; let mut shift = 0;
loop {
if bits.available() == 8 {
return Ok(());
}
let firstByte = bits.readBits(8)?;
if firstByte == 254 {
return Ok(());
}
parseTwoBytes(firstByte, bits.readBits(8)?, &mut cValues);
for cValue in cValues {
match shift {
0 => {
if cValue < 3 {
shift = cValue + 1;
} else if cValue < TEXT_BASIC_SET_CHARS.len() as u32 {
let textChar = TEXT_BASIC_SET_CHARS[cValue as usize];
if upperShift {
result.append_char(
char::from_u32(textChar as u32 + 128).ok_or(Exceptions::PARSE)?,
);
upperShift = false;
} else {
result.append_char(textChar);
}
} else {
return Err(Exceptions::FORMAT);
}
}
1 => {
if upperShift {
result.append_char(char::from_u32(cValue + 128).ok_or(Exceptions::PARSE)?);
upperShift = false;
} else {
result.append_char(char::from_u32(cValue).ok_or(Exceptions::PARSE)?);
}
shift = 0;
}
2 => {
if cValue < TEXT_SHIFT2_SET_CHARS.len() as u32 {
let textChar = TEXT_SHIFT2_SET_CHARS[cValue as usize];
if upperShift {
result.append_char(
char::from_u32(textChar as u32 + 128).ok_or(Exceptions::PARSE)?,
);
upperShift = false;
} else {
result.append_char(textChar);
}
} else {
match cValue {
27 => {
fnc1positions.push(result.len());
result.append_char(29 as char); }
30 =>
{
upperShift = true
}
_ => return Err(Exceptions::FORMAT),
}
}
shift = 0;
}
3 => {
if cValue < TEXT_SHIFT3_SET_CHARS.len() as u32 {
let textChar = TEXT_SHIFT3_SET_CHARS[cValue as usize];
if upperShift {
result.append_char(
char::from_u32(textChar as u32 + 128).ok_or(Exceptions::PARSE)?,
);
upperShift = false;
} else {
result.append_char(textChar);
}
shift = 0;
} else {
return Err(Exceptions::FORMAT);
}
}
_ => return Err(Exceptions::FORMAT),
}
}
if bits.available() == 0 {
break;
}
}
Ok(())
}
fn decodeAnsiX12Segment(bits: &mut BitSource, result: &mut ECIStringBuilder) -> Result<()> {
let mut cValues = [0; 3]; loop {
if bits.available() == 8 {
return Ok(());
}
let firstByte = bits.readBits(8)?;
if firstByte == 254 {
return Ok(());
}
parseTwoBytes(firstByte, bits.readBits(8)?, &mut cValues);
for cValue in cValues {
match cValue {
0 =>
{
result.append_char('\r')
}
1 =>
{
result.append_char('*')
}
2 =>
{
result.append_char('>')
}
3 =>
{
result.append_char(' ')
}
_ => {
if cValue < 14 {
result.append_char(char::from_u32(cValue + 44).ok_or(Exceptions::PARSE)?);
} else if cValue < 40 {
result.append_char(char::from_u32(cValue + 51).ok_or(Exceptions::PARSE)?);
} else {
return Err(Exceptions::FORMAT);
}
}
}
}
if bits.available() == 0 {
break;
}
}
Ok(())
}
fn parseTwoBytes(firstByte: u32, secondByte: u32, result: &mut [u32]) {
let mut fullBitValue = (firstByte << 8) + secondByte - 1;
let mut temp = fullBitValue / 1600;
result[0] = temp;
fullBitValue -= temp * 1600;
temp = fullBitValue / 40;
result[1] = temp;
result[2] = fullBitValue - temp * 40;
}
fn decodeEdifactSegment(bits: &mut BitSource, result: &mut ECIStringBuilder) -> Result<()> {
loop {
if bits.available() <= 16 {
return Ok(());
}
for _i in 0..4 {
let mut edifactValue = bits.readBits(6)?;
if edifactValue == 0x1F {
let bitsLeft = 8 - bits.getBitOffset();
if bitsLeft != 8 {
bits.readBits(bitsLeft)?;
}
return Ok(());
}
if (edifactValue & 0x20) == 0 {
edifactValue |= 0x40; }
result.append_char(char::from_u32(edifactValue).ok_or(Exceptions::PARSE)?);
}
if bits.available() == 0 {
break;
}
}
Ok(())
}
fn decodeBase256Segment(
bits: &mut BitSource,
result: &mut ECIStringBuilder,
byteSegments: &mut Vec<Vec<u8>>,
) -> Result<()> {
let mut codewordPosition = 1 + bits.getByteOffset(); let d1 = unrandomize255State(bits.readBits(8)?, codewordPosition);
codewordPosition += 1;
let count;
if d1 == 0 {
count = bits.available() as u32 / 8;
} else if d1 < 250 {
count = d1;
} else {
count = 250 * (d1 - 249) + unrandomize255State(bits.readBits(8)?, codewordPosition);
codewordPosition += 1;
}
let mut bytes = vec![0u8; count as usize];
for byte in bytes.iter_mut().take(count as usize) {
if bits.available() < 8 {
return Err(Exceptions::FORMAT);
}
*byte = unrandomize255State(bits.readBits(8)?, codewordPosition) as u8;
codewordPosition += 1;
}
result.append_string(&CharacterSet::ISO8859_1.decode(&bytes)?);
byteSegments.push(bytes);
Ok(())
}
fn decodeECISegment(bits: &mut BitSource, result: &mut ECIStringBuilder) -> Result<bool> {
let firstByte = bits.readBits(8)?;
if firstByte <= 127 {
result.append_eci(Eci::from(firstByte - 1));
return Ok(true);
}
let secondByte = bits.readBits(8)?;
if firstByte <= 191 {
result.append_eci(Eci::from((firstByte - 128) * 254 + 127 + secondByte - 1));
return Ok((firstByte - 128) * 254 + 127 + secondByte - 1 > 900);
}
let thirdByte = bits.readBits(8)?;
result.append_eci(Eci::from(
(firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1,
));
Ok((firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1 > 900)
}
fn parse_structured_append(bits: &mut BitSource, sai: &mut StructuredAppendInfo) -> Result<()> {
let symbolSequenceIndicator = bits.readBits(8)?;
sai.index = (symbolSequenceIndicator >> 4) as i32;
sai.count = (17 - (symbolSequenceIndicator & 0x0F)) as i32;
if sai.count == 17 || sai.count <= sai.index
{
sai.count = 0; }
let fileId1 = bits.readBits(8)?; let fileId2 = bits.readBits(8)?;
sai.id = ((fileId1 << 8) | fileId2).to_string();
Ok(())
}
struct StructuredAppendInfo {
index: i32, count: i32, id: String,
}
impl Default for StructuredAppendInfo {
fn default() -> Self {
Self {
index: -1,
count: -1,
id: Default::default(),
}
}
}
fn unrandomize255State(randomizedBase256Codeword: u32, base256CodewordPosition: usize) -> u32 {
let pseudoRandomNumber = ((149 * base256CodewordPosition as u32) % 255) + 1;
let tempVariable = randomizedBase256Codeword as i32 - pseudoRandomNumber as i32;
if tempVariable >= 0 {
tempVariable as u32
} else {
(tempVariable + 256) as u32
}
}
#[cfg(test)]
mod tests {
use crate::datamatrix::decoder::decoded_bit_stream_parser;
#[test]
fn testAsciiStandardDecode() {
let bytes = [
(b'a' + 1),
(b'b' + 1),
(b'c' + 1),
(b'A' + 1),
(b'B' + 1),
(b'C' + 1),
];
let decodedString = String::from(
decoded_bit_stream_parser::decode(&bytes, false)
.expect("decode")
.getText(),
);
assert_eq!("abcABC", decodedString);
}
#[test]
fn testAsciiDoubleDigitDecode() {
let bytes = [130, (1 + 130), (98 + 130), (99 + 130)];
let decodedString = String::from(
decoded_bit_stream_parser::decode(&bytes, false)
.expect("decode")
.getText(),
);
assert_eq!("00019899", decodedString);
}
}