/* * Copyright 2006-2007 Jeremias Maerki. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use std::rc::Rc; use crate::common::Result; use crate::{Dimension, Exceptions}; use super::{SymbolInfo, SymbolInfoLookup, SymbolShapeHint}; use encoding::{self, EncodingRef}; const ISO_8859_1_ENCODER: EncodingRef = encoding::all::ISO_8859_1; pub struct EncoderContext<'a> { symbol_lookup: Rc>, msg: String, shape: SymbolShapeHint, minSize: Option, maxSize: Option, codewords: String, pub(super) pos: u32, newEncoding: Option, symbolInfo: Option<&'a SymbolInfo>, skipAtEnd: u32, } impl<'a> EncoderContext<'_> { pub fn with_symbol_info_lookup( msg: &str, symbol_lookup: Rc>, ) -> Result> { let mut new_self = EncoderContext::new(msg)?; new_self.symbol_lookup = symbol_lookup.clone(); Ok(new_self) } pub fn new(msg: &str) -> Result { //From this point on Strings are not Unicode anymore! // let msgBinary = ISO_8859_1_ENCODER.encode(msg, encoding::EncoderTrap::Strict).expect("encode to bytes");//msg.getBytes(StandardCharsets.ISO_8859_1); // let sb = String::with_capacity(msgBinary.len()); // for (int i = 0, c = msgBinary.length; i < c; i++) { // char ch = (char) (msgBinary[i] & 0xff); // if (ch == '?' && msg.charAt(i) != '?') { // throw new IllegalArgumentException("Message contains characters outside ISO-8859-1 encoding."); // } // sb.append(ch); // } let sb = if let Ok(encoded_bytes) = ISO_8859_1_ENCODER.encode(msg, encoding::EncoderTrap::Strict) { ISO_8859_1_ENCODER .decode(&encoded_bytes, encoding::DecoderTrap::Strict) .map_err(|e| { Exceptions::ParseException(Some(format!( "round trip decode should always work: {e}" ))) })? } else { return Err(Exceptions::IllegalArgumentException(Some( "Message contains characters outside ISO-8859-1 encoding.".to_owned(), ))); }; Ok(Self { symbol_lookup: Rc::new(SymbolInfoLookup::new()), msg: sb, shape: SymbolShapeHint::FORCE_NONE, codewords: String::with_capacity(msg.chars().count()), newEncoding: None, minSize: None, maxSize: None, pos: 0, symbolInfo: None, skipAtEnd: 0, }) } pub fn setSymbolShape(&mut self, shape: SymbolShapeHint) { self.shape = shape; } pub fn setSizeConstraints(&mut self, minSize: Option, maxSize: Option) { self.minSize = minSize; self.maxSize = maxSize; } pub fn getMessage(&self) -> &str { &self.msg } pub fn setSkipAtEnd(&mut self, count: u32) { self.skipAtEnd = count; } /// panics if current position is out of bounds pub fn getCurrentChar(&self) -> char { self.msg.chars().nth(self.pos as usize).unwrap() } /// panics if current position is out of bounds pub fn getCurrent(&self) -> char { self.msg.chars().nth(self.pos as usize).unwrap() } pub fn getCodewords(&self) -> &str { &self.codewords } pub fn writeCodewords(&mut self, codewords: &str) { self.codewords.push_str(codewords); } pub fn writeCodeword(&mut self, codeword: u8) { self.codewords.push(codeword as char); } pub fn getCodewordCount(&self) -> usize { self.codewords.chars().count() } pub fn getNewEncoding(&self) -> Option { self.newEncoding } pub fn signalEncoderChange(&mut self, encoding: usize) { self.newEncoding = Some(encoding); } pub fn resetEncoderSignal(&mut self) { self.newEncoding = None; } pub fn hasMoreCharacters(&self) -> bool { self.pos < self.getTotalMessageCharCount() } fn getTotalMessageCharCount(&self) -> u32 { self.msg.chars().count() as u32 - self.skipAtEnd } pub fn getRemainingCharacters(&self) -> u32 { self.getTotalMessageCharCount() - self.pos } pub fn getSymbolInfo(&self) -> &Option<&SymbolInfo> { &self.symbolInfo } pub fn updateSymbolInfo(&mut self) { self.updateSymbolInfoWithLength(self.getCodewordCount()); } /// Update symbol info with the length /// /// This function can panic pub fn updateSymbolInfoWithLength(&mut self, len: usize) { if self.symbolInfo.is_none() || len > self.symbolInfo.as_ref().unwrap().getDataCapacity() as usize { self.symbolInfo = Some( self.symbol_lookup .lookup_with_codewords_shape_size_fail( len as u32, self.shape, &self.minSize, &self.maxSize, true, ) .unwrap() .unwrap(), ); } } pub fn resetSymbolInfo(&mut self) { self.symbolInfo = None; } }