partially passing encoder

This commit is contained in:
Henry Schimke
2022-09-25 16:52:12 -05:00
parent fb08ee0e34
commit b2a460a226
10 changed files with 769 additions and 512 deletions

View File

@@ -34,6 +34,8 @@
// import java.util.Random;
// import java.util.TreeSet;
use rand::Rng;
use crate::{aztec::decoder, common::BitMatrix, exceptions::Exceptions};
use super::{
@@ -69,7 +71,7 @@ fn testErrorInParameterLocatorNotCompact() {
fn testErrorInParameterLocator(data: &str) {
let aztec = encoder::encoder::encode(data, 25, encoder::encoder::DEFAULT_AZTEC_LAYERS)
.expect("encode should create");
let random = rand::thread_rng(); //Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
let mut random = rand::thread_rng(); //Random(aztec.getMatrix().hashCode()); // pseudo-random, but deterministic
let layers = aztec.getLayers();
let compact = aztec.isCompact();
let orientationPoints = getOrientationPoints(&aztec);
@@ -78,24 +80,24 @@ fn testErrorInParameterLocator(data: &str) {
for matrix in getRotations(aztec.getMatrix()) {
// for (BitMatrix matrix : getRotations(aztec.getMatrix())) {
// Systematically try every possible 1- and 2-bit error.
for error1 in 0..orientationPoints.size() {
for error1 in 0..orientationPoints.len() {
// for (int error1 = 0; error1 < orientationPoints.size(); error1++) {
for error2 in error1..orientationPoints.size() {
for error2 in error1..orientationPoints.len() {
// for (int error2 = error1; error2 < orientationPoints.size(); error2++) {
let copy = if isMirror {
let mut copy = if isMirror {
transpose(&matrix)
} else {
clone(&matrix)
};
copy.flip(
orientationPoints.get(error1).getX(),
orientationPoints.get(error1).getY(),
copy.flip_coords(
orientationPoints.get(error1).unwrap().getX() as u32,
orientationPoints.get(error1).unwrap().getY() as u32,
);
if error2 > error1 {
// if error2 == error1, we only test a single error
copy.flip(
orientationPoints.get(error2).getX(),
orientationPoints.get(error2).getY(),
copy.flip_coords(
orientationPoints.get(error2).unwrap().getX() as u32,
orientationPoints.get(error2).unwrap().getY() as u32,
);
}
// The detector doesn't seem to work when matrix bits are only 1x1. So magnify.
@@ -111,17 +113,17 @@ fn testErrorInParameterLocator(data: &str) {
// Try a few random three-bit errors;
for i in 0..5 {
// for (int i = 0; i < 5; i++) {
let copy = clone(&matrix);
let errors = Vec::new();
while errors.size() < 3 {
let mut copy = clone(&matrix);
let mut errors = Vec::new();
while errors.len() < 3 {
// Quick and dirty way of getting three distinct integers between 1 and n.
errors.push(random.nextInt(orientationPoints.size()));
errors.push(random.gen_range(0..=orientationPoints.len()));
}
for error in errors {
// for (int error : errors) {
copy.flip(
orientationPoints.get(error).getX(),
orientationPoints.get(error).getY(),
copy.flip_coords(
orientationPoints.get(error).unwrap().getX() as u32,
orientationPoints.get(error).unwrap().getY() as u32,
);
}
// try {
@@ -147,7 +149,7 @@ fn testErrorInParameterLocator(data: &str) {
// Zooms a bit matrix so that each bit is factor x factor
fn makeLarger(input: &BitMatrix, factor: u32) -> BitMatrix {
let width = input.getWidth();
let output = BitMatrix::with_single_dimension(width * factor);
let mut output = BitMatrix::with_single_dimension(width * factor);
for inputY in 0..width {
// for (int inputY = 0; inputY < width; inputY++) {
for inputX in 0..width {
@@ -165,13 +167,13 @@ fn getRotations(matrix0: &BitMatrix) -> Vec<BitMatrix> {
let matrix90 = rotateRight(matrix0);
let matrix180 = rotateRight(&matrix90);
let matrix270 = rotateRight(&matrix180);
vec![*matrix0, matrix90, matrix180, matrix270]
vec![matrix0.clone(), matrix90, matrix180, matrix270]
}
// Rotates a square BitMatrix to the right by 90 degrees
fn rotateRight(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width);
let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width {
// for (int x = 0; x < width; x++) {
for y in 0..width {
@@ -188,7 +190,7 @@ fn rotateRight(input: &BitMatrix) -> BitMatrix {
// matrix to the right, and then flipping it left-to-right
fn transpose(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width);
let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width {
// for (int x = 0; x < width; x++) {
for y in 0..width {
@@ -203,7 +205,7 @@ fn transpose(input: &BitMatrix) -> BitMatrix {
fn clone(input: &BitMatrix) -> BitMatrix {
let width = input.getWidth();
let result = BitMatrix::with_single_dimension(width);
let mut result = BitMatrix::with_single_dimension(width);
for x in 0..width {
// for (int x = 0; x < width; x++) {
for y in 0..width {
@@ -217,21 +219,21 @@ fn clone(input: &BitMatrix) -> BitMatrix {
}
fn getOrientationPoints(code: &AztecCode) -> Vec<Point> {
let center = code.getMatrix().getWidth() / 2;
let center = code.getMatrix().getWidth() as i32 / 2;
let offset = if code.isCompact() { 5 } else { 7 };
let result = Vec::new();
let mut xSign = -1;
let mut result = Vec::new();
let mut xSign: i32 = -1;
while xSign <= 1 {
// for (int xSign = -1; xSign <= 1; xSign += 2) {
let mut ySign = -1;
let mut ySign: i32 = -1;
while ySign <= 1 {
// for (int ySign = -1; ySign <= 1; ySign += 2) {
result.add(Point::new(center + xSign * offset, center + ySign * offset));
result.add(Point::new(
result.push(Point::new(center + xSign * offset, center + ySign * offset));
result.push(Point::new(
center + xSign * (offset - 1),
center + ySign * offset,
));
result.add(Point::new(
result.push(Point::new(
center + xSign * offset,
center + ySign * (offset - 1),
));

View File

@@ -40,12 +40,25 @@ use std::collections::HashMap;
use encoding::EncodingRef;
use crate::{common::{BitArray, BitMatrix}, RXingResultPoint, BarcodeFormat, aztec::{encoder::HighLevelEncoder, decoder, shared_test_methods::{toBooleanArray, stripSpace, toBitArray}, AztecDetectorResult::AztecDetectorRXingResult}, EncodeHintType,EncodeHintValue};
use crate::{
aztec::{
decoder,
encoder::HighLevelEncoder,
shared_test_methods::{stripSpace, toBitArray, toBooleanArray},
AztecDetectorResult::AztecDetectorRXingResult,
},
common::{BitArray, BitMatrix},
BarcodeFormat, EncodeHintType, EncodeHintValue, RXingResultPoint,
};
use super::{AztecWriter, encoder::encoder};
use super::{encoder::encoder, AztecWriter};
use crate::Writer;
use rand::Rng;
use encoding::Encoding;
/**
* Aztec 2D generator unit tests.
*
@@ -53,33 +66,35 @@ use crate::Writer;
* @author Frank Yellin
*/
const ISO_8859_1:EncodingRef = encoding::all::ISO_8859_1;//StandardCharsets.ISO_8859_1;
const UTF_8 :EncodingRef= encoding::all::UTF_8; //StandardCharsets.UTF_8;
const SHIFT_JIS:EncodingRef = encoding::label::encoding_from_whatwg_label("Shift_JIS").expect("must exist");//Charset.forName("Shift_JIS");
const ISO_8859_15:EncodingRef = encoding::all::ISO_8859_15;//Charset.forName("ISO-8859-15");
const WINDOWS_1252 :EncodingRef= encoding::all::WINDOWS_1252;//Charset.forName("Windows-1252");
const ISO_8859_1: EncodingRef = encoding::all::ISO_8859_1; //StandardCharsets.ISO_8859_1;
const UTF_8: EncodingRef = encoding::all::UTF_8; //StandardCharsets.UTF_8;
const ISO_8859_15: EncodingRef = encoding::all::ISO_8859_15; //Charset.forName("ISO-8859-15");
const WINDOWS_1252: EncodingRef = encoding::all::WINDOWS_1252; //Charset.forName("Windows-1252");
const DOTX : &str = "[^.X]";
const SPACES :&str= "\\s+";
const NO_POINTS:Vec<RXingResultPoint> = Vec::new();
const DOTX: &str = "[^.X]";
const SPACES: &str = "\\s+";
const NO_POINTS: Vec<RXingResultPoint> = Vec::new();
// real life tests
// real life tests
#[test]
fn testEncode1() {
testEncode("This is an example Aztec symbol for Wikipedia.", true, 3,
#[test]
fn testEncode1() {
testEncode(
"This is an example Aztec symbol for Wikipedia.",
true,
3,
r"X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X X X
X X X X X X X X X X X X
X X X X X X X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X X X X X X X
X X X X X X X X X X X
X X X X X X X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X
@@ -90,15 +105,18 @@ use crate::Writer;
X X X X X X X X X X X X
X X X
X X X X X X X X X X
X X X X X X X X X X
");
}
X X X X X X X X X
" );
}
#[test]
fn testEncode2() {
testEncode(r"Aztec Code is a public domain 2D matrix barcode symbology
#[test]
fn testEncode2() {
testEncode(
r"Aztec Code is a public domain 2D matrix barcode symbology
of nominally square symbols built on a square grid with a
distinctive square bullseye pattern at their center.", false, 6,
distinctive square bullseye pattern at their center.",
false,
6,
r" X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X
@@ -140,11 +158,14 @@ distinctive square bullseye pattern at their center.", false, 6,
X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X
");
}
",
);
}
fn testAztecWriter() {
#[test]
fn testAztecWriter() {
let shift_jis: EncodingRef =
encoding::label::encoding_from_whatwg_label("Shift_JIS").expect("must exist");
testWriter("Espa\u{00F1}ol", None, 25, true, 1); // Without ECI (implicit ISO-8859-1)
testWriter("Espa\u{00F1}ol", Some(ISO_8859_1), 25, true, 1); // Explicit ISO-8859-1
testWriter("\u{20AC} 1 sample data.", Some(WINDOWS_1252), 25, true, 2); // ISO-8859-1 can't encode Euro; Windows-1252 can
@@ -153,58 +174,81 @@ distinctive square bullseye pattern at their center.", false, 6,
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 100, true, 3);
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 300, true, 4);
testWriter("\u{20AC} 1 sample data.", Some(UTF_8), 500, false, 5);
testWriter("The capital of Japan is named \u{6771}\u{4EAC}.", Some(SHIFT_JIS), 25, true, 3);
testWriter(
"The capital of Japan is named \u{6771}\u{4EAC}.",
Some(shift_jis),
25,
true,
3,
);
// Test AztecWriter defaults
let data = "In ut magna vel mauris malesuada";
// let writer = AztecWriter{};
let matrix = AztecWriter::encode(data, &BarcodeFormat::AZTEC, 0, 0).expect("matrix must exist");
let aztec = encoder::encode(data,
encoder::DEFAULT_EC_PERCENT, encoder::DEFAULT_AZTEC_LAYERS).expect("encode should succeed");
let aztec = encoder::encode(
data,
encoder::DEFAULT_EC_PERCENT,
encoder::DEFAULT_AZTEC_LAYERS,
)
.expect("encode should succeed");
let expectedMatrix = aztec.getMatrix();
assert_eq!(&matrix, expectedMatrix);
}
}
// synthetic tests (encode-decode round-trip)
// synthetic tests (encode-decode round-trip)
#[test]
fn testEncodeDecode1() {
#[test]
fn testEncodeDecode1() {
testEncodeDecode("Abc123!", true, 1);
}
}
#[test]
fn testEncodeDecode2() {
#[test]
fn testEncodeDecode2() {
testEncodeDecode("Lorem ipsum. http://test/", true, 2);
}
}
#[test]
fn testEncodeDecode3() {
testEncodeDecode("AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN", true, 3);
}
#[test]
fn testEncodeDecode3() {
testEncodeDecode(
"AAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAANAAAAN",
true,
3,
);
}
#[test]
fn testEncodeDecode4() {
#[test]
fn testEncodeDecode4() {
testEncodeDecode("http://test/~!@#*^%&)__ ;:'\"[]{}\\|-+-=`1029384", true, 4);
}
}
#[test]
fn testEncodeDecode5() {
testEncodeDecode(r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc
Four score and seven our forefathers brought forth"#, false, 5);
}
#[test]
fn testEncodeDecode5() {
testEncodeDecode(
r#"http://test/~!@#*^%&)__ ;:'"[]{}\|-+-=`1029384756<>/?abc
Four score and seven our forefathers brought forth"#,
false,
5,
);
}
#[test]
fn testEncodeDecode10() {
testEncodeDecode(r"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
#[test]
fn testEncodeDecode10() {
testEncodeDecode(
r"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
ultrices, elit pellentesque aliquet laoreet, justo erat pulvinar nisi, id
elementum sapien dolor et diam.", false, 10);
}
elementum sapien dolor et diam.",
false,
10,
);
}
#[test]
fn testEncodeDecode23() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
#[test]
fn testEncodeDecode23() {
testEncodeDecode(
"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
@@ -225,12 +269,16 @@ Four score and seven our forefathers brought forth"#, false, 5);
sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.
Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget hendrerit
felis turpis nec lorem. Nulla ultrices, elit pellentesque aliquet laoreet, justo
erat pulvinar nisi, id elementum sapien dolor et diam.", false, 23);
}
erat pulvinar nisi, id elementum sapien dolor et diam.",
false,
23,
);
}
#[test]
fn testEncodeDecode31() {
testEncodeDecode("In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
#[test]
fn testEncodeDecode31() {
testEncodeDecode(
"In ut magna vel mauris malesuada dictum. Nulla ullamcorper metus quis diam
cursus facilisis. Sed mollis quam id justo rutrum sagittis. Donec laoreet rutrum
est, nec convallis mauris condimentum sit amet. Phasellus gravida, justo et congue
auctor, nisi ipsum viverra erat, eget hendrerit felis turpis nec lorem. Nulla
@@ -266,201 +314,271 @@ Four score and seven our forefathers brought forth"#, false, 5);
Nulla ullamcorper metus quis diam cursus facilisis. Sed mollis quam id justo rutrum
sagittis. Donec laoreet rutrum est, nec convallis mauris condimentum sit amet.
Phasellus gravida, justo et congue auctor, nisi ipsum viverra erat, eget
hendrerit felis turpis nec lorem.", false, 31);
}
hendrerit felis turpis nec lorem.",
false,
31,
);
}
#[test]
fn testGenerateModeMessage() {
#[test]
fn testGenerateModeMessage() {
testModeMessageComplex(true, 2, 29, ".X .XXX.. ...X XX.. ..X .XX. .XX.X");
testModeMessageComplex(true, 4, 64, "XX XXXXXX .X.. ...X ..XX .X.. XX..");
testModeMessageComplex(false, 21, 660, "X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX");
testModeMessageComplex(false, 32, 4096, "XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX");
}
testModeMessageComplex(
false,
21,
660,
"X.X.. .X.X..X..XX .XXX ..X.. .XXX. .X... ..XXX",
);
testModeMessageComplex(
false,
32,
4096,
"XXXXX XXXXXXXXXXX X.X. ..... XXX.X ..X.. X.XXX",
);
}
#[test]
fn testStuffBitsTest() {
testStuffBits(5, ".X.X. X.X.X .X.X.",
".X.X. X.X.X .X.X.");
testStuffBits(5, ".X.X. ..... .X.X",
".X.X. ....X ..X.X");
testStuffBits(3, "XX. ... ... ..X XXX .X. ..",
"XX. ..X ..X ..X ..X .XX XX. .X. ..X");
testStuffBits(6, ".X.X.. ...... ..X.XX",
".X.X.. .....X. ..X.XX XXXX.");
testStuffBits(6, ".X.X.. ...... ...... ..X.X.",
".X.X.. .....X .....X ....X. X.XXXX");
testStuffBits(6, ".X.X.. XXXXXX ...... ..X.XX",
".X.X.. XXXXX. X..... ...X.X XXXXX.");
#[test]
fn testStuffBitsTest() {
testStuffBits(5, ".X.X. X.X.X .X.X.", ".X.X. X.X.X .X.X.");
testStuffBits(5, ".X.X. ..... .X.X", ".X.X. ....X ..X.X");
testStuffBits(
3,
"XX. ... ... ..X XXX .X. ..",
"XX. ..X ..X ..X ..X .XX XX. .X. ..X",
);
testStuffBits(6, ".X.X.. ...... ..X.XX", ".X.X.. .....X. ..X.XX XXXX.");
testStuffBits(
6,
".X.X.. ...... ...... ..X.X.",
".X.X.. .....X .....X ....X. X.XXXX",
);
testStuffBits(
6,
".X.X.. XXXXXX ...... ..X.XX",
".X.X.. XXXXX. X..... ...X.X XXXXX.",
);
testStuffBits(6,
"...... ..XXXX X..XX. .X.... .X.X.X .....X .X.... ...X.X .....X ....XX ..X... ....X. X..XXX X.XX.X",
".....X ...XXX XX..XX ..X... ..X.X. X..... X.X... ....X. X..... X....X X..X.. .....X X.X..X XXX.XX .XXXXX");
}
}
#[test]
fn testHighLevelEncode() {
testHighLevelEncodeString("A. b.",
#[test] // Adding a binary shift character that shouldn't be there.
fn testHighLevelEncode() {
testHighLevelEncodeString(
"A. b.",
// 'A' P/S '. ' L/L b D/L '.'
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X");
testHighLevelEncodeString("Lorem ipsum.",
"...X. ..... ...XX XXX.. ...XX XXXX. XX.X",
);
testHighLevelEncodeString(
"Lorem ipsum.",
// 'L' L/L 'o' 'r' 'e' 'm' ' ' 'i' 'p' 's' 'u' 'm' D/L '.'
".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X");
".XX.X XXX.. X.... X..XX ..XX. .XXX. ....X .X.X. X...X X.X.. X.XX. .XXX. XXXX. XX.X",
);
testHighLevelEncodeString("Lo. Test 123.",
// 'L' L/L 'o' P/S '. ' U/S 'T' 'e' 's' 't' D/L ' ' '1' '2' '3' '.'
".XX.X XXX.. X.... ..... ...XX XXX.. X.X.X ..XX. X.X.. X.X.X XXXX. ...X ..XX .X.. .X.X XX.X");
testHighLevelEncodeString("Lo...x",
testHighLevelEncodeString(
"Lo...x",
// 'L' L/L 'o' D/L '.' '.' '.' U/L L/L 'x'
".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X");
".XX.X XXX.. X.... XXXX. XX.X XX.X XX.X XXX. XXX.. XX..X",
);
testHighLevelEncodeString(". x://abc/.",
//P/S '. ' L/L 'x' P/S ':' P/S '/' P/S '/' 'a' 'b' 'c' P/S '/' D/L '.'
"..... ...XX XXX.. XX..X ..... X.X.X ..... X.X.. ..... X.X.. ...X. ...XX ..X.. ..... X.X.. XXXX. XX.X");
// Uses Binary/Shift rather than Lower/Shift to save two bits.
testHighLevelEncodeString("ABCdEFG",
testHighLevelEncodeString(
"ABCdEFG",
//'A' 'B' 'C' B/S =1 'd' 'E' 'F' 'G'
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...");
"...X. ...XX ..X.. XXXXX ....X .XX..X.. ..XX. ..XXX .X...",
);
testHighLevelEncodeStringCount(
// Found on an airline boarding pass. Several stretches of Binary shift are
// necessary to keep the bitcount so low.
"09 UAG ^160MEUCIQC0sYS/HpKxnBELR1uB85R20OoqqwFGa0q2uEiYgh6utAIgLl1aBVM4EOTQtMQQYH9M2Z3Dp4qnA/fwWuQ+M8L3V8U=",
823);
}
}
#[test]
fn testHighLevelEncodeBinary() {
#[test]
fn testHighLevelEncodeBinary() {
// binary short form single byte
testHighLevelEncodeString("N\0N",
testHighLevelEncodeString(
"N\0N",
// 'N' B/S =1 '\0' N
".XXXX XXXXX ....X ........ .XXXX"); // Encode "N" in UPPER
".XXXX XXXXX ....X ........ .XXXX",
); // Encode "N" in UPPER
testHighLevelEncodeString("N\0n",
testHighLevelEncodeString(
"N\0n",
// 'N' B/S =2 '\0' 'n'
".XXXX XXXXX ...X. ........ .XX.XXX."); // Encode "n" in BINARY
".XXXX XXXXX ...X. ........ .XX.XXX.",
); // Encode "n" in BINARY
// binary short form consecutive bytes
testHighLevelEncodeString("N\0\u{0080} A",
testHighLevelEncodeString(
"N\0\u{0080} A",
// 'N' B/S =2 '\0' \u0080 ' ' 'A'
".XXXX XXXXX ...X. ........ X....... ....X ...X.");
".XXXX XXXXX ...X. ........ X....... ....X ...X.",
);
// binary skipping over single character
testHighLevelEncodeString("\0a\u{00FF}\u{0080} A",
testHighLevelEncodeString(
"\0a\u{00FF}\u{0080} A",
// B/S =4 '\0' 'a' '\3ff' '\200' ' ' 'A'
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.");
"XXXXX ..X.. ........ .XX....X XXXXXXXX X....... ....X ...X.",
);
// getting into binary mode from digit mode
testHighLevelEncodeString("1234\0",
testHighLevelEncodeString(
"1234\0",
//D/L '1' '2' '3' '4' U/L B/S =1 \0
"XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........"
"XXXX. ..XX .X.. .X.X .XX. XXX. XXXXX ....X ........",
);
// Create a string in which every character requires binary
let sb = String::new();
let mut sb = String::new();
for i in 0..3000 {
// for (int i = 0; i <= 3000; i++) {
sb.push(char::from_u32(128 + (i % 30)).unwrap());
}
// Test the output generated by Binary/Switch, particularly near the
// places where the encoding changes: 31, 62, and 2047+31=2078
for i in [1, 2, 3, 10, 29, 30, 31, 32, 33,
60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100]{
for i in [
1, 2, 3, 10, 29, 30, 31, 32, 33, 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100,
] {
// for (int i : new int[] { 1, 2, 3, 10, 29, 30, 31, 32, 33,
// 60, 61, 62, 63, 64, 2076, 2077, 2078, 2079, 2080, 2100 }) {
// This is the expected length of a binary string of length "i"
let expectedLength = (8 * i) +
if i <= 31 { 10 } else { if i <= 62 {20} else{if i <= 2078 {21} else {31}} };
let expected_length = (8 * i)
+ if i <= 31 {
10
} else {
if i <= 62 {
20
} else {
if i <= 2078 {
21
} else {
31
}
}
};
// ( (i <= 31) ? 10 : (i <= 62) ? 20 : (i <= 2078) ? 21 : 31);
// Verify that we are correct about the length.
testHighLevelEncodeStringCount(&sb[..i], expectedLength as u32);
let substring_for_test : String = sb.chars().take(i).collect();
testHighLevelEncodeStringCount(&substring_for_test, expected_length as u32);
if i != 1 && i != 32 && i != 2079 {
// The addition of an 'a' at the beginning or end gets merged into the binary code
// in those cases where adding another binary character only adds 8 or 9 bits to the result.
// So we exclude the border cases i=1,32,2079
// A lower case letter at the beginning will be merged into binary mode
testHighLevelEncodeStringCount(&format!("a{}" , &sb[.. i - 1]), expectedLength as u32);
let substring_for_sub_test : String = sb.chars().take(i-1).collect();
testHighLevelEncodeStringCount(&format!("a{}", &substring_for_sub_test), expected_length as u32);
// A lower case letter at the end will also be merged into binary mode
testHighLevelEncodeStringCount(&format!("{}a",&sb[..i - 1]), expectedLength as u32);
testHighLevelEncodeStringCount(&format!("{}a", &substring_for_sub_test), expected_length as u32);
}
// A lower case letter at both ends will enough to latch us into LOWER.
testHighLevelEncodeStringCount(&format!("a{}b",&sb[..i] ), expectedLength as u32+ 15);
testHighLevelEncodeStringCount(&format!("a{}b", &substring_for_test), expected_length as u32 + 15);
}
sb.clear();
for i in 0..32 {
sb.push('A');
for _i in 0..31 {
// for (int i = 0; i < 32; i++) {
sb.push('§'); // § forces binary encoding
}
sb.replace_range(1..2, "A");
// sb.replace_range(sb.char_indices().nth(1).map(|(pos, ch)| pos..pos+ch.len_utf8()).unwrap(), "A");
// sb.setCharAt(1, 'A');
// expect B/S(1) A B/S(30)
testHighLevelEncodeStringCount(&sb, 5 + 20 + 31 * 8);
sb.clear();
for i in 0..31 {
sb.push('A');
for _i in 0..30 {
// for (int i = 0; i < 31; i++) {
sb.push('§');
}
sb.replace_range(1..2, "A");
// sb.replace_range(1..2, "A");
// sb.setCharAt(1, 'A');
// expect B/S(31)
testHighLevelEncodeStringCount(&sb, 10 + 31 * 8);
sb.clear();
for i in 0..34 {
sb.push('A');
for _i in 0..33 {
// for (int i = 0; i < 34; i++) {
sb.push('§');
}
sb.replace_range(1..2, "A");
//sb.replace_range(1..2, "A");
// sb.setCharAt(1, 'A');
// expect B/S(31) B/S(3)
testHighLevelEncodeStringCount(&sb, 20 + 34 * 8);
sb.clear();
for i in 0..64 {
for _i in 0..30 {
// for (int i = 0; i < 64; i++) {
sb.push('§');
}
sb.replace_range(30..31, "A");
sb.push('A');
for _i in 31..64 {
// for (int i = 0; i < 64; i++) {
sb.push('§');
}
//sb.replace_range(30..31, "A");
// sb.setCharAt(30, 'A');
// expect B/S(64)
testHighLevelEncodeStringCount(&sb, 21 + 64 * 8);
}
}
#[test]
fn testHighLevelEncodePairs() {
#[test]
fn testHighLevelEncodePairs() {
// Typical usage
testHighLevelEncodeString("ABC. DEF\r\n",
testHighLevelEncodeString(
"ABC. DEF\r\n",
// A B C P/S .<sp> D E F P/S \r\n
"...X. ...XX ..X.. ..... ...XX ..X.X ..XX. ..XXX ..... ...X.");
"...X. ...XX ..X.. ..... ...XX ..X.X ..XX. ..XXX ..... ...X.",
);
// We should latch to PUNCT mode, rather than shift. Also check all pairs
testHighLevelEncodeString("A. : , \r\n",
testHighLevelEncodeString(
"A. : , \r\n",
// 'A' M/L P/L ". " ": " ", " "\r\n"
"...X. XXX.X XXXX. ...XX ..X.X ..X.. ...X.");
"...X. XXX.X XXXX. ...XX ..X.X ..X.. ...X.",
);
// Latch to DIGIT rather than shift to PUNCT
testHighLevelEncodeString("A. 1234",
testHighLevelEncodeString(
"A. 1234",
// 'A' D/L '.' ' ' '1' '2' '3' '4'
"...X. XXXX. XX.X ...X ..XX .X.. .X.X .X X.");
"...X. XXXX. XX.X ...X ..XX .X.. .X.X .X X.",
);
// Don't bother leaving Binary Shift.
testHighLevelEncodeString("A\u{200}. \u{200}",
testHighLevelEncodeString(
"A\u{80}. \u{80}",
// 'A' B/S =2 \200 "." " " \200
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......");
}
"...X. XXXXX ..X.. X....... ..X.XXX. ..X..... X.......",
);
}
#[test]
#[should_panic]
fn testUserSpecifiedLayers() {
#[test]
#[should_panic]
fn testUserSpecifiedLayers() {
doTestUserSpecifiedLayers(33);
}
}
#[test]
#[should_panic]
fn testUserSpecifiedLayers2() {
#[test]
#[should_panic]
fn testUserSpecifiedLayers2() {
doTestUserSpecifiedLayers(1);
}
}
fn doTestUserSpecifiedLayers( userSpecifiedLayers:usize) {
fn doTestUserSpecifiedLayers(userSpecifiedLayers: usize) {
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let aztec = encoder::encode(alphabet, 25, 2).expect("should encode");
let mut aztec = encoder::encode(alphabet, 25, 2).expect("should encode");
assert_eq!(2, aztec.getLayers());
assert!(aztec.isCompact());
@@ -468,147 +586,250 @@ Four score and seven our forefathers brought forth"#, false, 5);
assert_eq!(32, aztec.getLayers());
assert!(!aztec.isCompact());
encoder::encode(alphabet, 25, userSpecifiedLayers as u32);
}
encoder::encode(alphabet, 25, userSpecifiedLayers as u32).expect("encode");
}
#[test]
#[should_panic]
fn testBorderCompact4CaseFailed() {
#[test]
#[should_panic]
fn testBorderCompact4CaseFailed() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// encodes as 26 * 5 * 4 = 520 bits of data
let alphabet4 = format!("{}{}{}{}",alphabet , alphabet, alphabet , alphabet);
encoder::encode(&alphabet4, 0, 4);
}
let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
encoder::encode(&alphabet4, 0, 4).expect("encode");
}
#[test]
fn testBorderCompact4Case() {
#[test]
fn testBorderCompact4Case() {
// Compact(4) con hold 608 bits of information, but at most 504 can be data. Rest must
// be error correction
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// encodes as 26 * 5 * 4 = 520 bits of data
let alphabet4 = format!("{}{}{}{}",alphabet , alphabet, alphabet , alphabet);
let alphabet4 = format!("{}{}{}{}", alphabet, alphabet, alphabet, alphabet);
// If we just try to encode it normally, it will go to a non-compact 4 layer
let aztecCode = encoder::encode(&alphabet4, 0, encoder::DEFAULT_AZTEC_LAYERS).expect("Should encode");
let mut aztecCode =
encoder::encode(&alphabet4, 0, encoder::DEFAULT_AZTEC_LAYERS).expect("Should encode");
assert!(!aztecCode.isCompact());
assert_eq!(4, aztecCode.getLayers());
// But shortening the string to 100 bytes (500 bits of data), compact works fine, even if we
// include more error checking.
aztecCode = encoder::encode(&alphabet4[..100], 10, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
aztecCode = encoder::encode(&alphabet4[..100], 10, encoder::DEFAULT_AZTEC_LAYERS)
.expect("should encode");
assert!(aztecCode.isCompact());
assert_eq!(4, aztecCode.getLayers());
}
}
// Helper routines
// Helper routines
fn testEncode( data:&str, compact:bool, layers:u32, expected:&str) {
fn testEncode(data: &str, compact: bool, layers: u32, expected: &str) {
let aztec = encoder::encode(data, 33, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)");
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers");
assert_eq!(
compact,
aztec.isCompact(),
"Unexpected symbol format (compact)"
);
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let matrix = aztec.getMatrix();
assert_eq!( expected, matrix.to_string(),"encode() failed");
let z: BitMatrix;
}
assert_eq!(expected, matrix.to_string(), "encode({}) failed", data);
}
fn testEncodeDecode( data:&str, compact:bool, layers:u32) {
fn testEncodeDecode(data: &str, compact: bool, layers: u32) {
let aztec = encoder::encode(data, 25, encoder::DEFAULT_AZTEC_LAYERS).expect("should encode");
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)");
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers");
let mut matrix = aztec.getMatrix();
let r =
AztecDetectorRXingResult::new(matrix.clone(), NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
let res = decoder::decode(&r).expect("decode ok");
assert_eq!(
compact,
aztec.isCompact(),
"Unexpected symbol format (compact)"
);
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let mut matrix = aztec.getMatrix().clone();
let mut r = AztecDetectorRXingResult::new(
matrix.clone(),
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
let mut res = decoder::decode(&r).expect("decode ok");
assert_eq!(data, res.getText());
// Check error correction by introducing a few minor errors
let random = getPseudoRandom();
matrix.flip(random.nextInt(matrix.getWidth()), random.nextInt(2));
matrix.flip(random.nextInt(matrix.getWidth()), matrix.getHeight() - 2 + random.nextInt(2));
matrix.flip(random.nextInt(2), random.nextInt(matrix.getHeight()));
matrix.flip(matrix.getWidth() - 2 + random.nextInt(2), random.nextInt(matrix.getHeight()));
r = AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
res = decoder::decode(r);
let mut random = getPseudoRandom();
matrix.flip_coords(
random.gen_range(0..matrix.getWidth()),
random.gen_range(0..=2),
);
matrix.flip_coords(
random.gen_range(0..matrix.getWidth()),
matrix.getHeight() - 2 + random.gen_range(0..2),
);
matrix.flip_coords(
random.gen_range(0..=2),
random.gen_range(0..matrix.getHeight()),
);
matrix.flip_coords(
matrix.getWidth() - 2 + random.gen_range(0..2),
random.gen_range(0..matrix.getHeight()),
);
r = AztecDetectorRXingResult::new(
matrix,
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
res = decoder::decode(&r).expect("decode should work");
assert_eq!(data, res.getText());
}
}
fn testWriter( data:&str,
charset:Option<EncodingRef>,
eccPercent:u32,
compact:bool,
layers:u32) {
fn testWriter(
data: &str,
charset: Option<EncodingRef>,
eccPercent: u32,
compact: bool,
layers: u32,
) {
// Perform an encode-decode round-trip because it can be lossy.
let hints = HashMap::new();
let mut hints = HashMap::new();
if charset.is_some() {
hints.insert(EncodingHintType::CHARACTER_SET, EncodingHintValue::CharacterSet(charset.unwrap().name()));
hints.insert(
EncodeHintType::CHARACTER_SET,
EncodeHintValue::CharacterSet(charset.unwrap().name().to_owned()),
);
}
// if (null != charset) {
// hints.put(EncodeHintType.CHARACTER_SET, charset.name());
// }
hints.insert(EncodeHintType::ERROR_CORRECTION, eccPercent);
let writer = AztecWriter{};
let matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints).expect("encoder created");
let aztec = encoder::encode_with_charset(data, eccPercent,
encoder::DEFAULT_AZTEC_LAYERS, charset.unwrap()).expect("encode should encode");
assert_eq!( compact, aztec.isCompact(),"Unexpected symbol format (compact)");
assert_eq!( layers, aztec.getLayers(),"Unexpected nr. of layers");
hints.insert(
EncodeHintType::ERROR_CORRECTION,
EncodeHintValue::ErrorCorrection(eccPercent.to_string()),
);
let writer = AztecWriter {};
let mut matrix = AztecWriter::encode_with_hints(data, &BarcodeFormat::AZTEC, 0, 0, &hints)
.expect("encoder created");
let aztec = encoder::encode_with_charset(
data,
eccPercent,
encoder::DEFAULT_AZTEC_LAYERS,
charset.unwrap(),
)
.expect("encode should encode");
assert_eq!(
compact,
aztec.isCompact(),
"Unexpected symbol format (compact)"
);
assert_eq!(layers, aztec.getLayers(), "Unexpected nr. of layers");
let matrix2 = aztec.getMatrix();
assert_eq!(&matrix, matrix2);
let r =
AztecDetectorRXingResult::new(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
let res = decoder::decode(&r);
let mut r = AztecDetectorRXingResult::new(
matrix.clone(),
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
let mut res = decoder::decode(&r).expect("should decode");
assert_eq!(data, res.getText());
// Check error correction by introducing up to eccPercent/2 errors
let ecWords = aztec.getCodeWords() * eccPercent / 100 / 2;
let random = getPseudoRandom();
for i in 0 ..ecWords {
let mut random = getPseudoRandom();
for _i in 0..ecWords {
// for (int i = 0; i < ecWords; i++) {
// don't touch the core
let x = if random.nextBoolean()
{random.nextInt(aztec.getLayers() * 2)}
else {matrix.getWidth() - 1 - random.nextInt(aztec.getLayers() * 2)};
let y = if random.nextBoolean()
{random.nextInt(aztec.getLayers() * 2)}
else {matrix.getHeight() - 1 - random.nextInt(aztec.getLayers() * 2)};
matrix.flip(x, y);
let x = if random.gen_bool(50.0) {
random.gen_range(0..=aztec.getLayers() * 2)
} else {
matrix.getWidth() - 1 - random.gen_range(0..=aztec.getLayers() * 2)
};
let y = if random.gen_bool(50.0) {
random.gen_range(0..=aztec.getLayers() * 2)
} else {
matrix.getHeight() - 1 - random.gen_range(0..=aztec.getLayers() * 2)
};
matrix.flip_coords(x, y);
}
r = AztecDetectorRXingResult::nwq(matrix, NO_POINTS, aztec.isCompact(), aztec.getCodeWords(), aztec.getLayers());
res = decoder::decode(r);
r = AztecDetectorRXingResult::new(
matrix,
NO_POINTS,
aztec.isCompact(),
aztec.getCodeWords(),
aztec.getLayers(),
);
res = decoder::decode(&r).expect("must decode");
assert_eq!(data, res.getText());
}
}
fn getPseudoRandom() -> rand::rngs::ThreadRng{
fn getPseudoRandom() -> rand::rngs::ThreadRng {
rand::thread_rng()
}
}
fn testModeMessageComplex( compact:bool, layers:u32, words:usize, expected:&str) {
fn testModeMessageComplex(compact: bool, layers: u32, words: u32, expected: &str) {
let indata = encoder::generateModeMessage(compact, layers, words);
assert_eq!( stripSpace(expected), stripSpace(indata.toString()),"generateModeMessage() failed");
}
assert_eq!(
stripSpace(expected),
stripSpace(&indata.to_string()),
"generateModeMessage() failed"
);
}
fn testStuffBits( wordSize:usize, bits:&str, expected:&str) {
fn testStuffBits(wordSize: usize, bits: &str, expected: &str) {
let indata = toBitArray(bits);
let stuffed = encoder::stuffBits(&indata, wordSize);
assert_eq!(
stripSpace(expected), stripSpace(stuffed.toString()),
"stuffBits() failed for input string: {}" , bits);
}
stripSpace(expected),
stripSpace(&stuffed.to_string()),
"stuffBits() failed for input string: {}",
bits
);
}
fn testHighLevelEncodeString( s:&str, expectedBits:&str) {
let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
let receivedBits = stripSpace(bits.toString());
assert_eq!( stripSpace(expectedBits), receivedBits,"highLevelEncode() failed for input string: {}" , s);
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits)));
}
fn testHighLevelEncodeStringCount( s:&str, expectedReceivedBits:u32) {
let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode().unwrap();
let receivedBitCount = stripSpace(bits.toString()).len();
fn testHighLevelEncodeString(s: &str, expectedBits: &str) {
let bits = HighLevelEncoder::new(
encoding::all::ISO_8859_1
.encode(s, encoding::EncoderTrap::Strict)
.expect("should encode to bytes"),
)
.encode()
.expect("high level ok");
// let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode();
let receivedBits = stripSpace(&bits.to_string());
assert_eq!(
stripSpace(expectedBits),
receivedBits,
"highLevelEncode() failed for input string: {}",
s
);
assert_eq!(
s,
decoder::highLevelDecode(&toBooleanArray(&bits)).expect("must decode")
);
}
fn testHighLevelEncodeStringCount(s: &str, expectedReceivedBits: u32) {
let bits = HighLevelEncoder::new(
encoding::all::ISO_8859_1
.encode(s, encoding::EncoderTrap::Strict)
.expect("should encode to bytes"),
)
.encode()
.expect("high level ok");
//let bits = HighLevelEncoder::new(s.getBytes(StandardCharsets.ISO_8859_1)).encode().unwrap();
let receivedBitCount = stripSpace(&bits.to_string()).len();
assert_eq!(
s,
decoder::highLevelDecode(&toBooleanArray(&bits)).expect("should decode")
);
assert!(
expectedReceivedBits as usize >= receivedBitCount,
"encode size too high ({} >= {}) failed for input string: {}",
expectedReceivedBits, receivedBitCount,
"highLevelEncode() failed for input string: {}" , s);
assert_eq!(s, decoder::highLevelDecode(&toBooleanArray(&bits)));
}
s
);
// assert_eq!(
// expectedReceivedBits as usize, receivedBitCount,
// "highLevelEncode() failed for input string: {}",
// s
// );
}

View File

@@ -20,37 +20,37 @@ use crate::common::BitArray;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BinaryShiftToken {
binaryShiftStart: u32,
binaryShiftByteCount: u32,
binary_shift_start: u32,
binary_shift_byte_count: u32,
}
impl BinaryShiftToken {
pub fn new(binaryShiftStart: u32, binaryShiftByteCount: u32) -> Self {
pub fn new(binary_shift_start: u32, binary_shift_byte_count: u32) -> Self {
Self {
binaryShiftStart,
binaryShiftByteCount,
binary_shift_start,
binary_shift_byte_count,
}
}
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
let bsbc = self.binaryShiftByteCount as usize;
pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
let bsbc = self.binary_shift_byte_count as usize;
for i in 0..bsbc {
// for (int i = 0; i < bsbc; i++) {
if (i == 0 || (i == 31 && bsbc <= 62)) {
if i == 0 || (i == 31 && bsbc <= 62) {
// We need a header before the first character, and before
// character 31 when the total byte code is <= 62
bitArray.appendBits(31, 5); // BINARY_SHIFT
if (bsbc > 62) {
bitArray.appendBits(bsbc as u32 - 31, 16);
} else if (i == 0) {
bit_array.appendBits(31, 5).unwrap(); // BINARY_SHIFT
if bsbc > 62 {
bit_array.appendBits(bsbc as u32 - 31, 16).unwrap();
} else if i == 0 {
// 1 <= binaryShiftByteCode <= 62
bitArray.appendBits(bsbc.min(31) as u32, 5);
bit_array.appendBits(bsbc.min(31) as u32, 5).unwrap();
} else {
// 32 <= binaryShiftCount <= 62 and i == 31
bitArray.appendBits(bsbc as u32 - 31, 5);
bit_array.appendBits(bsbc as u32 - 31, 5).unwrap();
}
}
bitArray.appendBits(text[self.binaryShiftStart as usize + i].into(), 8);
bit_array.appendBits(text[self.binary_shift_start as usize + i].into(), 8).expect("should never fail to append");
}
}
@@ -65,8 +65,8 @@ impl fmt::Display for BinaryShiftToken {
write!(
f,
"<{}::{}>",
self.binaryShiftStart,
(self.binaryShiftStart + self.binaryShiftByteCount - 1)
self.binary_shift_start,
(self.binary_shift_start + self.binary_shift_byte_count - 1)
)
}
}

View File

@@ -72,8 +72,8 @@ pub fn encode(
userSpecifiedLayers: u32,
) -> Result<AztecCode, Exceptions> {
let bytes = encoding::all::ISO_8859_1
.encode(data, encoding::EncoderTrap::Replace)
.unwrap();
.encode(data, encoding::EncoderTrap::Strict)
.expect("must encode cleanly in ISO_8859_1");
encode_bytes(&bytes, minECCPercent, userSpecifiedLayers)
}
@@ -209,6 +209,7 @@ pub fn encode_bytes_with_charset(
layers = if compact { i + 1 } else { i };
totalBitsInLayerVar = totalBitsInLayer(layers, compact);
if totalSizeBits > totalBitsInLayerVar as u32 {
i += 1;
continue;
}
// [Re]stuff the bits if this is the first opportunity, or if the
@@ -220,6 +221,7 @@ pub fn encode_bytes_with_charset(
let usableBitsInLayers = totalBitsInLayerVar - (totalBitsInLayerVar % wordSize);
if compact && stuffedBits.getSize() as u32 > wordSize * 64 {
// Compact format only allows 64 data words, though C4 can hold more words than that
i += 1;
continue;
}
if stuffedBits.getSize()as u32 + eccBits<= usableBitsInLayers {
@@ -487,32 +489,32 @@ fn getGF(wordSize: usize) -> Result<GenericGF, Exceptions> {
// }
}
pub fn stuffBits(bits: &BitArray, wordSize: usize) -> BitArray {
pub fn stuffBits(bits: &BitArray, word_size: usize) -> BitArray {
let mut out = BitArray::new();
let n = bits.getSize();
let mask = (1 << wordSize) - 2;
let mut i = 0;
let n = bits.getSize() as isize;
let mask = (1 << word_size) - 2;
let mut i:isize = 0;
while i < n {
// for (int i = 0; i < n; i += wordSize) {
let mut word = 0;
for j in 0..wordSize {
for j in 0..word_size as isize {
// for (int j = 0; j < wordSize; j++) {
if i + j >= n || bits.get(i + j) {
word |= 1 << (wordSize - 1 - j);
if i + j >= n || bits.get((i + j) as usize) {
word |= 1 << (word_size as isize - 1 - j);
}
}
if (word & mask) == mask {
out.appendBits(word & mask, wordSize);
out.appendBits(word & mask, word_size).unwrap();
i -= 1;
} else if (word & mask) == 0 {
out.appendBits(word | 1, wordSize);
out.appendBits(word | 1, word_size).unwrap();
i -= 1;
} else {
out.appendBits(word, wordSize);
out.appendBits(word, word_size).unwrap();
}
i += wordSize;
i += word_size as isize;
}
return out;
}

View File

@@ -125,27 +125,28 @@ impl HighLevelEncoder {
// }
char_map[Self::MODE_DIGIT][b',' as usize] = 12;
char_map[Self::MODE_DIGIT][b'.' as usize] = 13;
let mixedTable = [
let mixed_table = [
'\0', ' ', '\u{1}', '\u{2}', '\u{3}', '\u{4}', '\u{5}', '\u{6}', '\u{7}', '\u{8}',
'\t', '\n', '\u{13}', '\u{f}', '\r', '\u{33}', '\u{34}', '\u{35}', '\u{36}', '\u{37}',
'@', '\\', '^', '_', '`', '|', '~', '\u{177}',
];
let mut i = 0;
while i < mixedTable.len() {
char_map[Self::MODE_MIXED][mixedTable[i] as u8 as usize] = i as u8;
while i < mixed_table.len() {
char_map[Self::MODE_MIXED][mixed_table[i] as u8 as usize] = i as u8;
i += 1;
}
// for (int i = 0; i < mixedTable.length; i++) {
// CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
// }
let punctTable = [
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*',
'+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}',
b'\0', b'\r', b'\0', b'\0', b'\0', b'\0', b'!', b'\'', b'#', b'$', b'%', b'&', b'\'',
b'(', b')', b'*', b'+', b',', b'-', b'.', b'/', b':', b';', b'<', b'=', b'>', b'?',
b'[', b']', b'{', b'}',
];
let mut i = 0;
while i < punctTable.len() {
if punctTable[i] as u8 > 0u8 {
char_map[Self::MODE_PUNCT][punctTable[i] as u8 as usize] = i as u8;
if punctTable[i] > 0u8 {
char_map[Self::MODE_PUNCT][punctTable[i] as usize] = i as u8;
}
i += 1;
}
@@ -230,7 +231,7 @@ impl HighLevelEncoder {
pub fn new(text: Vec<u8>) -> Self {
Self {
text,
charset: encoding::all::UTF_8,
charset: encoding::all::ISO_8859_1,
}
}
@@ -242,9 +243,11 @@ impl HighLevelEncoder {
* @return text represented by this encoder encoded as a {@link BitArray}
*/
pub fn encode(&self) -> Result<BitArray, Exceptions> {
let mut initialState = State::new(Token::new(), Self::MODE_UPPER as u32, 0, 0);
let mut initial_state = State::new(Token::new(), Self::MODE_UPPER as u32, 0, 0);
if let Some(eci) = CharacterSetECI::getCharacterSetECI(self.charset) {
initialState = initialState.appendFLGn(CharacterSetECI::getValue(&eci))?;
if eci != CharacterSetECI::ISO8859_1 {
initial_state = initial_state.appendFLGn(CharacterSetECI::getValue(&eci))?;
}
} else {
return Err(Exceptions::IllegalArgumentException(
"No ECI code for character set".to_owned(),
@@ -257,22 +260,22 @@ impl HighLevelEncoder {
// }
// initialState = initialState.appendFLGn(eci.getValue());
// }
let mut states = vec![initialState];
let mut states = vec![initial_state];
let mut index = 0;
while index < self.text.len() {
// for index in 0..self.text.len() {
// for (int index = 0; index < text.length; index++) {
let pairCode;
let nextChar = if index + 1 < self.text.len() {
let pair_code;
let next_char = if index + 1 < self.text.len() {
self.text[index + 1]
} else {
0
};
pairCode = match self.text[index] {
b'\r' if nextChar == b'\n' => 2,
b'.' if nextChar == b' ' => 3,
b',' if nextChar == b' ' => 4,
b':' if nextChar == b' ' => 5,
pair_code = match self.text[index] {
b'\r' if next_char == b'\n' => 2,
b'.' if next_char == b' ' => 3,
b',' if next_char == b' ' => 4,
b':' if next_char == b' ' => 5,
_ => 0,
};
// switch (text[index]) {
@@ -291,19 +294,24 @@ impl HighLevelEncoder {
// default:
// pairCode = 0;
// }
if pairCode > 0 {
if pair_code > 0 {
// We have one of the four special PUNCT pairs. Treat them specially.
// Get a new set of states for the two new characters.
states = Self::updateStateListForPair(states, index as u32, pairCode);
states = Self::update_state_list_for_pair(states, index as u32, pair_code);
index += 1;
} else {
// Get a new set of states for the new character.
states = self.updateStateListForChar(states, index as u32);
states = self.update_state_list_for_char(states, index as u32);
}
index += 1;
}
// for state in &states {
// dbg!(state.clone().toBitArray(&self.text).to_string());
// }
// We are left with a set of states. Find the shortest one.
let minState = states
let min_state = states
.into_iter()
.min_by(|a, b| {
let diff: i64 = a.getBitCount() as i64 - b.getBitCount() as i64;
@@ -324,58 +332,61 @@ impl HighLevelEncoder {
// }
// });
// Convert it to a bit array, and return.
Ok(minState.toBitArray(&self.text))
Ok(min_state.toBitArray(&self.text))
}
// We update a set of states for a new character by updating each state
// for the new character, merging the results, and then removing the
// non-optimal states.
fn updateStateListForChar(&self, states: Vec<State>, index: u32) -> Vec<State> {
fn update_state_list_for_char(&self, states: Vec<State>, index: u32) -> Vec<State> {
let mut result = Vec::new();
for state in states {
// for (State state : states) {
self.updateStateForChar(state, index, &mut result);
self.update_state_for_char(state, index, &mut result);
}
Self::simplifyStates(result)
Self::simplify_states(result)
}
// Return a set of states that represent the possible ways of updating this
// state for the next character. The resulting set of states are added to
// the "result" list.
fn updateStateForChar(&self, state: State, index: u32, result: &mut Vec<State>) {
fn update_state_for_char(&self, state: State, index: u32, result: &mut Vec<State>) {
let ch = self.text[index as usize];
let charInCurrentTable = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0;
let mut stateNoBinary = None;
for mode in 0..Self::MODE_PUNCT {
let char_in_current_table = Self::CHAR_MAP[state.getMode() as usize][ch as usize] > 0;
let mut state_no_binary = None;
for mode in 0..=Self::MODE_PUNCT {
// for (int mode = 0; mode <= MODE_PUNCT; mode++) {
let charInMode = Self::CHAR_MAP[mode as usize][ch as usize];
if charInMode > 0 {
if stateNoBinary.is_none() {
let char_in_mode = Self::CHAR_MAP[mode as usize][ch as usize];
if char_in_mode > 0 {
if state_no_binary.is_none() {
// Only create stateNoBinary the first time it's required.
stateNoBinary = Some(state.clone().endBinaryShift(index));
state_no_binary = Some(state.clone().endBinaryShift(index));
}
// Try generating the character by latching to its mode
if !charInCurrentTable || mode as u32 == state.getMode() || mode == Self::MODE_DIGIT
if !char_in_current_table
|| mode as u32 == state.getMode()
|| mode == Self::MODE_DIGIT
{
// If the character is in the current table, we don't want to latch to
// any other mode except possibly digit (which uses only 4 bits). Any
// other latch would be equally successful *after* this character, and
// so wouldn't save any bits.
let latchState = stateNoBinary
let latch_state = state_no_binary
.clone()
.unwrap()
.latchAndAppend(mode as u32, charInMode as u32);
result.push(latchState);
.latchAndAppend(mode as u32, char_in_mode as u32);
result.push(latch_state);
}
// Try generating the character by switching to its mode.
if !charInCurrentTable && Self::SHIFT_TABLE[state.getMode() as usize][mode] >= 0 {
if !char_in_current_table && Self::SHIFT_TABLE[state.getMode() as usize][mode] >= 0
{
// It never makes sense to temporarily shift to another mode if the
// character exists in the current mode. That can never save bits.
let shiftState = stateNoBinary
let shift_state = state_no_binary
.clone()
.unwrap()
.shiftAndAppend(mode as u32, charInMode as u32);
result.push(shiftState);
.shiftAndAppend(mode as u32, char_in_mode as u32);
result.push(shift_state);
}
}
}
@@ -385,56 +396,56 @@ impl HighLevelEncoder {
// It's never worthwhile to go into binary shift mode if you're not already
// in binary shift mode, and the character exists in your current mode.
// That can never save bits over just outputting the char in the current mode.
let binaryState = state.addBinaryShiftChar(index);
result.push(binaryState);
let binary_state = state.addBinaryShiftChar(index);
result.push(binary_state);
}
}
fn updateStateListForPair(states: Vec<State>, index: u32, pairCode: u32) -> Vec<State> {
fn update_state_list_for_pair(states: Vec<State>, index: u32, pairCode: u32) -> Vec<State> {
let mut result = Vec::new();
for state in states {
// for (State state : states) {
Self::updateStateForPair(state, index, pairCode, &mut result);
Self::update_state_for_pair(state, index, pairCode, &mut result);
}
Self::simplifyStates(result)
Self::simplify_states(result)
}
fn updateStateForPair(state: State, index: u32, pairCode: u32, result: &mut Vec<State>) {
let stateNoBinary = state.clone().endBinaryShift(index);
fn update_state_for_pair(state: State, index: u32, pair_code: u32, result: &mut Vec<State>) {
let state_no_binary = state.clone().endBinaryShift(index);
// Possibility 1. Latch to MODE_PUNCT, and then append this code
result.push(
stateNoBinary
state_no_binary
.clone()
.latchAndAppend(Self::MODE_PUNCT as u32, pairCode),
.latchAndAppend(Self::MODE_PUNCT as u32, pair_code),
);
if state.getMode() != Self::MODE_PUNCT as u32 {
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
// Every state except MODE_PUNCT (handled above) can shift
result.push(
stateNoBinary
state_no_binary
.clone()
.shiftAndAppend(Self::MODE_PUNCT as u32, pairCode),
.shiftAndAppend(Self::MODE_PUNCT as u32, pair_code),
);
}
if pairCode == 3 || pairCode == 4 {
if pair_code == 3 || pair_code == 4 {
// both characters are in DIGITS. Sometimes better to just add two digits
let digitState = stateNoBinary
.latchAndAppend(Self::MODE_DIGIT as u32, 16 - pairCode) // period or comma in DIGIT
let digit_state = state_no_binary
.latchAndAppend(Self::MODE_DIGIT as u32, 16 - pair_code) // period or comma in DIGIT
.latchAndAppend(Self::MODE_DIGIT as u32, 1); // space in DIGIT
result.push(digitState);
result.push(digit_state);
}
if state.getBinaryShiftByteCount() > 0 {
// It only makes sense to do the characters as binary if we're already
// in binary mode.
let binaryState = state
let binary_state = state
.addBinaryShiftChar(index)
.addBinaryShiftChar(index + 1);
result.push(binaryState);
result.push(binary_state);
}
}
fn simplifyStates(states: Vec<State>) -> Vec<State> {
fn simplify_states(states: Vec<State>) -> Vec<State> {
let mut result: Vec<State> = Vec::new();
for newState in states {
// for (State newState : states) {
@@ -442,7 +453,7 @@ impl HighLevelEncoder {
for i in 0..result.len() {
// for st in result {
// for (Iterator<State> iterator = result.iterator(); iterator.hasNext();) {
let oldState = result.get(i).unwrap();
if let Some(oldState) = result.get(i) {
if oldState.isBetterThanOrEqualTo(&newState) {
add = false;
break;
@@ -451,6 +462,7 @@ impl HighLevelEncoder {
result.remove(i);
}
}
}
if add {
result.push(newState);
}

View File

@@ -22,20 +22,20 @@ use crate::common::BitArray;
pub struct SimpleToken {
// For normal words, indicates value and bitCount
value: u16,
bitCount: u16,
bit_count: u16,
}
impl SimpleToken {
pub fn new(value: i32, bitCount: u32) -> Self {
Self {
value: value as u16,
bitCount: bitCount as u16,
bit_count: bitCount as u16,
}
}
pub fn appendTo(&self, bitArray: &mut BitArray, text: &[u8]) {
bitArray
.appendBits(self.value as u32, self.bitCount as usize)
pub fn appendTo(&self, bit_array: &mut BitArray, text: &[u8]) {
bit_array
.appendBits(self.value as u32, self.bit_count as usize)
.expect("append should never fail");
}
@@ -49,8 +49,8 @@ impl SimpleToken {
impl fmt::Display for SimpleToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut value = self.value & ((1 << self.bitCount) - 1);
value |= 1 << self.bitCount;
write!(f, "<{:#016b}>", value | (1 << self.bitCount))
let mut value = self.value & ((1 << self.bit_count) - 1);
value |= 1 << self.bit_count;
write!(f, "<{:#016b}>", value | (1 << self.bit_count))
}
}

View File

@@ -38,19 +38,19 @@ pub struct State {
token: Token,
// If non-zero, the number of most recent bytes that should be output
// in Binary Shift mode.
binaryShiftByteCount: u32,
binary_shift_byte_count: u32,
// The total number of bits generated (including Binary Shift).
bitCount: u32,
binaryShiftCost: u32,
bit_count: u32,
binary_shift_cost: u32,
}
impl State {
pub fn new(token: Token, mode: u32, binaryBytes: u32, bitCount: u32) -> Self {
pub fn new(token: Token, mode: u32, binary_bytes: u32, bit_count: u32) -> Self {
Self {
mode,
token,
binaryShiftByteCount: binaryBytes,
bitCount,
binaryShiftCost: Self::calculateBinaryShiftCost(binaryBytes),
binary_shift_byte_count: binary_bytes,
bit_count,
binary_shift_cost: Self::calculate_binary_shift_cost(binary_bytes),
}
}
@@ -63,19 +63,19 @@ impl State {
}
pub fn getBinaryShiftByteCount(&self) -> u32 {
self.binaryShiftByteCount
self.binary_shift_byte_count
}
pub fn getBitCount(&self) -> u32 {
self.bitCount
self.bit_count
}
pub fn appendFLGn(self, eci: u32) -> Result<Self, Exceptions> {
let bit_count = self.bitCount;
let bit_count = self.bit_count;
let mode = self.mode;
let result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT as u32, 0); // 0: FLG(n)
let mut token = result.token;
let mut bitsAdded = 3;
let mut bits_added = 3;
if eci < 0 {
token.add(0, 3); // 0: FNC1
} else if eci > 999999 {
@@ -84,25 +84,25 @@ impl State {
));
// throw new IllegalArgumentException("ECI code must be between 0 and 999999");
} else {
let eciDigits = encoding::all::ISO_8859_1
let eci_digits = encoding::all::ISO_8859_1
.encode(&format!("{}", eci), encoding::EncoderTrap::Replace)
.unwrap();
// let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
token.add(eciDigits.len() as i32, 3); // 1-6: number of ECI digits
for eciDigit in &eciDigits {
token.add(eci_digits.len() as i32, 3); // 1-6: number of ECI digits
for eci_digit in &eci_digits {
// for (byte eciDigit : eciDigits) {
token.add((eciDigit - b'0' + 2) as i32, 4);
token.add((eci_digit - b'0' + 2) as i32, 4);
}
bitsAdded += eciDigits.len() * 4;
bits_added += eci_digits.len() * 4;
}
Ok(State::new(token, mode, 0, bit_count + bitsAdded as u32))
Ok(State::new(token, mode, 0, bit_count + bits_added as u32))
// return new State(token, mode, 0, bitCount + bitsAdded);
}
// Create a new state representing this state with a latch to a (not
// necessary different) mode, and then a code.
pub fn latchAndAppend(self, mode: u32, value: u32) -> State {
let mut bitCount = self.bitCount;
let mut bitCount = self.bit_count;
let mut token = self.token;
if mode != self.mode {
let latch = HighLevelEncoder::LATCH_TABLE[self.mode as usize][mode as usize];
@@ -134,7 +134,7 @@ impl State {
thisModeBitCount,
);
token.add(value as i32, 5);
State::new(token, self.mode, 0, self.bitCount + thisModeBitCount + 5)
State::new(token, self.mode, 0, self.bit_count + thisModeBitCount + 5)
}
// Create a new state representing this state, but an additional character
@@ -142,7 +142,7 @@ impl State {
pub fn addBinaryShiftChar(self, index: u32) -> State {
let mut token = self.token;
let mut mode = self.mode;
let mut bitCount = self.bitCount;
let mut bitCount = self.bit_count;
if self.mode == HighLevelEncoder::MODE_PUNCT as u32
|| self.mode == HighLevelEncoder::MODE_DIGIT as u32
{
@@ -151,10 +151,10 @@ impl State {
bitCount += latch >> 16;
mode = HighLevelEncoder::MODE_UPPER as u32;
}
let deltaBitCount = if self.binaryShiftByteCount == 0 || self.binaryShiftByteCount == 31 {
let deltaBitCount = if self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31 {
18
} else {
if self.binaryShiftByteCount == 62 {
if self.binary_shift_byte_count == 62 {
9
} else {
8
@@ -163,10 +163,10 @@ impl State {
let mut result = State::new(
token,
mode,
self.binaryShiftByteCount + 1,
self.binary_shift_byte_count + 1,
bitCount + deltaBitCount,
);
if result.binaryShiftByteCount == 2047 + 31 {
if result.binary_shift_byte_count == 2047 + 31 {
// The string is as long as it's allowed to be. We should end it.
result = result.endBinaryShift(index + 1);
}
@@ -176,30 +176,30 @@ impl State {
// Create the state identical to this one, but we are no longer in
// Binary Shift mode.
pub fn endBinaryShift(self, index: u32) -> State {
if self.binaryShiftByteCount == 0 {
if self.binary_shift_byte_count == 0 {
return self;
}
let mut token = self.token;
token.addBinaryShift(index - self.binaryShiftByteCount, self.binaryShiftByteCount);
token.addBinaryShift(index - self.binary_shift_byte_count, self.binary_shift_byte_count);
State::new(token, self.mode, 0, self.bitCount)
State::new(token, self.mode, 0, self.bit_count)
}
// Returns true if "this" state is better (or equal) to be in than "that"
// state under all possible circumstances.
pub fn isBetterThanOrEqualTo(&self, other: &State) -> bool {
let mut newModeBitCount = self.bitCount
let mut new_mode_bit_count = self.bit_count
+ (HighLevelEncoder::LATCH_TABLE[self.mode as usize][other.mode as usize] >> 16);
if self.binaryShiftByteCount < other.binaryShiftByteCount {
if self.binary_shift_byte_count < other.binary_shift_byte_count {
// add additional B/S encoding cost of other, if any
newModeBitCount += other.binaryShiftCost - self.binaryShiftCost;
} else if self.binaryShiftByteCount > other.binaryShiftByteCount
&& other.binaryShiftByteCount > 0
new_mode_bit_count += other.binary_shift_cost - self.binary_shift_cost;
} else if self.binary_shift_byte_count > other.binary_shift_byte_count
&& other.binary_shift_byte_count > 0
{
// maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
newModeBitCount += 10;
new_mode_bit_count += 10;
}
newModeBitCount <= other.bitCount
new_mode_bit_count <= other.bit_count
}
pub fn toBitArray(self, text: &[u8]) -> BitArray {
@@ -215,28 +215,24 @@ impl State {
// symbols.push(tkn);
// tkn = tok.getPrevious();
// }
let mut bitArray = BitArray::new();
let mut bit_array = BitArray::new();
// Add each token to the result in forward order
for i in (0..symbols.len() - 1).rev() {
for symbol in symbols.into_iter().rev() {
// for i in (0..symbols.len()).rev() {
// for (int i = symbols.size() - 1; i >= 0; i--) {
symbols.get(i).unwrap().appendTo(&mut bitArray, text);
symbol.appendTo(&mut bit_array, text);
}
bitArray
bit_array
}
// @Override
// public String toString() {
// return String.format("%s bits=%d bytes=%d", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
// }
fn calculateBinaryShiftCost(binaryShiftByteCount: u32) -> u32 {
if binaryShiftByteCount > 62 {
fn calculate_binary_shift_cost(binary_shift_byte_count: u32) -> u32 {
if binary_shift_byte_count > 62 {
return 21; // B/S with extended length
}
if binaryShiftByteCount > 31 {
if binary_shift_byte_count > 31 {
return 20; // two B/S
}
if binaryShiftByteCount > 0 {
if binary_shift_byte_count > 0 {
return 10; // one B/S
}
return 0;
@@ -249,8 +245,8 @@ impl fmt::Display for State {
f,
"{} bits={} bytes={}",
HighLevelEncoder::MODE_NAMES[self.mode as usize],
self.bitCount,
self.binaryShiftByteCount
self.bit_count,
self.binary_shift_byte_count
)
}
}

View File

@@ -9,9 +9,9 @@ pub fn toBitArray( bits:&str) -> BitArray{
let mut ba_in = BitArray::new();
let replacer_regex = Regex::new(DOTX).unwrap();
let str = replacer_regex.replace_all(bits, "");
for aStr in str.chars() {
for a_str in str.chars() {
// for (char aStr : str) {
ba_in.appendBit(aStr == 'X');
ba_in.appendBit(a_str == 'X');
}
ba_in

View File

@@ -148,6 +148,21 @@ use rand::Rng;
}
}
#[test]
fn test_append_bit(){
let mut array = BitArray::new();
array.appendBits(0x000001E, 6);
let mut array_2 = BitArray::new();
array_2.appendBit(false);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(true);
array_2.appendBit(false);
assert_eq!(array, array_2)
}
#[test]
fn test_set_range() {
let mut array = BitArray::with_size(64);

View File

@@ -552,14 +552,19 @@ impl BitArray {
* @param numBits bits from value to append
*/
pub fn appendBits(&mut self, value: u32, numBits: usize) -> Result<(), Exceptions> {
if numBits < 0 || numBits > 32 {
if numBits > 32 {
return Err(Exceptions::IllegalArgumentException(
"Num bits must be between 0 and 32".to_owned(),
));
}
if numBits == 0 {
return Ok(());
}
let mut nextSize = self.size;
self.ensureCapacity(nextSize + numBits);
for numBitsLeft in (0..(numBits - 1)).rev() {
for numBitsLeft in (0..(numBits)).rev() {
//for (int numBitsLeft = numBits - 1; numBitsLeft >= 0; numBitsLeft--) {
if (value & (1 << numBitsLeft)) != 0 {
self.bits[nextSize / 32] |= 1 << (nextSize & 0x1F);
@@ -720,7 +725,6 @@ impl fmt::Display for BitArray {
* @author Sean Owen
*/
pub trait DetectorRXingResult {
fn getBits(&self) -> &BitMatrix;
fn getPoints(&self) -> &Vec<RXingResultPoint>;
@@ -841,25 +845,25 @@ impl BitMatrix {
}
pub fn parse_strings(
stringRepresentation: &str,
setString: &str,
unsetString: &str,
string_representation: &str,
set_string: &str,
unset_string: &str,
) -> Result<Self, Exceptions> {
// cannot pass nulls in rust
// if (stringRepresentation == null) {
// throw new IllegalArgumentException();
// }
let mut bits = vec![false; stringRepresentation.len()];
let mut bits = vec![false; string_representation.len()];
let mut bitsPos = 0;
let mut rowStartPos = 0;
let mut rowLength = 0; //-1;
let mut first_run = true;
let mut nRows = 0;
let mut pos = 0;
while pos < stringRepresentation.len() {
if stringRepresentation.chars().nth(pos).unwrap() == '\n'
|| stringRepresentation.chars().nth(pos).unwrap() == '\r'
while pos < string_representation.len() {
if string_representation.chars().nth(pos).unwrap() == '\n'
|| string_representation.chars().nth(pos).unwrap() == '\r'
{
if bitsPos > rowStartPos {
//if rowLength == -1 {
@@ -875,18 +879,18 @@ impl BitMatrix {
nRows += 1;
}
pos += 1;
} else if stringRepresentation[pos..].starts_with(setString) {
pos += setString.len();
} else if string_representation[pos..].starts_with(set_string) {
pos += set_string.len();
bits[bitsPos] = true;
bitsPos += 1;
} else if stringRepresentation[pos..].starts_with(unsetString) {
pos += unsetString.len();
} else if string_representation[pos..].starts_with(unset_string) {
pos += unset_string.len();
bits[bitsPos] = false;
bitsPos += 1;
} else {
return Err(Exceptions::IllegalArgumentException(format!(
"illegal character encountered: {}",
stringRepresentation[pos..].to_owned()
string_representation[pos..].to_owned()
)));
}
}
@@ -975,7 +979,8 @@ impl BitMatrix {
* @param mask XOR mask
*/
pub fn xor(&mut self, mask: &BitMatrix) -> Result<(), Exceptions> {
if self.width != mask.width || self.height != mask.height || self.row_size != mask.row_size {
if self.width != mask.width || self.height != mask.height || self.row_size != mask.row_size
{
return Err(Exceptions::IllegalArgumentException(
"input matrix dimensions do not match".to_owned(),
));
@@ -2398,6 +2403,7 @@ impl GridSampler for DefaultGridSampler {
*
* @author Sean Owen
*/
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CharacterSetECI {
// Enum name is a Java encoding valid for java.lang and java.io
Cp437, //(new int[]{0,2}),
@@ -2531,34 +2537,34 @@ impl CharacterSetECI {
* but unsupported
*/
pub fn getCharacterSetECI(charset: &'static dyn Encoding) -> Option<CharacterSetECI> {
match charset.whatwg_name().unwrap() {
match charset.name() {
"CP437" => Some(CharacterSetECI::Cp437),
"ISO-8859-1" => Some(CharacterSetECI::ISO8859_1),
"ISO-8859-2" => Some(CharacterSetECI::ISO8859_2),
"ISO-8859-3" => Some(CharacterSetECI::ISO8859_3),
"ISO-8859-4" => Some(CharacterSetECI::ISO8859_4),
"ISO-8859-5" => Some(CharacterSetECI::ISO8859_5),
"ISO-8859-6" => Some(CharacterSetECI::ISO8859_6),
"ISO-8859-7" => Some(CharacterSetECI::ISO8859_7),
"ISO-8859-8" => Some(CharacterSetECI::ISO8859_8),
"ISO-8859-9" => Some(CharacterSetECI::ISO8859_9),
"ISO-8859-10" => Some(CharacterSetECI::ISO8859_10),
"ISO-8859-11" => Some(CharacterSetECI::ISO8859_11),
"ISO-8859-13" => Some(CharacterSetECI::ISO8859_13),
"ISO-8859-14" => Some(CharacterSetECI::ISO8859_14),
"ISO-8859-15" => Some(CharacterSetECI::ISO8859_15),
"ISO-8859-16" => Some(CharacterSetECI::ISO8859_16),
"Shift_JIS" => Some(CharacterSetECI::SJIS),
"iso-8859-1" => Some(CharacterSetECI::ISO8859_1),
"iso-8859-2" => Some(CharacterSetECI::ISO8859_2),
"iso-8859-3" => Some(CharacterSetECI::ISO8859_3),
"iso-8859-4" => Some(CharacterSetECI::ISO8859_4),
"iso-8859-5" => Some(CharacterSetECI::ISO8859_5),
"iso-8859-6" => Some(CharacterSetECI::ISO8859_6),
"iso-8859-7" => Some(CharacterSetECI::ISO8859_7),
"iso-8859-8" => Some(CharacterSetECI::ISO8859_8),
"iso-8859-9" => Some(CharacterSetECI::ISO8859_9),
"iso-8859-10" => Some(CharacterSetECI::ISO8859_10),
"iso-8859-11" => Some(CharacterSetECI::ISO8859_11),
"iso-8859-13" => Some(CharacterSetECI::ISO8859_13),
"iso-8859-14" => Some(CharacterSetECI::ISO8859_14),
"iso-8859-15" => Some(CharacterSetECI::ISO8859_15),
"iso-8859-16" => Some(CharacterSetECI::ISO8859_16),
"shift_jis" => Some(CharacterSetECI::SJIS),
"windows-1250" => Some(CharacterSetECI::Cp1250),
"windows-1251" => Some(CharacterSetECI::Cp1251),
"windows-1252" => Some(CharacterSetECI::Cp1252),
"windows-1256" => Some(CharacterSetECI::Cp1256),
"UTF-16BE" => Some(CharacterSetECI::UnicodeBigUnmarked),
"UTF-8" => Some(CharacterSetECI::UTF8),
"US-ASCII" => Some(CharacterSetECI::ASCII),
"Big5" => Some(CharacterSetECI::Big5),
"GB2312" => Some(CharacterSetECI::GB18030),
"EUC-KR" => Some(CharacterSetECI::EUC_KR),
"utf-16be" => Some(CharacterSetECI::UnicodeBigUnmarked),
"utf-8" => Some(CharacterSetECI::UTF8),
"us-ascii" => Some(CharacterSetECI::ASCII),
"big5" => Some(CharacterSetECI::Big5),
"gb2312" => Some(CharacterSetECI::GB18030),
"euc-kr" => Some(CharacterSetECI::EUC_KR),
_ => None,
}
}
@@ -4052,6 +4058,9 @@ impl HybridBinarizer {
blackPoints[y as usize][x as usize] = average;
}
}
return blackPoints.into_iter().map(|x| x.iter().map(|y| *y as u32).collect()).collect();
return blackPoints
.into_iter()
.map(|x| x.iter().map(|y| *y as u32).collect())
.collect();
}
}