use crate::{SymbolType, color::Color, decoder::decode_e, img_scanner::ImageScanner};
fn width_class(e: u32, s: u32) -> u8 {
decode_e(e, s, 45) as u8
}
fn i25_decode1(enc: u8, e: u32, s: u32) -> u8 {
let e_val = width_class(e, s);
if e_val > 7 {
return 0xff;
}
let mut enc = enc << 1;
if e_val > 2 {
enc |= 1;
}
enc
}
fn i25_decode10(dcode: &ImageScanner, offset: u8) -> u8 {
let dcode25 = &dcode.i25;
if dcode25.s10 < 10 {
return 0xff;
}
let mut enc: u8 = 0;
let mut par: u8 = 0;
let mut i: i8 = 8;
while i >= 0 {
let j = offset
+ if dcode25.direction() {
i as u8
} else {
8 - i as u8
};
enc = i25_decode1(enc, dcode.get_width(j), dcode25.s10);
if enc == 0xff {
return 0xff;
}
if enc & 1 != 0 {
par += 1;
}
i -= 2;
}
if par != 2 {
return 0xff;
}
enc &= 0xf;
if enc & 8 != 0 {
if enc == 12 {
enc = 0;
} else {
enc -= 1;
if enc > 9 {
return 0xff;
}
}
}
enc
}
fn i25_decode_start(dcode: &mut ImageScanner) -> SymbolType {
let s10 = dcode.i25.s10;
if s10 < 10 {
return SymbolType::None;
}
let mut enc: u8 = 0;
let mut i: u8 = 10;
enc = i25_decode1(enc, dcode.get_width(i), s10);
i += 1;
enc = i25_decode1(enc, dcode.get_width(i), s10);
i += 1;
enc = i25_decode1(enc, dcode.get_width(i), s10);
i += 1;
let valid = if dcode.color() == Color::Bar {
enc == 4
} else {
enc = i25_decode1(enc, dcode.get_width(i), s10);
i += 1;
enc == 0
};
if !valid {
return SymbolType::None;
}
let quiet = dcode.get_width(i);
if quiet != 0 && quiet < s10 * 3 / 8 {
return SymbolType::None;
}
dcode.i25.set_direction(dcode.color() != Color::Space);
dcode.i25.set_element(1);
dcode.i25.set_character(0);
SymbolType::Partial
}
fn i25_acquire_lock(dcode: &mut ImageScanner) -> bool {
if !dcode.acquire_lock(SymbolType::I25) {
dcode.i25.set_character(-1);
return true;
}
false
}
fn i25_decode_end(dcode: &mut ImageScanner) -> SymbolType {
let width = dcode.i25.width;
let direction = dcode.i25.direction();
let character = dcode.i25.character();
let quiet = dcode.get_width(0);
if (quiet != 0 && quiet < width * 3 / 8)
|| decode_e(dcode.get_width(1), width, 45) > 2
|| decode_e(dcode.get_width(2), width, 45) > 2
{
return SymbolType::None;
}
let e = width_class(dcode.get_width(3), width);
let valid = if !direction {
e <= 7
} else {
e <= 2 && width_class(dcode.get_width(4), width) <= 2
};
if !valid {
return SymbolType::None;
}
if character <= 4 && i25_acquire_lock(dcode) {
return SymbolType::Partial;
}
dcode.direction = 1 - 2 * (direction as i32);
let char_count = character as usize;
let (min_len, max_len) = dcode.get_length_limits(SymbolType::I25).unwrap_or((6, 0));
if dcode.i25.buffer.len() < char_count {
return SymbolType::None;
}
if direction {
dcode.i25.buffer[..char_count].reverse();
}
if character < min_len as i16 || (max_len > 0 && character > max_len as i16) {
dcode.release_lock(SymbolType::I25);
dcode.i25.set_character(-1);
return SymbolType::None;
}
let holding = std::mem::take(&mut dcode.i25.buffer);
let copied = dcode
.buffer_mut_slice(char_count)
.map(|buf| buf.copy_from_slice(&holding[..char_count]));
dcode.i25.buffer = holding;
if copied.is_err() {
dcode.release_lock(SymbolType::I25);
dcode.i25.set_character(-1);
return SymbolType::None;
}
dcode.modifiers = 0;
dcode.i25.set_character(-1);
SymbolType::I25
}
fn i25_reset(dcode: &mut ImageScanner) -> SymbolType {
if dcode.i25.character() >= 4 {
dcode.release_lock(SymbolType::I25);
}
dcode.i25.set_character(-1);
SymbolType::None
}
pub(crate) fn decode_i25(dcode: &mut ImageScanner) -> SymbolType {
let w10 = dcode.get_width(10);
let w0 = dcode.get_width(0);
dcode.i25.s10 = dcode.i25.s10.wrapping_sub(w10).wrapping_add(w0);
if dcode.i25.character() < 0 && i25_decode_start(dcode) == SymbolType::None {
return SymbolType::None;
}
let element = dcode.i25.element();
dcode.i25.set_element(element.wrapping_sub(1));
let check_element = 6u8.wrapping_sub(dcode.i25.direction() as u8);
if dcode.i25.element() == check_element {
return i25_decode_end(dcode);
} else if dcode.i25.element() != 0 {
return SymbolType::None;
}
dcode.i25.width = dcode.i25.s10;
if dcode.i25.character() == 4 && i25_acquire_lock(dcode) {
return SymbolType::Partial;
}
let c = i25_decode10(dcode, 1);
if c > 9 {
return i25_reset(dcode);
}
let character = dcode.i25.character();
if dcode.set_buffer_capacity(character as usize + 3).is_err() {
return i25_reset(dcode);
}
dcode.i25.set_byte(character as usize, c + b'0');
dcode.i25.set_character(character + 1);
let c = i25_decode10(dcode, 0);
if c > 9 {
return i25_reset(dcode);
}
let character = dcode.i25.character();
dcode.i25.set_byte(character as usize, c + b'0');
dcode.i25.set_character(character + 1);
dcode.i25.set_element(10);
if dcode.i25.character() == 2 {
SymbolType::Partial
} else {
SymbolType::None
}
}