port qrcode metadata struct

This commit is contained in:
Henry Schimke
2022-10-05 14:02:53 -05:00
parent 4c51e2611c
commit 2e39ac061d
3 changed files with 154 additions and 155 deletions

View File

@@ -3,6 +3,7 @@ mod mode;
mod error_correction_level; mod error_correction_level;
mod format_information; mod format_information;
mod data_block; mod data_block;
mod qr_code_decoder_metaData;
#[cfg(test)] #[cfg(test)]
mod ErrorCorrectionLevelTestCase; mod ErrorCorrectionLevelTestCase;
@@ -16,3 +17,4 @@ 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::*; pub use data_block::*;
pub use qr_code_decoder_metaData::*;

View File

@@ -14,9 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.zxing.qrcode.decoder; use crate::RXingResultPoint;
import com.google.zxing.RXingResultPoint;
/** /**
* Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the * Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
@@ -24,19 +22,18 @@ import com.google.zxing.RXingResultPoint;
* *
* @see com.google.zxing.common.DecoderRXingResult#getOther() * @see com.google.zxing.common.DecoderRXingResult#getOther()
*/ */
public final class QRCodeDecoderMetaData { pub struct QRCodeDecoderMetaData(bool);
private final boolean mirrored; impl QRCodeDecoderMetaData {
pub fn new( mirrored:bool) -> Self {
QRCodeDecoderMetaData(boolean mirrored) { Self(mirrored)
this.mirrored = mirrored;
} }
/** /**
* @return true if the QR Code was mirrored. * @return true if the QR Code was mirrored.
*/ */
public boolean isMirrored() { pub fn isMirrored(&self) -> bool{
return mirrored; self.0
} }
/** /**
@@ -44,13 +41,13 @@ public final class QRCodeDecoderMetaData {
* *
* @param points Array of points to apply mirror correction to. * @param points Array of points to apply mirror correction to.
*/ */
public void applyMirroredCorrection(RXingResultPoint[] points) { pub fn applyMirroredCorrection(&self, points : &mut [RXingResultPoint]) {
if (!mirrored || points == null || points.length < 3) { if !self.0 || points.is_empty() || points.len() < 3 {
return; return
} }
RXingResultPoint bottomLeft = points[0]; let bottom_left = points[0];
points[0] = points[2]; points[0] = points[2];
points[2] = bottomLeft; points[2] = bottom_left;
// No need to 'fix' top-left and alignment pattern. // No need to 'fix' top-left and alignment pattern.
} }

View File

@@ -95,14 +95,14 @@ pub fn encode(content: &str, ecLevel: ErrorCorrectionLevel) -> Result<QRCode, Ex
pub fn encode_with_hints( pub fn encode_with_hints(
content: &str, content: &str,
ecLevel: ErrorCorrectionLevel, ec_level: ErrorCorrectionLevel,
hints: &EncodingHintDictionary, hints: &EncodingHintDictionary,
) -> Result<QRCode, Exceptions> { ) -> Result<QRCode, Exceptions> {
let version; let version;
let mut headerAndDataBits; let mut header_and_data_bits;
let mode; let mode;
let hasGS1FormatHint = hints.contains_key(&EncodeHintType::GS1_FORMAT) let has_gs1_format_hint = 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
@@ -112,7 +112,7 @@ pub fn encode_with_hints(
} else { } else {
false false
}; };
let hasCompactionHint = hints.contains_key(&EncodeHintType::QR_COMPACT) let has_compaction_hint = 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
@@ -125,8 +125,8 @@ pub fn encode_with_hints(
// 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 mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING; let mut encoding = None; //DEFAULT_BYTE_MODE_ENCODING;
let hasEncodingHint = hints.contains_key(&EncodeHintType::CHARACTER_SET); let has_encoding_hint = hints.contains_key(&EncodeHintType::CHARACTER_SET);
if hasEncodingHint { if has_encoding_hint {
if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap() if let EncodeHintValue::CharacterSet(v) = hints.get(&EncodeHintType::CHARACTER_SET).unwrap()
{ {
encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap()) encoding = Some(encoding::label::encoding_from_whatwg_label(v).unwrap())
@@ -134,21 +134,21 @@ pub fn encode_with_hints(
// 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());
} }
if hasCompactionHint { if has_compaction_hint {
mode = Mode::BYTE; mode = Mode::BYTE;
// dbg!("consider this a huge risk, not sure if it should be defaulting to default"); // dbg!("consider this a huge risk, not sure if it should be defaulting to default");
let priorityEncoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)}; let priority_encoding = encoding; //if encoding.name() == DEFAULT_BYTE_MODE_ENCODING.name() {None} else {Some(encoding)};
let rn = MinimalEncoder::encode_with_details( let rn = MinimalEncoder::encode_with_details(
content, content,
None, None,
priorityEncoding, priority_encoding,
hasGS1FormatHint, has_gs1_format_hint,
ecLevel, ec_level,
)?; )?;
headerAndDataBits = BitArray::new(); header_and_data_bits = BitArray::new();
rn.getBits(&mut headerAndDataBits)?; rn.getBits(&mut header_and_data_bits)?;
version = rn.getVersion(); version = rn.getVersion();
} else { } else {
//Switch to default encoding //Switch to default encoding
@@ -164,29 +164,29 @@ pub fn encode_with_hints(
// 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 mut headerBits = BitArray::new(); let mut header_bits = BitArray::new();
// Append ECI segment if applicable // Append ECI segment if applicable
if mode == Mode::BYTE && hasEncodingHint { if mode == Mode::BYTE && has_encoding_hint {
let eci = CharacterSetECI::getCharacterSetECI(encoding); let eci = CharacterSetECI::getCharacterSetECI(encoding);
if eci.is_some() { if eci.is_some() {
appendECI(&eci.unwrap(), &mut headerBits)?; appendECI(&eci.unwrap(), &mut header_bits)?;
} }
} }
// 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 has_gs1_format_hint {
// 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, &mut headerBits)?; appendModeInfo(Mode::FNC1_FIRST_POSITION, &mut header_bits)?;
} }
// (With ECI in place,) Write the mode marker // (With ECI in place,) Write the mode marker
appendModeInfo(mode, &mut headerBits)?; appendModeInfo(mode, &mut header_bits)?;
// 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 mut dataBits = BitArray::new(); let mut data_bits = BitArray::new();
appendBytes(content, mode, &mut dataBits, encoding)?; appendBytes(content, mode, &mut data_bits, encoding)?;
if hints.contains_key(&EncodeHintType::QR_VERSION) { if hints.contains_key(&EncodeHintType::QR_VERSION) {
let versionNumber = if let EncodeHintValue::QrVersion(v) = let versionNumber = if let EncodeHintValue::QrVersion(v) =
@@ -202,46 +202,46 @@ pub fn encode_with_hints(
}; };
// 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, &header_bits, &data_bits, version);
if !willFit(bitsNeeded, version, &ecLevel) { if !willFit(bitsNeeded, version, &ec_level) {
return Err(Exceptions::WriterException( return Err(Exceptions::WriterException(
"Data too big for requested version".to_owned(), "Data too big for requested version".to_owned(),
)); ));
} }
} else { } else {
version = recommendVersion(&ecLevel, mode, &headerBits, &dataBits)?; version = recommendVersion(&ec_level, mode, &header_bits, &data_bits)?;
} }
headerAndDataBits = BitArray::new(); header_and_data_bits = BitArray::new();
headerAndDataBits.appendBitArray(headerBits); header_and_data_bits.appendBitArray(header_bits);
// Find "length" of main segment and write it // Find "length" of main segment and write it
let numLetters = if mode == Mode::BYTE { let num_letters = if mode == Mode::BYTE {
dataBits.getSizeInBytes() data_bits.getSizeInBytes()
} else { } else {
content.graphemes(true).count() content.graphemes(true).count()
}; };
appendLengthInfo(numLetters as u32, version, mode, &mut headerAndDataBits)?; appendLengthInfo(num_letters as u32, version, mode, &mut header_and_data_bits)?;
// Put data together into the overall payload // Put data together into the overall payload
headerAndDataBits.appendBitArray(dataBits); header_and_data_bits.appendBitArray(data_bits);
} }
let ecBlocks = version.getECBlocksForLevel(ecLevel); let ec_blocks = version.getECBlocksForLevel(ec_level);
let numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords(); let num_data_bytes = version.getTotalCodewords() - ec_blocks.getTotalECCodewords();
// Terminate the bits properly. // Terminate the bits properly.
terminateBits(numDataBytes, &mut headerAndDataBits)?; terminateBits(num_data_bytes, &mut header_and_data_bits)?;
// Interleave data bits with error correction code. // Interleave data bits with error correction code.
let finalBits = interleaveWithECBytes( let final_bits = interleaveWithECBytes(
&headerAndDataBits, &header_and_data_bits,
version.getTotalCodewords(), version.getTotalCodewords(),
numDataBytes, num_data_bytes,
ecBlocks.getNumBlocks(), ec_blocks.getNumBlocks(),
)?; )?;
let mut qrCode = QRCode::new(); let mut qrCode = QRCode::new();
qrCode.setECLevel(ecLevel); qrCode.setECLevel(ec_level);
qrCode.setMode(mode); qrCode.setMode(mode);
qrCode.setVersion(version); qrCode.setVersion(version);
@@ -250,9 +250,9 @@ pub fn encode_with_hints(
let mut 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 mut maskPattern = -1; let mut mask_pattern = -1;
if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) { if hints.contains_key(&EncodeHintType::QR_MASK_PATTERN) {
let hintMaskPattern = if let EncodeHintValue::QrMaskPattern(v) = let hint_mask_pattern = if let EncodeHintValue::QrMaskPattern(v) =
hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap() hints.get(&EncodeHintType::QR_MASK_PATTERN).unwrap()
{ {
if let Ok(vb) = v.parse::<i32>() { if let Ok(vb) = v.parse::<i32>() {
@@ -264,20 +264,20 @@ pub fn encode_with_hints(
-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) { mask_pattern = if QRCode::isValidMaskPattern(hint_mask_pattern) {
hintMaskPattern hint_mask_pattern
} else { } else {
-1 -1
}; };
} }
if maskPattern == -1 { if mask_pattern == -1 {
maskPattern = chooseMaskPattern(&finalBits, &ecLevel, version, &mut matrix)? as i32; mask_pattern = chooseMaskPattern(&final_bits, &ec_level, version, &mut matrix)? as i32;
} }
qrCode.setMaskPattern(maskPattern); qrCode.setMaskPattern(mask_pattern);
// Build the matrix and set it to "qrCode". // Build the matrix and set it to "qrCode".
matrix_util::buildMatrix(&finalBits, &ecLevel, version, maskPattern, &mut matrix)?; matrix_util::buildMatrix(&final_bits, &ec_level, version, mask_pattern, &mut matrix)?;
qrCode.setMatrix(matrix); qrCode.setMatrix(matrix);
Ok(qrCode) Ok(qrCode)
@@ -289,31 +289,31 @@ pub fn encode_with_hints(
* @throws WriterException if the data cannot fit in any version * @throws WriterException if the data cannot fit in any version
*/ */
fn recommendVersion( fn recommendVersion(
ecLevel: &ErrorCorrectionLevel, ec_level: &ErrorCorrectionLevel,
mode: Mode, mode: Mode,
headerBits: &BitArray, header_bits: &BitArray,
dataBits: &BitArray, data_bits: &BitArray,
) -> Result<VersionRef, Exceptions> { ) -> 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 = let provisional_bits_needed =
calculateBitsNeeded(mode, headerBits, dataBits, Version::getVersionForNumber(1)?); calculateBitsNeeded(mode, header_bits, data_bits, Version::getVersionForNumber(1)?);
let provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel)?; let provisional_version = chooseVersion(provisional_bits_needed, ec_level)?;
// 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 bits_needed = calculateBitsNeeded(mode, header_bits, data_bits, provisional_version);
chooseVersion(bitsNeeded, ecLevel) chooseVersion(bits_needed, ec_level)
} }
fn calculateBitsNeeded( fn calculateBitsNeeded(
mode: Mode, mode: Mode,
headerBits: &BitArray, header_bits: &BitArray,
dataBits: &BitArray, data_bits: &BitArray,
version: VersionRef, version: VersionRef,
) -> u32 { ) -> u32 {
(headerBits.getSize() + mode.getCharacterCountBits(version) as usize + dataBits.getSize()) (header_bits.getSize() + mode.getCharacterCountBits(version) as usize + data_bits.getSize())
as u32 as u32
} }
@@ -344,23 +344,23 @@ fn chooseModeWithEncoding(content: &str, encoding: EncodingRef) -> Mode {
// 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 mut hasNumeric = false; let mut has_numeric = false;
let mut hasAlphanumeric = false; let mut has_alphanumeric = 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();
if c >= '0' && c <= '9' { if c >= '0' && c <= '9' {
hasNumeric = true; has_numeric = true;
} else if getAlphanumericCode(c as u32) != -1 { } else if getAlphanumericCode(c as u32) != -1 {
hasAlphanumeric = true; has_alphanumeric = true;
} else { } else {
return Mode::BYTE; return Mode::BYTE;
} }
} }
if hasAlphanumeric { if has_alphanumeric {
return Mode::ALPHANUMERIC; return Mode::ALPHANUMERIC;
} }
if hasNumeric { if has_numeric {
return Mode::NUMERIC; return Mode::NUMERIC;
} }
return Mode::BYTE; return Mode::BYTE;
@@ -390,24 +390,24 @@ pub fn isOnlyDoubleByteKanji(content: &str) -> bool {
fn chooseMaskPattern( fn chooseMaskPattern(
bits: &BitArray, bits: &BitArray,
ecLevel: &ErrorCorrectionLevel, ec_level: &ErrorCorrectionLevel,
version: VersionRef, version: VersionRef,
matrix: &mut ByteMatrix, matrix: &mut ByteMatrix,
) -> Result<u32, Exceptions> { ) -> Result<u32, Exceptions> {
let mut minPenalty = u32::MAX; // Lower penalty is better. let mut min_penalty = u32::MAX; // Lower penalty is better.
let mut bestMaskPattern = -1; let mut best_mask_pattern = -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++) {
let mut matrix = matrix.clone(); let mut matrix = matrix.clone();
matrix_util::buildMatrix(bits, ecLevel, version, maskPattern, &mut matrix)?; matrix_util::buildMatrix(bits, ec_level, version, maskPattern, &mut matrix)?;
let penalty = calculateMaskPenalty(&matrix); let penalty = calculateMaskPenalty(&matrix);
if penalty < minPenalty { if penalty < min_penalty {
minPenalty = penalty; min_penalty = penalty;
bestMaskPattern = maskPattern; best_mask_pattern = maskPattern;
} }
} }
Ok(bestMaskPattern as u32) Ok(best_mask_pattern as u32)
} }
fn chooseVersion( fn chooseVersion(
@@ -431,14 +431,14 @@ fn chooseVersion(
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 num_bytes = version.getTotalCodewords();
// getNumECBytes = 130 // getNumECBytes = 130
let ecBlocks = version.getECBlocksForLevel(*ecLevel); let ec_blocks = version.getECBlocksForLevel(*ecLevel);
let numEcBytes = ecBlocks.getTotalECCodewords(); let num_ec_bytes = ec_blocks.getTotalECCodewords();
// getNumDataBytes = 196 - 130 = 66 // getNumDataBytes = 196 - 130 = 66
let numDataBytes = numBytes - numEcBytes; let num_data_bytes = num_bytes - num_ec_bytes;
let totalInputBytes = (numInputBits + 7) / 8; let total_input_bytes = (numInputBits + 7) / 8;
return numDataBytes >= totalInputBytes; return num_data_bytes >= total_input_bytes;
} }
/** /**
@@ -496,49 +496,49 @@ pub fn terminateBits(num_data_bytes: u32, bits: &mut BitArray) -> Result<(), Exc
* JISX0510:2004 (p.30) * JISX0510:2004 (p.30)
*/ */
pub fn getNumDataBytesAndNumECBytesForBlockID( pub fn getNumDataBytesAndNumECBytesForBlockID(
numTotalBytes: u32, num_total_bytes: u32,
numDataBytes: u32, num_data_bytes: u32,
numRSBlocks: u32, num_rsblocks: u32,
blockID: u32, block_id: u32,
// numDataBytesInBlock: &mut [u32], // numDataBytesInBlock: &mut [u32],
// numECBytesInBlock: &mut [u32], // numECBytesInBlock: &mut [u32],
) -> Result<(u32, u32), Exceptions> { ) -> Result<(u32, u32), Exceptions> {
if blockID >= numRSBlocks { if block_id >= num_rsblocks {
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
let numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; let num_rs_blocks_in_group2 = num_total_bytes % num_rsblocks;
// numRsBlocksInGroup1 = 5 - 1 = 4 // numRsBlocksInGroup1 = 5 - 1 = 4
let numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; let num_rs_blocks_in_group1 = num_rsblocks - num_rs_blocks_in_group2;
// numTotalBytesInGroup1 = 196 / 5 = 39 // numTotalBytesInGroup1 = 196 / 5 = 39
let numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; let num_total_bytes_in_group1 = num_total_bytes / num_rsblocks;
// numTotalBytesInGroup2 = 39 + 1 = 40 // numTotalBytesInGroup2 = 39 + 1 = 40
let numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; let num_total_bytes_in_group2 = num_total_bytes_in_group1 + 1;
// numDataBytesInGroup1 = 66 / 5 = 13 // numDataBytesInGroup1 = 66 / 5 = 13
let numDataBytesInGroup1 = numDataBytes / numRSBlocks; let num_data_bytes_in_group1 = num_data_bytes / num_rsblocks;
// numDataBytesInGroup2 = 13 + 1 = 14 // numDataBytesInGroup2 = 13 + 1 = 14
let numDataBytesInGroup2 = numDataBytesInGroup1 + 1; let num_data_bytes_in_group2 = num_data_bytes_in_group1 + 1;
// numEcBytesInGroup1 = 39 - 13 = 26 // numEcBytesInGroup1 = 39 - 13 = 26
let numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; let num_ec_bytes_in_group1 = num_total_bytes_in_group1 - num_data_bytes_in_group1;
// numEcBytesInGroup2 = 40 - 14 = 26 // numEcBytesInGroup2 = 40 - 14 = 26
let numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; let numEcBytesInGroup2 = num_total_bytes_in_group2 - num_data_bytes_in_group2;
// Sanity checks. // Sanity checks.
// 26 = 26 // 26 = 26
if numEcBytesInGroup1 != numEcBytesInGroup2 { if num_ec_bytes_in_group1 != 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 num_rsblocks != num_rs_blocks_in_group1 + num_rs_blocks_in_group2 {
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 num_total_bytes
!= ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) != ((num_data_bytes_in_group1 + num_ec_bytes_in_group1) * num_rs_blocks_in_group1)
+ ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2) + ((num_data_bytes_in_group2 + numEcBytesInGroup2) * num_rs_blocks_in_group2)
{ {
return Err(Exceptions::WriterException( return Err(Exceptions::WriterException(
"Total bytes mismatch".to_owned(), "Total bytes mismatch".to_owned(),
@@ -547,10 +547,10 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
// throw new WriterException("Total bytes mismatch"); // throw new WriterException("Total bytes mismatch");
} }
Ok(if blockID < numRsBlocksInGroup1 { Ok(if block_id < num_rs_blocks_in_group1 {
(numDataBytesInGroup1, numEcBytesInGroup1) (num_data_bytes_in_group1, num_ec_bytes_in_group1)
} else { } else {
(numDataBytesInGroup2, numEcBytesInGroup2) (num_data_bytes_in_group2, numEcBytesInGroup2)
}) })
} }
@@ -560,12 +560,12 @@ pub fn getNumDataBytesAndNumECBytesForBlockID(
*/ */
pub fn interleaveWithECBytes( pub fn interleaveWithECBytes(
bits: &BitArray, bits: &BitArray,
numTotalBytes: u32, num_total_bytes: u32,
numDataBytes: u32, num_data_bytes: u32,
numRSBlocks: u32, num_rsblocks: u32,
) -> Result<BitArray, Exceptions> { ) -> 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 != num_data_bytes {
return Err(Exceptions::WriterException( return Err(Exceptions::WriterException(
"Number of bits and data bytes does not match".to_owned(), "Number of bits and data bytes does not match".to_owned(),
)); ));
@@ -573,21 +573,21 @@ pub fn interleaveWithECBytes(
// 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 mut dataBytesOffset = 0; let mut data_bytes_offset = 0;
let mut maxNumDataBytes = 0; let mut max_num_data_bytes = 0;
let mut maxNumEcBytes = 0; let mut max_num_ec_bytes = 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 mut blocks = Vec::new(); let mut blocks = Vec::new();
for i in 0..numRSBlocks { for i in 0..num_rsblocks {
// for (int i = 0; i < numRSBlocks; ++i) { // for (int i = 0; i < numRSBlocks; ++i) {
// let mut numDataBytesInBlock = vec![0; 1]; //new int[1]; // let mut numDataBytesInBlock = vec![0; 1]; //new int[1];
// let mut numEcBytesInBlock = vec![0; 1]; //new int[1]; // let mut numEcBytesInBlock = vec![0; 1]; //new int[1];
let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID( let (numDataBytesInBlock, numEcBytesInBlock) = getNumDataBytesAndNumECBytesForBlockID(
numTotalBytes, num_total_bytes,
numDataBytes, num_data_bytes,
numRSBlocks, num_rsblocks,
i, i,
// &mut numDataBytesInBlock, // &mut numDataBytesInBlock,
// &mut numEcBytesInBlock, // &mut numEcBytesInBlock,
@@ -595,15 +595,15 @@ pub fn interleaveWithECBytes(
let size = numDataBytesInBlock; let size = numDataBytesInBlock;
let mut 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 * data_bytes_offset, &mut dataBytes, 0, size as usize);
let ecBytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize); let ec_bytes = generateECBytes(&dataBytes, numEcBytesInBlock as usize);
blocks.push(BlockPair::new(dataBytes, ecBytes.clone())); blocks.push(BlockPair::new(dataBytes, ec_bytes.clone()));
maxNumDataBytes = maxNumDataBytes.max(size); max_num_data_bytes = max_num_data_bytes.max(size);
maxNumEcBytes = maxNumEcBytes.max(ecBytes.len()); max_num_ec_bytes = max_num_ec_bytes.max(ec_bytes.len());
dataBytesOffset += numDataBytesInBlock as usize; data_bytes_offset += numDataBytesInBlock as usize;
} }
if numDataBytes != dataBytesOffset as u32 { if num_data_bytes != data_bytes_offset as u32 {
return Err(Exceptions::WriterException( return Err(Exceptions::WriterException(
"Data bytes does not match offset".to_owned(), "Data bytes does not match offset".to_owned(),
)); ));
@@ -612,32 +612,32 @@ pub fn interleaveWithECBytes(
let mut 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..max_num_data_bytes 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 data_bytes = block.getDataBytes();
if i < dataBytes.len() { if i < data_bytes.len() {
result.appendBits(dataBytes[i] as u32, 8)?; result.appendBits(data_bytes[i] as u32, 8)?;
} }
} }
} }
// Then, place error correction blocks. // Then, place error correction blocks.
for i in 0..maxNumEcBytes { for i in 0..max_num_ec_bytes {
// 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 ec_bytes = block.getErrorCorrectionBytes();
if i < ecBytes.len() { if i < ec_bytes.len() {
result.appendBits(ecBytes[i] as u32, 8)?; result.appendBits(ec_bytes[i] as u32, 8)?;
} }
} }
} }
if numTotalBytes != result.getSizeInBytes() as u32 { if num_total_bytes != result.getSizeInBytes() as u32 {
// Should be same. // Should be same.
return Err(Exceptions::WriterException(format!( return Err(Exceptions::WriterException(format!(
"Interleaving error: {} and {} differ.", "Interleaving error: {} and {} differ.",
numTotalBytes, num_total_bytes,
result.getSizeInBytes() result.getSizeInBytes()
))); )));
// throw new WriterException("Interleaving error: " + numTotalBytes + " and " + // throw new WriterException("Interleaving error: " + numTotalBytes + " and " +
@@ -647,24 +647,24 @@ pub fn interleaveWithECBytes(
Ok(result) Ok(result)
} }
pub fn generateECBytes(dataBytes: &[u8], numEcBytesInBlock: usize) -> Vec<u8> { pub fn generateECBytes(dataBytes: &[u8], num_ec_bytes_in_block: usize) -> Vec<u8> {
let numDataBytes = dataBytes.len(); let num_data_bytes = dataBytes.len();
let mut toEncode = vec![0; numDataBytes + numEcBytesInBlock]; let mut to_encode = vec![0; num_data_bytes + num_ec_bytes_in_block];
for i in 0..numDataBytes { for i in 0..num_data_bytes {
// for (int i = 0; i < numDataBytes; i++) { // for (int i = 0; i < numDataBytes; i++) {
toEncode[i] = dataBytes[i] as i32; to_encode[i] = dataBytes[i] as i32;
} }
ReedSolomonEncoder::new(get_predefined_genericgf( ReedSolomonEncoder::new(get_predefined_genericgf(
PredefinedGenericGF::QrCodeField256, PredefinedGenericGF::QrCodeField256,
)) ))
.encode(&mut toEncode, numEcBytesInBlock) .encode(&mut to_encode, num_ec_bytes_in_block)
.expect("rs encode must complete"); .expect("rs encode must complete");
let mut ecBytes = vec![0u8; numEcBytesInBlock]; let mut ecBytes = vec![0u8; num_ec_bytes_in_block];
for i in 0..numEcBytesInBlock { for i in 0..num_ec_bytes_in_block {
// for (int i = 0; i < numEcBytesInBlock; i++) { // for (int i = 0; i < numEcBytesInBlock; i++) {
ecBytes[i] = toEncode[numDataBytes + i] as u8; ecBytes[i] = to_encode[num_data_bytes + i] as u8;
} }
return ecBytes; return ecBytes;
} }
@@ -681,20 +681,20 @@ pub fn appendModeInfo(mode: Mode, bits: &mut BitArray) -> Result<(), Exceptions>
* Append length info. On success, store the result in "bits". * Append length info. On success, store the result in "bits".
*/ */
pub fn appendLengthInfo( pub fn appendLengthInfo(
numLetters: u32, num_letters: u32,
version: VersionRef, version: VersionRef,
mode: Mode, mode: Mode,
bits: &mut BitArray, bits: &mut BitArray,
) -> Result<(), Exceptions> { ) -> Result<(), Exceptions> {
let numBits = mode.getCharacterCountBits(version); let numBits = mode.getCharacterCountBits(version);
if numLetters >= (1 << numBits) { if num_letters >= (1 << numBits) {
return Err(Exceptions::WriterException(format!( return Err(Exceptions::WriterException(format!(
"{} is bigger than {}", "{} is bigger than {}",
numLetters, num_letters,
((1 << numBits) - 1) ((1 << numBits) - 1)
))); )));
} }
bits.appendBits(numLetters, numBits as usize)?; bits.appendBits(num_letters, numBits as usize)?;
Ok(()) Ok(())
} }