Cleanup of many components of the code.

Many unwraps, expects, and panics removed or handled.

More rustification of the codebase.

Squashed commit of the following:

commit 80c6483cf8c819496a7b781f9e3a149d1f18d5fe
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 20:36:57 2023 -0600

    add other parsed result option

commit 412d92ae585e7bf194697f5282dbc045e448bace
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 19:06:34 2023 -0600

    fix some panics

commit 9108d3e931aadec00fc0bf346ebc52d24e5d8146
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 18:56:30 2023 -0600

    clippy --fix

commit 8cd89d314323f54f342f15fc73297b62d418ac79
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 18:55:45 2023 -0600

    some more cleanup in aztec

commit fb7f9242e273b85a4bb212f22a185a0dcbfafc36
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 18:19:54 2023 -0600

    cleanup root

commit 4fb7c0639830869149332b29be789e891eade3e7
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 16:50:15 2023 -0600

    format

commit 3ac271af657b25fbe5ee39cbdf8859e5aa38ea41
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 16:43:14 2023 -0600

    clippy --fix

commit 0c5b4c1477159db93a9da9645039f51cd1a7c574
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 16:04:31 2023 -0600

    qrcode cleanup complete

commit 70c1d107cc672e45d46567c650c46fece7e7da9c
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 13:28:25 2023 -0600

    clippy --fix

commit e13263d0f1f2a13dbb59b6e60d8b871a32babc92
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 13:27:44 2023 -0600

    qrcode detector cleanup

commit f7f2855099e469fe1091868c6099196705d0ae83
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 11:48:13 2023 -0600

    qrcode decoder

commit bdbaaba597b3479639c2ed3726465a69e3004471
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 11:13:18 2023 -0600

    clippy --fix

commit fd6dbcaeb1f45dc91ae98f0e7c58aad48d67df78
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 11:12:28 2023 -0600

    pdf417 cleanup complete

commit 7bbd47604c2639a5eb61bdb5533e71be3bce95a1
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 10:39:28 2023 -0600

    clippy --fix

commit 8f4962b7bb5f133524fe4d3d4948e5672a88c545
Author: Henry Schimke <henry@azule.info>
Date:   Fri Feb 10 10:39:00 2023 -0600

    cleanup on pdf417 hie

commit 254c8243953776d3c8704dd81529aadd05d5a94e
Author: Henry <henry@azule.info>
Date:   Fri Feb 10 02:51:21 2023 +0000

    partway through pdf417 hle

commit d4a5b00fde8c0282b0c6e4175a21c1e111b11533
Author: Henry <henry@azule.info>
Date:   Wed Feb 8 21:35:25 2023 +0000

    clippy --fix

commit 2bd4a8e218aa963a88997b50bc5a198f9a88205e
Author: Henry <henry@azule.info>
Date:   Wed Feb 8 21:31:55 2023 +0000

    pdf417 decode and detect cleanup

commit 05130ac54a72c2303045d64507bf6185aa74e531
Author: Henry Schimke <henry@azule.info>
Date:   Tue Feb 7 08:06:25 2023 -0600

    at decodeTextCompaction in decoded_bit_straem_parser

commit 924c023a7d2339dfffa6ef0c4a805fb192576796
Author: Henry Schimke <henry@azule.info>
Date:   Mon Feb 6 18:22:02 2023 -0600

    clippy --fix

commit 5cfb81a885c22b4b5ec937a79be31d0815def211
Author: Henry Schimke <henry@azule.info>
Date:   Mon Feb 6 18:20:22 2023 -0600

    oned cleanup

commit 0649b64854baf56a8e3314728d4f6cf4063db8b2
Author: Henry Schimke <henry@azule.info>
Date:   Mon Feb 6 11:47:28 2023 -0600

    rss cleanup

commit 2d3127898fc11f7e65d590e983cda799b798b646
Author: Henry Schimke <henry@azule.info>
Date:   Mon Feb 6 10:19:56 2023 -0600

    multi cleanup

commit 7e8b43a159083a2096123e6204d4d1d359c59981
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 21:41:59 2023 -0600

    cargo fmt

commit df8285e8da07b4bffd48ca6e596de3f010eb8d9e
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 21:41:29 2023 -0600

    maxicode cleanup

commit a51f923a14016eb416ca202b2194258808dde3e7
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 21:27:57 2023 -0600

    cargo fmt

commit 332d7eef4a25318611025a3fcb0b70c604d917be
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 21:27:48 2023 -0600

    cleanup datamatrix

commit eb2311c476a9c9993f271ab6cf9fd359aedca26f
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 21:27:26 2023 -0600

    cargo clippy --fix

commit 2abaa4c51d287f619d4c7a438f85ba2a30f159cf
Author: Henry <henry@azule.info>
Date:   Sun Feb 5 19:13:02 2023 -0600

    finish cleanup in parsers

commit 716aa2fbf728716cff36657a5fd80e7bca5276b7
Author: Henry Schimke <henry@azule.info>
Date:   Sun Feb 5 17:44:56 2023 -0600

    cleanup continues

commit 7d843788a49fa9cc82c4616d226c0f882e73612b
Author: Henry Schimke <henry@azule.info>
Date:   Sun Feb 5 15:15:09 2023 -0600

    common cleanup

commit fd251866c68f22d450dd428c93d7a3620bf1be27
Author: Henry Schimke <henry@azule.info>
Date:   Sun Feb 5 10:24:54 2023 -0600

    cleanup reedsolomon

commit 132e27ed1468f5c1ce998516ff5a00687217c3e6
Author: Henry Schimke <henry@azule.info>
Date:   Sun Feb 5 09:52:04 2023 -0600

    make MathUtils more generic

commit d8352b7fff4cb4f9ecc8e8a969710d26ef410e8b
Author: Henry Schimke <henry@azule.info>
Date:   Sun Feb 5 09:29:33 2023 -0600

    cleanup some string handling in ResultParser

    There may still be some edge cases where multi-byte characters break the parser
This commit is contained in:
Henry
2023-02-10 20:41:25 -06:00
parent 5222bb25b7
commit 28723be2eb
180 changed files with 3248 additions and 4117 deletions

View File

@@ -79,7 +79,13 @@ fn test_digits_only() {
let test_data = "374833744734397449";
let data = qrcode_encoder::encode(test_data, ErrorCorrectionLevel::H).expect("encode");
let decode = crate::qrcode::decoder::qrcode_decoder::decode_bitmatrix(
&data.getMatrix().as_ref().unwrap().clone().into(),
&data
.getMatrix()
.as_ref()
.unwrap()
.clone()
.try_into()
.expect("convert"),
)
.expect("decode");
assert_eq!(test_data, decode.getText());
@@ -743,7 +749,7 @@ fn testAppendKanjiBytes() {
#[test]
fn testGenerateECBytes() {
let dataBytes = &[32, 65, 205, 69, 41, 220, 46, 128, 236];
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17);
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17).expect("ecb");
let expected = [
42, 159, 74, 221, 244, 169, 239, 150, 138, 70, 237, 85, 224, 96, 74, 219, 61,
];
@@ -755,7 +761,7 @@ fn testGenerateECBytes() {
let dataBytes = &[
67, 70, 22, 38, 54, 70, 86, 102, 118, 134, 150, 166, 182, 198, 214,
];
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 18);
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 18).expect("ecb");
let expected = &[
175, 80, 155, 64, 178, 45, 214, 233, 65, 209, 12, 155, 117, 31, 140, 214, 27, 187,
];
@@ -766,7 +772,7 @@ fn testGenerateECBytes() {
}
// High-order zero coefficient case.
let dataBytes = &[32, 49, 205, 69, 42, 20, 0, 236, 17];
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17);
let ecBytes = qrcode_encoder::generateECBytes(dataBytes, 17).expect("ecb");
let expected = &[
0, 3, 130, 179, 194, 0, 55, 211, 110, 79, 98, 72, 170, 96, 211, 137, 213,
];

View File

@@ -16,7 +16,7 @@
use std::fmt;
use crate::common::BitMatrix;
use crate::{common::BitMatrix, Exceptions};
/**
* JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned
@@ -38,7 +38,6 @@ impl ByteMatrix {
width,
height,
}
// bytes = new byte[height][width];
}
pub fn getHeight(&self) -> u32 {
@@ -64,21 +63,14 @@ impl ByteMatrix {
self.bytes[y as usize][x as usize] = value;
}
// pub fn set(int x, int y, int value) {
// bytes[y][x] = (byte) value;
// }
pub fn set_bool(&mut self, x: u32, y: u32, value: bool) {
self.bytes[y as usize][x as usize] = u8::from(value); //if value { 1 } else { 0 };
}
pub fn clear(&mut self, value: u8) {
for row in self.bytes.iter_mut() {
*row = vec![value; row.len()];
row.fill(value);
}
// for (byte[] aByte : bytes) {
// Arrays.fill(aByte, value);
// }
}
}
@@ -86,27 +78,13 @@ impl fmt::Display for ByteMatrix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut result = String::with_capacity(2 * self.width as usize * self.height as usize + 2);
for y in 0..self.height as usize {
// for (int y = 0; y < height; ++y) {
let bytesY = &self.bytes[y];
for byte in bytesY.iter().take(self.width as usize) {
// for x in 0..self.width as usize {
// for (int x = 0; x < width; ++x) {
match *byte {
0 => result.push_str(" 0"),
1 => result.push_str(" 1"),
_ => result.push_str(" "),
};
// switch (bytesY[x]) {
// case 0:
// result.append(" 0");
// break;
// case 1:
// result.append(" 1");
// break;
// default:
// result.append(" ");
// break;
// }
}
result.push('\n');
}
@@ -114,16 +92,18 @@ impl fmt::Display for ByteMatrix {
}
}
impl From<ByteMatrix> for BitMatrix {
fn from(bm: ByteMatrix) -> Self {
let mut bit_matrix = BitMatrix::new(bm.getWidth(), bm.getHeight()).unwrap();
for y in 0..bm.getHeight() {
for x in 0..bm.getWidth() {
if bm.get(x, y) > 0 {
impl TryFrom<ByteMatrix> for BitMatrix {
type Error = Exceptions;
fn try_from(value: ByteMatrix) -> Result<Self, Self::Error> {
let mut bit_matrix = BitMatrix::new(value.getWidth(), value.getHeight())?;
for y in 0..value.getHeight() {
for x in 0..value.getWidth() {
if value.get(x, y) > 0 {
bit_matrix.set(x, y);
}
}
}
bit_matrix
Ok(bit_matrix)
}
}

View File

@@ -49,10 +49,8 @@ pub fn applyMaskPenaltyRule2(matrix: &ByteMatrix) -> u32 {
let width = matrix.getWidth();
let height = matrix.getHeight();
for y in 0..(height - 1) as usize {
// for (int y = 0; y < height - 1; y++) {
let arrayY = &array[y];
for x in 0..(width - 1) as usize {
// for (int x = 0; x < width - 1; x++) {
let value = arrayY[x];
if value == arrayY[x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1] {
penalty += 1;
@@ -73,9 +71,7 @@ pub fn applyMaskPenaltyRule3(matrix: &ByteMatrix) -> u32 {
let width = matrix.getWidth();
let height = matrix.getHeight();
for y in 0..height as usize {
// for (int y = 0; y < height; y++) {
for x in 0..width as usize {
// for (int x = 0; x < width; x++) {
let arrayY = &array[y]; // We can at least optimize this access
if x + 6 < width as usize
&& arrayY[x] == 1
@@ -113,7 +109,6 @@ pub fn isWhiteHorizontal(rowArray: &[u8], from: i32, to: u32) -> bool {
return false;
}
for i in from..to as i32 {
// for (int i = from; i < to; i++) {
if rowArray[i as usize] == 1 {
return false;
}
@@ -126,7 +121,6 @@ pub fn isWhiteVertical(array: &Vec<Vec<u8>>, col: u32, from: i32, to: u32) -> bo
return false;
}
for i in from..to as i32 {
// for (int i = from; i < to; i++) {
if array[i as usize][col as usize] == 1 {
return false;
}
@@ -144,12 +138,7 @@ pub fn applyMaskPenaltyRule4(matrix: &ByteMatrix) -> u32 {
let width = matrix.getWidth();
let height = matrix.getHeight();
for val_y in array.iter().take(height as usize) {
// for y in 0..height as usize {
// for (int y = 0; y < height; y++) {
// let arrayY = val_y;
for val_x in val_y.iter().take(width as usize) {
// for x in 0..width as usize {
// for (int x = 0; x < width; x++) {
if val_x == &1 {
numDarkCells += 1;
}
@@ -242,12 +231,9 @@ fn applyMaskPenaltyRule1Internal(matrix: &ByteMatrix, isHorizontal: bool) -> u32
};
let array = matrix.getArray();
for i in 0..iLimit as usize {
// for (int i = 0; i < iLimit; i++) {
let mut numSameBitCells = 0;
// let prevBit = -1;
let mut prevBit = 0;
for j in 0..jLimit as usize {
// for (int j = 0; j < jLimit; j++) {
let bit = if isHorizontal {
array[i][j]
} else {

View File

@@ -176,7 +176,6 @@ pub fn embedTypeInfo(
.enumerate()
.take(typeInfoBits.getSize())
{
// for (int i = 0; i < typeInfoBits.getSize(); ++i) {
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
// "typeInfoBits".
let bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i);
@@ -215,9 +214,7 @@ pub fn maybeEmbedVersionInfo(version: &Version, matrix: &mut ByteMatrix) -> Resu
let mut bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0.
for i in 0..6 {
// for (int i = 0; i < 6; ++i) {
for j in 0..3 {
// for (int j = 0; j < 3; ++j) {
// Place bits in LSB (least significant bit) to MSB order.
let bit = versionInfoBits.get(bitIndex);
bitIndex = bitIndex.saturating_sub(1);
@@ -250,7 +247,6 @@ pub fn embedDataBits(
}
while y >= 0 && y < matrix.getHeight() as i32 {
for i in 0..2 {
// for (int i = 0; i < 2; ++i) {
let xx = x - i;
// Skip the cell if it's not empty.
if !isEmpty(matrix.get(xx as u32, y as u32)) {
@@ -431,7 +427,6 @@ pub fn embedHorizontalSeparationPattern(
matrix: &mut ByteMatrix,
) -> Result<(), Exceptions> {
for x in 0..8 {
// for (int x = 0; x < 8; ++x) {
if !isEmpty(matrix.get(xStart + x, yStart)) {
return Err(Exceptions::WriterException(None));
}
@@ -446,10 +441,8 @@ pub fn embedVerticalSeparationPattern(
matrix: &mut ByteMatrix,
) -> Result<(), Exceptions> {
for y in 0..7 {
// for (int y = 0; y < 7; ++y) {
if !isEmpty(matrix.get(xStart, yStart + y)) {
return Err(Exceptions::WriterException(None));
// throw new WriterException();
}
matrix.set(xStart, yStart + y, 0);
}
@@ -458,11 +451,7 @@ pub fn embedVerticalSeparationPattern(
pub fn embedPositionAdjustmentPattern(xStart: u32, yStart: u32, matrix: &mut ByteMatrix) {
for (y, patternY) in POSITION_ADJUSTMENT_PATTERN.iter().enumerate() {
// for y in 0..5 {
// for (int y = 0; y < 5; ++y) {
// let patternY = POSITION_ADJUSTMENT_PATTERN[y];
for x in 0..5 {
// for (int x = 0; x < 5; ++x) {
matrix.set(xStart + x, yStart + y as u32, patternY[x as usize]);
}
}
@@ -470,11 +459,7 @@ pub fn embedPositionAdjustmentPattern(xStart: u32, yStart: u32, matrix: &mut Byt
pub fn embedPositionDetectionPattern(xStart: u32, yStart: u32, matrix: &mut ByteMatrix) {
for (y, patternY) in POSITION_DETECTION_PATTERN.iter().enumerate() {
// for y in 0..7 {
// for (int y = 0; y < 7; ++y) {
// let patternY = POSITION_DETECTION_PATTERN[y];
for x in 0..7 {
// for (int x = 0; x < 7; ++x) {
matrix.set(xStart + x, yStart + y as u32, patternY[x as usize]);
}
}
@@ -523,10 +508,8 @@ pub fn maybeEmbedPositionAdjustmentPatterns(version: &Version, matrix: &mut Byte
let index = version.getVersionNumber() - 1;
let coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index as usize];
for y in coordinates {
// for (int y : coordinates) {
if y >= 0 {
for x in coordinates {
// for (int x : coordinates) {
if x >= 0 && isEmpty(matrix.get(x as u32, y as u32)) {
// If the cell is unset, we embed the position adjustment pattern here.
// -2 is necessary since the x/y coordinates point to the center of the pattern, not the

View File

@@ -120,8 +120,6 @@ impl MinimalEncoder {
encoders: ECIEncoderSet::new(stringToEncode, priorityCharset, None),
ecLevel,
}
// let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1);
}
/**
@@ -157,7 +155,7 @@ impl MinimalEncoder {
let result = self.encodeSpecificVersion(version)?;
if !qrcode_encoder::willFit(
result.getSize(),
Self::getVersion(Self::getVersionSize(result.getVersion())),
Self::getVersion(Self::getVersionSize(result.getVersion()))?,
&self.ecLevel,
) {
return Err(Exceptions::WriterException(Some(format!(
@@ -168,9 +166,9 @@ impl MinimalEncoder {
} else {
// compute minimal encoding trying the three version sizes.
let versions = [
Self::getVersion(VersionSize::SMALL),
Self::getVersion(VersionSize::MEDIUM),
Self::getVersion(VersionSize::LARGE),
Self::getVersion(VersionSize::SMALL)?,
Self::getVersion(VersionSize::MEDIUM)?,
Self::getVersion(VersionSize::LARGE)?,
];
let results = [
self.encodeSpecificVersion(versions[0])?,
@@ -180,7 +178,6 @@ impl MinimalEncoder {
let mut smallestSize = u32::MAX;
let mut smallestRXingResult: i32 = -1;
for i in 0..3 {
// for (int i = 0; i < 3; i++) {
let size = results[i].getSize();
if qrcode_encoder::willFit(size, versions[i], &self.ecLevel) && size < smallestSize
{
@@ -198,40 +195,28 @@ impl MinimalEncoder {
}
pub fn getVersionSize(version: VersionRef) -> VersionSize {
if version.getVersionNumber() <= 9 {
VersionSize::SMALL
} else if version.getVersionNumber() <= 26 {
VersionSize::MEDIUM
} else {
VersionSize::LARGE
match version.getVersionNumber() {
0..=9 => VersionSize::SMALL,
10..=26 => VersionSize::MEDIUM,
_ => VersionSize::LARGE,
}
}
pub fn getVersion(versionSize: VersionSize) -> VersionRef {
pub fn getVersion(versionSize: VersionSize) -> Result<VersionRef, Exceptions> {
match versionSize {
VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"),
VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"),
VersionSize::LARGE => Version::getVersionForNumber(40).expect("should always exist"),
VersionSize::SMALL => Version::getVersionForNumber(9),
VersionSize::MEDIUM => Version::getVersionForNumber(26),
VersionSize::LARGE => Version::getVersionForNumber(40),
}
// switch (versionSize) {
// case SMALL:
// return Version.getVersionForNumber(9);
// case MEDIUM:
// return Version.getVersionForNumber(26);
// case LARGE:
// default:
// return Version.getVersionForNumber(40);
// }
}
pub fn isNumeric(c: &str) -> bool {
if c.len() == 1 {
let ch = c.chars().next().unwrap();
('0'..='9').contains(&ch)
} else {
false
if let Some(ch) = c.chars().next() {
return ('0'..='9').contains(&ch);
}
}
// return c >= '0' && c <= '9';
false
}
pub fn isDoubleByteKanji(c: &str) -> bool {
@@ -240,12 +225,11 @@ impl MinimalEncoder {
pub fn isAlphanumeric(c: &str) -> bool {
if c.len() == 1 {
let ch = c.chars().next().unwrap();
qrcode_encoder::getAlphanumericCode(ch as u32) != -1
} else {
false
if let Some(ch) = c.chars().next() {
return qrcode_encoder::getAlphanumericCode(ch as u32) != -1;
}
}
// return encoder::getAlphanumericCode(c as u8 as u32) != -1;
false
}
pub fn canEncode(&self, mode: &Mode, c: &str) -> bool {
@@ -260,30 +244,15 @@ impl MinimalEncoder {
}
pub fn getCompactedOrdinal(mode: Option<Mode>) -> Result<u32, Exceptions> {
if mode.is_none() {
return Ok(0);
}
match &mode.unwrap() {
Mode::NUMERIC => Ok(2),
Mode::ALPHANUMERIC => Ok(1),
Mode::BYTE => Ok(3),
Mode::KANJI => Ok(0),
match mode {
Some(Mode::NUMERIC) => Ok(2),
Some(Mode::ALPHANUMERIC) => Ok(1),
Some(Mode::BYTE) => Ok(3),
Some(Mode::KANJI) | None => Ok(0),
_ => Err(Exceptions::IllegalArgumentException(Some(format!(
"Illegal mode {mode:?}"
)))),
}
// switch (mode) {
// case KANJI:
// return 0;
// case ALPHANUMERIC:
// return 1;
// case NUMERIC:
// return 2;
// case BYTE:
// return 3;
// default:
// throw new IllegalStateException("Illegal mode " + mode);
// }
}
pub fn addEdge(
@@ -291,17 +260,33 @@ impl MinimalEncoder {
edges: &mut [Vec<Vec<Option<Rc<Edge>>>>],
position: usize,
edge: Option<Rc<Edge>>,
) {
let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize;
let modeEdges = &mut edges[vertexIndex][edge.as_ref().unwrap().charsetEncoderIndex];
let modeOrdinal =
Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
) -> Result<(), Exceptions> {
let vertexIndex = position
+ edge
.as_ref()
.ok_or(Exceptions::FormatException(None))?
.characterLength as usize;
let modeEdges = &mut edges[vertexIndex][edge
.as_ref()
.ok_or(Exceptions::FormatException(None))?
.charsetEncoderIndex];
let modeOrdinal = Self::getCompactedOrdinal(Some(
edge.as_ref().ok_or(Exceptions::FormatException(None))?.mode,
))? as usize;
if modeEdges[modeOrdinal].is_none()
|| modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize
> edge.as_ref().unwrap().cachedTotalSize
|| modeEdges[modeOrdinal]
.as_ref()
.ok_or(Exceptions::FormatException(None))?
.cachedTotalSize
> edge
.as_ref()
.ok_or(Exceptions::FormatException(None))?
.cachedTotalSize
{
modeEdges[modeOrdinal] = edge;
}
Ok(())
}
pub fn addEdges(
@@ -310,116 +295,162 @@ impl MinimalEncoder {
edges: &mut [Vec<Vec<Option<Rc<Edge>>>>],
from: usize,
previous: Option<Rc<Edge>>,
) {
) -> Result<(), Exceptions> {
let mut start = 0;
let mut end = self.encoders.len();
let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex();
if priorityEncoderIndex.is_some()
&& self.encoders.canEncode(
// self.stringToEncode.chars().nth(from as usize).unwrap() as i16,
&self.stringToEncode[from],
priorityEncoderIndex.unwrap(),
)
&& self
.encoders
.canEncode(
&self.stringToEncode[from],
priorityEncoderIndex.ok_or(Exceptions::FormatException(None))?,
)
.ok_or(Exceptions::FormatException(None))?
{
start = priorityEncoderIndex.unwrap();
end = priorityEncoderIndex.unwrap() + 1;
start = priorityEncoderIndex.ok_or(Exceptions::FormatException(None))?;
end = priorityEncoderIndex.ok_or(Exceptions::FormatException(None))? + 1;
}
for i in start..end {
// for (int i = start; i < end; i++) {
if self
.encoders
.canEncode(self.stringToEncode.get(from).unwrap(), i)
.canEncode(
self.stringToEncode
.get(from)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
i,
)
.ok_or(Exceptions::FormatException(None))?
{
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::BYTE,
Some(Rc::new(
Edge::new(
Mode::BYTE,
from,
i,
1,
previous.clone(),
version,
self.encoders.clone(),
self.stringToEncode.clone(),
)
.ok_or(Exceptions::WriterException(None))?,
)),
)?;
}
}
if self.canEncode(
&Mode::KANJI,
self.stringToEncode
.get(from)
.ok_or(Exceptions::FormatException(None))?,
) {
self.addEdge(
edges,
from,
Some(Rc::new(
Edge::new(
Mode::KANJI,
from,
i,
0,
1,
previous.clone(),
version,
self.encoders.clone(),
self.stringToEncode.clone(),
))),
);
}
}
if self.canEncode(&Mode::KANJI, self.stringToEncode.get(from).unwrap()) {
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::KANJI,
from,
0,
1,
previous.clone(),
version,
self.encoders.clone(),
self.stringToEncode.clone(),
))),
);
)
.ok_or(Exceptions::WriterException(None))?,
)),
)?;
}
let inputLength = self.stringToEncode.len();
if self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.get(from).unwrap()) {
if self.canEncode(
&Mode::ALPHANUMERIC,
self.stringToEncode
.get(from)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) {
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::ALPHANUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self.canEncode(
&Mode::ALPHANUMERIC,
self.stringToEncode.get(from + 1).unwrap(),
)
{
1
} else {
2
},
previous.clone(),
version,
self.encoders.clone(),
self.stringToEncode.clone(),
))),
);
Some(Rc::new(
Edge::new(
Mode::ALPHANUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self.canEncode(
&Mode::ALPHANUMERIC,
self.stringToEncode
.get(from + 1)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
)
{
1
} else {
2
},
previous.clone(),
version,
self.encoders.clone(),
self.stringToEncode.clone(),
)
.ok_or(Exceptions::WriterException(None))?,
)),
)?;
}
if self.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from).unwrap()) {
if self.canEncode(
&Mode::NUMERIC,
self.stringToEncode
.get(from)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
) {
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::NUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self
.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from + 1).unwrap())
{
1
} else if from + 2 >= inputLength
|| !self
.canEncode(&Mode::NUMERIC, self.stringToEncode.get(from + 2).unwrap())
{
2
} else {
3
},
previous,
version,
self.encoders.clone(),
self.stringToEncode.clone(),
))),
);
Some(Rc::new(
Edge::new(
Mode::NUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self.canEncode(
&Mode::NUMERIC,
self.stringToEncode
.get(from + 1)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
)
{
1
} else if from + 2 >= inputLength
|| !self.canEncode(
&Mode::NUMERIC,
self.stringToEncode
.get(from + 2)
.ok_or(Exceptions::IndexOutOfBoundsException(None))?,
)
{
2
} else {
3
},
previous,
version,
self.encoders.clone(),
self.stringToEncode.clone(),
)
.ok_or(Exceptions::WriterException(None))?,
)),
)?;
}
Ok(())
}
pub fn encodeSpecificVersion(
&self,
@@ -544,18 +575,15 @@ impl MinimalEncoder {
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
// function getCompactedOrdinal(Mode)
let mut edges = vec![vec![vec![None; 4]; self.encoders.len()]; inputLength + 1]; //new Edge[inputLength + 1][encoders.length()][4];
self.addEdges(version, &mut edges, 0, None);
let mut edges = vec![vec![vec![None; 4]; self.encoders.len()]; inputLength + 1];
self.addEdges(version, &mut edges, 0, None)?;
for i in 1..=inputLength {
// for (int i = 1; i <= inputLength; i++) {
for j in 0..self.encoders.len() {
// for (int j = 0; j < encoders.length(); j++) {
for k in 0..4 {
// for (int k = 0; k < 4; k++) {
if edges[i][j][k].is_some() && i < inputLength {
let e = edges[i][j][k].clone();
self.addEdges(version, &mut edges, i, e);
self.addEdges(version, &mut edges, i, e)?;
}
}
}
@@ -564,11 +592,8 @@ impl MinimalEncoder {
let mut minimalK = None;
let mut minimalSize = u32::MAX;
for j in 0..self.encoders.len() {
// for (int j = 0; j < encoders.length(); j++) {
for k in 0..4 {
// for (int k = 0; k < 4; k++) {
if edges[inputLength][j][k].is_some() {
let edge = edges[inputLength][j][k].as_ref().unwrap();
if let Some(edge) = &edges[inputLength][j][k] {
if edge.cachedTotalSize < minimalSize {
minimalSize = edge.cachedTotalSize;
minimalJ = Some(j);
@@ -577,26 +602,29 @@ impl MinimalEncoder {
}
}
}
if minimalJ.is_none() {
return Err(Exceptions::WriterException(Some(format!(
if let Some((minJ, minK)) = minimalJ.zip(minimalK) {
Ok(RXingResultList::new(
version,
edges[inputLength][minJ][minK]
.as_ref()
.ok_or(Exceptions::WriterException(None))?
.clone(),
self.isGS1,
&self.ecLevel,
self.encoders.clone(),
self.stringToEncode.clone(),
)
.ok_or(Exceptions::WriterException(None))?)
} else {
Err(Exceptions::WriterException(Some(format!(
r#"Internal error: failed to encode "{}"#,
self.stringToEncode
.iter()
.map(String::from)
.collect::<String>() //fold("", |acc,x| [acc,&x].concat())
))));
.collect::<String>()
))))
}
Ok(RXingResultList::new(
version,
edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()]
.as_ref()
.unwrap()
.clone(),
self.isGS1,
&self.ecLevel,
self.encoders.clone(),
self.stringToEncode.clone(),
))
}
}
@@ -621,13 +649,14 @@ impl Edge {
version: VersionRef,
encoders: ECIEncoderSet,
stringToEncode: Vec<String>,
) -> Self {
) -> Option<Self> {
let nci = if mode == Mode::BYTE || previous.is_none() {
charsetEncoderIndex
} else {
previous.as_ref().unwrap().charsetEncoderIndex
previous.as_ref()?.charsetEncoderIndex
};
Self {
Some(Self {
mode,
fromPosition,
charsetEncoderIndex: nci,
@@ -636,16 +665,16 @@ impl Edge {
_stringToEncode: stringToEncode.clone(),
cachedTotalSize: {
let mut size = if previous.is_some() {
previous.as_ref().unwrap().cachedTotalSize
previous.as_ref()?.cachedTotalSize
} else {
0
};
let needECI = mode == Mode::BYTE &&
(previous.is_none() && nci != 0) || // at the beginning and charset is not ISO-8859-1
(previous.is_some() && nci != previous.as_ref().unwrap().charsetEncoderIndex);
(previous.is_some() && nci != previous.as_ref()?.charsetEncoderIndex);
if previous.is_none() || mode != previous.as_ref().unwrap().mode || needECI {
if previous.is_none() || mode != previous.as_ref()?.mode || needECI {
size += 4 + mode.getCharacterCountBits(version) as u32;
}
match mode {
@@ -666,14 +695,7 @@ impl Edge {
.take(characterLength as usize)
.map(String::from)
.collect();
size += 8 * encoders.encode_string(&n, charsetEncoderIndex).len() as u32;
// size += 8 * encoders
// .encode_string(
// &stringToEncode[fromPosition as usize
// ..(fromPosition + characterLength as usize)],
// charsetEncoderIndex as usize,
// )
// .len() as u32;
size += 8 * encoders.encode_string(&n, charsetEncoderIndex)?.len() as u32;
if needECI {
size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
}
@@ -681,63 +703,10 @@ impl Edge {
Mode::KANJI => size += 13,
_ => {}
}
// switch (mode) {
// case KANJI:
// size += 13;
// break;
// case ALPHANUMERIC:
// size += characterLength == 1 ? 6 : 11;
// break;
// case NUMERIC:
// size += characterLength == 1 ? 4 : characterLength == 2 ? 7 : 10;
// break;
// case BYTE:
// size += 8 * encoders.encode(stringToEncode.substring(fromPosition, fromPosition + characterLength),
// charsetEncoderIndex).length;
// if (needECI) {
// size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
// }
// break;
// }
size
},
_encoders: encoders,
}
// this.mode = mode;
// this.fromPosition = fromPosition;
// this.charsetEncoderIndex = mode == Mode.BYTE || previous == null ? charsetEncoderIndex :
// previous.charsetEncoderIndex; // inherit the encoding if not of type BYTE
// this.characterLength = characterLength;
// this.previous = previous;
// int size = previous != null ? previous.cachedTotalSize : 0;
// boolean needECI = mode == Mode.BYTE &&
// (previous == null && this.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
// (previous != null && this.charsetEncoderIndex != previous.charsetEncoderIndex);
// if (previous == null || mode != previous.mode || needECI) {
// size += 4 + mode.getCharacterCountBits(version);
// }
// switch (mode) {
// case KANJI:
// size += 13;
// break;
// case ALPHANUMERIC:
// size += characterLength == 1 ? 6 : 11;
// break;
// case NUMERIC:
// size += characterLength == 1 ? 4 : characterLength == 2 ? 7 : 10;
// break;
// case BYTE:
// size += 8 * encoders.encode(stringToEncode.substring(fromPosition, fromPosition + characterLength),
// charsetEncoderIndex).length;
// if (needECI) {
// size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
// }
// break;
// }
// cachedTotalSize = size;
})
}
}
@@ -754,32 +723,29 @@ impl RXingResultList {
ecLevel: &ErrorCorrectionLevel,
encoders: ECIEncoderSet,
stringToEncode: Vec<String>,
) -> Self {
) -> Option<Self> {
let mut length = 0;
let mut current = Some(solution);
let mut containsECI = false;
let mut list = Vec::new();
while current.is_some() {
length += current.as_ref().unwrap().characterLength;
let previous = current.as_ref().unwrap().previous.clone();
while let Some(loop_current) = &current {
length += loop_current.characterLength;
let previous = current.as_ref()?.previous.clone();
let needECI = current.as_ref().unwrap().mode == Mode::BYTE &&
(previous.is_none() && current.as_ref().unwrap().charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
(previous.is_some() && current.as_ref().unwrap().charsetEncoderIndex != previous.as_ref().unwrap().charsetEncoderIndex);
let needECI = loop_current.mode == Mode::BYTE &&
(previous.is_none() && loop_current.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
(previous.is_some() && loop_current.charsetEncoderIndex != previous.as_ref()?.charsetEncoderIndex);
if needECI {
containsECI = true;
}
if previous.is_none()
|| previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode
|| needECI
{
if previous.is_none() || previous.as_ref()?.mode != loop_current.mode || needECI {
list.push(RXingResultNode::new(
current.as_ref().unwrap().mode,
current.as_ref().unwrap().fromPosition,
current.as_ref().unwrap().charsetEncoderIndex,
loop_current.mode,
loop_current.fromPosition,
loop_current.charsetEncoderIndex,
length,
encoders.clone(),
stringToEncode.clone(),
@@ -791,8 +757,8 @@ impl RXingResultList {
if needECI {
list.push(RXingResultNode::new(
Mode::ECI,
current.as_ref().unwrap().fromPosition,
current.as_ref().unwrap().charsetEncoderIndex,
loop_current.fromPosition,
loop_current.charsetEncoderIndex,
0,
encoders.clone(),
stringToEncode.clone(),
@@ -806,7 +772,6 @@ impl RXingResultList {
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
if isGS1 {
if let Some(first) = list.get(0) {
// if first != null && first.mode != Mode.ECI && containsECI {
if first.mode != Mode::ECI && containsECI {
// prepend a default character set ECI
list.push(RXingResultNode::new(
@@ -820,37 +785,30 @@ impl RXingResultList {
));
}
}
let first = list.get(0);
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
if first.is_some() && first.as_ref().unwrap().mode != Mode::ECI {
//&& containsECI {
list.insert(
if first.as_ref().unwrap().mode != Mode::ECI {
//first
list.len()
} else {
//second
list.len() - 1
},
RXingResultNode::new(
Mode::FNC1_FIRST_POSITION,
0,
0,
0,
encoders,
stringToEncode,
version,
),
);
// list.push(RXingResultNode::new(
// Mode::FNC1_FIRST_POSITION,
// 0,
// 0,
// 0,
// encoders.clone(),
// stringToEncode.clone(),
// version,
// ));
if let Some(first) = list.get(0) {
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
if first.mode != Mode::ECI {
//&& containsECI {
list.insert(
if first.mode != Mode::ECI {
//first
list.len()
} else {
//second
list.len() - 1
},
RXingResultNode::new(
Mode::FNC1_FIRST_POSITION,
0,
0,
0,
encoders,
stringToEncode,
version,
),
);
}
}
}
@@ -861,29 +819,13 @@ impl RXingResultList {
VersionSize::MEDIUM => (10, 26),
_ => (27, 40),
};
// let lowerLimit;
// let upperLimit;
// switch (getVersionSize(version)) {
// case SMALL:
// lowerLimit = 1;
// upperLimit = 9;
// break;
// case MEDIUM:
// lowerLimit = 10;
// upperLimit = 26;
// break;
// case LARGE:
// default:
// lowerLimit = 27;
// upperLimit = 40;
// break;
// }
let size = Self::internal_static_get_size(version, &list);
// increase version if needed
while versionNumber < upperLimit
&& !qrcode_encoder::willFit(
size,
Version::getVersionForNumber(versionNumber).unwrap(),
Version::getVersionForNumber(versionNumber).ok()?,
ecLevel,
)
{
@@ -893,15 +835,15 @@ impl RXingResultList {
while versionNumber > lowerLimit
&& qrcode_encoder::willFit(
size,
Version::getVersionForNumber(versionNumber - 1).unwrap(),
Version::getVersionForNumber(versionNumber - 1).ok()?,
ecLevel,
)
{
versionNumber -= 1;
}
let version = Version::getVersionForNumber(versionNumber).unwrap();
let version = Version::getVersionForNumber(versionNumber).ok()?;
list.reverse();
Self { list, version }
Some(Self { list, version })
}
/**
@@ -912,18 +854,15 @@ impl RXingResultList {
}
fn getSizeLocal(&self, version: VersionRef) -> u32 {
let mut result = 0;
for resultNode in &self.list {
result += resultNode.getSize(version);
}
let result = self
.list
.iter()
.fold(0, |acc, node| acc + node.getSize(version));
result
}
fn internal_static_get_size(version: VersionRef, list: &Vec<RXingResultNode>) -> u32 {
let mut result = 0;
for resultNode in list {
result += resultNode.getSize(version);
}
let result = list.iter().fold(0, |acc, node| acc + node.getSize(version));
result
}
@@ -1050,9 +989,6 @@ impl RXingResultNode {
if self.mode == Mode::BYTE {
self.encoders
.encode_string(
// &self.stringToEncode[self.fromPosition as usize
// ..(self.fromPosition + self.characterLength as usize)],
// self.stringToEncode.get(self.fromPosition).unwrap(),
&(self
.stringToEncode
.iter()
@@ -1062,6 +998,7 @@ impl RXingResultNode {
.collect::<String>()),
self.charsetEncoderIndex,
)
.unwrap_or_default()
.len() as u32
} else {
self.characterLength
@@ -1085,18 +1022,18 @@ impl RXingResultNode {
} else if self.characterLength > 0 {
// append data
qrcode_encoder::appendBytes(
// &self.stringToEncode[self.fromPosition as usize
// ..(self.fromPosition + self.characterLength as usize)],
&(self
.stringToEncode
.iter()
.skip(self.fromPosition)
.take(self.characterLength as usize)
.map(|s| s.as_str())
.collect::<String>()), //self.stringToEncode.get(self.fromPosition).unwrap(),
.collect::<String>()),
self.mode,
bits,
self.encoders.getCharset(self.charsetEncoderIndex),
self.encoders
.getCharset(self.charsetEncoderIndex)
.ok_or(Exceptions::WriterException(None))?,
)?;
}
Ok(())
@@ -1104,12 +1041,11 @@ impl RXingResultNode {
fn makePrintable(s: &str) -> String {
let mut result = String::new();
for i in 0..s.chars().count() {
// for (int i = 0; i < s.length(); i++) {
if (s.chars().nth(i).unwrap() as u32) < 32 || (s.chars().nth(i).unwrap() as u32) > 126 {
for ch in s.chars() {
if (ch as u32) < 32 || (ch as u32) > 126 {
result.push('.');
} else {
result.push(s.chars().nth(i).unwrap());
result.push(ch);
}
}
result
@@ -1122,7 +1058,12 @@ impl fmt::Display for RXingResultNode {
result.push_str(&format!("{:?}", self.mode));
result.push('(');
if self.mode == Mode::ECI {
result.push_str(self.encoders.getCharset(self.charsetEncoderIndex).name());
result.push_str(
self.encoders
.getCharset(self.charsetEncoderIndex)
.ok_or(fmt::Error)?
.name(),
);
} else {
let sub_string: String = self
.stringToEncode

View File

@@ -102,21 +102,21 @@ impl fmt::Display for QRCode {
result.push_str("<<\n");
result.push_str(" mode: ");
if self.mode.is_some() {
result.push_str(&format!("{:?}", self.mode.as_ref().unwrap()));
result.push_str(&format!("{:?}", self.mode.as_ref().ok_or(fmt::Error)?));
} else {
result.push_str("null");
}
// result.push_str(&format!("{:?}", self.mode));
result.push_str("\n ecLevel: ");
if self.ecLevel.is_some() {
result.push_str(&format!("{:?}", self.ecLevel.as_ref().unwrap()));
result.push_str(&format!("{:?}", self.ecLevel.as_ref().ok_or(fmt::Error)?));
} else {
result.push_str("null");
}
// result.push_str(&format!("{:?}", self.ecLevel));
result.push_str("\n version: ");
if self.version.is_some() {
result.push_str(&format!("{}", self.version.as_ref().unwrap()));
result.push_str(&format!("{}", self.version.as_ref().ok_or(fmt::Error)?));
} else {
result.push_str("null");
}
@@ -127,7 +127,7 @@ impl fmt::Display for QRCode {
} else {
result.push_str("\n matrix:\n");
if self.matrix.is_some() {
result.push_str(&format!("{}", self.matrix.as_ref().unwrap()));
result.push_str(&format!("{}", self.matrix.as_ref().ok_or(fmt::Error)?));
} else {
result.push_str("null");
}

View File

@@ -79,16 +79,15 @@ pub fn encode_with_hints(
let mut header_and_data_bits;
let mode;
let has_gs1_format_hint = hints.contains_key(&EncodeHintType::GS1_FORMAT)
&& if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
*v
} else {
false
};
let has_compaction_hint = hints.contains_key(&EncodeHintType::QR_COMPACT)
&& if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() {
if let Ok(vb) = v.parse::<bool>() {
vb
let has_gs1_format_hint = matches!(
hints.get(&EncodeHintType::GS1_FORMAT),
Some(EncodeHintValue::Gs1Format(true))
);
let has_compaction_hint =
if let Some(EncodeHintValue::QrCompact(vb)) = hints.get(&EncodeHintType::QR_COMPACT) {
if let Ok(v) = vb.parse::<bool>() {
v
} else {
false
}
@@ -100,11 +99,12 @@ pub fn encode_with_hints(
let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING;
let mut has_encoding_hint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
if has_encoding_hint {
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
{
encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap())
if let Some(EncodeHintValue::CharacterSet(v)) = hints.get(&EncodeHintType::CHARACTER_SET) {
encoding = Some(
encoding::label::encoding_from_whatwg_label(v)
.ok_or(Exceptions::WriterException(None))?,
)
}
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
}
if has_compaction_hint {
@@ -146,9 +146,8 @@ pub fn encode_with_hints(
// Append ECI segment if applicable
if mode == Mode::BYTE && has_encoding_hint {
let eci = CharacterSetECI::getCharacterSetECI(encoding);
if eci.is_some() {
appendECI(&eci.unwrap(), &mut header_bits)?;
if let Some(eci) = CharacterSetECI::getCharacterSetECI(encoding) {
appendECI(&eci, &mut header_bits)?;
}
}
@@ -167,8 +166,8 @@ pub fn encode_with_hints(
appendBytes(content, mode, &mut data_bits, encoding)?;
if hints.contains_key(&EncodeHintType::QR_VERSION) {
let versionNumber = if let EncodeHintValue::QrVersion(v) =
hints.get(&EncodeHintType::QR_VERSION).unwrap()
let versionNumber = if let Some(EncodeHintValue::QrVersion(v)) =
hints.get(&EncodeHintType::QR_VERSION)
{
if let Ok(vb) = v.parse::<u32>() {
vb
@@ -178,7 +177,7 @@ pub fn encode_with_hints(
} else {
0
};
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
version = Version::getVersionForNumber(versionNumber)?;
let bitsNeeded = calculateBitsNeeded(mode, &header_bits, &data_bits, version);
if !willFit(bitsNeeded, version, &ec_level) {
@@ -229,19 +228,13 @@ pub fn encode_with_hints(
// Enable manual selection of the pattern to be used via hint
let mut mask_pattern = -1;
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
let hint_mask_pattern = if let EncodeHintValue::QrMaskPattern(v) =
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
{
if let Ok(vb) = v.parse::<i32>() {
vb
} else {
-1
}
if let Some(EncodeHintValue::QrMaskPattern(v)) = hints.get(&EncodeHintType::QR_MASK_PATTERN) {
let hint_mask_pattern = if let Ok(vb) = v.parse::<i32>() {
vb
} else {
-1
};
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
mask_pattern = if QRCode::isValidMaskPattern(hint_mask_pattern) {
hint_mask_pattern
} else {
@@ -322,15 +315,12 @@ pub fn chooseMode(content: &str) -> Mode {
*/
fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
// if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) {
// Choose Kanji mode if all input are double-byte characters
return Mode::KANJI;
}
let mut has_numeric = false;
let mut has_alphanumeric = false;
for i in 0..content.len() {
// for (int i = 0; i < content.length(); ++i) {
let c = content.chars().nth(i).unwrap();
for c in content.chars() {
if ('0'..='9').contains(&c) {
has_numeric = true;
} else if getAlphanumericCode(c as u32) != -1 {
@@ -354,13 +344,13 @@ pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
} else {
return false;
};
let length = bytes.len();
if length % 2 != 0 {
return false;
}
let mut i = 0;
while i < length {
// for (int i = 0; i < length; i += 2) {
let byte1 = bytes[i];
if !(0x81..=0x9F).contains(&byte1) && !(0xE0..=0xEB).contains(&byte1) {
return false;
@@ -380,7 +370,6 @@ fn chooseMaskPattern(
let mut best_mask_pattern = -1;
// We try all mask patterns to choose the best one.
for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
let mut matrix = matrix.clone();
matrix_util::buildMatrix(bits, ec_level, version, maskPattern, &mut matrix)?;
let penalty = calculateMaskPenalty(&matrix);
@@ -397,13 +386,14 @@ fn chooseVersion(
ecLevel: &ErrorCorrectionLevel,
) -> Result<VersionRef, Exceptions> {
for versionNum in 1..=40 {
// for (int versionNum = 1; versionNum <= 40; versionNum++) {
let version = Version::getVersionForNumber(versionNum)?;
if willFit(numInputBits, version, ecLevel) {
return Ok(version);
}
}
Err(Exceptions::WriterException(Some("Data too big".to_owned())))
Err(Exceptions::WriterException(Some(format!(
"data too big {numInputBits}/{ecLevel:?}"
))))
}
/**
@@ -432,16 +422,12 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
return Err(Exceptions::WriterException(Some(format!(
"data bits cannot fit in the QR Code{capacity} > "
))));
// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
// capacity);
}
// Append Mode.TERMINATE if there is enough space (value is 0000)
for _i in 0..4 {
if bits.getSize() >= capacity as usize {
break;
}
// }
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
bits.appendBit(false);
}
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
@@ -449,7 +435,6 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
let num_bits_in_last_byte = bits.getSize() & 0x07;
if num_bits_in_last_byte > 0 {
for _i in num_bits_in_last_byte..8 {
// for (int i = numBitsInLastByte; i < 8; i++) {
bits.appendBit(false);
}
}
@@ -459,14 +444,12 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
if i >= num_padding_bytes {
break;
}
// for (int i = 0; i < numPaddingBytes; ++i) {
bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8)?;
}
if bits.getSize() != capacity as usize {
return Err(Exceptions::WriterException(Some(
"Bits size does not equal capacity".to_owned(),
)));
// throw new WriterException("Bits size does not equal capacity");
}
Ok(())
}
@@ -488,7 +471,6 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
return Err(Exceptions::WriterException(Some(
"Block ID too large".to_owned(),
)));
// throw new WriterException("Block ID too large");
}
// numRsBlocksInGroup2 = 196 % 5 = 1
let num_rs_blocks_in_group2 = num_total_bytes % num_rsblocks;
@@ -512,15 +494,12 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
return Err(Exceptions::WriterException(Some(
"EC bytes mismatch".to_owned(),
)));
// throw new WriterException("EC bytes mismatch");
}
// 5 = 4 + 1.
if num_rsblocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
return Err(Exceptions::WriterException(Some(
"RS blocks mismatch".to_owned(),
)));
// throw new WriterException("RS blocks mismatch");
}
// 196 = (13 + 26) * 4 + (14 + 26) * 1
if num_total_bytes
@@ -530,8 +509,6 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
return Err(Exceptions::WriterException(Some(
"total bytes mismatch".to_owned(),
)));
// throw new WriterException("Total bytes mismatch");
}
Ok(if block_id < num_rs_blocks_in_group1 {
@@ -568,9 +545,6 @@ pub fn interleaveWithECBytes(
let mut blocks = Vec::new();
for i in 0..num_rsblocks {
// for (int i = 0; i < numRSBlocks; ++i) {
// let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
// let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
num_total_bytes,
num_data_bytes,
@@ -583,7 +557,7 @@ pub fn interleaveWithECBytes(
let size = numDataBytesInBlock;
let mut dataBytes = vec![0u8; size as usize];
bits.toBytes(8 * data_bytes_offset, &mut dataBytes, 0, size as usize);
let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize);
let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize)?;
blocks.push(BlockPair::new(dataBytes, ec_bytes.clone()));
max_num_data_bytes = max_num_data_bytes.max(size);
@@ -600,9 +574,7 @@ pub fn interleaveWithECBytes(
// First, place data blocks.
for i in 0..max_num_data_bytes as usize {
// for (int i = 0; i < maxNumDataBytes; ++i) {
for block in &blocks {
// for (BlockPair block : blocks) {
let data_bytes = block.getDataBytes();
if i < data_bytes.len() {
result.appendBits(data_bytes[i] as u32, 8)?;
@@ -611,9 +583,7 @@ pub fn interleaveWithECBytes(
}
// Then, place error correction blocks.
for i in 0..max_num_ec_bytes {
// for (int i = 0; i < maxNumEcBytes; ++i) {
for block in &blocks {
// for (BlockPair block : blocks) {
let ec_bytes = block.getErrorCorrectionBytes();
if i < ec_bytes.len() {
result.appendBits(ec_bytes[i] as u32, 8)?;
@@ -627,41 +597,38 @@ pub fn interleaveWithECBytes(
num_total_bytes,
result.getSizeInBytes()
))));
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
// result.getSizeInBytes() + " differ.");
}
Ok(result)
}
pub fn generateECBytes(dataBytes: &[u8], num_ec_bytes_in_block: usize) -> Vec<u8> {
pub fn generateECBytes(
dataBytes: &[u8],
num_ec_bytes_in_block: usize,
) -> Result<Vec<u8>, Exceptions> {
let num_data_bytes = dataBytes.len();
let mut to_encode = vec![0; num_data_bytes + num_ec_bytes_in_block];
for i in 0..num_data_bytes {
// for (int i = 0; i < numDataBytes; i++) {
to_encode[i] = dataBytes[i] as i32;
}
ReedSolomonEncoder::new(get_predefined_genericgf(
PredefinedGenericGF::QrCodeField256,
))
.encode(&mut to_encode, num_ec_bytes_in_block)
.expect("rs encode must complete");
))?
.encode(&mut to_encode, num_ec_bytes_in_block)?;
let mut ecBytes = vec![0u8; num_ec_bytes_in_block];
for i in 0..num_ec_bytes_in_block {
// for (int i = 0; i < numEcBytesInBlock; i++) {
ecBytes[i] = to_encode[num_data_bytes + i] as u8;
}
ecBytes
Ok(ecBytes)
}
/**
* Append mode info. On success, store the result in "bits".
*/
pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(), Exceptions> {
bits.appendBits(mode.getBits() as u32, 4)?;
Ok(())
bits.appendBits(mode.getBits() as u32, 4)
}
/**
@@ -681,8 +648,7 @@ pub fn appendLengthInfo(
((1 << numBits) - 1)
))));
}
bits.appendBits(num_letters, numBits as usize)?;
Ok(())
bits.appendBits(num_letters, numBits as usize)
}
/**
@@ -703,38 +669,38 @@ pub fn appendBytes(
"Invalid mode: {mode:?}"
)))),
}
// switch (mode) {
// case NUMERIC:
// appendNumericBytes(content, bits);
// break;
// case ALPHANUMERIC:
// appendAlphanumericBytes(content, bits);
// break;
// case BYTE:
// append8BitBytes(content, bits, encoding);
// break;
// case KANJI:
// appendKanjiBytes(content, bits);
// break;
// default:
// throw new WriterException("Invalid mode: " + mode);
// }
}
pub fn appendNumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
let length = content.len();
let mut i = 0;
while i < length {
let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
let num1 = content
.chars()
.nth(i)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
- b'0';
if i + 2 < length {
// Encode three numeric letters in ten bits.
let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
let num3 = content.chars().nth(i + 2).unwrap() as u8 - b'0';
let num2 = content
.chars()
.nth(i + 1)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
- b'0';
let num3 = content
.chars()
.nth(i + 2)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
- b'0';
bits.appendBits(num1 as u32 * 100 + num2 as u32 * 10 + num3 as u32, 10)?;
i += 3;
} else if i + 1 < length {
// Encode two numeric letters in seven bits.
let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
let num2 = content
.chars()
.nth(i + 1)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u8
- b'0';
bits.appendBits(num1 as u32 * 10 + num2 as u32, 7)?;
i += 2;
} else {
@@ -750,12 +716,22 @@ pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<(),
let length = content.len();
let mut i = 0;
while i < length {
let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
let code1 = getAlphanumericCode(
content
.chars()
.nth(i)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u32,
);
if code1 == -1 {
return Err(Exceptions::WriterException(None));
}
if i + 1 < length {
let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32);
let code2 = getAlphanumericCode(
content
.chars()
.nth(i + 1)
.ok_or(Exceptions::IndexOutOfBoundsException(None))? as u32,
);
if code2 == -1 {
return Err(Exceptions::WriterException(None));
}
@@ -778,22 +754,19 @@ pub fn append8BitBytes(
) -> Result<(), Exceptions> {
let bytes = encoding
.encode(content, encoding::EncoderTrap::Strict)
.expect("should encode");
// let bytes = content.getBytes(encoding);
.map_err(|e| Exceptions::WriterException(Some(format!("error {e}"))))?;
for b in bytes {
// for (byte b : bytes) {
bits.appendBits(b as u32, 8)?;
}
Ok(())
}
pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
let sjis = &SHIFT_JIS_CHARSET; //encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
let sjis = &SHIFT_JIS_CHARSET;
let bytes = sjis
.encode(content, encoding::EncoderTrap::Strict)
.expect("should encode fine");
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
.map_err(|e| Exceptions::WriterException(Some(format!("error {e}"))))?;
if bytes.len() % 2 != 0 {
return Err(Exceptions::WriterException(Some(
"Kanji byte size not even".to_owned(),
@@ -802,7 +775,6 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except
let max_i = bytes.len() - 1; // bytes.length must be even
let mut i = 0;
while i < max_i {
// for (int i = 0; i < maxI; i += 2) {
let byte1 = bytes[i]; // & 0xFF;
let byte2 = bytes[i + 1]; // & 0xFF;
let code: u16 = ((byte1 as u16) << 8u16) | byte2 as u16;
@@ -828,6 +800,5 @@ pub fn appendKanjiBytes(content: &str, bits: &mut BitArray) -> Result<(), Except
fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) -> Result<(), Exceptions> {
bits.appendBits(Mode::ECI.getBits() as u32, 4)?;
// This is correct for values up to 127, which is all we need now.
bits.appendBits(eci.getValueSelf(), 8)?;
Ok(())
bits.appendBits(eci.getValueSelf(), 8)
}