mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 20:32:34 +00:00
port: migrate to new cpp Version / FormatInformation
This commit is contained in:
@@ -10,7 +10,7 @@ use crate::{
|
||||
Exceptions,
|
||||
};
|
||||
|
||||
use super::{data_mask::GetDataMaskBit, detector::AppendBit};
|
||||
use super::{data_mask::GetDataMaskBit, detector::AppendBit, Type};
|
||||
|
||||
pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option<bool>) -> bool {
|
||||
let mirrored = mirrored.unwrap_or(false);
|
||||
@@ -21,24 +21,27 @@ pub fn getBit(bitMatrix: &BitMatrix, x: u32, y: u32, mirrored: Option<bool>) ->
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hasValidDimension(bitMatrix: &BitMatrix, isMicro: bool) -> bool {
|
||||
let dimension = bitMatrix.height();
|
||||
if isMicro {
|
||||
(11..=17).contains(&dimension) && (dimension % 2) == 1
|
||||
} else {
|
||||
(21..=177).contains(&dimension) && (dimension % 4) == 1
|
||||
pub fn ReadVersion(bitMatrix: &BitMatrix, qr_type: Type) -> Result<VersionRef> {
|
||||
if !Version::HasValidSize(bitMatrix) {
|
||||
return Err(Exceptions::FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result<VersionRef> {
|
||||
let dimension = bitMatrix.height();
|
||||
let number = Version::Number(bitMatrix);
|
||||
|
||||
let mut version = Version::FromDimension(dimension, false)?;
|
||||
match qr_type {
|
||||
Type::Model1 => return Version::Model1(number),
|
||||
|
||||
Type::Micro => return Version::Micro(number),
|
||||
Type::Model2 => {}
|
||||
}
|
||||
let mut version = Version::Model2(number)?;
|
||||
|
||||
if version.getVersionNumber() < 7 {
|
||||
return Ok(version);
|
||||
}
|
||||
|
||||
let dimension = bitMatrix.height();
|
||||
|
||||
for mirror in [false, true] {
|
||||
// for (bool mirror : {false, true}) {
|
||||
// Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored)
|
||||
@@ -60,12 +63,8 @@ pub fn ReadVersion(bitMatrix: &BitMatrix) -> Result<VersionRef> {
|
||||
Err(Exceptions::FORMAT)
|
||||
}
|
||||
|
||||
pub fn ReadFormatInformation(bitMatrix: &BitMatrix, isMicro: bool) -> Result<FormatInformation> {
|
||||
if !hasValidDimension(bitMatrix, isMicro) {
|
||||
return Err(Exceptions::FORMAT);
|
||||
}
|
||||
|
||||
if isMicro {
|
||||
pub fn ReadFormatInformation(bitMatrix: &BitMatrix) -> Result<FormatInformation> {
|
||||
if Version::HasMicroSize(bitMatrix) {
|
||||
// Read top-left format info bits
|
||||
let mut formatInfoBits = 0;
|
||||
for x in 1..9 {
|
||||
@@ -345,15 +344,9 @@ pub fn ReadCodewords(
|
||||
version: VersionRef,
|
||||
formatInfo: &FormatInformation,
|
||||
) -> Result<Vec<u8>> {
|
||||
if !hasValidDimension(bitMatrix, version.isMicroQRCode()) {
|
||||
return Err(Exceptions::FORMAT);
|
||||
}
|
||||
|
||||
if version.isMicroQRCode() {
|
||||
ReadMQRCodewords(bitMatrix, version, formatInfo)
|
||||
} else if formatInfo.isModel1 {
|
||||
ReadQRCodewordsModel1(bitMatrix, version, formatInfo)
|
||||
} else {
|
||||
ReadQRCodewords(bitMatrix, version, formatInfo)
|
||||
match version.qr_type {
|
||||
Type::Model1 => ReadQRCodewordsModel1(bitMatrix, version, formatInfo),
|
||||
Type::Model2 => ReadQRCodewords(bitMatrix, version, formatInfo),
|
||||
Type::Micro => ReadMQRCodewords(bitMatrix, version, formatInfo),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ use crate::qrcode::cpp_port::bitmatrix_parser::{
|
||||
use crate::qrcode::decoder::{DataBlock, ErrorCorrectionLevel, Mode, Version};
|
||||
use crate::Exceptions;
|
||||
|
||||
use super::Type;
|
||||
|
||||
/**
|
||||
* <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
|
||||
* correct the errors in-place using Reed-Solomon error correction.</p>
|
||||
@@ -299,7 +301,7 @@ pub fn DecodeBitStream(
|
||||
let mut structuredAppend = StructuredAppendInfo::default();
|
||||
let modeBitLength = Mode::get_codec_mode_bits_length(version);
|
||||
|
||||
if version.isQRCodeModel1() {
|
||||
if version.isModel1() {
|
||||
bits.readBits(4)?; /* Model 1 is leading with 4 0-bits -> drop them */
|
||||
}
|
||||
|
||||
@@ -310,7 +312,7 @@ pub fn DecodeBitStream(
|
||||
} else {
|
||||
Mode::CodecModeForBits(
|
||||
bits.readBits(modeBitLength as usize)?,
|
||||
Some(version.isMicroQRCode()),
|
||||
Some(version.isMicro()),
|
||||
)?
|
||||
};
|
||||
|
||||
@@ -392,25 +394,23 @@ pub fn DecodeBitStream(
|
||||
.withEcLevel(ecLevel.to_string())
|
||||
.withVersionNumber(version.getVersionNumber())
|
||||
.withStructuredAppend(structuredAppend)
|
||||
.withIsModel1(version.isQRCodeModel1()))
|
||||
.withIsModel1(version.isModel1()))
|
||||
}
|
||||
|
||||
pub fn Decode(bits: &BitMatrix) -> Result<DecoderResult<bool>> {
|
||||
let isMicroQRCode = bits.height() < 21;
|
||||
let Ok(formatInfo) = ReadFormatInformation(bits, isMicroQRCode) else {
|
||||
if !Version::HasValidSize(bits) {
|
||||
return Err(Exceptions::format_with("Invalid symbol size"));
|
||||
}
|
||||
let Ok(formatInfo) = ReadFormatInformation(bits) else {
|
||||
return Err(Exceptions::format_with("Invalid format information"));
|
||||
};
|
||||
|
||||
let Ok(pversion) = (if formatInfo.isModel1 {
|
||||
Version::FromDimension(bits.height(), true)
|
||||
} else {
|
||||
ReadVersion(bits)
|
||||
}) else {
|
||||
let Ok(pversion) = ReadVersion(bits, formatInfo.qr_type()) else {
|
||||
return Err(Exceptions::format_with("Invalid version"));
|
||||
};
|
||||
let version = pversion;
|
||||
|
||||
let Ok(formatInfo) = ReadFormatInformation(bits, version.isMicroQRCode()) else {
|
||||
let Ok(formatInfo) = ReadFormatInformation(bits) else {
|
||||
return Err(Exceptions::format_with("Invalid format information"));
|
||||
};
|
||||
|
||||
|
||||
@@ -7,5 +7,8 @@ pub use qr_cpp_reader::QrReader;
|
||||
|
||||
mod bitmatrix_parser;
|
||||
|
||||
mod qr_type;
|
||||
pub use qr_type::Type;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
14
src/qrcode/cpp_port/qr_type.rs
Normal file
14
src/qrcode/cpp_port/qr_type.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Type {
|
||||
Model1,
|
||||
Model2,
|
||||
Micro,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub const fn const_eq(a: Type, b: Type) -> bool {
|
||||
let (a, b) = (a as u8, b as u8);
|
||||
|
||||
a == b
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,10 @@ XXX XX X X XXXX
|
||||
)
|
||||
.expect("parse must parse");
|
||||
|
||||
let version = ReadVersion(&bitMatrix).unwrap();
|
||||
let format = ReadFormatInformation(&bitMatrix).expect("could not read format information");
|
||||
let version = ReadVersion(&bitMatrix, format.qr_type()).expect("version found");
|
||||
assert_eq!(3, version.getVersionNumber());
|
||||
let format =
|
||||
ReadFormatInformation(&bitMatrix, true).expect("could not read format information");
|
||||
|
||||
let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords");
|
||||
assert_eq!(17, codewords.len());
|
||||
assert_eq!(0x0, codewords[10]);
|
||||
@@ -67,10 +67,10 @@ X X XXXX XXX
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let version = ReadVersion(&bitMatrix).unwrap();
|
||||
let format = ReadFormatInformation(&bitMatrix).expect("could not read format information");
|
||||
let version = ReadVersion(&bitMatrix, format.qr_type()).expect("could not read version");
|
||||
assert_eq!(3, version.getVersionNumber());
|
||||
let format =
|
||||
ReadFormatInformation(&bitMatrix, true).expect("could not read format information");
|
||||
|
||||
let codewords = ReadCodewords(&bitMatrix, version, &format).expect("could not read codewords");
|
||||
assert_eq!(17, codewords.len());
|
||||
assert_eq!(0x0, codewords[8]);
|
||||
|
||||
@@ -42,7 +42,7 @@ fn SimpleByteMode() {
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false, false).expect("find_version"),
|
||||
Version::Model2(1).expect("find_version"),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.expect("Decode")
|
||||
@@ -62,14 +62,10 @@ fn SimpleSJIS() {
|
||||
ba.appendBits(0xA3, 8).expect("append");
|
||||
ba.appendBits(0xD0, 8).expect("append");
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
assert_eq!("\u{ff61}\u{ff62}\u{ff63}\u{ff90}", result);
|
||||
}
|
||||
|
||||
@@ -84,14 +80,10 @@ fn ECI() {
|
||||
ba.appendBits(0xA2, 8).expect("append");
|
||||
ba.appendBits(0xA3, 8).expect("append");
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
assert_eq!("\u{ED}\u{F3}\u{FA}", result);
|
||||
}
|
||||
|
||||
@@ -103,14 +95,10 @@ fn Hanzi() {
|
||||
ba.appendBits(0x01, 8).expect("append"); // 1 characters
|
||||
ba.appendBits(0x03C1, 13).expect("append");
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
assert_eq!("\u{963f}", result);
|
||||
}
|
||||
|
||||
@@ -125,20 +113,16 @@ fn HanziLevel1() {
|
||||
|
||||
let bytes: Vec<u8> = ba.into();
|
||||
|
||||
let result = DecodeBitStream(
|
||||
&bytes,
|
||||
Version::FromNumber(1, false, false).unwrap(),
|
||||
ErrorCorrectionLevel::M,
|
||||
)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
let result = DecodeBitStream(&bytes, Version::Model2(1).unwrap(), ErrorCorrectionLevel::M)
|
||||
.unwrap()
|
||||
.content()
|
||||
.to_string();
|
||||
assert_eq!("\u{30a2}", result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn SymbologyIdentifier() {
|
||||
let version = Version::FromNumber(1, false, false).unwrap();
|
||||
let version = Version::Model2(1).unwrap();
|
||||
let ecLevel = ErrorCorrectionLevel::M;
|
||||
|
||||
// Plain "ANUM(1) A"
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::qrcode::decoder::{ErrorCorrectionLevel, FormatInformation};
|
||||
use crate::qrcode::{
|
||||
cpp_port::Type,
|
||||
decoder::{ErrorCorrectionLevel, FormatInformation},
|
||||
};
|
||||
|
||||
const MASKED_TEST_FORMAT_INFO: u32 = 0x2BED;
|
||||
const MASKED_TEST_FORMAT_INFO2: u32 =
|
||||
@@ -63,11 +66,12 @@ fn DecodeWithBitDifference() {
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x07,
|
||||
),
|
||||
);
|
||||
assert!(FormatInformation::DecodeQR(
|
||||
let unexpected = FormatInformation::DecodeQR(
|
||||
MASKED_TEST_FORMAT_INFO ^ 0x0F,
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F
|
||||
)
|
||||
.isValid());
|
||||
MASKED_TEST_FORMAT_INFO2 ^ 0x0F,
|
||||
);
|
||||
assert!(!&expected.cpp_eq(&unexpected));
|
||||
assert!(!(unexpected.isValid() && unexpected.qr_type() == Type::Model2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -27,39 +27,27 @@ fn CharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
10,
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(5, false, false).unwrap()
|
||||
)
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(5).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
12,
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(26, false, false).unwrap()
|
||||
)
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(26).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
14,
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::NUMERIC,
|
||||
Version::FromNumber(40, false, false).unwrap()
|
||||
)
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Model2(40).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
9,
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::ALPHANUMERIC,
|
||||
Version::FromNumber(6, false, false).unwrap()
|
||||
)
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Model2(6).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(7, false, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::Model2(7).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
8,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(8, false, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::Model2(8).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,29 +110,26 @@ fn MicroCharacterCount() {
|
||||
// Spot check a few values
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(1, true, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(1).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(2, true, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(2).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
6,
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::FromNumber(4, true, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::NUMERIC, Version::Micro(4).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
3,
|
||||
Mode::CharacterCountBits(
|
||||
&Mode::ALPHANUMERIC,
|
||||
Version::FromNumber(2, true, false).unwrap()
|
||||
)
|
||||
Mode::CharacterCountBits(&Mode::ALPHANUMERIC, Version::Micro(2).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::FromNumber(3, true, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::BYTE, Version::Micro(3).unwrap())
|
||||
);
|
||||
assert_eq!(
|
||||
4,
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::FromNumber(4, true, false).unwrap())
|
||||
Mode::CharacterCountBits(&Mode::KANJI, Version::Micro(4).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
fn CheckVersion(version: VersionRef, number: u32, dimension: u32) {
|
||||
// assert_ne!(version, nullptr);
|
||||
assert_eq!(number, version.getVersionNumber());
|
||||
if number > 1 && !version.isMicroQRCode() {
|
||||
if number > 1 && version.isModel2() {
|
||||
assert!(!version.getAlignmentPatternCenters().is_empty());
|
||||
}
|
||||
assert_eq!(dimension, version.getDimensionForVersion());
|
||||
@@ -26,13 +26,13 @@ fn DoTestVersion(expectedVersion: u32, mask: i32) {
|
||||
|
||||
#[test]
|
||||
fn VersionForNumber() {
|
||||
let version = Version::FromNumber(0, false, false);
|
||||
let version = Version::Model2(0);
|
||||
assert!(version.is_err(), "There is version with number 0");
|
||||
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
CheckVersion(
|
||||
Version::FromNumber(i, false, false).expect("version number found"),
|
||||
Version::Model2(i).expect("version number found"),
|
||||
i,
|
||||
4 * i + 17,
|
||||
);
|
||||
@@ -43,10 +43,13 @@ fn VersionForNumber() {
|
||||
fn GetProvisionalVersionForDimension() {
|
||||
for i in 1..=40 {
|
||||
// for (int i = 1; i <= 40; i++) {
|
||||
let prov = Version::FromDimension(4 * i + 17, false)
|
||||
.unwrap_or_else(|_| panic!("version should exist for {i}"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
assert_eq!(
|
||||
i,
|
||||
Version::Number(
|
||||
&BitMatrix::with_single_dimension(4 * i + 17).expect("must create bitmatrix")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,14 +66,13 @@ fn DecodeVersionInformation() {
|
||||
|
||||
#[test]
|
||||
fn MicroVersionForNumber() {
|
||||
let version = Version::FromNumber(0, true, false);
|
||||
let version = Version::Micro(0);
|
||||
assert!(version.is_err(), "There is version with number 0");
|
||||
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
CheckVersion(
|
||||
Version::FromNumber(i, true, false)
|
||||
.unwrap_or_else(|_| panic!("version for {i} should exist")),
|
||||
Version::Micro(i).unwrap_or_else(|_| panic!("version for {i} should exist")),
|
||||
i,
|
||||
2 * i + 9,
|
||||
);
|
||||
@@ -81,10 +83,12 @@ fn MicroVersionForNumber() {
|
||||
fn GetProvisionalMicroVersionForDimension() {
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
let prov = Version::FromDimension(2 * i + 9, false)
|
||||
.unwrap_or_else(|_| panic!("version for micro {i} should exist"));
|
||||
// assert_ne!(prov, nullptr);
|
||||
assert_eq!(i, prov.getVersionNumber());
|
||||
assert_eq!(
|
||||
i,
|
||||
Version::Number(
|
||||
&BitMatrix::with_single_dimension(2 * i + 9).expect("must create bitmatrix")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +105,7 @@ fn FunctionPattern() {
|
||||
};
|
||||
for i in 1..=4 {
|
||||
// for (int i = 1; i <= 4; i++) {
|
||||
let version = Version::FromNumber(i, true, false).expect("version must be found");
|
||||
let version = Version::Micro(i).expect("version must be found");
|
||||
let functionPattern = version
|
||||
.buildFunctionPattern()
|
||||
.expect("function pattern must be found");
|
||||
|
||||
Reference in New Issue
Block a user