encoder builds, no tests

This commit is contained in:
Henry Schimke
2022-10-03 16:03:28 -05:00
parent eaff1b6b64
commit e3c7af36f1
4 changed files with 1506 additions and 1146 deletions

View File

@@ -2867,6 +2867,7 @@ impl fmt::Display for ECIStringBuilder {
* *
* @author Alex Geller * @author Alex Geller
*/ */
#[derive(Clone)]
pub struct ECIEncoderSet { pub struct ECIEncoderSet {
encoders: Vec<EncodingRef>, encoders: Vec<EncodingRef>,
priorityEncoderIndex: usize, priorityEncoderIndex: usize,

View File

@@ -64,7 +64,7 @@ impl DataBlock {
let ecBlocks = version.getECBlocksForLevel(ecLevel); let ecBlocks = version.getECBlocksForLevel(ecLevel);
// First count the total number of data blocks // First count the total number of data blocks
let totalBlocks = 0; let mut totalBlocks = 0;
let ecBlockArray = ecBlocks.getECBlocks(); let ecBlockArray = ecBlocks.getECBlocks();
for ecBlock in ecBlockArray { for ecBlock in ecBlockArray {
// for (Version.ECB ecBlock : ecBlockArray) { // for (Version.ECB ecBlock : ecBlockArray) {
@@ -72,11 +72,11 @@ impl DataBlock {
} }
// Now establish DataBlocks of the appropriate size and number of data codewords // Now establish DataBlocks of the appropriate size and number of data codewords
let result = Vec::new(); let mut result = Vec::new();
let numRXingResultBlocks = 0; let mut numRXingResultBlocks = 0;
for ecBlock in ecBlockArray { for ecBlock in ecBlockArray {
// for (Version.ECB ecBlock : ecBlockArray) { // for (Version.ECB ecBlock : ecBlockArray) {
for i in 0..ecBlock.getCount() { for _i in 0..ecBlock.getCount() {
// for (int i = 0; i < ecBlock.getCount(); i++) { // for (int i = 0; i < ecBlock.getCount(); i++) {
let numDataCodewords = ecBlock.getDataCodewords(); let numDataCodewords = ecBlock.getDataCodewords();
let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords; let numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
@@ -88,7 +88,7 @@ impl DataBlock {
// All blocks have the same amount of data, except that the last n // 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. // (where n may be 0) have 1 more byte. Figure out where these start.
let shorterBlocksTotalCodewords = result[0].codewords.len(); let shorterBlocksTotalCodewords = result[0].codewords.len();
let longerBlocksStartAt = result.len() - 1; let mut longerBlocksStartAt = result.len() - 1;
while (longerBlocksStartAt >= 0) { while (longerBlocksStartAt >= 0) {
let numCodewords = result[longerBlocksStartAt].codewords.len(); let numCodewords = result[longerBlocksStartAt].codewords.len();
if (numCodewords == shorterBlocksTotalCodewords) { if (numCodewords == shorterBlocksTotalCodewords) {
@@ -101,7 +101,7 @@ impl DataBlock {
let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize; let shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock() as usize;
// The last elements of result may be 1 element longer; // The last elements of result may be 1 element longer;
// first fill out as many elements as all of them have // first fill out as many elements as all of them have
let rawCodewordsOffset = 0; let mut rawCodewordsOffset = 0;
for i in 0..shorterBlocksNumDataCodewords { for i in 0..shorterBlocksNumDataCodewords {
// for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { // for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
for j in 0..numRXingResultBlocks { for j in 0..numRXingResultBlocks {

View File

@@ -39,86 +39,95 @@ use encoding::EncodingRef;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use crate::{EncodingHintDictionary, common::{BitArray, CharacterSetECI, reedsolomon::{ReedSolomonEncoder, get_predefined_genericgf, PredefinedGenericGF}, StringUtils}, Exceptions, qrcode::decoder::{ErrorCorrectionLevel, Mode, VersionRef, Version}, EncodeHintType, EncodeHintValue}; use crate::{
common::{
reedsolomon::{get_predefined_genericgf, PredefinedGenericGF, ReedSolomonEncoder},
BitArray, CharacterSetECI, StringUtils,
},
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
EncodeHintType, EncodeHintValue, EncodingHintDictionary, Exceptions,
};
use super::{mask_util, ByteMatrix, QRCode, matrix_util, MinimalEncoder, BlockPair}; use super::{mask_util, matrix_util, BlockPair, ByteMatrix, MinimalEncoder, QRCode};
/** /**
* @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 !{ lazy_static! {
static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_whatwg_label("SJIS").unwrap(); 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
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f
36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
]; ];
const DEFAULT_BYTE_MODE_ENCODING : EncodingRef = encoding::all::ISO_8859_1; const DEFAULT_BYTE_MODE_ENCODING: EncodingRef = encoding::all::ISO_8859_1;
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details.
// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. // Basically it applies four rules and summate all penalties.
// Basically it applies four rules and summate all penalties. pub fn calculateMaskPenalty(matrix: &ByteMatrix) -> u32 {
pub fn calculateMaskPenalty( matrix:&ByteMatrix) -> u32{
return mask_util::applyMaskPenaltyRule1(matrix) return mask_util::applyMaskPenaltyRule1(matrix)
+ mask_util::applyMaskPenaltyRule2(matrix) + mask_util::applyMaskPenaltyRule2(matrix)
+ mask_util::applyMaskPenaltyRule3(matrix) + mask_util::applyMaskPenaltyRule3(matrix)
+ mask_util::applyMaskPenaltyRule4(matrix); + mask_util::applyMaskPenaltyRule4(matrix);
} }
/** /**
* @param content text to encode * @param content text to encode
* @param ecLevel error correction level to use * @param ecLevel error correction level to use
* @return {@link QRCode} representing the encoded QR code * @return {@link QRCode} representing the encoded QR code
* @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,
ecLevel:ErrorCorrectionLevel,
hints:EncodingHintDictionary) -> Result<QRCode, Exceptions> {
pub fn encode_with_hints(
content: &str,
ecLevel: ErrorCorrectionLevel,
hints: EncodingHintDictionary,
) -> Result<QRCode, Exceptions> {
let version; let version;
let headerAndDataBits; let mut headerAndDataBits;
let mode; let mode;
let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT) && let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT)
if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() { && if let EncodeHintValue::Gs1Format(v) = hints.get(&EncodeHintType::GS1_FORMAT).unwrap() {
if let Ok(vb) = v.parse::<bool>() { if let Ok(vb) = v.parse::<bool>() {
vb vb
}else { } else {
false false
} }
}else { } else {
false false
}; };
let hasCompactionHint = hints.contains_key(&EncodeHintType::QR_COMPACT) && let hasCompactionHint = hints.contains_key(&EncodeHintType::QR_COMPACT)
if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() { && if let EncodeHintValue::QrCompact(v) = hints.get(&EncodeHintType::QR_COMPACT).unwrap() {
if let Ok(vb) = v.parse::<bool>() { if let Ok(vb) = v.parse::<bool>() {
vb vb
}else { } else {
false false
} }
}else { } else {
false 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 mut encoding = DEFAULT_BYTE_MODE_ENCODING;
let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET); let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
if hasEncodingHint { if hasEncodingHint {
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap() { 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(v).unwrap()
} }
// encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap()); // encoding = encoding::label::encoding_from_whatwg_label(hints.get(&EncodeHintType::CHARACTER_SET).unwrap());
@@ -128,59 +137,67 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
mode = Mode::BYTE; mode = Mode::BYTE;
let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)}; let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
let rn = MinimalEncoder::encode_with_details(content, None, priorityEncoding, hasGS1FormatHint, ecLevel)?; let rn = MinimalEncoder::encode_with_details(
content,
None,
priorityEncoding,
hasGS1FormatHint,
ecLevel,
)?;
headerAndDataBits = BitArray::new(); headerAndDataBits = BitArray::new();
rn.getBits(&headerAndDataBits); rn.getBits(&mut 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 = chooseModeWithEncoding(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.
let headerBits = BitArray::new(); let mut headerBits = BitArray::new();
// Append ECI segment if applicable // Append ECI segment if applicable
if mode == Mode::BYTE && hasEncodingHint { if mode == Mode::BYTE && hasEncodingHint {
let eci = CharacterSetECI::getCharacterSetECI(encoding); let eci = CharacterSetECI::getCharacterSetECI(encoding);
if eci.is_some() { if eci.is_some() {
appendECI(&eci.unwrap(), &headerBits); appendECI(&eci.unwrap(), &mut 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, &mut headerBits);
} }
// (With ECI in place,) Write the mode marker // (With ECI in place,) Write the mode marker
appendModeInfo(mode, &headerBits); appendModeInfo(mode, &mut 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.
let dataBits = BitArray::new(); let mut dataBits = BitArray::new();
appendBytes(content, mode, &dataBits, encoding); appendBytes(content, mode, &mut dataBits, encoding);
if hints.contains_key(&EncodeHintType::QR_VERSION) { if hints.contains_key(&EncodeHintType::QR_VERSION) {
let versionNumber = if let EncodeHintValue::QrVersion(v) = hints.get(&EncodeHintType::QR_VERSION).unwrap() { let versionNumber = if let EncodeHintValue::QrVersion(v) =
hints.get(&EncodeHintType::QR_VERSION).unwrap()
{
if let Ok(vb) = v.parse::<u32>() { if let Ok(vb) = v.parse::<u32>() {
vb vb
}else { } else {
0 0
} }
}else { } else {
0 0
}; };
// let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()()); // let versionNumber = Integer.parseInt(hints.get(&EncodeHintType::QR_VERSION).unwrap()());
version = Version::getVersionForNumber(versionNumber)?; version = Version::getVersionForNumber(versionNumber)?;
let bitsNeeded = calculateBitsNeeded(mode, &headerBits, &dataBits, version); let bitsNeeded = calculateBitsNeeded(mode, &headerBits, &dataBits, version);
if !willFit(bitsNeeded, version, &ecLevel) { if !willFit(bitsNeeded, version, &ecLevel) {
return Err(Exceptions::WriterException("Data too big for requested version".to_owned())) 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)?;
@@ -189,8 +206,12 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
headerAndDataBits = BitArray::new(); 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
let numLetters = if mode == Mode::BYTE {dataBits.getSizeInBytes() }else {content.len()}; let numLetters = if mode == Mode::BYTE {
appendLengthInfo(numLetters as u32, version, mode, &headerAndDataBits); dataBits.getSizeInBytes()
} else {
content.len()
};
appendLengthInfo(numLetters as u32, version, mode, &mut headerAndDataBits);
// Put data together into the overall payload // Put data together into the overall payload
headerAndDataBits.appendBitArray(dataBits); headerAndDataBits.appendBitArray(dataBits);
} }
@@ -199,15 +220,17 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();
// Terminate the bits properly. // Terminate the bits properly.
terminateBits(numDataBytes, &headerAndDataBits); terminateBits(numDataBytes, &mut headerAndDataBits);
// Interleave data bits with error correction code. // Interleave data bits with error correction code.
let finalBits = interleaveWithECBytes(&headerAndDataBits, let finalBits = interleaveWithECBytes(
&headerAndDataBits,
version.getTotalCodewords(), version.getTotalCodewords(),
numDataBytes, numDataBytes,
ecBlocks.getNumBlocks())?; ecBlocks.getNumBlocks(),
)?;
let qrCode = QRCode::new(); let mut qrCode = QRCode::new();
qrCode.setECLevel(ecLevel); qrCode.setECLevel(ecLevel);
qrCode.setMode(mode); qrCode.setMode(mode);
@@ -215,26 +238,32 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
// Choose the mask pattern and set to "qrCode". // Choose the mask pattern and set to "qrCode".
let dimension = version.getDimensionForVersion(); let dimension = version.getDimensionForVersion();
let matrix = ByteMatrix::new(dimension, dimension); let mut 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
let maskPattern = -1; let mut maskPattern = -1;
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) { if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
let hintMaskPattern =if let EncodeHintValue::QrMaskPattern(v) = hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap() { let hintMaskPattern = if let EncodeHintValue::QrMaskPattern(v) =
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
{
if let Ok(vb) = v.parse::<i32>() { if let Ok(vb) = v.parse::<i32>() {
vb vb
}else { } else {
-1 -1
} }
}else { } else {
-1 -1
}; };
// let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()); // let hintMaskPattern = Integer.parseInt(hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap());
maskPattern = if QRCode::isValidMaskPattern(hintMaskPattern) {hintMaskPattern} else {-1}; maskPattern = if QRCode::isValidMaskPattern(hintMaskPattern) {
hintMaskPattern
} else {
-1
};
} }
if maskPattern == -1 { if maskPattern == -1 {
maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &matrix)? as i32; maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &mut matrix)? as i32;
} }
qrCode.setMaskPattern(maskPattern); qrCode.setMaskPattern(maskPattern);
@@ -242,65 +271,71 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix); matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix);
qrCode.setMatrix(matrix); qrCode.setMatrix(matrix);
Ok( qrCode) Ok(qrCode)
} }
/** /**
* Decides the smallest version of QR code that will contain all of the provided data. * Decides the smallest version of QR code that will contain all of the provided data.
* *
* @throws WriterException if the data cannot fit in any version * @throws WriterException if the data cannot fit in any version
*/ */
fn recommendVersion( ecLevel:&ErrorCorrectionLevel, fn recommendVersion(
mode:Mode, ecLevel: &ErrorCorrectionLevel,
headerBits:&BitArray, mode: Mode,
dataBits:&BitArray) -> Result<VersionRef,Exceptions> { headerBits: &BitArray,
dataBits: &BitArray,
) -> Result<VersionRef, Exceptions> {
// 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);
return chooseVersion(bitsNeeded, ecLevel); return chooseVersion(bitsNeeded, ecLevel);
} }
fn calculateBitsNeeded( mode:Mode, fn calculateBitsNeeded(
headerBits:&BitArray, mode: Mode,
dataBits:&BitArray, headerBits: &BitArray,
version:VersionRef) -> u32 { dataBits: &BitArray,
(headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize()) as u32 version: VersionRef,
} ) -> u32 {
(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) -> i8{ pub fn getAlphanumericCode(code: u32) -> i8 {
let code = code as usize; let code = code as usize;
if code < ALPHANUMERIC_TABLE.len() { if code < ALPHANUMERIC_TABLE.len() {
ALPHANUMERIC_TABLE[code] ALPHANUMERIC_TABLE[code]
}else{ } else {
-1 -1
} }
} }
pub fn chooseMode( content:&str) -> Mode{ pub fn chooseMode(content: &str) -> Mode {
return chooseModeWithEncoding(content, encoding::all::ISO_8859_1); 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:EncodingRef) -> Mode{ fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) { if SHIFT_JIS_CHARSET.name() == encoding.name() && isOnlyDoubleByteKanji(content) {
// if (StringUtils.SHIFT_JIS_CHARSET.equals(encoding) && 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;
} }
let hasNumeric = false; let mut hasNumeric = false;
let hasAlphanumeric = false; let mut hasAlphanumeric = false;
for i in 0..content.len() { for i in 0..content.len() {
// for (int i = 0; i < content.length(); ++i) { // for (int i = 0; i < content.length(); ++i) {
let c = content.chars().nth(i).unwrap(); let c = content.chars().nth(i).unwrap();
@@ -319,10 +354,12 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
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 = SHIFT_JIS_CHARSET.encode(content,encoding::EncoderTrap::Strict).expect("encode"); 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;
@@ -334,32 +371,36 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
if (byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB) { if (byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB) {
return false; return false;
} }
i+=2; i += 2;
} }
return true; return true;
} }
fn chooseMaskPattern( bits:&BitArray, fn chooseMaskPattern(
ecLevel:&ErrorCorrectionLevel, bits: &BitArray,
version:VersionRef, ecLevel: &ErrorCorrectionLevel,
matrix:&ByteMatrix) -> Result<u32, Exceptions> { version: VersionRef,
matrix: &mut ByteMatrix,
let minPenalty = u32::MAX; // Lower penalty is better. ) -> Result<u32, Exceptions> {
let bestMaskPattern = -1; let mut minPenalty = u32::MAX; // Lower penalty is better.
let mut bestMaskPattern = -1;
// 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, &mut matrix); matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, matrix);
let penalty = calculateMaskPenalty(matrix); let penalty = calculateMaskPenalty(matrix);
if penalty < minPenalty { if penalty < minPenalty {
minPenalty = penalty; minPenalty = penalty;
bestMaskPattern = maskPattern; bestMaskPattern = maskPattern;
} }
} }
Ok( bestMaskPattern as u32 ) 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)?;
@@ -368,13 +409,13 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
} }
} }
Err(Exceptions::WriterException("Data too big".to_owned())) Err(Exceptions::WriterException("Data too big".to_owned()))
} }
/** /**
* @return true if the number of input bits will fit in a code with the specified version and * @return true if the number of input bits will fit in a code with the specified version and
* error correction level. * error correction level.
*/ */
pub fn willFit( numInputBits:u32, version:VersionRef, ecLevel:&ErrorCorrectionLevel) -> bool { pub fn willFit(numInputBits: u32, version: VersionRef, ecLevel: &ErrorCorrectionLevel) -> bool {
// In the following comments, we use numbers of Version 7-H. // In the following comments, we use numbers of Version 7-H.
// numBytes = 196 // numBytes = 196
let numBytes = version.getTotalCodewords(); let numBytes = version.getTotalCodewords();
@@ -385,22 +426,26 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
let numDataBytes = numBytes - numEcBytes; let numDataBytes = numBytes - numEcBytes;
let totalInputBytes = (numInputBits + 7) / 8; let totalInputBytes = (numInputBits + 7) / 8;
return numDataBytes >= totalInputBytes; return numDataBytes >= totalInputBytes;
} }
/** /**
* Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
*/ */
pub fn terminateBits( numDataBytes:u32, bits:&BitArray) -> Result<(),Exceptions> { pub fn terminateBits(numDataBytes: u32, bits: &mut BitArray) -> Result<(), Exceptions> {
let capacity = numDataBytes * 8; let capacity = numDataBytes * 8;
if bits.getSize() > capacity as usize { if bits.getSize() > capacity as usize {
return Err(Exceptions::WriterException(format!("data bits cannot fit in the QR Code{} > " , return Err(Exceptions::WriterException(format!(
capacity))) "data bits cannot fit in the QR Code{} > ",
capacity
)));
// throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + // throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " +
// capacity); // capacity);
} }
// Append Mode.TERMINATE if there is enough space (value is 0000) // Append Mode.TERMINATE if there is enough space (value is 0000)
for i in 0..4 { for i in 0..4 {
if bits.getSize() > 0 { break } if bits.getSize() > 0 {
break;
}
// } // }
// for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { // for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) {
bits.appendBit(false); bits.appendBit(false);
@@ -418,28 +463,32 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
let numPaddingBytes = numDataBytes as usize - bits.getSizeInBytes(); let numPaddingBytes = numDataBytes as usize - bits.getSizeInBytes();
for i in 0..numPaddingBytes { for i in 0..numPaddingBytes {
// for (int i = 0; i < numPaddingBytes; ++i) { // for (int i = 0; i < numPaddingBytes; ++i) {
bits.appendBits(if (i & 0x01) == 0 {0xEC} else {0x11}, 8); bits.appendBits(if (i & 0x01) == 0 { 0xEC } else { 0x11 }, 8);
} }
if bits.getSize() != capacity as usize { if bits.getSize() != capacity as usize {
return Err(Exceptions::WriterException("Bits size does not equal capacity".to_owned())) return Err(Exceptions::WriterException(
"Bits size does not equal capacity".to_owned(),
));
// throw new WriterException("Bits size does not equal capacity"); // throw new WriterException("Bits size does not equal capacity");
} }
Ok(()) Ok(())
} }
/** /**
* Get number of data bytes and number of error correction bytes for block id "blockID". Store * Get number of data bytes and number of error correction bytes for block id "blockID". Store
* the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of
* JISX0510:2004 (p.30) * JISX0510:2004 (p.30)
*/ */
pub fn getNumDataBytesAndNumECBytesForBlockID( numTotalBytes:u32, pub fn getNumDataBytesAndNumECBytesForBlockID(
numDataBytes:u32, numTotalBytes: u32,
numRSBlocks:u32, numDataBytes: u32,
blockID:u32, numRSBlocks: u32,
numDataBytesInBlock:&[u32], blockID: u32,
numECBytesInBlock:&[u32]) -> Result<(),Exceptions> { numDataBytesInBlock: &mut [u32],
numECBytesInBlock: &mut [u32],
) -> Result<(), Exceptions> {
if blockID >= numRSBlocks { if blockID >= numRSBlocks {
return Err(Exceptions::WriterException("Block ID too large".to_owned())) return Err(Exceptions::WriterException("Block ID too large".to_owned()));
// throw new WriterException("Block ID too large"); // throw new WriterException("Block ID too large");
} }
// numRsBlocksInGroup2 = 196 % 5 = 1 // numRsBlocksInGroup2 = 196 % 5 = 1
@@ -461,22 +510,23 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
// Sanity checks. // Sanity checks.
// 26 = 26 // 26 = 26
if (numEcBytesInGroup1 != numEcBytesInGroup2) { if (numEcBytesInGroup1 != numEcBytesInGroup2) {
return Err(Exceptions::WriterException("EC bytes mismatch".to_owned())) return Err(Exceptions::WriterException("EC bytes mismatch".to_owned()));
// throw new WriterException("EC bytes mismatch"); // throw new WriterException("EC bytes mismatch");
} }
// 5 = 4 + 1. // 5 = 4 + 1.
if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) {
return Err(Exceptions::WriterException("RS blocks mismatch".to_owned())) return Err(Exceptions::WriterException("RS blocks mismatch".to_owned()));
// throw new WriterException("RS blocks mismatch"); // throw new WriterException("RS blocks mismatch");
} }
// 196 = (13 + 26) * 4 + (14 + 26) * 1 // 196 = (13 + 26) * 4 + (14 + 26) * 1
if (numTotalBytes != if (numTotalBytes
((numDataBytesInGroup1 + numEcBytesInGroup1) * != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1)
numRsBlocksInGroup1) + + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2))
((numDataBytesInGroup2 + numEcBytesInGroup2) * {
numRsBlocksInGroup2)) { return Err(Exceptions::WriterException(
return Err(Exceptions::WriterException("Total bytes mismatch".to_owned())) "Total bytes mismatch".to_owned(),
));
// throw new WriterException("Total bytes mismatch"); // throw new WriterException("Total bytes mismatch");
} }
@@ -489,59 +539,69 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
numECBytesInBlock[0] = numEcBytesInGroup2; numECBytesInBlock[0] = numEcBytesInGroup2;
} }
Ok(()) Ok(())
} }
/** /**
* Interleave "bits" with corresponding error correction bytes. On success, store the result in * Interleave "bits" with corresponding error correction bytes. On success, store the result in
* "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details.
*/ */
pub fn interleaveWithECBytes( bits:&BitArray, pub fn interleaveWithECBytes(
numTotalBytes:u32, bits: &BitArray,
numDataBytes:u32, numTotalBytes: u32,
numRSBlocks:u32) -> Result<BitArray,Exceptions> { numDataBytes: u32,
numRSBlocks: u32,
) -> Result<BitArray, Exceptions> {
// "bits" must have "getNumDataBytes" bytes of data. // "bits" must have "getNumDataBytes" bytes of data.
if bits.getSizeInBytes() as u32 != 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(),
));
} }
// Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll
// store the divided data bytes blocks and error correction bytes blocks into "blocks". // store the divided data bytes blocks and error correction bytes blocks into "blocks".
let dataBytesOffset = 0; let mut dataBytesOffset = 0;
let maxNumDataBytes = 0; let mut maxNumDataBytes = 0;
let maxNumEcBytes = 0; let mut maxNumEcBytes = 0;
// Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number.
let blocks = Vec::new(); let mut blocks = Vec::new();
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 = vec![0;1];//new int[1]; let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
let numEcBytesInBlock = vec![0;1];//new int[1]; let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
getNumDataBytesAndNumECBytesForBlockID( getNumDataBytesAndNumECBytesForBlockID(
numTotalBytes, numDataBytes, numRSBlocks, i, numTotalBytes,
&numDataBytesInBlock, &numEcBytesInBlock); numDataBytes,
numRSBlocks,
i,
&mut numDataBytesInBlock,
&mut numEcBytesInBlock,
);
let size = numDataBytesInBlock[0]; let size = numDataBytesInBlock[0];
let dataBytes = vec![0u8;size as usize]; let mut dataBytes = vec![0u8; size as usize];
bits.toBytes(8 * dataBytesOffset, &mut dataBytes, 0, size as usize); bits.toBytes(8 * dataBytesOffset, &mut dataBytes, 0, size as usize);
let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock[0] as usize); let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock[0] as usize);
blocks.push( BlockPair::new(dataBytes, ecBytes)); blocks.push(BlockPair::new(dataBytes, ecBytes.clone()));
maxNumDataBytes = maxNumDataBytes.max( size); maxNumDataBytes = maxNumDataBytes.max(size);
maxNumEcBytes = maxNumEcBytes.max( ecBytes.len()); maxNumEcBytes = maxNumEcBytes.max(ecBytes.len());
dataBytesOffset += numDataBytesInBlock[0] as usize; dataBytesOffset += numDataBytesInBlock[0] as usize;
} }
if numDataBytes != dataBytesOffset as u32 { 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 mut result = BitArray::new();
// First, place data blocks. // First, place data blocks.
for i in 0..maxNumDataBytes as usize{ for i in 0..maxNumDataBytes as usize {
// for (int i = 0; i < maxNumDataBytes; ++i) { // for (int i = 0; i < maxNumDataBytes; ++i) {
for block in blocks { for block in &blocks {
// for (BlockPair block : blocks) { // for (BlockPair block : blocks) {
let dataBytes = block.getDataBytes(); let dataBytes = block.getDataBytes();
if i < dataBytes.len() { if i < dataBytes.len() {
@@ -552,7 +612,7 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
// Then, place error correction blocks. // Then, place error correction blocks.
for i in 0..maxNumEcBytes { for i in 0..maxNumEcBytes {
// for (int i = 0; i < maxNumEcBytes; ++i) { // for (int i = 0; i < maxNumEcBytes; ++i) {
for block in blocks { for block in &blocks {
// for (BlockPair block : blocks) { // for (BlockPair block : blocks) {
let ecBytes = block.getErrorCorrectionBytes(); let ecBytes = block.getErrorCorrectionBytes();
if (i < ecBytes.len()) { if (i < ecBytes.len()) {
@@ -560,75 +620,91 @@ static ref SHIFT_JIS_CHARSET : EncodingRef = encoding::label::encoding_from_what
} }
} }
} }
if (numTotalBytes != result.getSizeInBytes() as u32) { // Should be same. if (numTotalBytes != result.getSizeInBytes() as u32) {
return Err( // Should be same.
Exceptions::WriterException( return Err(Exceptions::WriterException(format!(
format!(
"Interleaving error: {} and {} differ.", "Interleaving error: {} and {} differ.",
numTotalBytes,result.getSizeInBytes() numTotalBytes,
) result.getSizeInBytes()
) )));
)
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " + // throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
// result.getSizeInBytes() + " differ."); // result.getSizeInBytes() + " differ.");
} }
Ok(result) Ok(result)
} }
pub fn generateECBytes( dataBytes:&[u8], numEcBytesInBlock:usize) -> Vec<u8> { pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec<u8> {
let numDataBytes = dataBytes.len(); let numDataBytes = dataBytes.len();
let toEncode = vec![0;numDataBytes + numEcBytesInBlock]; let mut 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] as i32; 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);
let ecBytes = vec![0u8;numEcBytesInBlock]; let mut 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] as u8; ecBytes[i] = toEncode[numDataBytes + i] as u8;
} }
return ecBytes; return ecBytes;
} }
/** /**
* 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: &mut BitArray) {
bits.appendBits(mode.getBits() as u32, 4); bits.appendBits(mode.getBits() as u32, 4);
} }
/**
/**
* Append length info. On success, store the result in "bits". * Append length info. On success, store the result in "bits".
*/ */
pub fn appendLengthInfo( numLetters:u32, version:VersionRef, mode:Mode, bits:&BitArray) -> Result<(),Exceptions> { pub fn appendLengthInfo(
numLetters: u32,
version: VersionRef,
mode: Mode,
bits: &mut BitArray,
) -> Result<(), Exceptions> {
let numBits = mode.getCharacterCountBits(version); let numBits = mode.getCharacterCountBits(version);
if numLetters >= (1 << numBits) { if numLetters >= (1 << numBits) {
return Err(Exceptions::WriterException(format!("{} is bigger than {}" ,numLetters , ((1 << numBits) - 1)))) return Err(Exceptions::WriterException(format!(
"{} is bigger than {}",
numLetters,
((1 << numBits) - 1)
)));
} }
bits.appendBits(numLetters, numBits as usize); bits.appendBits(numLetters, numBits as usize);
Ok(()) Ok(())
} }
/** /**
* Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits".
*/ */
pub fn appendBytes( content:&str, pub fn appendBytes(
mode:Mode, content: &str,
bits:&BitArray, mode: Mode,
encoding:EncodingRef) -> Result<(),Exceptions>{ bits: &mut BitArray,
encoding: EncodingRef,
) -> Result<(), Exceptions> {
match mode { match mode {
Mode::NUMERIC => appendNumericBytes(content, bits), Mode::NUMERIC => appendNumericBytes(content, bits),
Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits)?, Mode::ALPHANUMERIC => appendAlphanumericBytes(content, bits)?,
Mode::BYTE => append8BitBytes(content, bits, encoding), Mode::BYTE => append8BitBytes(content, bits, encoding),
Mode::KANJI => appendKanjiBytes(content, bits)?, Mode::KANJI => appendKanjiBytes(content, bits)?,
_=> return Err(Exceptions::WriterException(format!("Invalid mode: {:?}" , mode))) _ => {
return Err(Exceptions::WriterException(format!(
"Invalid mode: {:?}",
mode
)))
}
}; };
Ok(()) Ok(())
// switch (mode) { // switch (mode) {
// case NUMERIC: // case NUMERIC:
// appendNumericBytes(content, bits); // appendNumericBytes(content, bits);
@@ -645,11 +721,11 @@ Ok(())
// default: // default:
// throw new WriterException("Invalid mode: " + mode); // throw new WriterException("Invalid mode: " + mode);
// } // }
} }
pub fn appendNumericBytes( content:&str, bits:&BitArray) { pub fn appendNumericBytes(content: &str, bits: &mut BitArray) {
let length = content.len(); let length = content.len();
let i = 0; let mut i = 0;
while i < length { while i < length {
let num1 = content.chars().nth(i).unwrap() as u8 - b'0'; let num1 = content.chars().nth(i).unwrap() as u8 - b'0';
if i + 2 < length { if i + 2 < length {
@@ -666,14 +742,14 @@ Ok(())
} else { } else {
// Encode one numeric letter in four bits. // Encode one numeric letter in four bits.
bits.appendBits(num1 as u32, 4); bits.appendBits(num1 as u32, 4);
i+=1; i += 1;
}
} }
} }
}
pub fn appendAlphanumericBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> { pub fn appendAlphanumericBytes(content: &str, bits: &mut BitArray) -> Result<(), Exceptions> {
let length = content.len(); let length = content.len();
let i = 0; let mut i = 0;
while i < length { while i < length {
let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32); let code1 = getAlphanumericCode(content.chars().nth(i).unwrap() as u32);
if code1 == -1 { if code1 == -1 {
@@ -683,7 +759,6 @@ Ok(())
let code2 = getAlphanumericCode(content.chars().nth(i + 1).unwrap() as u32); 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) as u32, 11); bits.appendBits((code1 * 45 + code2) as u32, 11);
@@ -691,56 +766,63 @@ Ok(())
} else { } else {
// Encode one alphanumeric letter in six bits. // Encode one alphanumeric letter in six bits.
bits.appendBits(code1 as u32, 6); bits.appendBits(code1 as u32, 6);
i+=1; i += 1;
} }
} }
Ok(()) Ok(())
} }
fn append8BitBytes( content:&str, bits:&BitArray, encoding:EncodingRef) { fn append8BitBytes(content: &str, bits: &mut BitArray, encoding: EncodingRef) {
let bytes = encoding.encode(content, encoding::EncoderTrap::Strict).expect("should encode"); let bytes = encoding
.encode(content, encoding::EncoderTrap::Strict)
.expect("should encode");
// let bytes = content.getBytes(encoding); // let bytes = content.getBytes(encoding);
for b in bytes { for b in bytes {
// for (byte b : bytes) { // for (byte b : bytes) {
bits.appendBits(b as u32, 8); bits.appendBits(b as u32, 8);
} }
} }
fn appendKanjiBytes( content:&str, bits:&BitArray) -> Result<(),Exceptions> { 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; //encoding::label::encoding_from_whatwg_label("SJIS").unwrap();
let bytes = sjis.encode(content, encoding::EncoderTrap::Strict).expect("should encode fine"); let bytes = sjis
.encode(content, encoding::EncoderTrap::Strict)
.expect("should encode fine");
// let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET); // let bytes = content.getBytes(StringUtils::SHIFT_JIS_CHARSET);
if bytes.len() % 2 != 0 { 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.len() - 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:u16 = ((byte1 as u16) << 8u16) | byte2 as u16;
let subtracted:i32 = -1; let mut subtracted: i32 = -1;
if code >= 0x8140 && code <= 0x9ffc { if code >= 0x8140 && code <= 0x9ffc {
subtracted = code as i32 - 0x8140; subtracted = code as i32 - 0x8140;
} else if code >= 0xe040 && code <= 0xebbf { } else if code >= 0xe040 && code <= 0xebbf {
subtracted = code as i32 - 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 as u32, 13); bits.appendBits(encoded as u32, 13);
i+=2; i += 2;
} }
Ok(()) Ok(())
} }
fn appendECI( eci:&CharacterSetECI, bits:&BitArray) { fn appendECI(eci: &CharacterSetECI, bits: &mut BitArray) {
bits.appendBits(Mode::ECI.getBits() as u32, 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.getValueSelf(), 8); bits.appendBits(eci.getValueSelf(), 8);
} }

View File

@@ -18,15 +18,18 @@ use std::{fmt, rc::Rc};
use encoding::EncodingRef; use encoding::EncodingRef;
use crate::{common::{ECIEncoderSet, BitArray}, qrcode::decoder::{ErrorCorrectionLevel, Version, Mode, VersionRef}, Exceptions}; use crate::{
common::{BitArray, ECIEncoderSet},
qrcode::decoder::{ErrorCorrectionLevel, Mode, Version, VersionRef},
Exceptions,
};
use super::encoder; use super::encoder;
pub enum VersionSize {
enum VersionSize { SMALL, //("version 1-9"),
SMALL,//("version 1-9"), MEDIUM, //("version 10-26"),
MEDIUM,//("version 10-26"), LARGE, //("version 27-40");
LARGE,//("version 27-40");
// private final String description; // private final String description;
@@ -41,15 +44,18 @@ enum VersionSize {
impl fmt::Display for VersionSize { impl fmt::Display for VersionSize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( f, "{}", match self { write!(
f,
"{}",
match self {
VersionSize::SMALL => "version 1-9", VersionSize::SMALL => "version 1-9",
VersionSize::MEDIUM => "version 10-26", VersionSize::MEDIUM => "version 10-26",
VersionSize::LARGE => "version 27-40", VersionSize::LARGE => "version 27-40",
}) }
)
} }
} }
/** /**
* Encoder that encodes minimally * Encoder that encodes minimally
* *
@@ -77,16 +83,14 @@ impl fmt::Display for VersionSize {
* *
* @author Alex Geller * @author Alex Geller
*/ */
pub struct MinimalEncoder<'a> { pub struct MinimalEncoder {
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,16 +103,20 @@ impl MinimalEncoder<'_> {
* @param ecLevel The error correction level. * @param ecLevel The error correction level.
* @see RXingResultList#getVersion * @see RXingResultList#getVersion
*/ */
pub fn new( stringToEncode:&str, priorityCharset: EncodingRef, isGS1:bool, ecLevel:ErrorCorrectionLevel) -> Self { pub fn new(
stringToEncode: &str,
priorityCharset: EncodingRef,
isGS1: bool,
ecLevel: ErrorCorrectionLevel,
) -> Self {
Self { Self {
stringToEncode, stringToEncode: String::from(stringToEncode),
isGS1, isGS1,
encoders: ECIEncoderSet::new(&stringToEncode, priorityCharset, -1), encoders: ECIEncoderSet::new(&stringToEncode, priorityCharset, -1),
ecLevel, ecLevel,
} }
// let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1); // let encoders = ECIEncoderSet::new(&stringToEncode, priorityCharset, -1);
} }
/** /**
@@ -128,21 +136,31 @@ impl MinimalEncoder<'_> {
* @see RXingResultList#getVersion * @see RXingResultList#getVersion
* @see RXingResultList#getSize * @see RXingResultList#getSize
*/ */
pub fn encode_with_details<'a>( stringToEncode:&str, version:Option<VersionRef>, priorityCharset:EncodingRef, isGS1:bool, pub fn encode_with_details(
ecLevel:ErrorCorrectionLevel) -> Result<RXingResultList<'a>,Exceptions> { stringToEncode: &str,
version: Option<VersionRef>,
priorityCharset: EncodingRef,
isGS1: bool,
ecLevel: ErrorCorrectionLevel,
) -> Result<RXingResultList, Exceptions> {
MinimalEncoder::new(stringToEncode, priorityCharset, isGS1, ecLevel).encode(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> {
if version.is_none() { // compute minimal encoding trying the three version sizes. if version.is_none() {
let versions = [ Self::getVersion(VersionSize::SMALL), // compute minimal encoding trying the three version sizes.
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 smallestRXingResult:i32 = -1; let mut smallestSize = u32::MAX;
let mut 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();
@@ -152,25 +170,42 @@ impl MinimalEncoder<'_> {
} }
} }
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(),
));
} }
Ok(results[smallestRXingResult as usize]) Ok(results[smallestRXingResult as usize].clone())
} else { // compute minimal encoding for a given version } else {
// compute minimal encoding for a given version
let version = version.unwrap(); let version = version.unwrap();
let result = self.encodeSpecificVersion(version)?; let result = self.encodeSpecificVersion(version)?;
if !encoder::willFit(result.getSize(), Self::getVersion(Self::getVersionSize(result.getVersion())), &self.ecLevel) { if !encoder::willFit(
return Err(Exceptions::WriterException(format!("Data too big for version {}" , version))); result.getSize(),
Self::getVersion(Self::getVersionSize(result.getVersion())),
&self.ecLevel,
) {
return Err(Exceptions::WriterException(format!(
"Data too big for version {}",
version
)));
} }
Ok(result) Ok(result)
} }
} }
pub fn getVersionSize( version:&Version) -> VersionSize { pub fn getVersionSize(version: VersionRef) -> VersionSize {
return if version.getVersionNumber() <= 9 { VersionSize::SMALL} else {if version.getVersionNumber() <= 26 return if version.getVersionNumber() <= 9 {
{VersionSize::MEDIUM} else {VersionSize::LARGE}}; VersionSize::SMALL
} else {
if version.getVersionNumber() <= 26 {
VersionSize::MEDIUM
} else {
VersionSize::LARGE
}
};
} }
pub fn getVersion( versionSize:VersionSize)->VersionRef { pub fn getVersion(versionSize: VersionSize) -> VersionRef {
match versionSize { match versionSize {
VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"), VersionSize::SMALL => Version::getVersionForNumber(9).expect("should always exist"),
VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"), VersionSize::MEDIUM => Version::getVersionForNumber(26).expect("should always exist"),
@@ -187,31 +222,31 @@ impl MinimalEncoder<'_> {
// } // }
} }
pub fn isNumeric( c:char) -> bool{ pub fn isNumeric(c: char) -> bool {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';
} }
pub fn isDoubleByteKanji( c:char) -> bool{ pub fn isDoubleByteKanji(c: char) -> bool {
return encoder::isOnlyDoubleByteKanji(&String::from(c)); return encoder::isOnlyDoubleByteKanji(&String::from(c));
} }
pub fn isAlphanumeric( c: char) -> bool{ pub fn isAlphanumeric(c: char) -> bool {
return encoder::getAlphanumericCode(c as u8 as u32) != -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 {
match mode { match mode {
Mode::NUMERIC => Self::isNumeric(c), Mode::NUMERIC => Self::isNumeric(c),
Mode::ALPHANUMERIC => Self::isAlphanumeric(c), Mode::ALPHANUMERIC => Self::isAlphanumeric(c),
Mode::STRUCTURED_APPEND => todo!(), Mode::STRUCTURED_APPEND => todo!(),
Mode::BYTE => true, Mode::BYTE => true,
Mode::KANJI => Self::isDoubleByteKanji(c), Mode::KANJI => Self::isDoubleByteKanji(c),
_=> false,// any character can be encoded as byte(s). Up to the caller to manage splitting into _ => false, // any character can be encoded as byte(s). Up to the caller to manage splitting into
// multiple bytes when String.getBytes(Charset) return more than one byte. // multiple bytes when String.getBytes(Charset) return more than one byte.
} }
} }
pub fn getCompactedOrdinal( mode:Option<Mode>) -> Result<u32,Exceptions>{ pub fn getCompactedOrdinal(mode: Option<Mode>) -> Result<u32, Exceptions> {
if mode.is_none() { if mode.is_none() {
return Ok(0); return Ok(0);
} }
@@ -220,7 +255,10 @@ impl MinimalEncoder<'_> {
Mode::ALPHANUMERIC => Ok(1), Mode::ALPHANUMERIC => Ok(1),
Mode::BYTE => Ok(3), Mode::BYTE => Ok(3),
Mode::KANJI => Ok(0), Mode::KANJI => Ok(0),
_=> Err(Exceptions::IllegalArgumentException(format!("Illegal mode {:?}", mode))), _ => Err(Exceptions::IllegalArgumentException(format!(
"Illegal mode {:?}",
mode
))),
} }
// switch (mode) { // switch (mode) {
// case KANJI: // case KANJI:
@@ -236,49 +274,157 @@ impl MinimalEncoder<'_> {
// } // }
} }
pub fn addEdge(&self, edges:&Vec<Vec<Vec<Option<&'_ Edge>>>>, position:usize, edge:Option<&Edge>) { pub fn addEdge(
&self,
edges: &mut Vec<Vec<Vec<Option<Rc<Edge>>>>>,
position: usize,
edge: Option<Rc<Edge>>,
) {
let vertexIndex = position + edge.as_ref().unwrap().characterLength as usize; 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 =
let modeOrdinal = Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize; &mut edges[vertexIndex as usize][edge.as_ref().unwrap().charsetEncoderIndex as usize];
if modeEdges[modeOrdinal].is_none() || modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize > (&edge).unwrap().cachedTotalSize { let modeOrdinal =
Self::getCompactedOrdinal(Some(edge.as_ref().unwrap().mode)).expect("value") as usize;
if modeEdges[modeOrdinal].is_none()
|| modeEdges[modeOrdinal].as_ref().unwrap().cachedTotalSize
> edge.as_ref().unwrap().cachedTotalSize
{
modeEdges[modeOrdinal] = edge; modeEdges[modeOrdinal] = edge;
} }
} }
pub fn addEdges( &self, version:VersionRef, edges:&Vec<Vec<Vec<Option<&Edge>>>>, from:usize, previous:Option<&Edge>) { pub fn addEdges(
let start = 0; &self,
let end = self.encoders.len(); version: VersionRef,
edges: &mut Vec<Vec<Vec<Option<Rc<Edge>>>>>,
from: usize,
previous: Option<Rc<Edge>>,
) {
let mut start = 0;
let mut 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 as usize).unwrap() as i16,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() as i16, i) { if self
self.addEdge(edges, from, Some(&Edge::new(Mode::BYTE, from, i, 1, previous, version,&self.encoders,&self.stringToEncode))); .encoders
.canEncode(self.stringToEncode.chars().nth(from).unwrap() as i16, i)
{
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::BYTE,
from,
i,
1,
previous.clone(),
version,
self.encoders.clone(),
&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, Some(&Edge::new(Mode::KANJI, from, 0, 1, previous, version,&self.encoders,&self.stringToEncode))); self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::KANJI,
from,
0,
1,
previous.clone(),
version,
self.encoders.clone(),
&self.stringToEncode,
))),
);
} }
let inputLength = self.stringToEncode.len(); let inputLength = self.stringToEncode.len();
if self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from).unwrap()) { if self.canEncode(
self.addEdge(edges, from, Some(&Edge::new(Mode::ALPHANUMERIC, from, 0, if from + 1 >= inputLength || &Mode::ALPHANUMERIC,
!self.canEncode(&Mode::ALPHANUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {2}, previous, version,&self.encoders,&self.stringToEncode))); self.stringToEncode.chars().nth(from).unwrap(),
) {
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::ALPHANUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self.canEncode(
&Mode::ALPHANUMERIC,
self.stringToEncode.chars().nth(from + 1).unwrap(),
)
{
1
} else {
2
},
previous.clone(),
version,
self.encoders.clone(),
&self.stringToEncode,
))),
);
} }
if self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from).unwrap()) { if self.canEncode(
self.addEdge(edges, from, Some(&Edge::new(Mode::NUMERIC, from, 0, if from + 1 >= inputLength || &Mode::NUMERIC,
!self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 1).unwrap()) {1} else {if from + 2 >= inputLength || self.stringToEncode.chars().nth(from).unwrap(),
!self.canEncode(&Mode::NUMERIC, self.stringToEncode.chars().nth(from + 2).unwrap()) {2} else {3}}, previous, version,&self.encoders,&self.stringToEncode))); ) {
self.addEdge(
edges,
from,
Some(Rc::new(Edge::new(
Mode::NUMERIC,
from,
0,
if from + 1 >= inputLength
|| !self.canEncode(
&Mode::NUMERIC,
self.stringToEncode.chars().nth(from + 1).unwrap(),
)
{
1
} else {
if from + 2 >= inputLength
|| !self.canEncode(
&Mode::NUMERIC,
self.stringToEncode.chars().nth(from + 2).unwrap(),
)
{
2
} else {
3
}
},
previous.clone(),
version,
self.encoders.clone(),
&self.stringToEncode,
))),
);
} }
} }
pub fn encodeSpecificVersion(&self, version:VersionRef) ->Result< RXingResultList, Exceptions >{ pub fn encodeSpecificVersion(
&self,
version: VersionRef,
) -> Result<RXingResultList, Exceptions> {
// @SuppressWarnings("checkstyle:lineLength") // @SuppressWarnings("checkstyle:lineLength")
/* A vertex represents a tuple of a position in the input, a mode and a character encoding where position 0 /* A vertex represents a tuple of a position in the input, a mode and a character encoding where position 0
* denotes the position left of the first character, 1 the position left of the second character and so on. * denotes the position left of the first character, 1 the position left of the second character and so on.
@@ -397,8 +543,8 @@ 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![None;4];self.encoders.len()];inputLength+1];//new Edge[inputLength + 1][encoders.length()][4]; let mut 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, &mut edges, 0, None);
for i in 1..=inputLength { for i in 1..=inputLength {
// for (int i = 1; i <= inputLength; i++) { // for (int i = 1; i <= inputLength; i++) {
@@ -407,15 +553,15 @@ impl MinimalEncoder<'_> {
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].is_some() && i < inputLength { if edges[i][j][k].is_some() && i < inputLength {
self.addEdges(version, &edges, i, edges[i][j][k]); let e = edges[i][j][k].clone();
self.addEdges(version, &mut edges, i, e);
} }
} }
} }
} }
let minimalJ = None; let mut minimalJ = None;
let minimalK = None; let mut minimalK = None;
let minimalSize = u32::MAX; let mut 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 {
@@ -431,58 +577,96 @@ impl MinimalEncoder<'_> {
} }
} }
if minimalJ.is_none() { 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.unwrap()][minimalK.unwrap()].unwrap(),self.isGS1,&self.ecLevel, &self.encoders, &self.stringToEncode)) Ok(RXingResultList::new(
version,
edges[inputLength][minimalJ.unwrap()][minimalK.unwrap()].as_ref().unwrap().clone(),
self.isGS1,
&self.ecLevel,
self.encoders.clone(),
&self.stringToEncode,
))
} }
} }
pub struct Edge {
struct Edge<'a> { pub mode: Mode,
pub mode:Mode, fromPosition: usize,
fromPosition:usize, charsetEncoderIndex: usize,
charsetEncoderIndex:usize, characterLength: u32,
characterLength:u32, previous: Option<Rc<Edge>>,
previous:Option<&'a Edge<'a>>, cachedTotalSize: u32,
cachedTotalSize:u32, encoders: ECIEncoderSet,
encoders:&'a ECIEncoderSet, stringToEncode: String,
stringToEncode: &'a str,
} }
impl Edge<'_> { impl Edge {
pub fn new(
pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, previous:Option<&'_ Edge>, mode: Mode,
version:&Version, encoders: &'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self { fromPosition: usize,
let nci = if mode == Mode::BYTE || previous.is_none() {charsetEncoderIndex} else charsetEncoderIndex: usize,
{previous.as_ref().unwrap().charsetEncoderIndex}; characterLength: u32,
previous: Option<Rc<Edge>>,
version: VersionRef,
encoders: ECIEncoderSet,
stringToEncode: &'_ str,
) -> Self {
let nci = if mode == Mode::BYTE || previous.is_none() {
charsetEncoderIndex
} else {
previous.as_ref().unwrap().charsetEncoderIndex
};
Self { Self {
mode, mode,
fromPosition, fromPosition,
charsetEncoderIndex: nci, charsetEncoderIndex: nci,
characterLength, characterLength,
previous, previous: previous.clone(),
stringToEncode, stringToEncode: String::from(stringToEncode),
cachedTotalSize: { cachedTotalSize: {
let size = if previous.is_some() {previous.as_ref().unwrap().cachedTotalSize} else {0}; let mut size = if previous.is_some() {
previous.as_ref().unwrap().cachedTotalSize
} else {
0
};
let needECI = mode == Mode::BYTE && let needECI = mode == Mode::BYTE &&
(previous.is_none() && nci != 0) || // at the beginning and charset is not ISO-8859-1 (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().unwrap().charsetEncoderIndex);
if previous.is_none()|| mode != previous.as_ref().unwrap().mode || needECI { if previous.is_none() || mode != previous.as_ref().unwrap().mode || needECI {
size += 4 + mode.getCharacterCountBits(&version) as u32; size += 4 + mode.getCharacterCountBits(&version) as u32;
} }
match mode { match mode {
Mode::NUMERIC => size += if characterLength == 1 {4} else {if characterLength == 2 {7} else {10}}, Mode::NUMERIC => {
Mode::ALPHANUMERIC => size += if characterLength == 1 {6} else {11}, size += if characterLength == 1 {
Mode::BYTE =>{ 4
size += 8 * encoders.encode_string(&stringToEncode[fromPosition as usize..(fromPosition + characterLength as usize)], } else {
charsetEncoderIndex as usize).len() as u32; if characterLength == 2 {
7
} else {
10
}
}
}
Mode::ALPHANUMERIC => size += if characterLength == 1 { 6 } else { 11 },
Mode::BYTE => {
size += 8 * encoders
.encode_string(
&stringToEncode[fromPosition as usize
..(fromPosition + characterLength as usize)],
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
} }
}, }
Mode::KANJI => size += 13, Mode::KANJI => size += 13,
_=> {}, _ => {}
} }
// switch (mode) { // switch (mode) {
// case KANJI: // case KANJI:
@@ -504,7 +688,7 @@ impl Edge<'_> {
// } // }
size size
}, },
encoders encoders,
} }
// this.mode = mode; // this.mode = mode;
// this.fromPosition = fromPosition; // this.fromPosition = fromPosition;
@@ -544,21 +728,28 @@ impl Edge<'_> {
} }
} }
struct RXingResultList<'a> { #[derive(Clone)]
list: Vec<RXingResultNode<'a>>, pub struct RXingResultList {
list: Vec<RXingResultNode>,
version: VersionRef, version: VersionRef,
} }
impl RXingResultList<'_> { impl RXingResultList {
pub fn new(
pub fn new( version:VersionRef, solution:&'_ Edge, isGS1:bool, ecLevel: &ErrorCorrectionLevel, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str) -> Self { version: VersionRef,
let length = 0; solution: Rc<Edge>,
let current = Some(solution); isGS1: bool,
let containsECI = false; ecLevel: &ErrorCorrectionLevel,
let list = Vec::new(); encoders: ECIEncoderSet,
stringToEncode: &str,
) -> Self {
let mut length = 0;
let mut current = Some(solution);
let mut containsECI = false;
let mut list = Vec::new();
while current.is_some() { while current.is_some() {
length += current.as_ref().unwrap().characterLength; length += current.as_ref().unwrap().characterLength;
let previous = current.as_ref().unwrap().previous; let previous = current.as_ref().unwrap().previous.clone();
let needECI = current.as_ref().unwrap().mode == Mode::BYTE && 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_none() && current.as_ref().unwrap().charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1
@@ -568,13 +759,32 @@ impl RXingResultList<'_> {
containsECI = true; containsECI = true;
} }
if previous.is_none() || previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode || needECI { if previous.is_none()
list.push( RXingResultNode::new(current.as_ref().unwrap().mode, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, length,encoders,stringToEncode, version)); || previous.as_ref().unwrap().mode != current.as_ref().unwrap().mode
|| needECI
{
list.push(RXingResultNode::new(
current.as_ref().unwrap().mode,
current.as_ref().unwrap().fromPosition,
current.as_ref().unwrap().charsetEncoderIndex,
length,
encoders.clone(),
stringToEncode,
version,
));
length = 0; length = 0;
} }
if needECI { if needECI {
list.push( RXingResultNode::new(Mode::ECI, current.as_ref().unwrap().fromPosition, current.as_ref().unwrap().charsetEncoderIndex, 0,encoders,stringToEncode, version)); list.push(RXingResultNode::new(
Mode::ECI,
current.as_ref().unwrap().fromPosition,
current.as_ref().unwrap().charsetEncoderIndex,
0,
encoders.clone(),
stringToEncode,
version,
));
} }
current = previous; current = previous;
} }
@@ -582,26 +792,41 @@ impl RXingResultList<'_> {
// prepend FNC1 if needed. If the bits contain an ECI then the FNC1 must be preceeded by an ECI. // prepend FNC1 if needed. If the bits contain an ECI then the FNC1 must be preceeded by an ECI.
// If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1) // If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1)
if isGS1 { if isGS1 {
if let Some(first) = list.get(0){ if let Some(first) = list.get(0) {
// 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( RXingResultNode::new(Mode::ECI, 0, 0, 0,encoders,stringToEncode,version)); list.push(RXingResultNode::new(
}} Mode::ECI,
0,
0,
0,
encoders.clone(),
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,encoders,stringToEncode,version)); list.push(RXingResultNode::new(
Mode::FNC1_FIRST_POSITION,
0,
0,
0,
encoders.clone(),
stringToEncode,
version,
));
} }
// set version to smallest version into which the bits fit. // set version to smallest version into which the bits fit.
let versionNumber = version.getVersionNumber(); let mut versionNumber = version.getVersionNumber();
let (lowerLimit,upperLimit) = let (lowerLimit, upperLimit) = match MinimalEncoder::getVersionSize(&version) {
match MinimalEncoder::getVersionSize(&version) { VersionSize::SMALL => (1, 9),
VersionSize::SMALL => VersionSize::MEDIUM => (10, 26),
(1,9), _ => (27, 40),
VersionSize::MEDIUM=>(10,26),
_=>(27,40),
}; };
// let lowerLimit; // let lowerLimit;
// let upperLimit; // let upperLimit;
@@ -620,41 +845,48 @@ impl RXingResultList<'_> {
// upperLimit = 40; // upperLimit = 40;
// break; // break;
// } // }
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).unwrap(), while versionNumber < upperLimit
ecLevel) { && !encoder::willFit(
versionNumber+=1; size,
Version::getVersionForNumber(versionNumber).unwrap(),
ecLevel,
)
{
versionNumber += 1;
} }
// shrink version if possible // shrink version if possible
while versionNumber > lowerLimit && encoder::willFit(size, Version::getVersionForNumber(versionNumber - 1).unwrap(), while versionNumber > lowerLimit
ecLevel) { && encoder::willFit(
versionNumber-=1; size,
Version::getVersionForNumber(versionNumber - 1).unwrap(),
ecLevel,
)
{
versionNumber -= 1;
} }
let version = Version::getVersionForNumber(versionNumber).unwrap(); let version = Version::getVersionForNumber(versionNumber).unwrap();
Self { Self { list, version }
list,
version,
}
} }
/** /**
* returns the size in bits * returns the size in bits
*/ */
pub fn getSize(&self) -> u32{ pub fn getSize(&self) -> u32 {
self. getSizeLocal(self.version) self.getSizeLocal(self.version)
} }
fn getSizeLocal(&self, version:VersionRef) -> u32{ fn getSizeLocal(&self, version: VersionRef) -> u32 {
let result = 0; let mut result = 0;
for resultNode in &self.list { for resultNode in &self.list {
result += resultNode.getSize(version); result += resultNode.getSize(version);
} }
return result; return result;
} }
fn internal_static_get_size(version:VersionRef, list: &Vec<RXingResultNode>) -> u32 { fn internal_static_get_size(version: VersionRef, list: &Vec<RXingResultNode>) -> u32 {
let result = 0; let mut result = 0;
for resultNode in list { for resultNode in list {
result += resultNode.getSize(version); result += resultNode.getSize(version);
} }
@@ -664,22 +896,22 @@ impl RXingResultList<'_> {
/** /**
* appends the bits * appends the bits
*/ */
pub fn getBits(&self, bits:&BitArray) -> Result<(),Exceptions> { pub fn getBits(&self, bits: &mut BitArray) -> Result<(), Exceptions> {
for resultNode in &self.list { for resultNode in &self.list {
resultNode.getBits(bits); resultNode.getBits(bits);
} }
Ok(()) Ok(())
} }
pub fn getVersion(&self) -> &Version{ pub fn getVersion(&self) -> VersionRef {
&self. version self.version
} }
} }
impl fmt::Display for RXingResultList<'_> { impl fmt::Display for RXingResultList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut result = String::new(); let mut result = String::new();
let previous = None; let mut previous = None;
for current in &self.list { for current in &self.list {
// for (RXingResultNode current : list) { // for (RXingResultNode current : list) {
if previous.is_some() { if previous.is_some() {
@@ -688,31 +920,38 @@ impl fmt::Display for RXingResultList<'_> {
result.push_str(&current.to_string()); result.push_str(&current.to_string());
previous = Some(current); previous = Some(current);
} }
write!(f,"{}", result) write!(f, "{}", result)
} }
} }
struct RXingResultNode<'a> { #[derive(Clone)]
struct RXingResultNode {
mode:Mode, mode: Mode,
fromPosition:usize, fromPosition: usize,
charsetEncoderIndex:usize, charsetEncoderIndex: usize,
characterLength:u32, characterLength: u32,
encoders:&'a ECIEncoderSet, encoders: ECIEncoderSet,
version: VersionRef, version: VersionRef,
stringToEncode: &'a str, stringToEncode: String,
} }
impl RXingResultNode<'_> { impl RXingResultNode {
pub fn new(
pub fn new( mode:Mode, fromPosition:usize, charsetEncoderIndex:usize, characterLength:u32, encoders:&'_ ECIEncoderSet, stringToEncode: &'_ str, version: &'_ Version) -> Self { mode: Mode,
fromPosition: usize,
charsetEncoderIndex: usize,
characterLength: u32,
encoders: ECIEncoderSet,
stringToEncode: &str,
version: VersionRef,
) -> Self {
Self { Self {
mode, mode,
fromPosition, fromPosition,
charsetEncoderIndex, charsetEncoderIndex,
characterLength, characterLength,
encoders, encoders,
stringToEncode, stringToEncode: String::from(stringToEncode),
version, version,
} }
} }
@@ -720,22 +959,34 @@ impl RXingResultNode<'_> {
/** /**
* returns the size in bits * returns the size in bits
*/ */
fn getSize(&self, version:&Version) -> u32{ fn getSize(&self, version: &Version) -> u32 {
let size = 4 + self.mode.getCharacterCountBits(version) as u32; let mut size = 4 + self.mode.getCharacterCountBits(version) as u32;
match self.mode { match self.mode {
Mode::NUMERIC => { Mode::NUMERIC => {
size += (self.characterLength / 3) * 10; size += (self.characterLength / 3) * 10;
let rest = self.characterLength % 3; let rest = self.characterLength % 3;
size += if rest == 1 {4} else { if rest == 2 {7} else {0}}; size += if rest == 1 {
}, 4
} else {
if rest == 2 {
7
} else {
0
}
};
}
Mode::ALPHANUMERIC => { Mode::ALPHANUMERIC => {
size += (self.characterLength / 2) * 11; size += (self.characterLength / 2) * 11;
size += if (self.characterLength % 2) == 1 {6} else {0}; size += if (self.characterLength % 2) == 1 {
}, 6
} else {
0
};
}
Mode::BYTE => size += 8 * self.getCharacterCountIndicator(), Mode::BYTE => size += 8 * self.getCharacterCountIndicator(),
Mode::ECI => size += 8, Mode::ECI => size += 8,
Mode::KANJI => size += 13 * self.characterLength, Mode::KANJI => size += 13 * self.characterLength,
_ => {}, _ => {}
} }
// switch (mode) { // switch (mode) {
// case KANJI: // case KANJI:
@@ -763,32 +1014,51 @@ impl RXingResultNode<'_> {
* returns the length in characters according to the specification (differs from getCharacterLength() in BYTE mode * returns the length in characters according to the specification (differs from getCharacterLength() in BYTE mode
* for multi byte encoded characters) * for multi byte encoded characters)
*/ */
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
self.charsetEncoderIndex as usize).len() as u32} else {self.characterLength} .encode_string(
&self.stringToEncode[self.fromPosition as usize
..(self.fromPosition + self.characterLength as usize)],
self.charsetEncoderIndex as usize,
)
.len() as u32
} else {
self.characterLength
}
} }
/** /**
* appends the bits * appends the bits
*/ */
fn getBits(&self, bits:&BitArray) -> Result<(),Exceptions> { fn getBits(&self, bits: &mut BitArray) -> Result<(), Exceptions> {
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 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.encoders.getCharset(self.charsetEncoderIndex as usize)); &self.stringToEncode[self.fromPosition as usize
..(self.fromPosition + self.characterLength as usize)],
self.mode,
bits,
self.encoders.getCharset(self.charsetEncoderIndex as usize),
);
} }
Ok(()) Ok(())
} }
fn makePrintable( s:&str) -> String { fn makePrintable(s: &str) -> String {
let mut result = String::new(); let mut result = String::new();
for i in 0..s.chars().count() { for i in 0..s.chars().count() {
// for (int i = 0; i < s.length(); i++) { // for (int i = 0; i < s.length(); i++) {
@@ -800,20 +1070,27 @@ impl RXingResultNode<'_> {
} }
result result
} }
} }
impl fmt::Display for RXingResultNode<'_> { impl fmt::Display for RXingResultNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let result = String::new(); let mut result = String::new();
result.push_str(&format!("{:?}",self.mode)); result.push_str(&format!("{:?}", self.mode));
result.push('('); result.push('(');
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(')');
write!(f,"{}", result) write!(f, "{}", result)
} }
} }