|
|
|
|
@@ -18,11 +18,14 @@
|
|
|
|
|
* This file has been modified from its original form in Barcode4J.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
use std::{fmt::Display, any::TypeId};
|
|
|
|
|
use std::{any::TypeId, fmt::Display};
|
|
|
|
|
|
|
|
|
|
use encoding::EncodingRef;
|
|
|
|
|
|
|
|
|
|
use crate::{Exceptions, common::{ECIInput, MinimalECIInput, CharacterSetECI}};
|
|
|
|
|
use crate::{
|
|
|
|
|
common::{CharacterSetECI, ECIInput, MinimalECIInput},
|
|
|
|
|
Exceptions,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use super::Compaction;
|
|
|
|
|
|
|
|
|
|
@@ -31,147 +34,149 @@ use super::Compaction;
|
|
|
|
|
* annex P.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* code for Text compaction
|
|
|
|
|
*/
|
|
|
|
|
const TEXT_COMPACTION : u32= 0;
|
|
|
|
|
const TEXT_COMPACTION: u32 = 0;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* code for Byte compaction
|
|
|
|
|
*/
|
|
|
|
|
const BYTE_COMPACTION:u32 = 1;
|
|
|
|
|
const BYTE_COMPACTION: u32 = 1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* code for Numeric compaction
|
|
|
|
|
*/
|
|
|
|
|
const NUMERIC_COMPACTION:u32 = 2;
|
|
|
|
|
const NUMERIC_COMPACTION: u32 = 2;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Text compaction submode Alpha
|
|
|
|
|
*/
|
|
|
|
|
const SUBMODE_ALPHA:u32 = 0;
|
|
|
|
|
const SUBMODE_ALPHA: u32 = 0;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Text compaction submode Lower
|
|
|
|
|
*/
|
|
|
|
|
const SUBMODE_LOWER:u32 = 1;
|
|
|
|
|
const SUBMODE_LOWER: u32 = 1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Text compaction submode Mixed
|
|
|
|
|
*/
|
|
|
|
|
const SUBMODE_MIXED:u32 = 2;
|
|
|
|
|
const SUBMODE_MIXED: u32 = 2;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Text compaction submode Punctuation
|
|
|
|
|
*/
|
|
|
|
|
const SUBMODE_PUNCTUATION:u32 = 3;
|
|
|
|
|
const SUBMODE_PUNCTUATION: u32 = 3;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* mode latch to Text Compaction mode
|
|
|
|
|
*/
|
|
|
|
|
const LATCH_TO_TEXT:u32 = 900;
|
|
|
|
|
const LATCH_TO_TEXT: u32 = 900;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* mode latch to Byte Compaction mode (number of characters NOT a multiple of 6)
|
|
|
|
|
*/
|
|
|
|
|
const LATCH_TO_BYTE_PADDED:u32 = 901;
|
|
|
|
|
const LATCH_TO_BYTE_PADDED: u32 = 901;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* mode latch to Numeric Compaction mode
|
|
|
|
|
*/
|
|
|
|
|
const LATCH_TO_NUMERIC:u32 = 902;
|
|
|
|
|
const LATCH_TO_NUMERIC: u32 = 902;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* mode shift to Byte Compaction mode
|
|
|
|
|
*/
|
|
|
|
|
const SHIFT_TO_BYTE:u32 = 913;
|
|
|
|
|
const SHIFT_TO_BYTE: u32 = 913;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* mode latch to Byte Compaction mode (number of characters a multiple of 6)
|
|
|
|
|
*/
|
|
|
|
|
const LATCH_TO_BYTE:u32 = 924;
|
|
|
|
|
const LATCH_TO_BYTE: u32 = 924;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* identifier for a user defined Extended Channel Interpretation (ECI)
|
|
|
|
|
*/
|
|
|
|
|
const ECI_USER_DEFINED :u32= 925;
|
|
|
|
|
const ECI_USER_DEFINED: u32 = 925;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* identifier for a general purpose ECO format
|
|
|
|
|
*/
|
|
|
|
|
const ECI_GENERAL_PURPOSE:u32 = 926;
|
|
|
|
|
const ECI_GENERAL_PURPOSE: u32 = 926;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* identifier for an ECI of a character set of code page
|
|
|
|
|
*/
|
|
|
|
|
const ECI_CHARSET:u32 = 927;
|
|
|
|
|
const ECI_CHARSET: u32 = 927;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Raw code table for text compaction Mixed sub-mode
|
|
|
|
|
*/
|
|
|
|
|
const TEXT_MIXED_RAW : [u8;30]= [
|
|
|
|
|
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58,
|
|
|
|
|
35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0];
|
|
|
|
|
const TEXT_MIXED_RAW: [u8; 30] = [
|
|
|
|
|
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, 35, 45, 46, 36, 47, 43, 37, 42, 61,
|
|
|
|
|
94, 0, 32, 0, 0, 0,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Raw code table for text compaction: Punctuation sub-mode
|
|
|
|
|
*/
|
|
|
|
|
const TEXT_PUNCTUATION_RAW :[u8;30] = [
|
|
|
|
|
59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58,
|
|
|
|
|
10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0];
|
|
|
|
|
const TEXT_PUNCTUATION_RAW: [u8; 30] = [
|
|
|
|
|
59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, 10, 45, 46, 36, 47, 34, 124, 42,
|
|
|
|
|
40, 41, 63, 123, 125, 39, 0,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// const MIXED : [u8;128]= [0;128];//new byte[128];
|
|
|
|
|
// const MIXED : [u8;128]= [0;128];//new byte[128];
|
|
|
|
|
|
|
|
|
|
// const PUNCTUATION : [u8;128]= [0;128];//new byte[128];
|
|
|
|
|
// const PUNCTUATION : [u8;128]= [0;128];//new byte[128];
|
|
|
|
|
|
|
|
|
|
const DEFAULT_ENCODING : EncodingRef= encoding::all::ISO_8859_1; //StandardCharsets.ISO_8859_1;
|
|
|
|
|
const DEFAULT_ENCODING: EncodingRef = encoding::all::ISO_8859_1; //StandardCharsets.ISO_8859_1;
|
|
|
|
|
|
|
|
|
|
const MIXED : [i8;128] = {
|
|
|
|
|
let mut mixed = [-1_i8;128];
|
|
|
|
|
const MIXED: [i8; 128] = {
|
|
|
|
|
let mut mixed = [-1_i8; 128];
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
while i < TEXT_MIXED_RAW.len() {
|
|
|
|
|
let b = TEXT_MIXED_RAW[i] as usize;
|
|
|
|
|
if b > 0 {
|
|
|
|
|
mixed[b] = i as i8;
|
|
|
|
|
}
|
|
|
|
|
i+=1;
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mixed
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const PUNCTUATION : [i8;128] = {
|
|
|
|
|
let mut punct = [-1_i8;128];
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
while i < TEXT_PUNCTUATION_RAW.len() {
|
|
|
|
|
const PUNCTUATION: [i8; 128] = {
|
|
|
|
|
let mut punct = [-1_i8; 128];
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
while i < TEXT_PUNCTUATION_RAW.len() {
|
|
|
|
|
let b = TEXT_PUNCTUATION_RAW[i] as usize;
|
|
|
|
|
if b > 0 {
|
|
|
|
|
punct[b] = i as i8;
|
|
|
|
|
}
|
|
|
|
|
i += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
punct
|
|
|
|
|
};
|
|
|
|
|
// static {
|
|
|
|
|
// //Construct inverse lookups
|
|
|
|
|
// Arrays.fill(MIXED, (byte) -1);
|
|
|
|
|
// for (int i = 0; i < TEXT_MIXED_RAW.length; i++) {
|
|
|
|
|
// byte b = TEXT_MIXED_RAW[i];
|
|
|
|
|
// if (b > 0) {
|
|
|
|
|
// MIXED[b] = (byte) i;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// Arrays.fill(PUNCTUATION, (byte) -1);
|
|
|
|
|
// for (int i = 0; i < TEXT_PUNCTUATION_RAW.length; i++) {
|
|
|
|
|
// byte b = TEXT_PUNCTUATION_RAW[i];
|
|
|
|
|
// if (b > 0) {
|
|
|
|
|
// PUNCTUATION[b] = (byte) i;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
punct
|
|
|
|
|
};
|
|
|
|
|
// static {
|
|
|
|
|
// //Construct inverse lookups
|
|
|
|
|
// Arrays.fill(MIXED, (byte) -1);
|
|
|
|
|
// for (int i = 0; i < TEXT_MIXED_RAW.length; i++) {
|
|
|
|
|
// byte b = TEXT_MIXED_RAW[i];
|
|
|
|
|
// if (b > 0) {
|
|
|
|
|
// MIXED[b] = (byte) i;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// Arrays.fill(PUNCTUATION, (byte) -1);
|
|
|
|
|
// for (int i = 0; i < TEXT_PUNCTUATION_RAW.length; i++) {
|
|
|
|
|
// byte b = TEXT_PUNCTUATION_RAW[i];
|
|
|
|
|
// if (b > 0) {
|
|
|
|
|
// PUNCTUATION[b] = (byte) i;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Performs high-level encoding of a PDF417 message using the algorithm described in annex P
|
|
|
|
|
* of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction
|
|
|
|
|
* is used.
|
|
|
|
|
@@ -187,11 +192,17 @@ punct
|
|
|
|
|
* then charsets will be chosen so that the byte representation is minimal.
|
|
|
|
|
* @return the encoded message (the char values range from 0 to 928)
|
|
|
|
|
*/
|
|
|
|
|
pub fn encodeHighLevel( msg:&str, compaction:Compaction, encoding:Option<EncodingRef>, autoECI:bool)
|
|
|
|
|
-> Result<String,Exceptions> {
|
|
|
|
|
let mut encoding = encoding;
|
|
|
|
|
pub fn encodeHighLevel(
|
|
|
|
|
msg: &str,
|
|
|
|
|
compaction: Compaction,
|
|
|
|
|
encoding: Option<EncodingRef>,
|
|
|
|
|
autoECI: bool,
|
|
|
|
|
) -> Result<String, Exceptions> {
|
|
|
|
|
let mut encoding = encoding;
|
|
|
|
|
if msg.is_empty() {
|
|
|
|
|
return Err(Exceptions::WriterException("Empty message not allowed".to_owned()));
|
|
|
|
|
return Err(Exceptions::WriterException(
|
|
|
|
|
"Empty message not allowed".to_owned(),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if encoding.is_none() && !autoECI {
|
|
|
|
|
@@ -205,7 +216,7 @@ let mut encoding = encoding;
|
|
|
|
|
//the codewords 0..928 are encoded as Unicode characters
|
|
|
|
|
let mut sb = String::with_capacity(msg.len()); //new StringBuilder(msg.length());
|
|
|
|
|
|
|
|
|
|
let input:Box<dyn ECIInput>;
|
|
|
|
|
let input: Box<dyn ECIInput>;
|
|
|
|
|
if autoECI {
|
|
|
|
|
input = Box::new(MinimalECIInput::new(msg, encoding, None));
|
|
|
|
|
} else {
|
|
|
|
|
@@ -226,39 +237,51 @@ let mut encoding = encoding;
|
|
|
|
|
|
|
|
|
|
// User selected encoding mode
|
|
|
|
|
match compaction {
|
|
|
|
|
Compaction::TEXT=>
|
|
|
|
|
{encodeText(&input, p, len as u32, &mut sb, textSubMode)?;},
|
|
|
|
|
Compaction:: BYTE=>
|
|
|
|
|
Compaction::TEXT => {
|
|
|
|
|
encodeText(&input, p, len as u32, &mut sb, textSubMode)?;
|
|
|
|
|
}
|
|
|
|
|
Compaction::BYTE => {
|
|
|
|
|
if autoECI {
|
|
|
|
|
encodeMultiECIBinary(&input, 0, input.length() as u32, TEXT_COMPACTION, &mut sb)?;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
let msgBytes = encoding.as_ref().unwrap().encode(&input.to_string(), encoding::EncoderTrap::Strict).unwrap_or_default(); //input.to_string().getBytes(encoding);
|
|
|
|
|
encodeBinary(&msgBytes, p, msgBytes.len() as u32, BYTE_COMPACTION, &mut sb);
|
|
|
|
|
},
|
|
|
|
|
Compaction:: NUMERIC=>
|
|
|
|
|
{sb.push(char::from_u32( LATCH_TO_NUMERIC).unwrap());
|
|
|
|
|
encodeNumeric(&input, p, len as u32, &mut sb);},
|
|
|
|
|
_=>{
|
|
|
|
|
let msgBytes = encoding
|
|
|
|
|
.as_ref()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.encode(&input.to_string(), encoding::EncoderTrap::Strict)
|
|
|
|
|
.unwrap_or_default(); //input.to_string().getBytes(encoding);
|
|
|
|
|
encodeBinary(
|
|
|
|
|
&msgBytes,
|
|
|
|
|
p,
|
|
|
|
|
msgBytes.len() as u32,
|
|
|
|
|
BYTE_COMPACTION,
|
|
|
|
|
&mut sb,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Compaction::NUMERIC => {
|
|
|
|
|
sb.push(char::from_u32(LATCH_TO_NUMERIC).unwrap());
|
|
|
|
|
encodeNumeric(&input, p, len as u32, &mut sb);
|
|
|
|
|
}
|
|
|
|
|
_ => {
|
|
|
|
|
let mut encodingMode = TEXT_COMPACTION; //Default mode, see 4.4.2.1
|
|
|
|
|
while p < len as u32 {
|
|
|
|
|
while p < len as u32 && input.isECI(p)? {
|
|
|
|
|
encodingECI(input.getECIValue(p as usize)?, &mut sb)?;
|
|
|
|
|
p+=1;
|
|
|
|
|
p += 1;
|
|
|
|
|
}
|
|
|
|
|
if p >= len as u32 {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
let n = determineConsecutiveDigitCount(&input, p);
|
|
|
|
|
if n >= 13 {
|
|
|
|
|
sb.push(char::from_u32( LATCH_TO_NUMERIC).unwrap());
|
|
|
|
|
sb.push(char::from_u32(LATCH_TO_NUMERIC).unwrap());
|
|
|
|
|
encodingMode = NUMERIC_COMPACTION;
|
|
|
|
|
textSubMode = SUBMODE_ALPHA; //Reset after latch
|
|
|
|
|
encodeNumeric(&input, p, n, &mut sb);
|
|
|
|
|
p += n;
|
|
|
|
|
} else {
|
|
|
|
|
let t = determineConsecutiveTextCount(&input, p);
|
|
|
|
|
if t >= 5 || n == len as u32{
|
|
|
|
|
if t >= 5 || n == len as u32 {
|
|
|
|
|
if encodingMode != TEXT_COMPACTION {
|
|
|
|
|
sb.push(char::from_u32(LATCH_TO_TEXT).unwrap());
|
|
|
|
|
encodingMode = TEXT_COMPACTION;
|
|
|
|
|
@@ -267,34 +290,61 @@ let mut encoding = encoding;
|
|
|
|
|
textSubMode = encodeText(&input, p, t, &mut sb, textSubMode)?;
|
|
|
|
|
p += t;
|
|
|
|
|
} else {
|
|
|
|
|
let mut b = determineConsecutiveBinaryCount(&input, p, if autoECI {None} else {encoding})?;
|
|
|
|
|
let mut b = determineConsecutiveBinaryCount(
|
|
|
|
|
&input,
|
|
|
|
|
p,
|
|
|
|
|
if autoECI { None } else { encoding },
|
|
|
|
|
)?;
|
|
|
|
|
if b == 0 {
|
|
|
|
|
b = 1;
|
|
|
|
|
}
|
|
|
|
|
let bytes = if autoECI {None} else {
|
|
|
|
|
let str = input.subSequence(p as usize, (p + b) as usize)?.iter().collect::<String>();
|
|
|
|
|
if let Ok(enc_str) = encoding.as_ref().unwrap().encode(&str, encoding::EncoderTrap::Strict) {
|
|
|
|
|
let bytes = if autoECI {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
let str = input
|
|
|
|
|
.subSequence(p as usize, (p + b) as usize)?
|
|
|
|
|
.iter()
|
|
|
|
|
.collect::<String>();
|
|
|
|
|
if let Ok(enc_str) = encoding
|
|
|
|
|
.as_ref()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.encode(&str, encoding::EncoderTrap::Strict)
|
|
|
|
|
{
|
|
|
|
|
Some(enc_str)
|
|
|
|
|
}else{
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
};//.getBytes(encoding))};
|
|
|
|
|
}; //.getBytes(encoding))};
|
|
|
|
|
// if let Some(byts) = bytes {
|
|
|
|
|
let bytes_ok = if let Some(_) = bytes { true } else {false};
|
|
|
|
|
if ((bytes_ok && b == 1) || (!bytes_ok && bytes.as_ref().unwrap().len() == 1))
|
|
|
|
|
&& encodingMode == TEXT_COMPACTION {
|
|
|
|
|
let bytes_ok = if let Some(_) = bytes { true } else { false };
|
|
|
|
|
if ((bytes_ok && b == 1)
|
|
|
|
|
|| (!bytes_ok && bytes.as_ref().unwrap().len() == 1))
|
|
|
|
|
&& encodingMode == TEXT_COMPACTION
|
|
|
|
|
{
|
|
|
|
|
//Switch for one byte (instead of latch)
|
|
|
|
|
if autoECI {
|
|
|
|
|
encodeMultiECIBinary(&input, p, 1, TEXT_COMPACTION, &mut sb)?;
|
|
|
|
|
} else {
|
|
|
|
|
encodeBinary(bytes.as_ref().unwrap(), 0, 1, TEXT_COMPACTION, &mut sb);
|
|
|
|
|
encodeBinary(
|
|
|
|
|
bytes.as_ref().unwrap(),
|
|
|
|
|
0,
|
|
|
|
|
1,
|
|
|
|
|
TEXT_COMPACTION,
|
|
|
|
|
&mut sb,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
//Mode latch performed by encodeBinary()
|
|
|
|
|
if autoECI {
|
|
|
|
|
encodeMultiECIBinary(&input, p, p + b, encodingMode, &mut sb)?;
|
|
|
|
|
} else {
|
|
|
|
|
encodeBinary(bytes.as_ref().unwrap(), 0, bytes.as_ref().unwrap().len() as u32, encodingMode, &mut sb);
|
|
|
|
|
encodeBinary(
|
|
|
|
|
bytes.as_ref().unwrap(),
|
|
|
|
|
0,
|
|
|
|
|
bytes.as_ref().unwrap().len() as u32,
|
|
|
|
|
encodingMode,
|
|
|
|
|
&mut sb,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
encodingMode = BYTE_COMPACTION;
|
|
|
|
|
textSubMode = SUBMODE_ALPHA; //Reset after latch
|
|
|
|
|
@@ -302,13 +352,14 @@ let mut encoding = encoding;
|
|
|
|
|
p += b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(sb)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E),
|
|
|
|
|
* chapter 4.4.2.
|
|
|
|
|
*
|
|
|
|
|
@@ -319,71 +370,75 @@ let mut encoding = encoding;
|
|
|
|
|
* @param initialSubmode should normally be SUBMODE_ALPHA
|
|
|
|
|
* @return the text submode in which this method ends
|
|
|
|
|
*/
|
|
|
|
|
fn encodeText<T:ECIInput+?Sized>( input:&Box<T>,
|
|
|
|
|
startpos:u32,
|
|
|
|
|
count:u32,
|
|
|
|
|
sb:&mut String,
|
|
|
|
|
initialSubmode:u32) -> Result<u32,Exceptions> {
|
|
|
|
|
fn encodeText<T: ECIInput + ?Sized>(
|
|
|
|
|
input: &Box<T>,
|
|
|
|
|
startpos: u32,
|
|
|
|
|
count: u32,
|
|
|
|
|
sb: &mut String,
|
|
|
|
|
initialSubmode: u32,
|
|
|
|
|
) -> Result<u32, Exceptions> {
|
|
|
|
|
let mut tmp = String::with_capacity(count as usize);
|
|
|
|
|
let mut submode = initialSubmode;
|
|
|
|
|
let mut idx = 0;
|
|
|
|
|
loop {
|
|
|
|
|
if input.isECI(startpos + idx)? {
|
|
|
|
|
encodingECI(input.getECIValue((startpos + idx) as usize)?, sb)?;
|
|
|
|
|
idx+=1;
|
|
|
|
|
idx += 1;
|
|
|
|
|
} else {
|
|
|
|
|
let ch = input.charAt((startpos + idx) as usize)?;
|
|
|
|
|
match submode {
|
|
|
|
|
SUBMODE_ALPHA=>
|
|
|
|
|
SUBMODE_ALPHA => {
|
|
|
|
|
if isAlphaUpper(ch) {
|
|
|
|
|
if ch == ' ' {
|
|
|
|
|
tmp.push( 26 as char); //space
|
|
|
|
|
tmp.push(26 as char); //space
|
|
|
|
|
} else {
|
|
|
|
|
tmp.push(char::from_u32(ch as u32- 65).unwrap());
|
|
|
|
|
tmp.push(char::from_u32(ch as u32 - 65).unwrap());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if isAlphaLower(ch) {
|
|
|
|
|
submode = SUBMODE_LOWER;
|
|
|
|
|
tmp.push( 27 as char); //ll
|
|
|
|
|
tmp.push(27 as char); //ll
|
|
|
|
|
continue;
|
|
|
|
|
} else if isMixed(ch) {
|
|
|
|
|
submode = SUBMODE_MIXED;
|
|
|
|
|
tmp.push( 28 as char); //ml
|
|
|
|
|
tmp.push(28 as char); //ml
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
tmp.push( 29 as char); //ps
|
|
|
|
|
tmp.push(29 as char); //ps
|
|
|
|
|
tmp.push(char::from_u32(PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// break;
|
|
|
|
|
SUBMODE_LOWER=>
|
|
|
|
|
SUBMODE_LOWER => {
|
|
|
|
|
if isAlphaLower(ch) {
|
|
|
|
|
if ch == ' ' {
|
|
|
|
|
tmp.push( 26 as char); //space
|
|
|
|
|
tmp.push(26 as char); //space
|
|
|
|
|
} else {
|
|
|
|
|
tmp.push(char::from_u32( ch as u32 - 97).unwrap());
|
|
|
|
|
tmp.push(char::from_u32(ch as u32 - 97).unwrap());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if isAlphaUpper(ch) {
|
|
|
|
|
tmp.push( 27 as char); //as
|
|
|
|
|
tmp.push(char::from_u32( ch as u32 - 65).unwrap());
|
|
|
|
|
tmp.push(27 as char); //as
|
|
|
|
|
tmp.push(char::from_u32(ch as u32 - 65).unwrap());
|
|
|
|
|
//space cannot happen here, it is also in "Lower"
|
|
|
|
|
break;
|
|
|
|
|
} else if isMixed(ch) {
|
|
|
|
|
submode = SUBMODE_MIXED;
|
|
|
|
|
tmp.push( 28 as char); //ml
|
|
|
|
|
tmp.push(28 as char); //ml
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
tmp.push( 29 as char); //ps
|
|
|
|
|
tmp.push(char::from_u32( PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
tmp.push(29 as char); //ps
|
|
|
|
|
tmp.push(char::from_u32(PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// break;
|
|
|
|
|
SUBMODE_MIXED=>
|
|
|
|
|
SUBMODE_MIXED => {
|
|
|
|
|
if isMixed(ch) {
|
|
|
|
|
tmp.push( char::from_u32(MIXED[ch as usize] as u32).unwrap());
|
|
|
|
|
tmp.push(char::from_u32(MIXED[ch as usize] as u32).unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
if isAlphaUpper(ch) {
|
|
|
|
|
submode = SUBMODE_ALPHA;
|
|
|
|
|
@@ -391,30 +446,36 @@ let mut encoding = encoding;
|
|
|
|
|
continue;
|
|
|
|
|
} else if isAlphaLower(ch) {
|
|
|
|
|
submode = SUBMODE_LOWER;
|
|
|
|
|
tmp.push( 27 as char); //ll
|
|
|
|
|
tmp.push(27 as char); //ll
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
if startpos + idx + 1 < count {
|
|
|
|
|
if !input.isECI(startpos + idx + 1)? && isPunctuation(input.charAt((startpos + idx + 1) as usize)?) {
|
|
|
|
|
if !input.isECI(startpos + idx + 1)?
|
|
|
|
|
&& isPunctuation(input.charAt((startpos + idx + 1) as usize)?)
|
|
|
|
|
{
|
|
|
|
|
submode = SUBMODE_PUNCTUATION;
|
|
|
|
|
tmp.push( 25 as char); //pl
|
|
|
|
|
tmp.push(25 as char); //pl
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tmp.push( 29 as char); //ps
|
|
|
|
|
tmp.push(29 as char); //ps
|
|
|
|
|
tmp.push(char::from_u32(PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
_=> //SUBMODE_PUNCTUATION
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ =>
|
|
|
|
|
//SUBMODE_PUNCTUATION
|
|
|
|
|
{
|
|
|
|
|
if isPunctuation(ch) {
|
|
|
|
|
tmp.push(char::from_u32( PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
tmp.push(char::from_u32(PUNCTUATION[ch as usize] as u32).unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
submode = SUBMODE_ALPHA;
|
|
|
|
|
tmp.push( 29 as char); //al
|
|
|
|
|
tmp.push(29 as char); //al
|
|
|
|
|
continue;
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
idx+=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
idx += 1;
|
|
|
|
|
if idx >= count {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@@ -426,19 +487,19 @@ let mut encoding = encoding;
|
|
|
|
|
// for (int i = 0; i < len; i++) {
|
|
|
|
|
let odd = (i % 2) != 0;
|
|
|
|
|
if odd {
|
|
|
|
|
h = char::from_u32( (h as u32 * 30) + tmp.chars().nth(i).unwrap() as u32).unwrap();
|
|
|
|
|
h = char::from_u32((h as u32 * 30) + tmp.chars().nth(i).unwrap() as u32).unwrap();
|
|
|
|
|
sb.push(h);
|
|
|
|
|
} else {
|
|
|
|
|
h = tmp.chars().nth(i).unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (len % 2) != 0 {
|
|
|
|
|
sb.push(char::from_u32( (h as u32* 30) + 29).unwrap()); //ps
|
|
|
|
|
sb.push(char::from_u32((h as u32 * 30) + 29).unwrap()); //ps
|
|
|
|
|
}
|
|
|
|
|
Ok(submode)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Encode all of the message using Byte Compaction as described in ISO/IEC 15438:2001(E)
|
|
|
|
|
*
|
|
|
|
|
* @param input the input
|
|
|
|
|
@@ -447,23 +508,25 @@ let mut encoding = encoding;
|
|
|
|
|
* @param startmode the mode from which this method starts
|
|
|
|
|
* @param sb receives the encoded codewords
|
|
|
|
|
*/
|
|
|
|
|
fn encodeMultiECIBinary<T:ECIInput + ?Sized>( input:&Box<T>,
|
|
|
|
|
startpos:u32,
|
|
|
|
|
count:u32,
|
|
|
|
|
startmode:u32,
|
|
|
|
|
sb:&mut String) -> Result<(),Exceptions> {
|
|
|
|
|
fn encodeMultiECIBinary<T: ECIInput + ?Sized>(
|
|
|
|
|
input: &Box<T>,
|
|
|
|
|
startpos: u32,
|
|
|
|
|
count: u32,
|
|
|
|
|
startmode: u32,
|
|
|
|
|
sb: &mut String,
|
|
|
|
|
) -> Result<(), Exceptions> {
|
|
|
|
|
let end = (startpos + count).min(input.length() as u32);
|
|
|
|
|
let mut localStart = startpos;
|
|
|
|
|
loop {
|
|
|
|
|
//encode all leading ECIs and advance localStart
|
|
|
|
|
while localStart < end && input.isECI(localStart)? {
|
|
|
|
|
encodingECI(input.getECIValue(localStart as usize)?, sb)?;
|
|
|
|
|
localStart+=1;
|
|
|
|
|
localStart += 1;
|
|
|
|
|
}
|
|
|
|
|
let mut localEnd = localStart;
|
|
|
|
|
//advance end until before the next ECI
|
|
|
|
|
while localEnd < end && !input.isECI(localEnd)? {
|
|
|
|
|
localEnd+=1;
|
|
|
|
|
localEnd += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let localCount = localEnd - localStart;
|
|
|
|
|
@@ -472,26 +535,35 @@ let mut encoding = encoding;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
//encode the segment
|
|
|
|
|
encodeBinary(&subBytes(input, localStart, localEnd),
|
|
|
|
|
0, localCount, if localStart == startpos {startmode} else {BYTE_COMPACTION}, sb);
|
|
|
|
|
encodeBinary(
|
|
|
|
|
&subBytes(input, localStart, localEnd),
|
|
|
|
|
0,
|
|
|
|
|
localCount,
|
|
|
|
|
if localStart == startpos {
|
|
|
|
|
startmode
|
|
|
|
|
} else {
|
|
|
|
|
BYTE_COMPACTION
|
|
|
|
|
},
|
|
|
|
|
sb,
|
|
|
|
|
);
|
|
|
|
|
localStart = localEnd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn subBytes<T:ECIInput+?Sized>( input:&Box<T>, start:u32, end:u32) -> Vec<u8>{
|
|
|
|
|
pub fn subBytes<T: ECIInput + ?Sized>(input: &Box<T>, start: u32, end: u32) -> Vec<u8> {
|
|
|
|
|
let count = (end - start) as usize;
|
|
|
|
|
let mut result = vec![0_u8;count];
|
|
|
|
|
let mut result = vec![0_u8; count];
|
|
|
|
|
for i in start as usize..end as usize {
|
|
|
|
|
// for (int i = start; i < end; i++) {
|
|
|
|
|
result[i - start as usize] = input.charAt(i).unwrap() as u8 ;
|
|
|
|
|
result[i - start as usize] = input.charAt(i).unwrap() as u8;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Encode parts of the message using Byte Compaction as described in ISO/IEC 15438:2001(E),
|
|
|
|
|
* chapter 4.4.3. The Unicode characters will be converted to binary using the cp437
|
|
|
|
|
* codepage.
|
|
|
|
|
@@ -502,25 +574,21 @@ let mut encoding = encoding;
|
|
|
|
|
* @param startmode the mode from which this method starts
|
|
|
|
|
* @param sb receives the encoded codewords
|
|
|
|
|
*/
|
|
|
|
|
fn encodeBinary( bytes:&[u8],
|
|
|
|
|
startpos: u32,
|
|
|
|
|
count: u32,
|
|
|
|
|
startmode: u32,
|
|
|
|
|
sb:&mut String) {
|
|
|
|
|
fn encodeBinary(bytes: &[u8], startpos: u32, count: u32, startmode: u32, sb: &mut String) {
|
|
|
|
|
if count == 1 && startmode == TEXT_COMPACTION {
|
|
|
|
|
sb.push(char::from_u32( SHIFT_TO_BYTE).unwrap());
|
|
|
|
|
sb.push(char::from_u32(SHIFT_TO_BYTE).unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
if (count % 6) == 0 {
|
|
|
|
|
sb.push(char::from_u32( LATCH_TO_BYTE).unwrap());
|
|
|
|
|
sb.push(char::from_u32(LATCH_TO_BYTE).unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
sb.push(char::from_u32( LATCH_TO_BYTE_PADDED).unwrap());
|
|
|
|
|
sb.push(char::from_u32(LATCH_TO_BYTE_PADDED).unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut idx = startpos;
|
|
|
|
|
// Encode sixpacks
|
|
|
|
|
if count >= 6 {
|
|
|
|
|
let mut chars = [0 as char; 5];//new char[5];
|
|
|
|
|
let mut chars = [0 as char; 5]; //new char[5];
|
|
|
|
|
while (startpos + count - idx) >= 6 {
|
|
|
|
|
let mut t: i64 = 0;
|
|
|
|
|
for i in 0..6 {
|
|
|
|
|
@@ -530,7 +598,7 @@ let mut encoding = encoding;
|
|
|
|
|
}
|
|
|
|
|
for i in 0..5 {
|
|
|
|
|
// for (int i = 0; i < 5; i++) {
|
|
|
|
|
chars[i] = char::from_u32((t % 900)as u32).unwrap();
|
|
|
|
|
chars[i] = char::from_u32((t % 900) as u32).unwrap();
|
|
|
|
|
t /= 900;
|
|
|
|
|
}
|
|
|
|
|
for i in (0..chars.len()).rev() {
|
|
|
|
|
@@ -541,28 +609,40 @@ let mut encoding = encoding;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//Encode rest (remaining n<5 bytes if any)
|
|
|
|
|
for i in idx..(startpos+count) {
|
|
|
|
|
for i in idx..(startpos + count) {
|
|
|
|
|
// for (int i = idx; i < startpos + count; i++) {
|
|
|
|
|
let ch = bytes[i as usize];
|
|
|
|
|
sb.push( ch as char);
|
|
|
|
|
}
|
|
|
|
|
sb.push(ch as char);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn encodeNumeric<T:ECIInput+?Sized>( input:&Box<T>, startpos:u32, count:u32, sb:&mut String) {
|
|
|
|
|
fn encodeNumeric<T: ECIInput + ?Sized>(input: &Box<T>, startpos: u32, count: u32, sb: &mut String) {
|
|
|
|
|
let mut idx = 0;
|
|
|
|
|
let mut tmp = String::with_capacity(count as usize / 3 + 1);
|
|
|
|
|
let num900 : u128 = 900;
|
|
|
|
|
let num0 : u128 = 0;
|
|
|
|
|
let num900: u128 = 900;
|
|
|
|
|
let num0: u128 = 0;
|
|
|
|
|
while idx < count {
|
|
|
|
|
tmp.clear();
|
|
|
|
|
let len = 44.min(count as isize - idx as isize);
|
|
|
|
|
let part = format!("1{}", input.subSequence((startpos + idx) as usize, (startpos + idx + len as u32) as usize).unwrap().iter().collect::<String>());
|
|
|
|
|
let part = format!(
|
|
|
|
|
"1{}",
|
|
|
|
|
input
|
|
|
|
|
.subSequence(
|
|
|
|
|
(startpos + idx) as usize,
|
|
|
|
|
(startpos + idx + len as u32) as usize
|
|
|
|
|
)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.iter()
|
|
|
|
|
.collect::<String>()
|
|
|
|
|
);
|
|
|
|
|
let mut bigint: u128 = part.parse().unwrap();
|
|
|
|
|
loop {
|
|
|
|
|
tmp.push(char::from_u32( (bigint % num900) as u32).unwrap());
|
|
|
|
|
tmp.push(char::from_u32((bigint % num900) as u32).unwrap());
|
|
|
|
|
bigint = bigint / num900;
|
|
|
|
|
|
|
|
|
|
if !(!bigint == num0) { break; }
|
|
|
|
|
if !(!bigint == num0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} //while (!bigint.equals(num0));
|
|
|
|
|
|
|
|
|
|
//Reverse temporary string
|
|
|
|
|
@@ -571,73 +651,77 @@ let mut encoding = encoding;
|
|
|
|
|
// for (int i = tmp.length() - 1; i >= 0; i--) {
|
|
|
|
|
sb.push(tmp.chars().nth(i as usize).unwrap());
|
|
|
|
|
|
|
|
|
|
i-=1;
|
|
|
|
|
i -= 1;
|
|
|
|
|
}
|
|
|
|
|
idx += len as u32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn isDigit( ch:char) -> bool{
|
|
|
|
|
fn isDigit(ch: char) -> bool {
|
|
|
|
|
return ch >= '0' && ch <= '9';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn isAlphaUpper( ch:char) -> bool{
|
|
|
|
|
fn isAlphaUpper(ch: char) -> bool {
|
|
|
|
|
return ch == ' ' || (ch >= 'A' && ch <= 'Z');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn isAlphaLower( ch:char) -> bool{
|
|
|
|
|
fn isAlphaLower(ch: char) -> bool {
|
|
|
|
|
return ch == ' ' || (ch >= 'a' && ch <= 'z');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn isMixed( ch:char) -> bool{
|
|
|
|
|
fn isMixed(ch: char) -> bool {
|
|
|
|
|
return MIXED[ch as usize] != -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn isPunctuation( ch:char) -> bool{
|
|
|
|
|
fn isPunctuation(ch: char) -> bool {
|
|
|
|
|
return PUNCTUATION[ch as usize] != -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn isText( ch:char) -> bool{
|
|
|
|
|
fn isText(ch: char) -> bool {
|
|
|
|
|
return ch == '\t' || ch == '\n' || ch == '\r' || (ch as u32 >= 32 && ch as u32 <= 126);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Determines the number of consecutive characters that are encodable using numeric compaction.
|
|
|
|
|
*
|
|
|
|
|
* @param input the input
|
|
|
|
|
* @param startpos the start position within the input
|
|
|
|
|
* @return the requested character count
|
|
|
|
|
*/
|
|
|
|
|
fn determineConsecutiveDigitCount<T:ECIInput+?Sized>( input:&Box<T>, startpos:u32) -> u32{
|
|
|
|
|
fn determineConsecutiveDigitCount<T: ECIInput + ?Sized>(input: &Box<T>, startpos: u32) -> u32 {
|
|
|
|
|
let mut count = 0;
|
|
|
|
|
let len = input.length();
|
|
|
|
|
let mut idx = startpos as usize;
|
|
|
|
|
if idx < len {
|
|
|
|
|
while idx < len && !input.isECI(idx as u32).unwrap() && isDigit(input.charAt(idx).unwrap()) {
|
|
|
|
|
count+=1;
|
|
|
|
|
idx+=1;
|
|
|
|
|
while idx < len && !input.isECI(idx as u32).unwrap() && isDigit(input.charAt(idx).unwrap())
|
|
|
|
|
{
|
|
|
|
|
count += 1;
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Determines the number of consecutive characters that are encodable using text compaction.
|
|
|
|
|
*
|
|
|
|
|
* @param input the input
|
|
|
|
|
* @param startpos the start position within the input
|
|
|
|
|
* @return the requested character count
|
|
|
|
|
*/
|
|
|
|
|
fn determineConsecutiveTextCount<T:ECIInput+?Sized>( input:&Box<T>, startpos:u32) -> u32{
|
|
|
|
|
fn determineConsecutiveTextCount<T: ECIInput + ?Sized>(input: &Box<T>, startpos: u32) -> u32 {
|
|
|
|
|
let len = input.length();
|
|
|
|
|
let mut idx = startpos as usize;
|
|
|
|
|
while idx < len {
|
|
|
|
|
let mut numericCount = 0;
|
|
|
|
|
while numericCount < 13 && idx < len && !input.isECI(idx as u32).unwrap() && isDigit(input.charAt(idx).unwrap()) {
|
|
|
|
|
numericCount+=1;
|
|
|
|
|
idx+=1;
|
|
|
|
|
while numericCount < 13
|
|
|
|
|
&& idx < len
|
|
|
|
|
&& !input.isECI(idx as u32).unwrap()
|
|
|
|
|
&& isDigit(input.charAt(idx).unwrap())
|
|
|
|
|
{
|
|
|
|
|
numericCount += 1;
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
if numericCount >= 13 {
|
|
|
|
|
return (idx - startpos as usize - numericCount) as u32;
|
|
|
|
|
@@ -651,12 +735,12 @@ let mut encoding = encoding;
|
|
|
|
|
if input.isECI(idx as u32).unwrap() || !isText(input.charAt(idx).unwrap()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
idx+=1;
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
(idx - startpos as usize) as u32
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
/**
|
|
|
|
|
* Determines the number of consecutive characters that are encodable using binary compaction.
|
|
|
|
|
*
|
|
|
|
|
* @param input the input
|
|
|
|
|
@@ -664,8 +748,11 @@ let mut encoding = encoding;
|
|
|
|
|
* @param encoding the charset used to convert the message to a byte array
|
|
|
|
|
* @return the requested character count
|
|
|
|
|
*/
|
|
|
|
|
fn determineConsecutiveBinaryCount<T: ECIInput+?Sized+'static>( input:&Box<T>, startpos:u32, encoding:Option<EncodingRef>)
|
|
|
|
|
-> Result<u32,Exceptions> {
|
|
|
|
|
fn determineConsecutiveBinaryCount<T: ECIInput + ?Sized + 'static>(
|
|
|
|
|
input: &Box<T>,
|
|
|
|
|
startpos: u32,
|
|
|
|
|
encoding: Option<EncodingRef>,
|
|
|
|
|
) -> Result<u32, Exceptions> {
|
|
|
|
|
// CharsetEncoder encoder = encoding == null ? null : encoding.newEncoder();
|
|
|
|
|
let len = input.length();
|
|
|
|
|
let mut idx = startpos as usize;
|
|
|
|
|
@@ -673,8 +760,11 @@ let mut encoding = encoding;
|
|
|
|
|
let mut numericCount = 0;
|
|
|
|
|
|
|
|
|
|
let mut i = idx;
|
|
|
|
|
while numericCount < 13 && !input.isECI(i as u32).unwrap() && isDigit(input.charAt(i).unwrap()) {
|
|
|
|
|
numericCount+=1;
|
|
|
|
|
while numericCount < 13
|
|
|
|
|
&& !input.isECI(i as u32).unwrap()
|
|
|
|
|
&& isDigit(input.charAt(i).unwrap())
|
|
|
|
|
{
|
|
|
|
|
numericCount += 1;
|
|
|
|
|
//textCount++;
|
|
|
|
|
i = idx + numericCount;
|
|
|
|
|
if i >= len {
|
|
|
|
|
@@ -682,43 +772,55 @@ let mut encoding = encoding;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if numericCount >= 13 {
|
|
|
|
|
return Ok(idx as u32- startpos);
|
|
|
|
|
return Ok(idx as u32 - startpos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(encoder) = encoding {
|
|
|
|
|
let can_encode = encoder.encode(&input.charAt(idx)?.to_string(), encoding::EncoderTrap::Strict).is_ok();
|
|
|
|
|
let can_encode = encoder
|
|
|
|
|
.encode(
|
|
|
|
|
&input.charAt(idx)?.to_string(),
|
|
|
|
|
encoding::EncoderTrap::Strict,
|
|
|
|
|
)
|
|
|
|
|
.is_ok();
|
|
|
|
|
|
|
|
|
|
// if encoder != null && !encoder.canEncode(input.charAt(idx)) {
|
|
|
|
|
if !can_encode {
|
|
|
|
|
assert!(TypeId::of::<T>() == TypeId::of::<NoECIInput>());
|
|
|
|
|
// assert!(input instanceof NoECIInput);
|
|
|
|
|
let ch = input.charAt(idx).unwrap();
|
|
|
|
|
return Err(Exceptions::WriterException(format!("Non-encodable character detected: {} (Unicode: {})", ch, ch as u32)));
|
|
|
|
|
}}
|
|
|
|
|
idx+=1;
|
|
|
|
|
return Err(Exceptions::WriterException(format!(
|
|
|
|
|
"Non-encodable character detected: {} (Unicode: {})",
|
|
|
|
|
ch, ch as u32
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
Ok(idx as u32- startpos)
|
|
|
|
|
}
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
Ok(idx as u32 - startpos)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn encodingECI( eci:i32, sb:&mut String) -> Result<(),Exceptions> {
|
|
|
|
|
fn encodingECI(eci: i32, sb: &mut String) -> Result<(), Exceptions> {
|
|
|
|
|
if eci >= 0 && eci < 900 {
|
|
|
|
|
sb.push(char::from_u32( ECI_CHARSET).unwrap());
|
|
|
|
|
sb.push(char::from_u32( eci as u32).unwrap());
|
|
|
|
|
sb.push(char::from_u32(ECI_CHARSET).unwrap());
|
|
|
|
|
sb.push(char::from_u32(eci as u32).unwrap());
|
|
|
|
|
} else if eci < 810900 {
|
|
|
|
|
sb.push(char::from_u32( ECI_GENERAL_PURPOSE).unwrap());
|
|
|
|
|
sb.push(char::from_u32( (eci / 900 - 1) as u32).unwrap());
|
|
|
|
|
sb.push(char::from_u32( (eci % 900) as u32).unwrap());
|
|
|
|
|
sb.push(char::from_u32(ECI_GENERAL_PURPOSE).unwrap());
|
|
|
|
|
sb.push(char::from_u32((eci / 900 - 1) as u32).unwrap());
|
|
|
|
|
sb.push(char::from_u32((eci % 900) as u32).unwrap());
|
|
|
|
|
} else if eci < 811800 {
|
|
|
|
|
sb.push(char::from_u32( ECI_USER_DEFINED).unwrap());
|
|
|
|
|
sb.push(char::from_u32( (810900 - eci) as u32).unwrap());
|
|
|
|
|
sb.push(char::from_u32(ECI_USER_DEFINED).unwrap());
|
|
|
|
|
sb.push(char::from_u32((810900 - eci) as u32).unwrap());
|
|
|
|
|
} else {
|
|
|
|
|
return Err(Exceptions::WriterException(format!("ECI number not in valid range from 0..811799, but was {}" , eci)));
|
|
|
|
|
return Err(Exceptions::WriterException(format!(
|
|
|
|
|
"ECI number not in valid range from 0..811799, but was {}",
|
|
|
|
|
eci
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct NoECIInput(String);
|
|
|
|
|
impl ECIInput for NoECIInput {
|
|
|
|
|
struct NoECIInput(String);
|
|
|
|
|
impl ECIInput for NoECIInput {
|
|
|
|
|
fn length(&self) -> usize {
|
|
|
|
|
self.0.chars().count()
|
|
|
|
|
}
|
|
|
|
|
@@ -726,13 +828,13 @@ let mut encoding = encoding;
|
|
|
|
|
fn charAt(&self, index: usize) -> Result<char, Exceptions> {
|
|
|
|
|
if let Some(ch) = self.0.chars().nth(index) {
|
|
|
|
|
Ok(ch)
|
|
|
|
|
}else {
|
|
|
|
|
} else {
|
|
|
|
|
Err(Exceptions::IndexOutOfBoundsException("".to_owned()))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn subSequence(&self, start: usize, end: usize) -> Result<Vec<char>, Exceptions> {
|
|
|
|
|
let res: Vec<char> = self.0.chars().skip(start).take(end-start).collect();
|
|
|
|
|
let res: Vec<char> = self.0.chars().skip(start).take(end - start).collect();
|
|
|
|
|
Ok(res)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -748,14 +850,13 @@ let mut encoding = encoding;
|
|
|
|
|
index + n <= self.0.len()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl NoECIInput {
|
|
|
|
|
|
|
|
|
|
pub fn new( input:String) -> Self {
|
|
|
|
|
impl NoECIInput {
|
|
|
|
|
pub fn new(input: String) -> Self {
|
|
|
|
|
Self(input)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl Display for NoECIInput {
|
|
|
|
|
}
|
|
|
|
|
impl Display for NoECIInput {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
write!(f,"{}", self.0)
|
|
|
|
|
write!(f, "{}", self.0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|