encoder ported, no compile

This commit is contained in:
Henry Schimke
2022-10-03 14:34:17 -05:00
parent bbf0b920bf
commit eaff1b6b64
8 changed files with 484 additions and 370 deletions

View File

@@ -14,6 +14,9 @@ use crate::Exceptions;
use crate::LuminanceSource; use crate::LuminanceSource;
use crate::RXingResultPoint; use crate::RXingResultPoint;
use encoding::Encoding; use encoding::Encoding;
use encoding::EncodingRef;
use lazy_static::lazy_static;
#[cfg(test)] #[cfg(test)]
mod StringUtilsTestCase; mod StringUtilsTestCase;
@@ -80,6 +83,10 @@ pub struct StringUtils {
const ASSUME_SHIFT_JIS: bool = false; const ASSUME_SHIFT_JIS: bool = false;
static SHIFT_JIS: &'static str = "SJIS"; static SHIFT_JIS: &'static str = "SJIS";
static GB2312: &'static str = "GB2312"; static GB2312: &'static str = "GB2312";
lazy_static! {
pub static ref SHIFT_JIS_CHARSET: EncodingRef = encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
}
// private static final boolean ASSUME_SHIFT_JIS = // private static final boolean ASSUME_SHIFT_JIS =
// SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING) || // SHIFT_JIS_CHARSET.equals(PLATFORM_DEFAULT_ENCODING) ||
@@ -2466,6 +2473,10 @@ impl CharacterSetECI {
// this.otherEncodingNames = otherEncodingNames; // this.otherEncodingNames = otherEncodingNames;
// } // }
pub fn getValueSelf(&self) -> u32{
Self::getValue(self)
}
pub fn getValue(cs_eci: &CharacterSetECI) -> u32 { pub fn getValue(cs_eci: &CharacterSetECI) -> u32 {
match cs_eci { match cs_eci {
CharacterSetECI::Cp437 => 0, CharacterSetECI::Cp437 => 0,
@@ -2498,7 +2509,7 @@ impl CharacterSetECI {
} }
} }
pub fn getCharset(cs_eci: &CharacterSetECI) -> &'static dyn Encoding { pub fn getCharset(cs_eci: &CharacterSetECI) -> EncodingRef {
let name = match cs_eci { let name = match cs_eci {
CharacterSetECI::Cp437 => "CP437", CharacterSetECI::Cp437 => "CP437",
CharacterSetECI::ISO8859_1 => "ISO-8859-1", CharacterSetECI::ISO8859_1 => "ISO-8859-1",
@@ -2857,7 +2868,7 @@ impl fmt::Display for ECIStringBuilder {
* @author Alex Geller * @author Alex Geller
*/ */
pub struct ECIEncoderSet { pub struct ECIEncoderSet {
encoders: Vec<&'static dyn encoding::Encoding>, encoders: Vec<EncodingRef>,
priorityEncoderIndex: usize, priorityEncoderIndex: usize,
} }
@@ -2872,11 +2883,11 @@ impl ECIEncoderSet {
*/ */
pub fn new( pub fn new(
stringToEncode: &str, stringToEncode: &str,
priorityCharset: &'static dyn encoding::Encoding, priorityCharset: EncodingRef,
fnc1: i16, fnc1: i16,
) -> Self { ) -> Self {
// List of encoders that potentially encode characters not in ISO-8859-1 in one byte. // List of encoders that potentially encode characters not in ISO-8859-1 in one byte.
let mut ENCODERS = Vec::new(); let mut ENCODERS :Vec<EncodingRef> = Vec::new();
let names = [ let names = [
"IBM437", "IBM437",
@@ -2910,10 +2921,10 @@ impl ECIEncoderSet {
} }
} }
let mut encoders: Vec<&'static dyn Encoding>; let mut encoders: Vec<EncodingRef>;
let mut priorityEncoderIndexValue = 0; let mut priorityEncoderIndexValue = 0;
let mut neededEncoders: Vec<&'static dyn encoding::Encoding> = Vec::new(); let mut neededEncoders: Vec<EncodingRef> = Vec::new();
//we always need the ISO-8859-1 encoder. It is the default encoding //we always need the ISO-8859-1 encoder. It is the default encoding
neededEncoders.push(encoding::all::ISO_8859_1); neededEncoders.push(encoding::all::ISO_8859_1);
@@ -3010,7 +3021,7 @@ impl ECIEncoderSet {
return self.encoders[index].name(); return self.encoders[index].name();
} }
pub fn getCharset(&self, index: usize) -> &'static dyn Encoding { pub fn getCharset(&self, index: usize) -> EncodingRef {
assert!(index < self.len()); assert!(index < self.len());
return self.encoders[index]; return self.encoders[index];
} }
@@ -3244,7 +3255,7 @@ impl MinimalECIInput {
* @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not GS1 * @param fnc1 denotes the character in the input that represents the FNC1 character or -1 if this is not GS1
* input. * input.
*/ */
pub fn new(stringToEncode: &str, priorityCharset: &'static dyn Encoding, fnc1: i16) -> Self { pub fn new(stringToEncode: &str, priorityCharset: EncodingRef, fnc1: i16) -> Self {
let encoderSet = ECIEncoderSet::new(stringToEncode, priorityCharset, fnc1); let encoderSet = ECIEncoderSet::new(stringToEncode, priorityCharset, fnc1);
let bytes = if encoderSet.len() == 1 { let bytes = if encoderSet.len() == 1 {
//optimization for the case when all can be encoded without ECI in ISO-8859-1 //optimization for the case when all can be encoded without ECI in ISO-8859-1

View File

@@ -702,7 +702,7 @@ pub trait Writer {
format: &BarcodeFormat, format: &BarcodeFormat,
width: i32, width: i32,
height: i32, height: i32,
hints: &HashMap<EncodeHintType, EncodeHintValue>, hints: &EncodingHintDictionary,
) -> Result<BitMatrix, Exceptions>; ) -> Result<BitMatrix, Exceptions>;
} }
@@ -765,7 +765,7 @@ pub trait Reader {
fn decode_with_hints( fn decode_with_hints(
&self, &self,
image: &BinaryBitmap, image: &BinaryBitmap,
hints: &HashMap<DecodeHintType, DecodeHintValue>, hints: &DecodingHintDictionary,
) -> Result<RXingResult, Exceptions>; ) -> Result<RXingResult, Exceptions>;
/** /**

View File

@@ -1,122 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.zxing.qrcode.decoder;
/**
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
* is represented by an instance of this class.</p>
*
* @author Sean Owen
*/
final class DataBlock {
private final int numDataCodewords;
private final byte[] codewords;
private DataBlock(int numDataCodewords, byte[] codewords) {
this.numDataCodewords = numDataCodewords;
this.codewords = codewords;
}
/**
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
* method will separate the data into original blocks.</p>
*
* @param rawCodewords bytes as read directly from the QR Code
* @param version version of the QR Code
* @param ecLevel error-correction level of the QR Code
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
* QR Code
*/
static DataBlock[] getDataBlocks(byte[] rawCodewords,
Version version,
ErrorCorrectionLevel ecLevel) {
if (rawCodewords.length != version.getTotalCodewords()) {
throw new IllegalArgumentException();
}
// Figure out the number and size of data blocks used by this version and
// error correction level
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
// First count the total number of data blocks
int totalBlocks = 0;
Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();
for (Version.ECB ecBlock : ecBlockArray) {
totalBlocks += ecBlock.getCount();
}
// Now establish DataBlocks of the appropriate size and number of data codewords
DataBlock[] result = new DataBlock[totalBlocks];
int numRXingResultBlocks = 0;
for (Version.ECB ecBlock : ecBlockArray) {
for (int i = 0; i < ecBlock.getCount(); i++) {
int numDataCodewords = ecBlock.getDataCodewords();
int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
result[numRXingResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 more byte. Figure out where these start.
int shorterBlocksTotalCodewords = result[0].codewords.length;
int longerBlocksStartAt = result.length - 1;
while (longerBlocksStartAt >= 0) {
int numCodewords = result[longerBlocksStartAt].codewords.length;
if (numCodewords == shorterBlocksTotalCodewords) {
break;
}
longerBlocksStartAt--;
}
longerBlocksStartAt++;
int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();
// The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have
int rawCodewordsOffset = 0;
for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
for (int j = 0; j < numRXingResultBlocks; j++) {
result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
}
}
// Fill out the last data block in the longer ones
for (int j = longerBlocksStartAt; j < numRXingResultBlocks; j++) {
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
}
// Now add in error correction blocks
int max = result[0].codewords.length;
for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
for (int j = 0; j < numRXingResultBlocks; j++) {
int iOffset = j < longerBlocksStartAt ? i : i + 1;
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}
return result;
}
int getNumDataCodewords() {
return numDataCodewords;
}
byte[] getCodewords() {
return codewords;
}
}

141
src/qrcode/decoder/data_block.rs Executable file
View File

@@ -0,0 +1,141 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::Exceptions;
use super::{VersionRef, ErrorCorrectionLevel};
/**
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
* is represented by an instance of this class.</p>
*
* @author Sean Owen
*/
pub struct DataBlock {
numDataCodewords:u32,
codewords:Vec<u8>,
}
impl DataBlock {
fn new( numDataCodewords:u32, codewords:Vec<u8>) -> Self{
Self{
numDataCodewords,
codewords,
}
}
/**
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
* method will separate the data into original blocks.</p>
*
* @param rawCodewords bytes as read directly from the QR Code
* @param version version of the QR Code
* @param ecLevel error-correction level of the QR Code
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
* QR Code
*/
pub fn getDataBlocks( rawCodewords:&[u8],
version:VersionRef,
ecLevel:ErrorCorrectionLevel) -> Result<Vec<Self>,Exceptions> {
if rawCodewords.len() as u32 != version.getTotalCodewords() {
return Err(Exceptions::IllegalArgumentException("".to_owned()))
}
// Figure out the number and size of data blocks used by this version and
// error correction level
let ecBlocks = version.getECBlocksForLevel(ecLevel);
// First count the total number of data blocks
let totalBlocks = 0;
let ecBlockArray = ecBlocks.getECBlocks();
for ecBlock in ecBlockArray {
// for (Version.ECB ecBlock : ecBlockArray) {
totalBlocks += ecBlock.getCount();
}
// Now establish DataBlocks of the appropriate size and number of data codewords
let result = Vec::new();
let numRXingResultBlocks = 0;
for ecBlock in ecBlockArray {
// for (Version.ECB ecBlock : ecBlockArray) {
for i in 0..ecBlock.getCount() {
// for (int i = 0; i < ecBlock.getCount(); i++) {
let numDataCodewords = ecBlock.getDataCodewords();
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
result[numRXingResultBlocks] = DataBlock::new(numDataCodewords, vec![0u8;numBlockCodewords as usize]);
numRXingResultBlocks += 1;
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 more byte. Figure out where these start.
let shorterBlocksTotalCodewords = result[0].codewords.len();
let longerBlocksStartAt = result.len() - 1;
while (longerBlocksStartAt >= 0) {
let numCodewords = result[longerBlocksStartAt].codewords.len();
if (numCodewords == shorterBlocksTotalCodewords) {
break;
}
longerBlocksStartAt-=1;
}
longerBlocksStartAt+=1;
let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
// The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have
let rawCodewordsOffset = 0;
for i in 0..shorterBlocksNumDataCodewords {
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
for j in 0..numRXingResultBlocks {
// for (int j = 0; j < numRXingResultBlocks; j++) {
result[j].codewords[i] = rawCodewords[rawCodewordsOffset];
rawCodewordsOffset += 1;
}
}
// Fill out the last data block in the longer ones
for j in longerBlocksStartAt..numRXingResultBlocks{
// for (int j = longerBlocksStartAt; j < numRXingResultBlocks; j++) {
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset];
rawCodewordsOffset += 1;
}
// Now add in error correction blocks
let max = result[0].codewords.len();
for i in shorterBlocksNumDataCodewords..max {
// for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
for j in 0..numRXingResultBlocks {
// for (int j = 0; j < numRXingResultBlocks; j++) {
let iOffset = if j < longerBlocksStartAt {i} else {i + 1};
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset];
rawCodewordsOffset += 1;
}
}
Ok(result)
}
pub fn getNumDataCodewords(&self) -> u32{
self. numDataCodewords
}
pub fn getCodewords(&self) -> &[u8] {
&self.codewords
}
}

View File

@@ -2,6 +2,7 @@ mod version;
mod mode; mod mode;
mod error_correction_level; mod error_correction_level;
mod format_information; mod format_information;
mod data_block;
#[cfg(test)] #[cfg(test)]
mod ErrorCorrectionLevelTestCase; mod ErrorCorrectionLevelTestCase;
@@ -13,4 +14,5 @@ mod VersionTestCase;
pub use version::*; pub use version::*;
pub use mode::*; pub use mode::*;
pub use error_correction_level::*; pub use error_correction_level::*;
pub use format_information::*; pub use format_information::*;
pub use data_block::*;

View File

@@ -37,15 +37,21 @@ use std::collections::HashMap;
use encoding::EncodingRef; use encoding::EncodingRef;
use crate::{EncodingHintDictionary, common::{BitArray, CharacterSetECI, reedsolomon::{ReedSolomonEncoder, get_predefined_genericgf, PredefinedGenericGF}, StringUtils}, Exceptions, qrcode::decoder::{ErrorCorrectionLevel, Mode, VersionRef, Version}}; use lazy_static::lazy_static;
use super::{mask_util, ByteMatrix, QRCode, matrix_util}; use crate::{EncodingHintDictionary, common::{BitArray, CharacterSetECI, reedsolomon::{ReedSolomonEncoder, get_predefined_genericgf, PredefinedGenericGF}, StringUtils}, Exceptions, qrcode::decoder::{ErrorCorrectionLevel, Mode, VersionRef, Version}, EncodeHintType, EncodeHintValue};
use super::{mask_util, ByteMatrix, QRCode, matrix_util, MinimalEncoder, BlockPair};
/** /**
* @author satorux@google.com (Satoru Takabayashi) - creator * @author satorux@google.com (Satoru Takabayashi) - creator
* @author dswitkin@google.com (Daniel Switkin) - ported from C++ * @author dswitkin@google.com (Daniel Switkin) - ported from C++
*/ */
lazy_static !{
static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
}
// The original table is defined in the table 5 of JISX0510:2004 (p.19). // The original table is defined in the table 5 of JISX0510:2004 (p.19).
const ALPHANUMERIC_TABLE : [i8;96]= [ const ALPHANUMERIC_TABLE : [i8;96]= [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f
@@ -75,131 +81,168 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
* @throws WriterException if encoding can't succeed, because of for example invalid content * @throws WriterException if encoding can't succeed, because of for example invalid content
* or configuration * or configuration
*/ */
pub fn encode( content:&str, ecLevel:&ErrorCorrectionLevel) -> Result<QRCode, Exceptions> { pub fn encode( content:&str, ecLevel:ErrorCorrectionLevel) -> Result<QRCode, Exceptions> {
return encode_with_hints(content, ecLevel, HashMap::new()); return encode_with_hints(content, ecLevel, HashMap::new());
} }
pub fn encode_with_hints( content:&str, pub fn encode_with_hints( content:&str,
ecLevel:&ErrorCorrectionLevel, ecLevel:ErrorCorrectionLevel,
hints:EncodingHintDictionary) -> Result<QRCode, Exceptions> { hints:EncodingHintDictionary) -> Result<QRCode, Exceptions> {
let version; let version;
let headerAndDataBits; let headerAndDataBits;
let mode; let mode;
let hasGS1FormatHint = hints != null && hints.containsKey(EncodeHintType::GS1_FORMAT) && let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT) &&
Boolean.parseBoolean(hints.get(EncodeHintType::GS1_FORMAT).toString()); if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
let hasCompactionHint = hints != null && hints.containsKey(EncodeHintType::QR_COMPACT) && if let Ok(vb) = v.parse::<bool>() {
Boolean.parseBoolean(hints.get(EncodeHintType::QR_COMPACT).toString()); vb
}else {
false
}
}else {
false
};
let hasCompactionHint = 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
}else {
false
}
}else {
false
};
// Determine what character encoding has been specified by the caller, if any // Determine what character encoding has been specified by the caller, if any
let encoding = DEFAULT_BYTE_MODE_ENCODING; let encoding = DEFAULT_BYTE_MODE_ENCODING;
let hasEncodingHint = hints != null && hints.containsKey(EncodeHintType::CHARACTER_SET); let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
if (hasEncodingHint) { if hasEncodingHint {
encoding = Charset.forName(hints.get(EncodeHintType.CHARACTER_SET).toString()); if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap() {
encoding = encoding::label::encoding_from_whatwg_label(v).unwrap()
}
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
} }
if (hasCompactionHint) { if hasCompactionHint {
mode = Mode.BYTE; mode = Mode::BYTE;
Charset priorityEncoding = encoding.equals(DEFAULT_BYTE_MODE_ENCODING) ? null : encoding; let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
MinimalEncoder.RXingResultList rn = MinimalEncoder.encode(content, null, priorityEncoding, hasGS1FormatHint, ecLevel); let rn = MinimalEncoder::encode_with_details(content, None, priorityEncoding, hasGS1FormatHint, ecLevel)?;
headerAndDataBits = new BitArray(); headerAndDataBits = BitArray::new();
rn.getBits(headerAndDataBits); rn.getBits(&headerAndDataBits);
version = rn.getVersion(); version = rn.getVersion();
} else { } else {
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use // Pick an encoding mode appropriate for the content. Note that this will not attempt to use
// multiple modes / segments even if that were more efficient. // multiple modes / segments even if that were more efficient.
mode = chooseMode(content, encoding); mode = chooseModeWithEncoding(content, encoding);
// This will store the header information, like mode and // This will store the header information, like mode and
// length, as well as "header" segments like an ECI segment. // length, as well as "header" segments like an ECI segment.
BitArray headerBits = new BitArray(); let headerBits = BitArray::new();
// Append ECI segment if applicable // Append ECI segment if applicable
if (mode == Mode.BYTE && hasEncodingHint) { if mode == Mode::BYTE && hasEncodingHint {
CharacterSetECI eci = CharacterSetECI.getCharacterSetECI(encoding); let eci = CharacterSetECI::getCharacterSetECI(encoding);
if (eci != null) { if eci.is_some() {
appendECI(eci, headerBits); appendECI(&eci.unwrap(), &headerBits);
} }
} }
// Append the FNC1 mode header for GS1 formatted data if applicable // Append the FNC1 mode header for GS1 formatted data if applicable
if (hasGS1FormatHint) { if hasGS1FormatHint {
// GS1 formatted codes are prefixed with a FNC1 in first position mode header // GS1 formatted codes are prefixed with a FNC1 in first position mode header
appendModeInfo(Mode.FNC1_FIRST_POSITION, headerBits); appendModeInfo(Mode::FNC1_FIRST_POSITION, &headerBits);
} }
// (With ECI in place,) Write the mode marker // (With ECI in place,) Write the mode marker
appendModeInfo(mode, headerBits); appendModeInfo(mode, &headerBits);
// Collect data within the main segment, separately, to count its size if needed. Don't add it to // Collect data within the main segment, separately, to count its size if needed. Don't add it to
// main payload yet. // main payload yet.
BitArray dataBits = new BitArray(); let dataBits = BitArray::new();
appendBytes(content, mode, dataBits, encoding); appendBytes(content, mode, &dataBits, encoding);
if (hints != null && hints.containsKey(EncodeHintType.QR_VERSION)) { if hints.contains_key(&EncodeHintType::QR_VERSION) {
int versionNumber = Integer.parseInt(hints.get(EncodeHintType.QR_VERSION).toString()); let versionNumber = if let EncodeHintValue::QrVersion(v) = hints.get(&EncodeHintType::QR_VERSION).unwrap() {
version = Version.getVersionForNumber(versionNumber); if let Ok(vb) = v.parse::<u32>() {
int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version); vb
if (!willFit(bitsNeeded, version, ecLevel)) { }else {
throw new WriterException("Data too big for requested version"); 0
}
}else {
0
};
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
version = Version::getVersionForNumber(versionNumber)?;
let bitsNeeded = calculateBitsNeeded(mode, &headerBits, &dataBits, version);
if !willFit(bitsNeeded, version, &ecLevel) {
return Err(Exceptions::WriterException("Data too big for requested version".to_owned()))
} }
} else { } else {
version = recommendVersion(ecLevel, mode, headerBits, dataBits); version = recommendVersion(&ecLevel, mode, &headerBits, &dataBits)?;
} }
headerAndDataBits = new BitArray(); headerAndDataBits = BitArray::new();
headerAndDataBits.appendBitArray(headerBits); headerAndDataBits.appendBitArray(headerBits);
// Find "length" of main segment and write it // Find "length" of main segment and write it
int numLetters = mode == Mode.BYTE ? dataBits.getSizeInBytes() : content.length(); let numLetters = if mode == Mode::BYTE {dataBits.getSizeInBytes() }else {content.len()};
appendLengthInfo(numLetters, version, mode, headerAndDataBits); appendLengthInfo(numLetters as u32, version, mode, &headerAndDataBits);
// Put data together into the overall payload // Put data together into the overall payload
headerAndDataBits.appendBitArray(dataBits); headerAndDataBits.appendBitArray(dataBits);
} }
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); let ecBlocks = version.getECBlocksForLevel(ecLevel);
int numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
// Terminate the bits properly. // Terminate the bits properly.
terminateBits(numDataBytes, headerAndDataBits); terminateBits(numDataBytes, &headerAndDataBits);
// Interleave data bits with error correction code. // Interleave data bits with error correction code.
BitArray finalBits = interleaveWithECBytes(headerAndDataBits, let finalBits = interleaveWithECBytes(&headerAndDataBits,
version.getTotalCodewords(), version.getTotalCodewords(),
numDataBytes, numDataBytes,
ecBlocks.getNumBlocks()); ecBlocks.getNumBlocks())?;
QRCode qrCode = new QRCode(); let qrCode = QRCode::new();
qrCode.setECLevel(ecLevel); qrCode.setECLevel(ecLevel);
qrCode.setMode(mode); qrCode.setMode(mode);
qrCode.setVersion(version); qrCode.setVersion(version);
// Choose the mask pattern and set to "qrCode". // Choose the mask pattern and set to "qrCode".
int dimension = version.getDimensionForVersion(); let dimension = version.getDimensionForVersion();
ByteMatrix matrix = new ByteMatrix(dimension, dimension); let matrix = ByteMatrix::new(dimension, dimension);
// Enable manual selection of the pattern to be used via hint // Enable manual selection of the pattern to be used via hint
int maskPattern = -1; let maskPattern = -1;
if (hints != null && hints.containsKey(EncodeHintType.QR_MASK_PATTERN)) { if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
int hintMaskPattern = Integer.parseInt(hints.get(EncodeHintType.QR_MASK_PATTERN).toString()); let hintMaskPattern =if let EncodeHintValue::QrMaskPattern(v) = hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap() {
maskPattern = QRCode.isValidMaskPattern(hintMaskPattern) ? hintMaskPattern : -1; if let Ok(vb) = v.parse::<i32>() {
vb
}else {
-1
}
}else {
-1
};
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
maskPattern = if QRCode::isValidMaskPattern(hintMaskPattern) {hintMaskPattern} else {-1};
} }
if (maskPattern == -1) { if maskPattern == -1 {
maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &matrix)? as i32;
} }
qrCode.setMaskPattern(maskPattern); qrCode.setMaskPattern(maskPattern);
// Build the matrix and set it to "qrCode". // Build the matrix and set it to "qrCode".
matrix_util::buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix);
qrCode.setMatrix(matrix); qrCode.setMatrix(matrix);
return qrCode; Ok( qrCode)
} }
/** /**
@@ -214,8 +257,8 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
// Hard part: need to know version to know how many bits length takes. But need to know how many // Hard part: need to know version to know how many bits length takes. But need to know how many
// bits it takes to know version. First we take a guess at version by assuming version will be // bits it takes to know version. First we take a guess at version by assuming version will be
// the minimum, 1: // the minimum, 1:
let provisionalBitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)); let provisionalBitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)?);
let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel); let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel)?;
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases. // Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
let bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion); let bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, provisionalVersion);
@@ -226,56 +269,60 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
headerBits:&BitArray, headerBits:&BitArray,
dataBits:&BitArray, dataBits:&BitArray,
version:VersionRef) -> u32 { version:VersionRef) -> u32 {
return headerBits.getSize() + mode.getCharacterCountBits(version) + dataBits.getSize(); (headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize()) as u32
} }
/** /**
* @return the code point of the table used in alphanumeric mode or * @return the code point of the table used in alphanumeric mode or
* -1 if there is no corresponding code in the table. * -1 if there is no corresponding code in the table.
*/ */
pub fn getAlphanumericCode( code:u32) -> u32{ pub fn getAlphanumericCode( code:u32) -> i8{
let code = code as usize;
if code < ALPHANUMERIC_TABLE.len() { if code < ALPHANUMERIC_TABLE.len() {
return ALPHANUMERIC_TABLE[code]; ALPHANUMERIC_TABLE[code]
}else{
-1
} }
return -1;
} }
pub fn chooseMode( content:&str) -> Mode{ pub fn chooseMode( content:&str) -> Mode{
return chooseModeWithEncoding(content, None); return chooseModeWithEncoding(content, encoding::all::ISO_8859_1);
} }
/** /**
* Choose the best mode by examining the content. Note that 'encoding' is used as a hint; * Choose the best mode by examining the content. Note that 'encoding' is used as a hint;
* if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}.
*/ */
fn chooseModeWithEncoding( content:&str, encoding:Option<EncodingRef>) -> Mode{ fn chooseModeWithEncoding( content:&str, encoding:EncodingRef) -> Mode{
if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && isOnlyDoubleByteKanji(content)) { 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 // Choose Kanji mode if all input are double-byte characters
return Mode.KANJI; return Mode::KANJI;
} }
boolean hasNumeric = false; let hasNumeric = false;
boolean hasAlphanumeric = false; let hasAlphanumeric = false;
for (int i = 0; i < content.length(); ++i) { for i in 0..content.len() {
char c = content.charAt(i); // for (int i = 0; i < content.length(); ++i) {
if (c >= '0' && c <= '9') { let c = content.chars().nth(i).unwrap();
if c >= '0' && c <= '9' {
hasNumeric = true; hasNumeric = true;
} else if (getAlphanumericCode(c) != -1) { } else if (getAlphanumericCode(c as u32) != -1) {
hasAlphanumeric = true; hasAlphanumeric = true;
} else { } else {
return Mode.BYTE; return Mode::BYTE;
} }
} }
if (hasAlphanumeric) { if (hasAlphanumeric) {
return Mode.ALPHANUMERIC; return Mode::ALPHANUMERIC;
} }
if (hasNumeric) { if (hasNumeric) {
return Mode.NUMERIC; return Mode::NUMERIC;
} }
return Mode.BYTE; return Mode::BYTE;
} }
pub fn isOnlyDoubleByteKanji( content:&str) -> bool{ pub fn isOnlyDoubleByteKanji( content:&str) -> bool{
let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET); let bytes = SHIFT_JIS_CHARSET.encode(content,encoding::EncoderTrap::Strict).expect("encode");
let length = bytes.len(); let length = bytes.len();
if length % 2 != 0 { if length % 2 != 0 {
return false; return false;
@@ -302,25 +349,25 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
// We try all mask patterns to choose the best one. // We try all mask patterns to choose the best one.
for maskPattern in 0..QRCode::NUM_MASK_PATTERNS { for maskPattern in 0..QRCode::NUM_MASK_PATTERNS {
// for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { // for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) {
matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, matrix); matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, &mut matrix);
let penalty = calculateMaskPenalty(matrix); let penalty = calculateMaskPenalty(matrix);
if (penalty < minPenalty) { if penalty < minPenalty {
minPenalty = penalty; minPenalty = penalty;
bestMaskPattern = maskPattern; bestMaskPattern = maskPattern;
} }
} }
return bestMaskPattern; Ok( bestMaskPattern as u32 )
} }
fn chooseVersion( numInputBits:u32, ecLevel:&ErrorCorrectionLevel) -> Result<VersionRef,Exceptions> { fn chooseVersion( numInputBits:u32, ecLevel:&ErrorCorrectionLevel) -> Result<VersionRef,Exceptions> {
for versionNum in 1..=40 { for versionNum in 1..=40 {
// for (int versionNum = 1; versionNum <= 40; versionNum++) { // for (int versionNum = 1; versionNum <= 40; versionNum++) {
let version = Version::getVersionForNumber(versionNum); let version = Version::getVersionForNumber(versionNum)?;
if willFit(numInputBits, version, ecLevel) { if willFit(numInputBits, version, ecLevel) {
return version; return Ok(version);
} }
} }
Err(Exceptions::WriterException("Data too big".to_owned())); Err(Exceptions::WriterException("Data too big".to_owned()))
} }
/** /**
@@ -332,7 +379,7 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
// numBytes = 196 // numBytes = 196
let numBytes = version.getTotalCodewords(); let numBytes = version.getTotalCodewords();
// getNumECBytes = 130 // getNumECBytes = 130
let ecBlocks = version.getECBlocksForLevel(ecLevel); let ecBlocks = version.getECBlocksForLevel(*ecLevel);
let numEcBytes = ecBlocks.getTotalECCodewords(); let numEcBytes = ecBlocks.getTotalECCodewords();
// getNumDataBytes = 196 - 130 = 66 // getNumDataBytes = 196 - 130 = 66
let numDataBytes = numBytes - numEcBytes; let numDataBytes = numBytes - numEcBytes;
@@ -345,30 +392,39 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
*/ */
pub fn terminateBits( numDataBytes:u32, bits:&BitArray) -> Result<(),Exceptions> { pub fn terminateBits( numDataBytes:u32, bits:&BitArray) -> Result<(),Exceptions> {
let capacity = numDataBytes * 8; let capacity = numDataBytes * 8;
if (bits.getSize() > capacity) { if bits.getSize() > capacity as usize {
throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + return Err(Exceptions::WriterException(format!("data bits cannot fit in the QR Code{} > " ,
capacity); 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) // Append Mode.TERMINATE if there is enough space (value is 0000)
for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { for i in 0..4 {
if bits.getSize() > 0 { break }
// }
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
bits.appendBit(false); bits.appendBit(false);
} }
// Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details.
// If the last byte isn't 8-bit aligned, we'll add padding bits. // If the last byte isn't 8-bit aligned, we'll add padding bits.
int numBitsInLastByte = bits.getSize() & 0x07; let numBitsInLastByte = bits.getSize() & 0x07;
if (numBitsInLastByte > 0) { if numBitsInLastByte > 0 {
for (int i = numBitsInLastByte; i < 8; i++) { for i in numBitsInLastByte..8 {
// for (int i = numBitsInLastByte; i < 8; i++) {
bits.appendBit(false); bits.appendBit(false);
} }
} }
// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
int numPaddingBytes = numDataBytes - bits.getSizeInBytes(); let numPaddingBytes = numDataBytes as usize - bits.getSizeInBytes();
for (int i = 0; i < numPaddingBytes; ++i) { for i in 0..numPaddingBytes {
bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); // for (int i = 0; i < numPaddingBytes; ++i) {
bits.appendBits(if (i & 0x01) == 0 {0xEC} else {0x11}, 8);
} }
if (bits.getSize() != capacity) { if bits.getSize() != capacity as usize {
throw new WriterException("Bits size does not equal capacity"); return Err(Exceptions::WriterException("Bits size does not equal capacity".to_owned()))
// throw new WriterException("Bits size does not equal capacity");
} }
Ok(())
} }
/** /**
@@ -383,32 +439,36 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
numDataBytesInBlock:&[u32], numDataBytesInBlock:&[u32],
numECBytesInBlock:&[u32]) -> Result<(),Exceptions> { numECBytesInBlock:&[u32]) -> Result<(),Exceptions> {
if blockID >= numRSBlocks { if blockID >= numRSBlocks {
throw new WriterException("Block ID too large"); return Err(Exceptions::WriterException("Block ID too large".to_owned()))
// throw new WriterException("Block ID too large");
} }
// numRsBlocksInGroup2 = 196 % 5 = 1 // numRsBlocksInGroup2 = 196 % 5 = 1
int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; let numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
// numRsBlocksInGroup1 = 5 - 1 = 4 // numRsBlocksInGroup1 = 5 - 1 = 4
int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; let numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
// numTotalBytesInGroup1 = 196 / 5 = 39 // numTotalBytesInGroup1 = 196 / 5 = 39
int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; let numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
// numTotalBytesInGroup2 = 39 + 1 = 40 // numTotalBytesInGroup2 = 39 + 1 = 40
int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; let numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
// numDataBytesInGroup1 = 66 / 5 = 13 // numDataBytesInGroup1 = 66 / 5 = 13
int numDataBytesInGroup1 = numDataBytes / numRSBlocks; let numDataBytesInGroup1 = numDataBytes / numRSBlocks;
// numDataBytesInGroup2 = 13 + 1 = 14 // numDataBytesInGroup2 = 13 + 1 = 14
int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; let numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
// numEcBytesInGroup1 = 39 - 13 = 26 // numEcBytesInGroup1 = 39 - 13 = 26
int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; let numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
// numEcBytesInGroup2 = 40 - 14 = 26 // numEcBytesInGroup2 = 40 - 14 = 26
int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; let numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
// Sanity checks. // Sanity checks.
// 26 = 26 // 26 = 26
if (numEcBytesInGroup1 != numEcBytesInGroup2) { if (numEcBytesInGroup1 != numEcBytesInGroup2) {
throw new WriterException("EC bytes mismatch"); return Err(Exceptions::WriterException("EC bytes mismatch".to_owned()))
// throw new WriterException("EC bytes mismatch");
} }
// 5 = 4 + 1. // 5 = 4 + 1.
if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) {
throw new WriterException("RS blocks mismatch"); return Err(Exceptions::WriterException("RS blocks mismatch".to_owned()))
// throw new WriterException("RS blocks mismatch");
} }
// 196 = (13 + 26) * 4 + (14 + 26) * 1 // 196 = (13 + 26) * 4 + (14 + 26) * 1
if (numTotalBytes != if (numTotalBytes !=
@@ -416,7 +476,9 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
numRsBlocksInGroup1) + numRsBlocksInGroup1) +
((numDataBytesInGroup2 + numEcBytesInGroup2) * ((numDataBytesInGroup2 + numEcBytesInGroup2) *
numRsBlocksInGroup2)) { numRsBlocksInGroup2)) {
throw new WriterException("Total bytes mismatch"); return Err(Exceptions::WriterException("Total bytes mismatch".to_owned()))
// throw new WriterException("Total bytes mismatch");
} }
if (blockID < numRsBlocksInGroup1) { if (blockID < numRsBlocksInGroup1) {
@@ -426,6 +488,7 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
numDataBytesInBlock[0] = numDataBytesInGroup2; numDataBytesInBlock[0] = numDataBytesInGroup2;
numECBytesInBlock[0] = numEcBytesInGroup2; numECBytesInBlock[0] = numEcBytesInGroup2;
} }
Ok(())
} }
/** /**
@@ -438,7 +501,7 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
numRSBlocks:u32) -> Result<BitArray,Exceptions> { numRSBlocks:u32) -> Result<BitArray,Exceptions> {
// "bits" must have "getNumDataBytes" bytes of data. // "bits" must have "getNumDataBytes" bytes of data.
if bits.getSizeInBytes() != numDataBytes { if bits.getSizeInBytes() as u32 != numDataBytes {
return Err(Exceptions::WriterException("Number of bits and data bytes does not match".to_owned())) return Err(Exceptions::WriterException("Number of bits and data bytes does not match".to_owned()))
} }
@@ -453,60 +516,72 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
for i in 0..numRSBlocks { for i in 0..numRSBlocks {
// for (int i = 0; i < numRSBlocks; ++i) { // for (int i = 0; i < numRSBlocks; ++i) {
let numDataBytesInBlock = new int[1]; let numDataBytesInBlock = vec![0;1];//new int[1];
let numEcBytesInBlock = new int[1]; let numEcBytesInBlock = vec![0;1];//new int[1];
getNumDataBytesAndNumECBytesForBlockID( getNumDataBytesAndNumECBytesForBlockID(
numTotalBytes, numDataBytes, numRSBlocks, i, numTotalBytes, numDataBytes, numRSBlocks, i,
numDataBytesInBlock, numEcBytesInBlock); &numDataBytesInBlock, &numEcBytesInBlock);
let size = numDataBytesInBlock[0]; let size = numDataBytesInBlock[0];
let dataBytes = new byte[size]; let dataBytes = vec![0u8;size as usize];
bits.toBytes(8 * dataBytesOffset, dataBytes, 0, size); bits.toBytes(8 * dataBytesOffset, &mut dataBytes, 0, size as usize);
let ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock[0] as usize);
blocks.add(new BlockPair(dataBytes, ecBytes)); blocks.push( BlockPair::new(dataBytes, ecBytes));
maxNumDataBytes = Math.max(maxNumDataBytes, size); maxNumDataBytes = maxNumDataBytes.max( size);
maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); maxNumEcBytes = maxNumEcBytes.max( ecBytes.len());
dataBytesOffset += numDataBytesInBlock[0]; dataBytesOffset += numDataBytesInBlock[0] as usize;
} }
if (numDataBytes != dataBytesOffset) { if numDataBytes != dataBytesOffset as u32 {
return Err(Exceptions::WriterException("Data bytes does not match offset".to_owned())) return Err(Exceptions::WriterException("Data bytes does not match offset".to_owned()))
} }
let result = BitArray::new(); let result = BitArray::new();
// First, place data blocks. // First, place data blocks.
for (int i = 0; i < maxNumDataBytes; ++i) { for i in 0..maxNumDataBytes as usize{
for (BlockPair block : blocks) { // for (int i = 0; i < maxNumDataBytes; ++i) {
byte[] dataBytes = block.getDataBytes(); for block in blocks {
if (i < dataBytes.length) { // for (BlockPair block : blocks) {
result.appendBits(dataBytes[i], 8); let dataBytes = block.getDataBytes();
if i < dataBytes.len() {
result.appendBits(dataBytes[i] as u32, 8);
} }
} }
} }
// Then, place error correction blocks. // Then, place error correction blocks.
for (int i = 0; i < maxNumEcBytes; ++i) { for i in 0..maxNumEcBytes {
for (BlockPair block : blocks) { // for (int i = 0; i < maxNumEcBytes; ++i) {
byte[] ecBytes = block.getErrorCorrectionBytes(); for block in blocks {
if (i < ecBytes.length) { // for (BlockPair block : blocks) {
result.appendBits(ecBytes[i], 8); let ecBytes = block.getErrorCorrectionBytes();
if (i < ecBytes.len()) {
result.appendBits(ecBytes[i] as u32, 8);
} }
} }
} }
if (numTotalBytes != result.getSizeInBytes()) { // Should be same. if (numTotalBytes != result.getSizeInBytes() as u32) { // Should be same.
throw new WriterException("Interleaving error: " + numTotalBytes + " and " + return Err(
result.getSizeInBytes() + " differ."); Exceptions::WriterException(
format!(
"Interleaving error: {} and {} differ.",
numTotalBytes,result.getSizeInBytes()
)
)
)
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
// result.getSizeInBytes() + " differ.");
} }
return result; Ok(result)
} }
pub fn generateECBytes( dataBytes:&[u8], numEcBytesInBlock:u32) -> Vec<u8> { pub fn generateECBytes( dataBytes:&[u8], numEcBytesInBlock:usize) -> Vec<u8> {
let numDataBytes = dataBytes.length; let numDataBytes = dataBytes.len();
let toEncode = vec![0;numDataBytes + numEcBytesInBlock]; let toEncode = vec![0;numDataBytes + numEcBytesInBlock];
for i in 0..numDataBytes { for i in 0..numDataBytes {
// for (int i = 0; i < numDataBytes; i++) { // for (int i = 0; i < numDataBytes; i++) {
toEncode[i] = dataBytes[i] & 0xFF; toEncode[i] = dataBytes[i] as i32;
} }
ReedSolomonEncoder::new(get_predefined_genericgf(PredefinedGenericGF::QrCodeField256)).encode(&mut toEncode, numEcBytesInBlock); ReedSolomonEncoder::new(get_predefined_genericgf(PredefinedGenericGF::QrCodeField256)).encode(&mut toEncode, numEcBytesInBlock);
@@ -514,7 +589,7 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
let ecBytes = vec![0u8;numEcBytesInBlock]; let ecBytes = vec![0u8;numEcBytesInBlock];
for i in 0..numEcBytesInBlock { for i in 0..numEcBytesInBlock {
// for (int i = 0; i < numEcBytesInBlock; i++) { // for (int i = 0; i < numEcBytesInBlock; i++) {
ecBytes[i] = toEncode[numDataBytes + i]; ecBytes[i] = toEncode[numDataBytes + i] as u8;
} }
return ecBytes; return ecBytes;
} }
@@ -523,7 +598,7 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
* Append mode info. On success, store the result in "bits". * Append mode info. On success, store the result in "bits".
*/ */
pub fn appendModeInfo( mode:Mode, bits:&BitArray) { pub fn appendModeInfo( mode:Mode, bits:&BitArray) {
bits.appendBits(mode.getBits(), 4); bits.appendBits(mode.getBits() as u32, 4);
} }
@@ -533,9 +608,9 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
pub fn appendLengthInfo( numLetters:u32, version:VersionRef, mode:Mode, bits:&BitArray) -> Result<(),Exceptions> { pub fn appendLengthInfo( numLetters:u32, version:VersionRef, mode:Mode, bits:&BitArray) -> Result<(),Exceptions> {
let numBits = mode.getCharacterCountBits(version); let numBits = mode.getCharacterCountBits(version);
if numLetters >= (1 << numBits) { if numLetters >= (1 << numBits) {
return Err(Exceptions::WriterExceptin(format!("{} is bigger than {}" ,numLetters , ((1 << numBits) - 1)))) return Err(Exceptions::WriterException(format!("{} is bigger than {}" ,numLetters , ((1 << numBits) - 1))))
} }
bits.appendBits(numLetters, numBits); bits.appendBits(numLetters, numBits as usize);
Ok(()) Ok(())
} }
@@ -547,12 +622,13 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
bits:&BitArray, bits:&BitArray,
encoding:EncodingRef) -> Result<(),Exceptions>{ encoding:EncodingRef) -> Result<(),Exceptions>{
match mode { match mode {
Mode::NUMERIC => Ok(appendNumericBytes(content, bits)), Mode::NUMERIC => appendNumericBytes(content, bits),
Mode::ALPHANUMERIC => Ok(appendAlphanumericBytes(content, bits)), Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits)?,
Mode::BYTE => Ok(append8BitBytes(content, bits, encoding)), Mode::BYTE => append8BitBytes(content, bits, encoding),
Mode::KANJI => Ok(appendKanjiBytes(content, bits)), Mode::KANJI => appendKanjiBytes(content, bits)?,
_=> Err(Exceptions::WriterException(format!("Invalid mode: {}" , mode))) _=> return Err(Exceptions::WriterException(format!("Invalid mode: {:?}" , mode)))
} };
Ok(())
// switch (mode) { // switch (mode) {
// case NUMERIC: // case NUMERIC:
// appendNumericBytes(content, bits); // appendNumericBytes(content, bits);
@@ -572,24 +648,24 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
} }
pub fn appendNumericBytes( content:&str, bits:&BitArray) { pub fn appendNumericBytes( content:&str, bits:&BitArray) {
let length = content.length(); let length = content.len();
let i = 0; let i = 0;
while i < length { while i < length {
let num1 = content.charAt(i) - '0'; let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
if i + 2 < length { if i + 2 < length {
// Encode three numeric letters in ten bits. // Encode three numeric letters in ten bits.
let num2 = content.charAt(i + 1) - '0'; let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
let num3 = content.charAt(i + 2) - '0'; let num3 = content.chars().nth(i + 2).unwrap() as u8 - b'0';
bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); bits.appendBits((num1 * 100 + num2 * 10 + num3) as u32, 10);
i += 3; i += 3;
} else if i + 1 < length { } else if i + 1 < length {
// Encode two numeric letters in seven bits. // Encode two numeric letters in seven bits.
let num2 = content.charAt(i + 1) - '0'; let num2 = content.chars().nth(i + 1).unwrap() as u8 - b'0';
bits.appendBits(num1 * 10 + num2, 7); bits.appendBits((num1 * 10 + num2) as u32, 7);
i += 2; i += 2;
} else { } else {
// Encode one numeric letter in four bits. // Encode one numeric letter in four bits.
bits.appendBits(num1, 4); bits.appendBits(num1 as u32, 4);
i+=1; i+=1;
} }
} }
@@ -599,22 +675,22 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
let length = content.len(); let length = content.len();
let i = 0; let i = 0;
while i < length { while i < length {
let code1 = getAlphanumericCode(content.charAt(i)); let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
if code1 == -1 { if code1 == -1 {
return Err(Exceptions::WriterException("".to_owned())); return Err(Exceptions::WriterException("".to_owned()));
} }
if i + 1 < length { if i + 1 < length {
let code2 = getAlphanumericCode(content.charAt(i + 1)); let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32);
if (code2 == -1) { if (code2 == -1) {
return Err(Exceptions::WriterException("".to_owned())); return Err(Exceptions::WriterException("".to_owned()));
} }
// Encode two alphanumeric letters in 11 bits. // Encode two alphanumeric letters in 11 bits.
bits.appendBits(code1 * 45 + code2, 11); bits.appendBits((code1 * 45 + code2) as u32, 11);
i += 2; i += 2;
} else { } else {
// Encode one alphanumeric letter in six bits. // Encode one alphanumeric letter in six bits.
bits.appendBits(code1, 6); bits.appendBits(code1 as u32, 6);
i+=1; i+=1;
} }
} }
@@ -622,36 +698,40 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
} }
fn append8BitBytes( content:&str, bits:&BitArray, encoding:EncodingRef) { fn append8BitBytes( content:&str, bits:&BitArray, encoding:EncodingRef) {
let bytes = content.getBytes(encoding); let bytes = encoding.encode(content, encoding::EncoderTrap::Strict).expect("should encode");
// let bytes = content.getBytes(encoding);
for b in bytes { for b in bytes {
// for (byte b : bytes) { // for (byte b : bytes) {
bits.appendBits(b, 8); bits.appendBits(b as u32, 8);
} }
} }
fn appendKanjiBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> { fn appendKanjiBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> {
let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET); let sjis = SHIFT_JIS_CHARSET; //encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
if bytes.length % 2 != 0 {
let bytes = sjis.encode(content, encoding::EncoderTrap::Strict).expect("should encode fine");
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
if bytes.len() % 2 != 0 {
return Err(Exceptions::WriterException("Kanji byte size not even".to_owned())) return Err(Exceptions::WriterException("Kanji byte size not even".to_owned()))
} }
let maxI = bytes.length - 1; // bytes.length must be even let maxI = bytes.len() - 1; // bytes.length must be even
let mut i = 0; let mut i = 0;
while i < maxI { while i < maxI {
// for (int i = 0; i < maxI; i += 2) { // for (int i = 0; i < maxI; i += 2) {
let byte1 = bytes[i] & 0xFF; let byte1 = bytes[i] & 0xFF;
let byte2 = bytes[i + 1] & 0xFF; let byte2 = bytes[i + 1] & 0xFF;
let code = (byte1 << 8) | byte2; let code = (byte1 << 8) | byte2;
let subtracted = -1; let subtracted:i32 = -1;
if code >= 0x8140 && code <= 0x9ffc { if code >= 0x8140 && code <= 0x9ffc {
subtracted = code - 0x8140; subtracted = code as i32 - 0x8140;
} else if (code >= 0xe040 && code <= 0xebbf) { } else if code >= 0xe040 && code <= 0xebbf {
subtracted = code - 0xc140; subtracted = code as i32 - 0xc140;
} }
if subtracted == -1 { if subtracted == -1 {
return Err(Exceptions::WriterException("Invalid byte sequence".to_owned())) return Err(Exceptions::WriterException("Invalid byte sequence".to_owned()))
} }
let encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); let encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
bits.appendBits(encoded, 13); bits.appendBits(encoded as u32, 13);
i+=2; i+=2;
} }
@@ -659,8 +739,8 @@ use super::{mask_util, ByteMatrix, QRCode, matrix_util};
} }
fn appendECI( eci:&CharacterSetECI, bits:&BitArray) { fn appendECI( eci:&CharacterSetECI, bits:&BitArray) {
bits.appendBits(Mode::ECI.getBits(), 4); bits.appendBits(Mode::ECI.getBits() as u32, 4);
// This is correct for values up to 127, which is all we need now. // This is correct for values up to 127, which is all we need now.
bits.appendBits(eci.getValue(), 8); bits.appendBits(eci.getValueSelf(), 8);
} }

View File

@@ -77,15 +77,15 @@ impl fmt::Display for VersionSize {
* *
* @author Alex Geller * @author Alex Geller
*/ */
pub struct MinimalEncoder { pub struct MinimalEncoder<'a> {
stringToEncode: String, stringToEncode: &'a str,
isGS1: bool, isGS1: bool,
encoders: ECIEncoderSet, encoders: ECIEncoderSet,
ecLevel:ErrorCorrectionLevel, ecLevel:ErrorCorrectionLevel,
} }
impl MinimalEncoder { impl MinimalEncoder<'_> {
/** /**
* Creates a MinimalEncoder * Creates a MinimalEncoder
@@ -99,7 +99,7 @@ impl MinimalEncoder {
* @param ecLevel The error correction level. * @param ecLevel The error correction level.
* @see RXingResultList#getVersion * @see RXingResultList#getVersion
*/ */
pub fn new( stringToEncode:String, priorityCharset: EncodingRef, isGS1:bool, ecLevel:ErrorCorrectionLevel) -> Self { pub fn new( stringToEncode:&str, priorityCharset: EncodingRef, isGS1:bool, ecLevel:ErrorCorrectionLevel) -> Self {
Self { Self {
stringToEncode, stringToEncode,
isGS1, isGS1,
@@ -128,9 +128,9 @@ impl MinimalEncoder {
* @see RXingResultList#getVersion * @see RXingResultList#getVersion
* @see RXingResultList#getSize * @see RXingResultList#getSize
*/ */
pub fn encode_with_details<'a>( stringToEncode:String, version:VersionRef, priorityCharset:EncodingRef, isGS1:bool, pub fn encode_with_details<'a>( stringToEncode:&str, version:Option<VersionRef>, priorityCharset:EncodingRef, isGS1:bool,
ecLevel:ErrorCorrectionLevel) -> Result<RXingResultList<'a>,Exceptions> { ecLevel:ErrorCorrectionLevel) -> Result<RXingResultList<'a>,Exceptions> {
MinimalEncoder::new(stringToEncode, priorityCharset, isGS1, ecLevel).encode(Some(version)) MinimalEncoder::new(stringToEncode, priorityCharset, isGS1, ecLevel).encode(version)
} }
pub fn encode(&self, version:Option<VersionRef>) -> Result<RXingResultList,Exceptions> { pub fn encode(&self, version:Option<VersionRef>) -> Result<RXingResultList,Exceptions> {
@@ -138,29 +138,30 @@ impl MinimalEncoder {
let versions = [ Self::getVersion(VersionSize::SMALL), let versions = [ Self::getVersion(VersionSize::SMALL),
Self::getVersion(VersionSize::MEDIUM), Self::getVersion(VersionSize::MEDIUM),
Self::getVersion(VersionSize::LARGE) ]; Self::getVersion(VersionSize::LARGE) ];
let results = [ self.encodeSpecificVersion(&versions[0]), let results = [ self.encodeSpecificVersion(&versions[0])?,
self.encodeSpecificVersion(&versions[1]), self.encodeSpecificVersion(&versions[1])?,
self.encodeSpecificVersion(&versions[2]) ]; self.encodeSpecificVersion(&versions[2])? ];
let smallestSize = u32::MAX; let smallestSize = u32::MAX;
let smallestRXingResult = -1; let smallestRXingResult:i32 = -1;
for i in 0..3 { for i in 0..3 {
// for (int i = 0; i < 3; i++) { // for (int i = 0; i < 3; i++) {
let size = results[i].getSize(); let size = results[i].getSize();
if encoder::willFit(size, versions[i], self.ecLevel) && size < smallestSize { if encoder::willFit(size, versions[i], &self.ecLevel) && size < smallestSize {
smallestSize = size; smallestSize = size;
smallestRXingResult = i; smallestRXingResult = i as i32;
} }
} }
if smallestRXingResult < 0 { if smallestRXingResult < 0 {
return Err(Exceptions::WriterException("Data too big for any version".to_owned())); return Err(Exceptions::WriterException("Data too big for any version".to_owned()));
} }
return results[smallestRXingResult]; Ok(results[smallestRXingResult as usize])
} else { // compute minimal encoding for a given version } else { // compute minimal encoding for a given version
let result = self.encodeSpecificVersion(version); let version = version.unwrap();
if !encoder::willFit(result.getSize(), Self::getVersion(Self::getVersionSize(result.getVersion())), self.ecLevel) { let result = self.encodeSpecificVersion(version)?;
if !encoder::willFit(result.getSize(), Self::getVersion(Self::getVersionSize(result.getVersion())), &self.ecLevel) {
return Err(Exceptions::WriterException(format!("Data too big for version {}" , version))); return Err(Exceptions::WriterException(format!("Data too big for version {}" , version)));
} }
return result; Ok(result)
} }
} }
@@ -191,11 +192,11 @@ impl MinimalEncoder {
} }
pub fn isDoubleByteKanji( c:char) -> bool{ pub fn isDoubleByteKanji( c:char) -> bool{
return encoder::isOnlyDoubleByteKanji(String.valueOf(c)); return encoder::isOnlyDoubleByteKanji(&String::from(c));
} }
pub fn isAlphanumeric( c: char) -> bool{ pub fn isAlphanumeric( c: char) -> bool{
return encoder::getAlphanumericCode(c) != -1; return encoder::getAlphanumericCode(c as u8 as u32) != -1;
} }
pub fn canEncode(&self, mode:&Mode, c:char) -> bool { pub fn canEncode(&self, mode:&Mode, c:char) -> bool {
@@ -235,45 +236,45 @@ impl MinimalEncoder {
// } // }
} }
pub fn addEdge(&self, edges:&Vec<Vec<Vec<&'_ Edge>>>, position:u32, edge:Option<&Edge>) { pub fn addEdge(&self, edges:&Vec<Vec<Vec<Option<&'_ Edge>>>>, position:usize, edge:Option<&Edge>) {
let vertexIndex = position + edge.as_ref().unwrap().characterLength; let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize;
let modeEdges = edges[vertexIndex as usize][edge.as_ref().unwrap().charsetEncoderIndex as usize]; let modeEdges = edges[vertexIndex as usize][edge.as_ref().unwrap().charsetEncoderIndex as usize];
let modeOrdinal = Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize; let modeOrdinal = Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
if /*modeEdges[modeOrdinal] == null ||*/ modeEdges[modeOrdinal].cachedTotalSize > (&edge).unwrap().cachedTotalSize { if modeEdges[modeOrdinal].is_none() || modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize > (&edge).unwrap().cachedTotalSize {
modeEdges[modeOrdinal] = edge.unwrap(); modeEdges[modeOrdinal] = edge;
} }
} }
pub fn addEdges( &self, version:&Edge, edges:&Vec<Vec<Vec<Edge>>>, from:u32, previous:&Edge) { pub fn addEdges( &self, version:VersionRef, edges:&Vec<Vec<Vec<Option<&Edge>>>>, from:usize, previous:Option<&Edge>) {
let start = 0; let start = 0;
let end = self.encoders.len(); let end = self.encoders.len();
let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex(); let priorityEncoderIndex = self.encoders.getPriorityEncoderIndex();
if priorityEncoderIndex >= 0 && self.encoders.canEncode(self.stringToEncode.chars().nth(from).unwrap(),priorityEncoderIndex) { if priorityEncoderIndex >= 0 && self.encoders.canEncode(self.stringToEncode.chars().nth(from as usize).unwrap() as i16,priorityEncoderIndex) {
start = priorityEncoderIndex; start = priorityEncoderIndex;
end = priorityEncoderIndex + 1; end = priorityEncoderIndex + 1;
} }
for i in start..end { for i in start..end {
// for (int i = start; i < end; i++) { // for (int i = start; i < end; i++) {
if self.encoders.canEncode(self.stringToEncode.chars().nth(from).unwrap(), i) { if self.encoders.canEncode(self.stringToEncode.chars().nth(from).unwrap() as i16, i) {
self.addEdge(edges, from, Edge::new(Mode::BYTE, from, i, 1, previous, version)); self.addEdge(edges, from, Some(&Edge::new(Mode::BYTE, from, i, 1, previous, version,&self.encoders,&self.stringToEncode)));
} }
} }
if self.canEncode(Mode::KANJI, self.stringToEncode.chars().nth(from).unwrap()) { if self.canEncode(&Mode::KANJI, self.stringToEncode.chars().nth(from).unwrap()) {
self.addEdge(edges, from, Edge::(Mode::KANJI, from, 0, 1, previous, version)); self.addEdge(edges, from, Some(&Edge::new(Mode::KANJI, from, 0, 1, previous, version,&self.encoders,&self.stringToEncode)));
} }
let inputLength = self.stringToEncode.len(); let inputLength = self.stringToEncode.len();
if self.canEncode(Mode::ALPHANUMERIC, self.stringToEncode.charAt(from)) { if self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from).unwrap()) {
self.addEdge(edges, from, Edge::new(Mode::ALPHANUMERIC, from, 0, from + 1 >= inputLength || self.addEdge(edges, from, Some(&Edge::new(Mode::ALPHANUMERIC, from, 0, if from + 1 >= inputLength ||
!self.canEncode(Mode::ALPHANUMERIC, self.stringToEncode.charAt(from + 1)) ? 1 : 2, previous, version)); !self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {2}, previous, version,&self.encoders,&self.stringToEncode)));
} }
if self.canEncode(Mode::NUMERIC, self.stringToEncode.chars().nth(from).unwrap()) { if self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from).unwrap()) {
self.addEdge(edges, from, Edge::new(Mode::NUMERIC, from, 0, from + 1 >= inputLength || self.addEdge(edges, from, Some(&Edge::new(Mode::NUMERIC, from, 0, if from + 1 >= inputLength ||
!self.canEncode(Mode::NUMERIC, self.stringToEncode.charAt(from + 1)) ? 1 : from + 2 >= inputLength || !self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {if from + 2 >= inputLength ||
!self.canEncode(Mode::NUMERIC, self.stringToEncode.charAt(from + 2)) ? 2 : 3, previous, version)); !self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 2).unwrap()) {2} else {3}}, previous, version,&self.encoders,&self.stringToEncode)));
} }
} }
pub fn encodeSpecificVersion(&self, version:VersionRef) ->Result< RXingResultList, Exceptions >{ pub fn encodeSpecificVersion(&self, version:VersionRef) ->Result< RXingResultList, Exceptions >{
@@ -396,7 +397,7 @@ impl MinimalEncoder {
// The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the // The last dimension in the array below encodes the 4 modes KANJI, ALPHANUMERIC, NUMERIC and BYTE via the
// function getCompactedOrdinal(Mode) // function getCompactedOrdinal(Mode)
let edges = vec![vec![vec![]]];//new Edge[inputLength + 1][encoders.length()][4]; let edges = vec![vec![vec![None;4];self.encoders.len()];inputLength+1];//new Edge[inputLength + 1][encoders.length()][4];
self. addEdges(version, &edges, 0, None); self. addEdges(version, &edges, 0, None);
for i in 1..=inputLength { for i in 1..=inputLength {
@@ -405,42 +406,42 @@ impl MinimalEncoder {
// for (int j = 0; j < encoders.length(); j++) { // for (int j = 0; j < encoders.length(); j++) {
for k in 0..4 { for k in 0..4 {
// for (int k = 0; k < 4; k++) { // for (int k = 0; k < 4; k++) {
if edges[i][j][k] != null && i < inputLength { if edges[i][j][k].is_some() && i < inputLength {
self.addEdges(version, edges, i, edges[i][j][k]); self.addEdges(version, &edges, i, edges[i][j][k]);
} }
} }
} }
} }
let minimalJ = -1; let minimalJ = None;
let minimalK = -1; let minimalK = None;
let minimalSize = u32::MAX; let minimalSize = u32::MAX;
for j in 0..self.encoders.len() { for j in 0..self.encoders.len() {
// for (int j = 0; j < encoders.length(); j++) { // for (int j = 0; j < encoders.length(); j++) {
for k in 0..4 { for k in 0..4 {
// for (int k = 0; k < 4; k++) { // for (int k = 0; k < 4; k++) {
if edges[inputLength][j][k] != null { if edges[inputLength][j][k].is_some() {
let edge = edges[inputLength][j][k]; let edge = edges[inputLength][j][k].as_ref().unwrap();
if edge.cachedTotalSize < minimalSize { if edge.cachedTotalSize < minimalSize {
minimalSize = edge.cachedTotalSize; minimalSize = edge.cachedTotalSize;
minimalJ = j; minimalJ = Some(j);
minimalK = k; minimalK = Some(k);
} }
} }
} }
} }
if minimalJ < 0 { if minimalJ.is_none() {
return Err(Exceptions::WriterException(format!(r#"Internal error: failed to encode "{}"#,self.stringToEncode))); return Err(Exceptions::WriterException(format!(r#"Internal error: failed to encode "{}"#,self.stringToEncode)));
} }
Ok(RXingResultList::new(version, edges[inputLength][minimalJ][minimalK])) Ok(RXingResultList::new(version, edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()].unwrap(),self.isGS1,&self.ecLevel, &self.encoders, &self.stringToEncode))
} }
} }
struct Edge<'a> { struct Edge<'a> {
mode:Mode, pub mode:Mode,
fromPosition:u32, fromPosition:usize,
charsetEncoderIndex:u32, charsetEncoderIndex:usize,
characterLength:u32, characterLength:u32,
previous:Option<&'a Edge<'a>>, previous:Option<&'a Edge<'a>>,
cachedTotalSize:u32, cachedTotalSize:u32,
@@ -449,7 +450,7 @@ struct Edge<'a> {
} }
impl Edge<'_> { impl Edge<'_> {
pub fn new( mode:Mode, fromPosition:u32, charsetEncoderIndex:u32, characterLength:u32, previous:Option<&'_ Edge>, pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, previous:Option<&'_ Edge>,
version:&Version, encoders: &'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self { version:&Version, encoders: &'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self {
let nci = if mode == Mode::BYTE || previous.is_none() {charsetEncoderIndex} else let nci = if mode == Mode::BYTE || previous.is_none() {charsetEncoderIndex} else
{previous.as_ref().unwrap().charsetEncoderIndex}; {previous.as_ref().unwrap().charsetEncoderIndex};
@@ -474,7 +475,7 @@ impl Edge<'_> {
Mode::NUMERIC => size += if characterLength == 1 {4} else {if characterLength == 2 {7} else {10}}, Mode::NUMERIC => size += if characterLength == 1 {4} else {if characterLength == 2 {7} else {10}},
Mode::ALPHANUMERIC => size += if characterLength == 1 {6} else {11}, Mode::ALPHANUMERIC => size += if characterLength == 1 {6} else {11},
Mode::BYTE =>{ Mode::BYTE =>{
size += 8 * encoders.encode_string(&stringToEncode[fromPosition as usize..(fromPosition + characterLength)as usize], size += 8 * encoders.encode_string(&stringToEncode[fromPosition as usize..(fromPosition + characterLength as usize)],
charsetEncoderIndex as usize).len() as u32; charsetEncoderIndex as usize).len() as u32;
if needECI { if needECI {
size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long
@@ -549,7 +550,7 @@ struct RXingResultList<'a> {
} }
impl RXingResultList<'_> { impl RXingResultList<'_> {
pub fn new( version:VersionRef, solution:&'_ Edge, isGS1:bool, ecLevel: &ErrorCorrectionLevel) -> Self { pub fn new( version:VersionRef, solution:&'_ Edge, isGS1:bool, ecLevel: &ErrorCorrectionLevel, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self {
let length = 0; let length = 0;
let current = Some(solution); let current = Some(solution);
let containsECI = false; let containsECI = false;
@@ -568,12 +569,12 @@ impl RXingResultList<'_> {
} }
if previous.is_none() || previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode || needECI { if previous.is_none() || previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode || needECI {
list.push( RXingResultNode::new(current.mode, current.fromPosition, current.charsetEncoderIndex, length)); list.push( RXingResultNode::new(current.as_ref().unwrap().mode, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, length,encoders,stringToEncode, version));
length = 0; length = 0;
} }
if needECI { if needECI {
list.push( RXingResultNode::new(Mode::ECI, current.fromPosition, current.charsetEncoderIndex, 0)); list.push( RXingResultNode::new(Mode::ECI, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, 0,encoders,stringToEncode, version));
} }
current = previous; current = previous;
} }
@@ -585,12 +586,12 @@ impl RXingResultList<'_> {
// if first != null && first.mode != Mode.ECI && containsECI { // if first != null && first.mode != Mode.ECI && containsECI {
if first.mode != Mode::ECI && containsECI { if first.mode != Mode::ECI && containsECI {
// prepend a default character set ECI // prepend a default character set ECI
list.push(0, RXingResultNode::new(Mode::ECI, 0, 0, 0)); list.push( RXingResultNode::new(Mode::ECI, 0, 0, 0,encoders,stringToEncode,version));
}} }}
let first = list.get(0).unwrap(); let first = list.get(0).unwrap();
// prepend or insert a FNC1_FIRST_POSITION after the ECI (if any) // prepend or insert a FNC1_FIRST_POSITION after the ECI (if any)
// if first != null && first.mode != Mode.ECI && containsECI { // if first != null && first.mode != Mode.ECI && containsECI {
list.push( RXingResultNode::new(Mode::FNC1_FIRST_POSITION, 0, 0, 0)); list.push( RXingResultNode::new(Mode::FNC1_FIRST_POSITION, 0, 0, 0,encoders,stringToEncode,version));
} }
// set version to smallest version into which the bits fit. // set version to smallest version into which the bits fit.
@@ -621,12 +622,12 @@ impl RXingResultList<'_> {
// } // }
let size = Self::internal_static_get_size(version,&list); let size = Self::internal_static_get_size(version,&list);
// increase version if needed // increase version if needed
while versionNumber < upperLimit && !encoder::willFit(size, Version::getVersionForNumber(versionNumber), while versionNumber < upperLimit && !encoder::willFit(size, Version::getVersionForNumber(versionNumber).unwrap(),
ecLevel) { ecLevel) {
versionNumber+=1; versionNumber+=1;
} }
// shrink version if possible // shrink version if possible
while versionNumber > lowerLimit && encoder::willFit(size, Version::getVersionForNumber(versionNumber - 1), while versionNumber > lowerLimit && encoder::willFit(size, Version::getVersionForNumber(versionNumber - 1).unwrap(),
ecLevel) { ecLevel) {
versionNumber-=1; versionNumber-=1;
} }
@@ -652,7 +653,7 @@ impl RXingResultList<'_> {
return result; return result;
} }
fn internal_static_get_size(version:VersionRef, list: &Vec<RXingResultNode>) { fn internal_static_get_size(version:VersionRef, list: &Vec<RXingResultNode>) -> u32 {
let result = 0; let result = 0;
for resultNode in list { for resultNode in list {
result += resultNode.getSize(version); result += resultNode.getSize(version);
@@ -694,8 +695,8 @@ impl fmt::Display for RXingResultList<'_> {
struct RXingResultNode<'a> { struct RXingResultNode<'a> {
mode:Mode, mode:Mode,
fromPosition:u32, fromPosition:usize,
charsetEncoderIndex:u32, charsetEncoderIndex:usize,
characterLength:u32, characterLength:u32,
encoders:&'a ECIEncoderSet, encoders:&'a ECIEncoderSet,
version: VersionRef, version: VersionRef,
@@ -704,7 +705,7 @@ struct RXingResultNode<'a> {
impl RXingResultNode<'_> { impl RXingResultNode<'_> {
pub fn new( mode:Mode, fromPosition:u32, charsetEncoderIndex:u32, characterLength:u32, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str, version: &'_ Version) -> Self { pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str, version: &'_ Version) -> Self {
Self { Self {
mode, mode,
fromPosition, fromPosition,
@@ -764,7 +765,7 @@ impl RXingResultNode<'_> {
*/ */
fn getCharacterCountIndicator(&self) -> u32{ fn getCharacterCountIndicator(&self) -> u32{
if self.mode == Mode::BYTE if self.mode == Mode::BYTE
{self.encoders.encode_string(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength) as usize], {self.encoders.encode_string(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)],
self.charsetEncoderIndex as usize).len() as u32} else {self.characterLength} self.charsetEncoderIndex as usize).len() as u32} else {self.characterLength}
} }
@@ -775,13 +776,13 @@ impl RXingResultNode<'_> {
bits.appendBits(self.mode.getBits() as u32, 4); bits.appendBits(self.mode.getBits() as u32, 4);
if self.characterLength > 0 { if self.characterLength > 0 {
let length = self.getCharacterCountIndicator(); let length = self.getCharacterCountIndicator();
bits.appendBits(length, self.mode.getCharacterCountBits(self.version.as_ref()) as usize); bits.appendBits(length, self.mode.getCharacterCountBits(self.version) as usize);
} }
if self.mode == Mode::ECI { if self.mode == Mode::ECI {
bits.appendBits(self.encoders.getECIValue(self.charsetEncoderIndex as usize), 8); bits.appendBits(self.encoders.getECIValue(self.charsetEncoderIndex as usize), 8);
} else if self.characterLength > 0 { } else if self.characterLength > 0 {
// append data // append data
encoder::appendBytes(self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength) as usize], self.mode, bits, encoder::appendBytes(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)], self.mode, bits,
self.encoders.getCharset(self.charsetEncoderIndex as usize)); self.encoders.getCharset(self.charsetEncoderIndex as usize));
} }
Ok(()) Ok(())
@@ -809,7 +810,7 @@ impl RXingResultNode<'_> {
if self.mode == Mode::ECI { if self.mode == Mode::ECI {
result.push_str(self.encoders.getCharset(self.charsetEncoderIndex as usize).name()); result.push_str(self.encoders.getCharset(self.charsetEncoderIndex as usize).name());
} else { } else {
result.push_str(&Self::makePrintable(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength) as usize])); result.push_str(&Self::makePrintable(&self.stringToEncode[self.fromPosition as usize..(self.fromPosition + self.characterLength as usize)]));
} }
result.push(')'); result.push(')');

View File

@@ -20,7 +20,6 @@ use crate::qrcode::decoder::{Mode, ErrorCorrectionLevel, Version};
use super::ByteMatrix; use super::ByteMatrix;
const NUM_MASK_PATTERNS : i32 = 8;
/** /**
* @author satorux@google.com (Satoru Takabayashi) - creator * @author satorux@google.com (Satoru Takabayashi) - creator
@@ -39,6 +38,8 @@ pub struct QRCode {
} }
impl QRCode { impl QRCode {
pub const NUM_MASK_PATTERNS : i32 = 8;
pub fn new()->Self { pub fn new()->Self {
Self { Self {
mode: None, mode: None,
@@ -96,7 +97,7 @@ impl QRCode {
// Check if "mask_pattern" is valid. // Check if "mask_pattern" is valid.
pub fn isValidMaskPattern( maskPattern:i32) -> bool{ pub fn isValidMaskPattern( maskPattern:i32) -> bool{
maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS maskPattern >= 0 && maskPattern < Self::NUM_MASK_PATTERNS
} }
} }