mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-26 04:12:34 +00:00
1935 lines
79 KiB
Rust
1935 lines
79 KiB
Rust
use crate::{FormatException,DecodeHintType,ChecksumException,ResultPoint};
|
|
use crate::comon::{BitMatrix,BitSource,CharacterSetECI,DecoderResult,StringUtils};
|
|
use crate::common::reedsolomon::{GenericGF,ReedSolomonDecoder,ReedSolomonException};
|
|
|
|
|
|
|
|
// NEW FILE: bit_matrix_parser.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* @author Sean Owen
|
|
*/
|
|
struct BitMatrixParser {
|
|
|
|
let bit_matrix: BitMatrix;
|
|
|
|
let parsed_version: Version;
|
|
|
|
let parsed_format_info: FormatInformation;
|
|
|
|
let mirror: bool;
|
|
}
|
|
|
|
impl BitMatrixParser {
|
|
|
|
/**
|
|
* @param bitMatrix {@link BitMatrix} to parse
|
|
* @throws FormatException if dimension is not >= 21 and 1 mod 4
|
|
*/
|
|
fn new( bit_matrix: &BitMatrix) -> BitMatrixParser throws FormatException {
|
|
let dimension: i32 = bit_matrix.get_height();
|
|
if dimension < 21 || (dimension & 0x03) != 1 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let .bitMatrix = bit_matrix;
|
|
}
|
|
|
|
/**
|
|
* <p>Reads format information from one of its two locations within the QR Code.</p>
|
|
*
|
|
* @return {@link FormatInformation} encapsulating the QR Code's format info
|
|
* @throws FormatException if both format information locations cannot be parsed as
|
|
* the valid encoding of format information
|
|
*/
|
|
fn read_format_information(&self) -> /* throws FormatException */Result<FormatInformation, Rc<Exception>> {
|
|
if self.parsed_format_info != null {
|
|
return Ok(self.parsed_format_info);
|
|
}
|
|
// Read top-left format info bits
|
|
let format_info_bits1: i32 = 0;
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < 6 {
|
|
{
|
|
format_info_bits1 = self.copy_bit(i, 8, format_info_bits1);
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// .. and skip a bit in the timing pattern ...
|
|
format_info_bits1 = self.copy_bit(7, 8, format_info_bits1);
|
|
format_info_bits1 = self.copy_bit(8, 8, format_info_bits1);
|
|
format_info_bits1 = self.copy_bit(8, 7, format_info_bits1);
|
|
// .. and skip a bit in the timing pattern ...
|
|
{
|
|
let mut j: i32 = 5;
|
|
while j >= 0 {
|
|
{
|
|
format_info_bits1 = self.copy_bit(8, j, format_info_bits1);
|
|
}
|
|
j -= 1;
|
|
}
|
|
}
|
|
|
|
// Read the top-right/bottom-left pattern too
|
|
let dimension: i32 = self.bit_matrix.get_height();
|
|
let format_info_bits2: i32 = 0;
|
|
let j_min: i32 = dimension - 7;
|
|
{
|
|
let mut j: i32 = dimension - 1;
|
|
while j >= j_min {
|
|
{
|
|
format_info_bits2 = self.copy_bit(8, j, format_info_bits2);
|
|
}
|
|
j -= 1;
|
|
}
|
|
}
|
|
|
|
{
|
|
let mut i: i32 = dimension - 8;
|
|
while i < dimension {
|
|
{
|
|
format_info_bits2 = self.copy_bit(i, 8, format_info_bits2);
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
self.parsed_format_info = FormatInformation::decode_format_information(format_info_bits1, format_info_bits2);
|
|
if self.parsed_format_info != null {
|
|
return Ok(self.parsed_format_info);
|
|
}
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
|
|
/**
|
|
* <p>Reads version information from one of its two locations within the QR Code.</p>
|
|
*
|
|
* @return {@link Version} encapsulating the QR Code's version
|
|
* @throws FormatException if both version information locations cannot be parsed as
|
|
* the valid encoding of version information
|
|
*/
|
|
fn read_version(&self) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
|
if self.parsed_version != null {
|
|
return Ok(self.parsed_version);
|
|
}
|
|
let dimension: i32 = self.bit_matrix.get_height();
|
|
let provisional_version: i32 = (dimension - 17) / 4;
|
|
if provisional_version <= 6 {
|
|
return Ok(Version::get_version_for_number(provisional_version));
|
|
}
|
|
// Read top-right version info: 3 wide by 6 tall
|
|
let version_bits: i32 = 0;
|
|
let ij_min: i32 = dimension - 11;
|
|
{
|
|
let mut j: i32 = 5;
|
|
while j >= 0 {
|
|
{
|
|
{
|
|
let mut i: i32 = dimension - 9;
|
|
while i >= ij_min {
|
|
{
|
|
version_bits = self.copy_bit(i, j, version_bits);
|
|
}
|
|
i -= 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
j -= 1;
|
|
}
|
|
}
|
|
|
|
let the_parsed_version: Version = Version::decode_version_information(version_bits);
|
|
if the_parsed_version != null && the_parsed_version.get_dimension_for_version() == dimension {
|
|
self.parsed_version = the_parsed_version;
|
|
return Ok(the_parsed_version);
|
|
}
|
|
// Hmm, failed. Try bottom left: 6 wide by 3 tall
|
|
version_bits = 0;
|
|
{
|
|
let mut i: i32 = 5;
|
|
while i >= 0 {
|
|
{
|
|
{
|
|
let mut j: i32 = dimension - 9;
|
|
while j >= ij_min {
|
|
{
|
|
version_bits = self.copy_bit(i, j, version_bits);
|
|
}
|
|
j -= 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
i -= 1;
|
|
}
|
|
}
|
|
|
|
the_parsed_version = Version::decode_version_information(version_bits);
|
|
if the_parsed_version != null && the_parsed_version.get_dimension_for_version() == dimension {
|
|
self.parsed_version = the_parsed_version;
|
|
return Ok(the_parsed_version);
|
|
}
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
|
|
fn copy_bit(&self, i: i32, j: i32, version_bits: i32) -> i32 {
|
|
let bit: bool = if self.mirror { self.bit_matrix.get(j, i) } else { self.bit_matrix.get(i, j) };
|
|
return if bit { (version_bits << 1) | 0x1 } else { version_bits << 1 };
|
|
}
|
|
|
|
/**
|
|
* <p>Reads the bits in the {@link BitMatrix} representing the finder pattern in the
|
|
* correct order in order to reconstruct the codewords bytes contained within the
|
|
* QR Code.</p>
|
|
*
|
|
* @return bytes encoded within the QR Code
|
|
* @throws FormatException if the exact number of bytes expected is not read
|
|
*/
|
|
fn read_codewords(&self) -> /* throws FormatException */Result<Vec<i8>, Rc<Exception>> {
|
|
let format_info: FormatInformation = self.read_format_information();
|
|
let version: Version = self.read_version();
|
|
// Get the data mask for the format used in this QR Code. This will exclude
|
|
// some bits from reading as we wind through the bit matrix.
|
|
let data_mask: DataMask = DataMask::values()[format_info.get_data_mask()];
|
|
let dimension: i32 = self.bit_matrix.get_height();
|
|
data_mask.unmask_bit_matrix(self.bit_matrix, dimension);
|
|
let function_pattern: BitMatrix = version.build_function_pattern();
|
|
let reading_up: bool = true;
|
|
let mut result: [i8; version.get_total_codewords()] = [0; version.get_total_codewords()];
|
|
let result_offset: i32 = 0;
|
|
let current_byte: i32 = 0;
|
|
let bits_read: i32 = 0;
|
|
// Read columns in pairs, from right to left
|
|
{
|
|
let mut j: i32 = dimension - 1;
|
|
while j > 0 {
|
|
{
|
|
if j == 6 {
|
|
// Skip whole column with vertical alignment pattern;
|
|
// saves time and makes the other code proceed more cleanly
|
|
j -= 1;
|
|
}
|
|
// Read alternatingly from bottom to top then top to bottom
|
|
{
|
|
let mut count: i32 = 0;
|
|
while count < dimension {
|
|
{
|
|
let i: i32 = if reading_up { dimension - 1 - count } else { count };
|
|
{
|
|
let mut col: i32 = 0;
|
|
while col < 2 {
|
|
{
|
|
// Ignore bits covered by the function pattern
|
|
if !function_pattern.get(j - col, i) {
|
|
// Read a bit
|
|
bits_read += 1;
|
|
current_byte <<= 1;
|
|
if self.bit_matrix.get(j - col, i) {
|
|
current_byte |= 1;
|
|
}
|
|
// If we've made a whole byte, save it off
|
|
if bits_read == 8 {
|
|
result[result_offset += 1 !!!check!!! post increment] = current_byte as i8;
|
|
bits_read = 0;
|
|
current_byte = 0;
|
|
}
|
|
}
|
|
}
|
|
col += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
// readingUp = !readingUp; // switch directions
|
|
reading_up ^= true;
|
|
}
|
|
j -= 2;
|
|
}
|
|
}
|
|
|
|
if result_offset != version.get_total_codewords() {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
return Ok(result);
|
|
}
|
|
|
|
/**
|
|
* Revert the mask removal done while reading the code words. The bit matrix should revert to its original state.
|
|
*/
|
|
fn remask(&self) {
|
|
if self.parsed_format_info == null {
|
|
// We have no format information, and have no data mask
|
|
return;
|
|
}
|
|
let data_mask: DataMask = DataMask::values()[self.parsed_format_info.get_data_mask()];
|
|
let dimension: i32 = self.bit_matrix.get_height();
|
|
data_mask.unmask_bit_matrix(self.bit_matrix, dimension);
|
|
}
|
|
|
|
/**
|
|
* Prepare the parser for a mirrored operation.
|
|
* This flag has effect only on the {@link #readFormatInformation()} and the
|
|
* {@link #readVersion()}. Before proceeding with {@link #readCodewords()} the
|
|
* {@link #mirror()} method should be called.
|
|
*
|
|
* @param mirror Whether to read version and format information mirrored.
|
|
*/
|
|
fn set_mirror(&self, mirror: bool) {
|
|
self.parsed_version = null;
|
|
self.parsed_format_info = null;
|
|
self.mirror = mirror;
|
|
}
|
|
|
|
/** Mirror the bit matrix in order to attempt a second reading. */
|
|
fn mirror(&self) {
|
|
{
|
|
let mut x: i32 = 0;
|
|
while x < self.bit_matrix.get_width() {
|
|
{
|
|
{
|
|
let mut y: i32 = x + 1;
|
|
while y < self.bit_matrix.get_height() {
|
|
{
|
|
if self.bit_matrix.get(x, y) != self.bit_matrix.get(y, x) {
|
|
self.bit_matrix.flip(y, x);
|
|
self.bit_matrix.flip(x, y);
|
|
}
|
|
}
|
|
y += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
x += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// NEW FILE: data_block.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>Encapsulates a block of data within a QR Code. QR Codes may split their data into
|
|
* multiple blocks, each of which is a unit of data and error-correction codewords. Each
|
|
* is represented by an instance of this class.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
struct DataBlock {
|
|
|
|
let num_data_codewords: i32;
|
|
|
|
let mut codewords: Vec<i8>;
|
|
}
|
|
|
|
impl DataBlock {
|
|
|
|
fn new( num_data_codewords: i32, codewords: &Vec<i8>) -> DataBlock {
|
|
let .numDataCodewords = num_data_codewords;
|
|
let .codewords = codewords;
|
|
}
|
|
|
|
/**
|
|
* <p>When QR Codes use multiple data blocks, they are actually interleaved.
|
|
* That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
|
|
* method will separate the data into original blocks.</p>
|
|
*
|
|
* @param rawCodewords bytes as read directly from the QR Code
|
|
* @param version version of the QR Code
|
|
* @param ecLevel error-correction level of the QR Code
|
|
* @return DataBlocks containing original bytes, "de-interleaved" from representation in the
|
|
* QR Code
|
|
*/
|
|
fn get_data_blocks( raw_codewords: &Vec<i8>, version: &Version, ec_level: &ErrorCorrectionLevel) -> Vec<DataBlock> {
|
|
if raw_codewords.len() != version.get_total_codewords() {
|
|
throw IllegalArgumentException::new();
|
|
}
|
|
// Figure out the number and size of data blocks used by this version and
|
|
// error correction level
|
|
let ec_blocks: Version.ECBlocks = version.get_e_c_blocks_for_level(ec_level);
|
|
// First count the total number of data blocks
|
|
let total_blocks: i32 = 0;
|
|
let ec_block_array: Vec<Version.ECB> = ec_blocks.get_e_c_blocks();
|
|
for let ec_block: Version.ECB in ec_block_array {
|
|
total_blocks += ec_block.get_count();
|
|
}
|
|
// Now establish DataBlocks of the appropriate size and number of data codewords
|
|
let mut result: [Option<DataBlock>; total_blocks] = [None; total_blocks];
|
|
let num_result_blocks: i32 = 0;
|
|
for let ec_block: Version.ECB in ec_block_array {
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < ec_block.get_count() {
|
|
{
|
|
let num_data_codewords: i32 = ec_block.get_data_codewords();
|
|
let num_block_codewords: i32 = ec_blocks.get_e_c_codewords_per_block() + num_data_codewords;
|
|
result[num_result_blocks += 1 !!!check!!! post increment] = DataBlock::new(num_data_codewords, : [i8; num_block_codewords] = [0; num_block_codewords]);
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
// All blocks have the same amount of data, except that the last n
|
|
// (where n may be 0) have 1 more byte. Figure out where these start.
|
|
let shorter_blocks_total_codewords: i32 = result[0].codewords.len();
|
|
let longer_blocks_start_at: i32 = result.len() - 1;
|
|
while longer_blocks_start_at >= 0 {
|
|
let num_codewords: i32 = result[longer_blocks_start_at].codewords.len();
|
|
if num_codewords == shorter_blocks_total_codewords {
|
|
break;
|
|
}
|
|
longer_blocks_start_at -= 1;
|
|
}
|
|
longer_blocks_start_at += 1;
|
|
let shorter_blocks_num_data_codewords: i32 = shorter_blocks_total_codewords - ec_blocks.get_e_c_codewords_per_block();
|
|
// The last elements of result may be 1 element longer;
|
|
// first fill out as many elements as all of them have
|
|
let raw_codewords_offset: i32 = 0;
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < shorter_blocks_num_data_codewords {
|
|
{
|
|
{
|
|
let mut j: i32 = 0;
|
|
while j < num_result_blocks {
|
|
{
|
|
result[j].codewords[i] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
|
}
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// Fill out the last data block in the longer ones
|
|
{
|
|
let mut j: i32 = longer_blocks_start_at;
|
|
while j < num_result_blocks {
|
|
{
|
|
result[j].codewords[shorter_blocks_num_data_codewords] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
|
}
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
// Now add in error correction blocks
|
|
let max: i32 = result[0].codewords.len();
|
|
{
|
|
let mut i: i32 = shorter_blocks_num_data_codewords;
|
|
while i < max {
|
|
{
|
|
{
|
|
let mut j: i32 = 0;
|
|
while j < num_result_blocks {
|
|
{
|
|
let i_offset: i32 = if j < longer_blocks_start_at { i } else { i + 1 };
|
|
result[j].codewords[i_offset] = raw_codewords[raw_codewords_offset += 1 !!!check!!! post increment];
|
|
}
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
fn get_num_data_codewords(&self) -> i32 {
|
|
return self.num_data_codewords;
|
|
}
|
|
|
|
fn get_codewords(&self) -> Vec<i8> {
|
|
return self.codewords;
|
|
}
|
|
}
|
|
|
|
// NEW FILE: data_mask.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations
|
|
* of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix,
|
|
* including areas used for finder patterns, timing patterns, etc. These areas should be unused
|
|
* after the point they are unmasked anyway.</p>
|
|
*
|
|
* <p>Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position
|
|
* and j is row position. In fact, as the text says, i is row position and j is column position.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
enum DataMask {
|
|
|
|
/**
|
|
* 000: mask bits for which (x + y) mod 2 == 0
|
|
*/
|
|
DATA_MASK_000() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return ((i + j) & 0x01) == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 001: mask bits for which x mod 2 == 0
|
|
*/
|
|
DATA_MASK_001() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return (i & 0x01) == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 010: mask bits for which y mod 3 == 0
|
|
*/
|
|
DATA_MASK_010() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return j % 3 == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 011: mask bits for which (x + y) mod 3 == 0
|
|
*/
|
|
DATA_MASK_011() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return (i + j) % 3 == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 100: mask bits for which (x/2 + y/3) mod 2 == 0
|
|
*/
|
|
DATA_MASK_100() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return (((i / 2) + (j / 3)) & 0x01) == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 101: mask bits for which xy mod 2 + xy mod 3 == 0
|
|
* equivalently, such that xy mod 6 == 0
|
|
*/
|
|
DATA_MASK_101() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return (i * j) % 6 == 0;
|
|
}
|
|
}
|
|
, /**
|
|
* 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0
|
|
* equivalently, such that xy mod 6 < 3
|
|
*/
|
|
DATA_MASK_110() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return ((i * j) % 6) < 3;
|
|
}
|
|
}
|
|
, /**
|
|
* 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0
|
|
* equivalently, such that (x + y + xy mod 3) mod 2 == 0
|
|
*/
|
|
DATA_MASK_111() {
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool {
|
|
return ((i + j + ((i * j) % 3)) & 0x01) == 0;
|
|
}
|
|
}
|
|
;
|
|
|
|
// End of enum constants.
|
|
/**
|
|
* <p>Implementations of this method reverse the data masking process applied to a QR Code and
|
|
* make its bits ready to read.</p>
|
|
*
|
|
* @param bits representation of QR Code bits
|
|
* @param dimension dimension of QR Code, represented by bits, being unmasked
|
|
*/
|
|
fn unmask_bit_matrix(&self, bits: &BitMatrix, dimension: i32) {
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < dimension {
|
|
{
|
|
{
|
|
let mut j: i32 = 0;
|
|
while j < dimension {
|
|
{
|
|
if self.is_masked(i, j) {
|
|
bits.flip(j, i);
|
|
}
|
|
}
|
|
j += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
fn is_masked(&self, i: i32, j: i32) -> bool ;
|
|
}
|
|
// NEW FILE: decoded_bit_stream_parser.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>QR Codes can encode text as bits in one of several modes, and can use multiple modes
|
|
* in one QR Code. This class decodes the bits back into text.</p>
|
|
*
|
|
* <p>See ISO 18004:2006, 6.4.3 - 6.4.7</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
|
|
/**
|
|
* See ISO 18004:2006, 6.4.4 Table 5
|
|
*/
|
|
const ALPHANUMERIC_CHARS: Vec<char> = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".to_char_array();
|
|
|
|
const GB2312_SUBSET: i32 = 1;
|
|
struct DecodedBitStreamParser {
|
|
}
|
|
|
|
impl DecodedBitStreamParser {
|
|
|
|
fn new() -> DecodedBitStreamParser {
|
|
}
|
|
|
|
fn decode( bytes: &Vec<i8>, version: &Version, ec_level: &ErrorCorrectionLevel, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException */Result<DecoderResult, Rc<Exception>> {
|
|
let bits: BitSource = BitSource::new(&bytes);
|
|
let result: StringBuilder = StringBuilder::new(50);
|
|
let byte_segments: List<Vec<i8>> = ArrayList<>::new(1);
|
|
let symbol_sequence: i32 = -1;
|
|
let parity_data: i32 = -1;
|
|
let symbology_modifier: i32;
|
|
let tryResult1 = 0;
|
|
'try1: loop {
|
|
{
|
|
let current_character_set_e_c_i: CharacterSetECI = null;
|
|
let fc1_in_effect: bool = false;
|
|
let has_f_n_c1first: bool = false;
|
|
let has_f_n_c1second: bool = false;
|
|
let mut mode: Mode;
|
|
loop { {
|
|
// While still another segment to read...
|
|
if bits.available() < 4 {
|
|
// OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
|
|
mode = Mode::TERMINATOR;
|
|
} else {
|
|
// mode is encoded by 4 bits
|
|
mode = Mode::for_bits(&bits.read_bits(4));
|
|
}
|
|
match mode {
|
|
TERMINATOR =>
|
|
{
|
|
break;
|
|
}
|
|
FNC1_FIRST_POSITION =>
|
|
{
|
|
// symbology detection
|
|
has_f_n_c1first = true;
|
|
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
|
fc1_in_effect = true;
|
|
break;
|
|
}
|
|
FNC1_SECOND_POSITION =>
|
|
{
|
|
// symbology detection
|
|
has_f_n_c1second = true;
|
|
// We do little with FNC1 except alter the parsed result a bit according to the spec
|
|
fc1_in_effect = true;
|
|
break;
|
|
}
|
|
STRUCTURED_APPEND =>
|
|
{
|
|
if bits.available() < 16 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
// sequence number and parity is added later to the result metadata
|
|
// Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
|
|
symbol_sequence = bits.read_bits(8);
|
|
parity_data = bits.read_bits(8);
|
|
break;
|
|
}
|
|
ECI =>
|
|
{
|
|
// Count doesn't apply to ECI
|
|
let value: i32 = ::parse_e_c_i_value(bits);
|
|
current_character_set_e_c_i = CharacterSetECI::get_character_set_e_c_i_by_value(value);
|
|
if current_character_set_e_c_i == null {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
break;
|
|
}
|
|
HANZI =>
|
|
{
|
|
// First handle Hanzi mode which does not start with character count
|
|
// Chinese mode contains a sub set indicator right after mode indicator
|
|
let subset: i32 = bits.read_bits(4);
|
|
let count_hanzi: i32 = bits.read_bits(&mode.get_character_count_bits(version));
|
|
if subset == GB2312_SUBSET {
|
|
::decode_hanzi_segment(bits, &result, count_hanzi);
|
|
}
|
|
break;
|
|
}
|
|
_ =>
|
|
{
|
|
// "Normal" QR code modes:
|
|
// How many characters will follow, encoded in this mode?
|
|
let count: i32 = bits.read_bits(&mode.get_character_count_bits(version));
|
|
match mode {
|
|
NUMERIC =>
|
|
{
|
|
::decode_numeric_segment(bits, &result, count);
|
|
break;
|
|
}
|
|
ALPHANUMERIC =>
|
|
{
|
|
::decode_alphanumeric_segment(bits, &result, count, fc1_in_effect);
|
|
break;
|
|
}
|
|
BYTE =>
|
|
{
|
|
::decode_byte_segment(bits, &result, count, current_character_set_e_c_i, &byte_segments, &hints);
|
|
break;
|
|
}
|
|
KANJI =>
|
|
{
|
|
::decode_kanji_segment(bits, &result, count);
|
|
break;
|
|
}
|
|
_ =>
|
|
{
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}if !(mode != Mode::TERMINATOR) break;}
|
|
if current_character_set_e_c_i != null {
|
|
if has_f_n_c1first {
|
|
symbology_modifier = 4;
|
|
} else if has_f_n_c1second {
|
|
symbology_modifier = 6;
|
|
} else {
|
|
symbology_modifier = 2;
|
|
}
|
|
} else {
|
|
if has_f_n_c1first {
|
|
symbology_modifier = 3;
|
|
} else if has_f_n_c1second {
|
|
symbology_modifier = 5;
|
|
} else {
|
|
symbology_modifier = 1;
|
|
}
|
|
}
|
|
}
|
|
break 'try1
|
|
}
|
|
match tryResult1 {
|
|
catch ( iae: &IllegalArgumentException) {
|
|
throw FormatException::get_format_instance();
|
|
} 0 => break
|
|
}
|
|
|
|
return Ok(DecoderResult::new(&bytes, &result.to_string(), if byte_segments.is_empty() { null } else { byte_segments }, if ec_level == null { null } else { ec_level.to_string() }, symbol_sequence, parity_data, symbology_modifier));
|
|
}
|
|
|
|
/**
|
|
* See specification GBT 18284-2000
|
|
*/
|
|
fn decode_hanzi_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
|
// Don't crash trying to read more bits than we have available.
|
|
if count * 13 > bits.available() {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
|
// and decode as GB2312 afterwards
|
|
let mut buffer: [i8; 2 * count] = [0; 2 * count];
|
|
let mut offset: i32 = 0;
|
|
while count > 0 {
|
|
// Each 13 bits encodes a 2-byte character
|
|
let two_bytes: i32 = bits.read_bits(13);
|
|
let assembled_two_bytes: i32 = ((two_bytes / 0x060) << 8) | (two_bytes % 0x060);
|
|
if assembled_two_bytes < 0x00A00 {
|
|
// In the 0xA1A1 to 0xAAFE range
|
|
assembled_two_bytes += 0x0A1A1;
|
|
} else {
|
|
// In the 0xB0A1 to 0xFAFE range
|
|
assembled_two_bytes += 0x0A6A1;
|
|
}
|
|
buffer[offset] = ((assembled_two_bytes >> 8) & 0xFF) as i8;
|
|
buffer[offset + 1] = (assembled_two_bytes & 0xFF) as i8;
|
|
offset += 2;
|
|
count -= 1;
|
|
}
|
|
result.append(String::new(&buffer, StringUtils::GB2312_CHARSET));
|
|
}
|
|
|
|
fn decode_kanji_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
|
// Don't crash trying to read more bits than we have available.
|
|
if count * 13 > bits.available() {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
// Each character will require 2 bytes. Read the characters as 2-byte pairs
|
|
// and decode as Shift_JIS afterwards
|
|
let mut buffer: [i8; 2 * count] = [0; 2 * count];
|
|
let mut offset: i32 = 0;
|
|
while count > 0 {
|
|
// Each 13 bits encodes a 2-byte character
|
|
let two_bytes: i32 = bits.read_bits(13);
|
|
let assembled_two_bytes: i32 = ((two_bytes / 0x0C0) << 8) | (two_bytes % 0x0C0);
|
|
if assembled_two_bytes < 0x01F00 {
|
|
// In the 0x8140 to 0x9FFC range
|
|
assembled_two_bytes += 0x08140;
|
|
} else {
|
|
// In the 0xE040 to 0xEBBF range
|
|
assembled_two_bytes += 0x0C140;
|
|
}
|
|
buffer[offset] = (assembled_two_bytes >> 8) as i8;
|
|
buffer[offset + 1] = assembled_two_bytes as i8;
|
|
offset += 2;
|
|
count -= 1;
|
|
}
|
|
result.append(String::new(&buffer, StringUtils::SHIFT_JIS_CHARSET));
|
|
}
|
|
|
|
fn decode_byte_segment( bits: &BitSource, result: &StringBuilder, count: i32, current_character_set_e_c_i: &CharacterSetECI, byte_segments: &Collection<Vec<i8>>, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
|
// Don't crash trying to read more bits than we have available.
|
|
if 8 * count > bits.available() {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let read_bytes: [i8; count] = [0; count];
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < count {
|
|
{
|
|
read_bytes[i] = bits.read_bits(8) as i8;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
let mut encoding: Charset;
|
|
if current_character_set_e_c_i == null {
|
|
// The spec isn't clear on this mode; see
|
|
// section 6.4.5: t does not say which encoding to assuming
|
|
// upon decoding. I have seen ISO-8859-1 used as well as
|
|
// Shift_JIS -- without anything like an ECI designator to
|
|
// give a hint.
|
|
encoding = StringUtils::guess_charset(&read_bytes, &hints);
|
|
} else {
|
|
encoding = current_character_set_e_c_i.get_charset();
|
|
}
|
|
result.append(String::new(&read_bytes, &encoding));
|
|
byte_segments.add(&read_bytes);
|
|
}
|
|
|
|
fn to_alpha_numeric_char( value: i32) -> /* throws FormatException */Result<char, Rc<Exception>> {
|
|
if value >= ALPHANUMERIC_CHARS.len() {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
return Ok(ALPHANUMERIC_CHARS[value]);
|
|
}
|
|
|
|
fn decode_alphanumeric_segment( bits: &BitSource, result: &StringBuilder, count: i32, fc1_in_effect: bool) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
|
// Read two characters at a time
|
|
let start: i32 = result.length();
|
|
while count > 1 {
|
|
if bits.available() < 11 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let next_two_chars_bits: i32 = bits.read_bits(11);
|
|
result.append(&::to_alpha_numeric_char(next_two_chars_bits / 45));
|
|
result.append(&::to_alpha_numeric_char(next_two_chars_bits % 45));
|
|
count -= 2;
|
|
}
|
|
if count == 1 {
|
|
// special case: one character left
|
|
if bits.available() < 6 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
result.append(&::to_alpha_numeric_char(&bits.read_bits(6)));
|
|
}
|
|
// See section 6.4.8.1, 6.4.8.2
|
|
if fc1_in_effect {
|
|
// We need to massage the result a bit if in an FNC1 mode:
|
|
{
|
|
let mut i: i32 = start;
|
|
while i < result.length() {
|
|
{
|
|
if result.char_at(i) == '%' {
|
|
if i < result.length() - 1 && result.char_at(i + 1) == '%' {
|
|
// %% is rendered as %
|
|
result.delete_char_at(i + 1);
|
|
} else {
|
|
// In alpha mode, % should be converted to FNC1 separator 0x1D
|
|
result.set_char_at(i, 0x1D as char);
|
|
}
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
fn decode_numeric_segment( bits: &BitSource, result: &StringBuilder, count: i32) -> /* throws FormatException */Result<Void, Rc<Exception>> {
|
|
// Read three digits at a time
|
|
while count >= 3 {
|
|
// Each 10 bits encodes three digits
|
|
if bits.available() < 10 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let three_digits_bits: i32 = bits.read_bits(10);
|
|
if three_digits_bits >= 1000 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
result.append(&::to_alpha_numeric_char(three_digits_bits / 100));
|
|
result.append(&::to_alpha_numeric_char((three_digits_bits / 10) % 10));
|
|
result.append(&::to_alpha_numeric_char(three_digits_bits % 10));
|
|
count -= 3;
|
|
}
|
|
if count == 2 {
|
|
// Two digits left over to read, encoded in 7 bits
|
|
if bits.available() < 7 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let two_digits_bits: i32 = bits.read_bits(7);
|
|
if two_digits_bits >= 100 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
result.append(&::to_alpha_numeric_char(two_digits_bits / 10));
|
|
result.append(&::to_alpha_numeric_char(two_digits_bits % 10));
|
|
} else if count == 1 {
|
|
// One digit left over to read
|
|
if bits.available() < 4 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let digit_bits: i32 = bits.read_bits(4);
|
|
if digit_bits >= 10 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
result.append(&::to_alpha_numeric_char(digit_bits));
|
|
}
|
|
}
|
|
|
|
fn parse_e_c_i_value( bits: &BitSource) -> /* throws FormatException */Result<i32, Rc<Exception>> {
|
|
let first_byte: i32 = bits.read_bits(8);
|
|
if (first_byte & 0x80) == 0 {
|
|
// just one byte
|
|
return Ok(first_byte & 0x7F);
|
|
}
|
|
if (first_byte & 0xC0) == 0x80 {
|
|
// two bytes
|
|
let second_byte: i32 = bits.read_bits(8);
|
|
return Ok(((first_byte & 0x3F) << 8) | second_byte);
|
|
}
|
|
if (first_byte & 0xE0) == 0xC0 {
|
|
// three bytes
|
|
let second_third_bytes: i32 = bits.read_bits(16);
|
|
return Ok(((first_byte & 0x1F) << 16) | second_third_bytes);
|
|
}
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
}
|
|
|
|
// NEW FILE: decoder.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>The main class which implements QR Code decoding -- as opposed to locating and extracting
|
|
* the QR Code from an image.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub struct Decoder {
|
|
|
|
let rs_decoder: ReedSolomonDecoder;
|
|
}
|
|
|
|
impl Decoder {
|
|
|
|
pub fn new() -> Decoder {
|
|
rs_decoder = ReedSolomonDecoder::new(GenericGF::QR_CODE_FIELD_256);
|
|
}
|
|
|
|
pub fn decode(&self, image: &Vec<Vec<bool>>) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
|
return Ok(self.decode(&image, null));
|
|
}
|
|
|
|
/**
|
|
* <p>Convenience method that can decode a QR Code represented as a 2D array of booleans.
|
|
* "true" is taken to mean a black module.</p>
|
|
*
|
|
* @param image booleans representing white/black QR Code modules
|
|
* @param hints decoding hints that should be used to influence decoding
|
|
* @return text and bytes encoded within the QR Code
|
|
* @throws FormatException if the QR Code cannot be decoded
|
|
* @throws ChecksumException if error correction fails
|
|
*/
|
|
pub fn decode(&self, image: &Vec<Vec<bool>>, hints: &Map<DecodeHintType, ?>) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
|
return Ok(self.decode(&BitMatrix::parse(&image), &hints));
|
|
}
|
|
|
|
pub fn decode(&self, bits: &BitMatrix) -> /* throws ChecksumException, FormatException */Result<DecoderResult, Rc<Exception>> {
|
|
return Ok(self.decode(bits, null));
|
|
}
|
|
|
|
/**
|
|
* <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p>
|
|
*
|
|
* @param bits booleans representing white/black QR Code modules
|
|
* @param hints decoding hints that should be used to influence decoding
|
|
* @return text and bytes encoded within the QR Code
|
|
* @throws FormatException if the QR Code cannot be decoded
|
|
* @throws ChecksumException if error correction fails
|
|
*/
|
|
pub fn decode(&self, bits: &BitMatrix, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
|
// Construct a parser and read version, error-correction level
|
|
let parser: BitMatrixParser = BitMatrixParser::new(bits);
|
|
let mut fe: FormatException = null;
|
|
let mut ce: ChecksumException = null;
|
|
let tryResult1 = 0;
|
|
'try1: loop {
|
|
{
|
|
return Ok(self.decode(parser, &hints));
|
|
}
|
|
break 'try1
|
|
}
|
|
match tryResult1 {
|
|
catch ( e: &FormatException) {
|
|
fe = e;
|
|
} catch ( e: &ChecksumException) {
|
|
ce = e;
|
|
} 0 => break
|
|
}
|
|
|
|
let tryResult1 = 0;
|
|
'try1: loop {
|
|
{
|
|
// Revert the bit matrix
|
|
parser.remask();
|
|
// Will be attempting a mirrored reading of the version and format info.
|
|
parser.set_mirror(true);
|
|
// Preemptively read the version.
|
|
parser.read_version();
|
|
// Preemptively read the format information.
|
|
parser.read_format_information();
|
|
/*
|
|
* Since we're here, this means we have successfully detected some kind
|
|
* of version and format information when mirrored. This is a good sign,
|
|
* that the QR code may be mirrored, and we should try once more with a
|
|
* mirrored content.
|
|
*/
|
|
// Prepare for a mirrored reading.
|
|
parser.mirror();
|
|
let result: DecoderResult = self.decode(parser, &hints);
|
|
// Success! Notify the caller that the code was mirrored.
|
|
result.set_other(QRCodeDecoderMetaData::new(true));
|
|
return Ok(result);
|
|
}
|
|
break 'try1
|
|
}
|
|
match tryResult1 {
|
|
catch ( e: &FormatExceptionChecksumException | ) {
|
|
if fe != null {
|
|
throw fe;
|
|
}
|
|
throw ce;
|
|
} 0 => break
|
|
}
|
|
|
|
}
|
|
|
|
fn decode(&self, parser: &BitMatrixParser, hints: &Map<DecodeHintType, ?>) -> /* throws FormatException, ChecksumException */Result<DecoderResult, Rc<Exception>> {
|
|
let version: Version = parser.read_version();
|
|
let ec_level: ErrorCorrectionLevel = parser.read_format_information().get_error_correction_level();
|
|
// Read codewords
|
|
let codewords: Vec<i8> = parser.read_codewords();
|
|
// Separate into data blocks
|
|
let data_blocks: Vec<DataBlock> = DataBlock::get_data_blocks(&codewords, version, ec_level);
|
|
// Count total number of data bytes
|
|
let total_bytes: i32 = 0;
|
|
for let data_block: DataBlock in data_blocks {
|
|
total_bytes += data_block.get_num_data_codewords();
|
|
}
|
|
let result_bytes: [i8; total_bytes] = [0; total_bytes];
|
|
let result_offset: i32 = 0;
|
|
// Error-correct and copy data blocks together into a stream of bytes
|
|
for let data_block: DataBlock in data_blocks {
|
|
let codeword_bytes: Vec<i8> = data_block.get_codewords();
|
|
let num_data_codewords: i32 = data_block.get_num_data_codewords();
|
|
self.correct_errors(&codeword_bytes, num_data_codewords);
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < num_data_codewords {
|
|
{
|
|
result_bytes[result_offset += 1 !!!check!!! post increment] = codeword_bytes[i];
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
// Decode the contents of that stream of bytes
|
|
return Ok(DecodedBitStreamParser::decode(&result_bytes, version, ec_level, &hints));
|
|
}
|
|
|
|
/**
|
|
* <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>
|
|
*
|
|
* @param codewordBytes data and error correction codewords
|
|
* @param numDataCodewords number of codewords that are data bytes
|
|
* @throws ChecksumException if error correction fails
|
|
*/
|
|
fn correct_errors(&self, codeword_bytes: &Vec<i8>, num_data_codewords: i32) -> /* throws ChecksumException */Result<Void, Rc<Exception>> {
|
|
let num_codewords: i32 = codeword_bytes.len();
|
|
// First read into an array of ints
|
|
let codewords_ints: [i32; num_codewords] = [0; num_codewords];
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < num_codewords {
|
|
{
|
|
codewords_ints[i] = codeword_bytes[i] & 0xFF;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
let tryResult1 = 0;
|
|
'try1: loop {
|
|
{
|
|
self.rs_decoder.decode(&codewords_ints, codeword_bytes.len() - num_data_codewords);
|
|
}
|
|
break 'try1
|
|
}
|
|
match tryResult1 {
|
|
catch ( ignored: &ReedSolomonException) {
|
|
throw ChecksumException::get_checksum_instance();
|
|
} 0 => break
|
|
}
|
|
|
|
// We don't care about errors in the error-correction codewords
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < num_data_codewords {
|
|
{
|
|
codeword_bytes[i] = codewords_ints[i] as i8;
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// NEW FILE: error_correction_level.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
|
|
* defined by the QR code standard.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub enum ErrorCorrectionLevel {
|
|
|
|
/** L = ~7% correction */
|
|
L(0x01), /** M = ~15% correction */
|
|
M(0x00), /** Q = ~25% correction */
|
|
Q(0x03), /** H = ~30% correction */
|
|
H(0x02);
|
|
|
|
const FOR_BITS: vec![Vec<ErrorCorrectionLevel>; 4] = vec![M, L, H, Q, ]
|
|
;
|
|
|
|
let bits: i32;
|
|
|
|
fn new( bits: i32) -> ErrorCorrectionLevel {
|
|
let .bits = bits;
|
|
}
|
|
|
|
pub fn get_bits(&self) -> i32 {
|
|
return self.bits;
|
|
}
|
|
|
|
/**
|
|
* @param bits int containing the two bits encoding a QR Code's error correction level
|
|
* @return ErrorCorrectionLevel representing the encoded error correction level
|
|
*/
|
|
pub fn for_bits( bits: i32) -> ErrorCorrectionLevel {
|
|
if bits < 0 || bits >= FOR_BITS.len() {
|
|
throw IllegalArgumentException::new();
|
|
}
|
|
return FOR_BITS[bits];
|
|
}
|
|
}
|
|
// NEW FILE: format_information.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>Encapsulates a QR Code's format information, including the data mask used and
|
|
* error correction level.</p>
|
|
*
|
|
* @author Sean Owen
|
|
* @see DataMask
|
|
* @see ErrorCorrectionLevel
|
|
*/
|
|
|
|
const FORMAT_INFO_MASK_QR: i32 = 0x5412;
|
|
|
|
/**
|
|
* See ISO 18004:2006, Annex C, Table C.1
|
|
*/
|
|
const FORMAT_INFO_DECODE_LOOKUP: vec![vec![Vec<Vec<i32>>; 2]; 32] = vec![vec![0x5412, 0x00, ]
|
|
, vec![0x5125, 0x01, ]
|
|
, vec![0x5E7C, 0x02, ]
|
|
, vec![0x5B4B, 0x03, ]
|
|
, vec![0x45F9, 0x04, ]
|
|
, vec![0x40CE, 0x05, ]
|
|
, vec![0x4F97, 0x06, ]
|
|
, vec![0x4AA0, 0x07, ]
|
|
, vec![0x77C4, 0x08, ]
|
|
, vec![0x72F3, 0x09, ]
|
|
, vec![0x7DAA, 0x0A, ]
|
|
, vec![0x789D, 0x0B, ]
|
|
, vec![0x662F, 0x0C, ]
|
|
, vec![0x6318, 0x0D, ]
|
|
, vec![0x6C41, 0x0E, ]
|
|
, vec![0x6976, 0x0F, ]
|
|
, vec![0x1689, 0x10, ]
|
|
, vec![0x13BE, 0x11, ]
|
|
, vec![0x1CE7, 0x12, ]
|
|
, vec![0x19D0, 0x13, ]
|
|
, vec![0x0762, 0x14, ]
|
|
, vec![0x0255, 0x15, ]
|
|
, vec![0x0D0C, 0x16, ]
|
|
, vec![0x083B, 0x17, ]
|
|
, vec![0x355F, 0x18, ]
|
|
, vec![0x3068, 0x19, ]
|
|
, vec![0x3F31, 0x1A, ]
|
|
, vec![0x3A06, 0x1B, ]
|
|
, vec![0x24B4, 0x1C, ]
|
|
, vec![0x2183, 0x1D, ]
|
|
, vec![0x2EDA, 0x1E, ]
|
|
, vec![0x2BED, 0x1F, ]
|
|
, ]
|
|
;
|
|
struct FormatInformation {
|
|
|
|
let error_correction_level: ErrorCorrectionLevel;
|
|
|
|
let data_mask: i8;
|
|
}
|
|
|
|
impl FormatInformation {
|
|
|
|
fn new( format_info: i32) -> FormatInformation {
|
|
// Bits 3,4
|
|
error_correction_level = ErrorCorrectionLevel::for_bits((format_info >> 3) & 0x03);
|
|
// Bottom 3 bits
|
|
data_mask = (format_info & 0x07) as i8;
|
|
}
|
|
|
|
fn num_bits_differing( a: i32, b: i32) -> i32 {
|
|
return Integer::bit_count(a ^ b);
|
|
}
|
|
|
|
/**
|
|
* @param maskedFormatInfo1 format info indicator, with mask still applied
|
|
* @param maskedFormatInfo2 second copy of same info; both are checked at the same time
|
|
* to establish best match
|
|
* @return information about the format it specifies, or {@code null}
|
|
* if doesn't seem to match any known pattern
|
|
*/
|
|
fn decode_format_information( masked_format_info1: i32, masked_format_info2: i32) -> FormatInformation {
|
|
let format_info: FormatInformation = ::do_decode_format_information(masked_format_info1, masked_format_info2);
|
|
if format_info != null {
|
|
return format_info;
|
|
}
|
|
// first
|
|
return ::do_decode_format_information(masked_format_info1 ^ FORMAT_INFO_MASK_QR, masked_format_info2 ^ FORMAT_INFO_MASK_QR);
|
|
}
|
|
|
|
fn do_decode_format_information( masked_format_info1: i32, masked_format_info2: i32) -> FormatInformation {
|
|
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
|
|
let best_difference: i32 = Integer::MAX_VALUE;
|
|
let best_format_info: i32 = 0;
|
|
for let decode_info: Vec<i32> in FORMAT_INFO_DECODE_LOOKUP {
|
|
let target_info: i32 = decode_info[0];
|
|
if target_info == masked_format_info1 || target_info == masked_format_info2 {
|
|
// Found an exact match
|
|
return FormatInformation::new(decode_info[1]);
|
|
}
|
|
let bits_difference: i32 = ::num_bits_differing(masked_format_info1, target_info);
|
|
if bits_difference < best_difference {
|
|
best_format_info = decode_info[1];
|
|
best_difference = bits_difference;
|
|
}
|
|
if masked_format_info1 != masked_format_info2 {
|
|
// also try the other option
|
|
bits_difference = ::num_bits_differing(masked_format_info2, target_info);
|
|
if bits_difference < best_difference {
|
|
best_format_info = decode_info[1];
|
|
best_difference = bits_difference;
|
|
}
|
|
}
|
|
}
|
|
// differing means we found a match
|
|
if best_difference <= 3 {
|
|
return FormatInformation::new(best_format_info);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
fn get_error_correction_level(&self) -> ErrorCorrectionLevel {
|
|
return self.error_correction_level;
|
|
}
|
|
|
|
fn get_data_mask(&self) -> i8 {
|
|
return self.data_mask;
|
|
}
|
|
|
|
pub fn hash_code(&self) -> i32 {
|
|
return (self.error_correction_level.ordinal() << 3) | self.data_mask;
|
|
}
|
|
|
|
pub fn equals(&self, o: &Object) -> bool {
|
|
if !(o instanceof FormatInformation) {
|
|
return false;
|
|
}
|
|
let other: FormatInformation = o as FormatInformation;
|
|
return self.errorCorrectionLevel == other.errorCorrectionLevel && self.dataMask == other.dataMask;
|
|
}
|
|
}
|
|
|
|
// NEW FILE: mode.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* <p>See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
|
|
* data can be encoded to bits in the QR code standard.</p>
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
pub enum Mode {
|
|
|
|
// Not really a mode...
|
|
TERMINATOR( : vec![i32; 3] = vec![0, 0, 0, ]
|
|
, 0x00), NUMERIC( : vec![i32; 3] = vec![10, 12, 14, ]
|
|
, 0x01), ALPHANUMERIC( : vec![i32; 3] = vec![9, 11, 13, ]
|
|
, 0x02), // Not supported
|
|
STRUCTURED_APPEND( : vec![i32; 3] = vec![0, 0, 0, ]
|
|
, 0x03), BYTE( : vec![i32; 3] = vec![8, 16, 16, ]
|
|
, 0x04), // character counts don't apply
|
|
ECI( : vec![i32; 3] = vec![0, 0, 0, ]
|
|
, 0x07), KANJI( : vec![i32; 3] = vec![8, 10, 12, ]
|
|
, 0x08), FNC1_FIRST_POSITION( : vec![i32; 3] = vec![0, 0, 0, ]
|
|
, 0x05), FNC1_SECOND_POSITION( : vec![i32; 3] = vec![0, 0, 0, ]
|
|
, 0x09), /** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */
|
|
HANZI( : vec![i32; 3] = vec![8, 10, 12, ]
|
|
, 0x0D);
|
|
|
|
let character_count_bits_for_versions: Vec<i32>;
|
|
|
|
let bits: i32;
|
|
|
|
fn new( character_count_bits_for_versions: &Vec<i32>, bits: i32) -> Mode {
|
|
let .characterCountBitsForVersions = character_count_bits_for_versions;
|
|
let .bits = bits;
|
|
}
|
|
|
|
/**
|
|
* @param bits four bits encoding a QR Code data mode
|
|
* @return Mode encoded by these bits
|
|
* @throws IllegalArgumentException if bits do not correspond to a known mode
|
|
*/
|
|
pub fn for_bits( bits: i32) -> Mode {
|
|
match bits {
|
|
0x0 =>
|
|
{
|
|
return TERMINATOR;
|
|
}
|
|
0x1 =>
|
|
{
|
|
return NUMERIC;
|
|
}
|
|
0x2 =>
|
|
{
|
|
return ALPHANUMERIC;
|
|
}
|
|
0x3 =>
|
|
{
|
|
return STRUCTURED_APPEND;
|
|
}
|
|
0x4 =>
|
|
{
|
|
return BYTE;
|
|
}
|
|
0x5 =>
|
|
{
|
|
return FNC1_FIRST_POSITION;
|
|
}
|
|
0x7 =>
|
|
{
|
|
return ECI;
|
|
}
|
|
0x8 =>
|
|
{
|
|
return KANJI;
|
|
}
|
|
0x9 =>
|
|
{
|
|
return FNC1_SECOND_POSITION;
|
|
}
|
|
0xD =>
|
|
{
|
|
// 0xD is defined in GBT 18284-2000, may not be supported in foreign country
|
|
return HANZI;
|
|
}
|
|
_ =>
|
|
{
|
|
throw IllegalArgumentException::new();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param version version in question
|
|
* @return number of bits used, in this QR Code symbol {@link Version}, to encode the
|
|
* count of characters that will follow encoded in this Mode
|
|
*/
|
|
pub fn get_character_count_bits(&self, version: &Version) -> i32 {
|
|
let number: i32 = version.get_version_number();
|
|
let mut offset: i32;
|
|
if number <= 9 {
|
|
offset = 0;
|
|
} else if number <= 26 {
|
|
offset = 1;
|
|
} else {
|
|
offset = 2;
|
|
}
|
|
return self.character_count_bits_for_versions[offset];
|
|
}
|
|
|
|
pub fn get_bits(&self) -> i32 {
|
|
return self.bits;
|
|
}
|
|
}
|
|
// NEW FILE: q_r_code_decoder_meta_data.rs
|
|
/*
|
|
* Copyright 2013 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the
|
|
* decoding caller. Callers are expected to process this.
|
|
*
|
|
* @see com.google.zxing.common.DecoderResult#getOther()
|
|
*/
|
|
pub struct QRCodeDecoderMetaData {
|
|
|
|
let mirrored: bool;
|
|
}
|
|
|
|
impl QRCodeDecoderMetaData {
|
|
|
|
fn new( mirrored: bool) -> QRCodeDecoderMetaData {
|
|
let .mirrored = mirrored;
|
|
}
|
|
|
|
/**
|
|
* @return true if the QR Code was mirrored.
|
|
*/
|
|
pub fn is_mirrored(&self) -> bool {
|
|
return self.mirrored;
|
|
}
|
|
|
|
/**
|
|
* Apply the result points' order correction due to mirroring.
|
|
*
|
|
* @param points Array of points to apply mirror correction to.
|
|
*/
|
|
pub fn apply_mirrored_correction(&self, points: &Vec<ResultPoint>) {
|
|
if !self.mirrored || points == null || points.len() < 3 {
|
|
return;
|
|
}
|
|
let bottom_left: ResultPoint = points[0];
|
|
points[0] = points[2];
|
|
points[2] = bottom_left;
|
|
// No need to 'fix' top-left and alignment pattern.
|
|
}
|
|
}
|
|
|
|
// NEW FILE: version.rs
|
|
/*
|
|
* Copyright 2007 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// package com::google::zxing::qrcode::decoder;
|
|
|
|
/**
|
|
* See ISO 18004:2006 Annex D
|
|
*
|
|
* @author Sean Owen
|
|
*/
|
|
|
|
/**
|
|
* See ISO 18004:2006 Annex D.
|
|
* Element i represents the raw version bits that specify version i + 7
|
|
*/
|
|
const VERSION_DECODE_INFO: vec![Vec<i32>; 34] = vec![0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69, ]
|
|
;
|
|
|
|
const VERSIONS: Vec<Version> = ::build_versions();
|
|
pub struct Version {
|
|
|
|
let version_number: i32;
|
|
|
|
let alignment_pattern_centers: Vec<i32>;
|
|
|
|
let ec_blocks: Vec<ECBlocks>;
|
|
|
|
let total_codewords: i32;
|
|
}
|
|
|
|
impl Version {
|
|
|
|
fn new( version_number: i32, alignment_pattern_centers: &Vec<i32>, ec_blocks: &ECBlocks) -> Version {
|
|
let .versionNumber = version_number;
|
|
let .alignmentPatternCenters = alignment_pattern_centers;
|
|
let .ecBlocks = ec_blocks;
|
|
let mut total: i32 = 0;
|
|
let ec_codewords: i32 = ec_blocks[0].get_e_c_codewords_per_block();
|
|
let ecb_array: Vec<ECB> = ec_blocks[0].get_e_c_blocks();
|
|
for let ec_block: ECB in ecb_array {
|
|
total += ec_block.get_count() * (ec_block.get_data_codewords() + ec_codewords);
|
|
}
|
|
let .totalCodewords = total;
|
|
}
|
|
|
|
pub fn get_version_number(&self) -> i32 {
|
|
return self.version_number;
|
|
}
|
|
|
|
pub fn get_alignment_pattern_centers(&self) -> Vec<i32> {
|
|
return self.alignment_pattern_centers;
|
|
}
|
|
|
|
pub fn get_total_codewords(&self) -> i32 {
|
|
return self.total_codewords;
|
|
}
|
|
|
|
pub fn get_dimension_for_version(&self) -> i32 {
|
|
return 17 + 4 * self.version_number;
|
|
}
|
|
|
|
pub fn get_e_c_blocks_for_level(&self, ec_level: &ErrorCorrectionLevel) -> ECBlocks {
|
|
return self.ec_blocks[ec_level.ordinal()];
|
|
}
|
|
|
|
/**
|
|
* <p>Deduces version information purely from QR Code dimensions.</p>
|
|
*
|
|
* @param dimension dimension in modules
|
|
* @return Version for a QR Code of that dimension
|
|
* @throws FormatException if dimension is not 1 mod 4
|
|
*/
|
|
pub fn get_provisional_version_for_dimension( dimension: i32) -> /* throws FormatException */Result<Version, Rc<Exception>> {
|
|
if dimension % 4 != 1 {
|
|
throw FormatException::get_format_instance();
|
|
}
|
|
let tryResult1 = 0;
|
|
'try1: loop {
|
|
{
|
|
return Ok(::get_version_for_number((dimension - 17) / 4));
|
|
}
|
|
break 'try1
|
|
}
|
|
match tryResult1 {
|
|
catch ( ignored: &IllegalArgumentException) {
|
|
throw FormatException::get_format_instance();
|
|
} 0 => break
|
|
}
|
|
|
|
}
|
|
|
|
pub fn get_version_for_number( version_number: i32) -> Version {
|
|
if version_number < 1 || version_number > 40 {
|
|
throw IllegalArgumentException::new();
|
|
}
|
|
return VERSIONS[version_number - 1];
|
|
}
|
|
|
|
fn decode_version_information( version_bits: i32) -> Version {
|
|
let best_difference: i32 = Integer::MAX_VALUE;
|
|
let best_version: i32 = 0;
|
|
{
|
|
let mut i: i32 = 0;
|
|
while i < VERSION_DECODE_INFO.len() {
|
|
{
|
|
let target_version: i32 = VERSION_DECODE_INFO[i];
|
|
// Do the version info bits match exactly? done.
|
|
if target_version == version_bits {
|
|
return ::get_version_for_number(i + 7);
|
|
}
|
|
// Otherwise see if this is the closest to a real version info bit string
|
|
// we have seen so far
|
|
let bits_difference: i32 = FormatInformation::num_bits_differing(version_bits, target_version);
|
|
if bits_difference < best_difference {
|
|
best_version = i + 7;
|
|
best_difference = bits_difference;
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
// differ in less than 8 bits.
|
|
if best_difference <= 3 {
|
|
return ::get_version_for_number(best_version);
|
|
}
|
|
// If we didn't find a close enough match, fail
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* See ISO 18004:2006 Annex E
|
|
*/
|
|
fn build_function_pattern(&self) -> BitMatrix {
|
|
let dimension: i32 = self.get_dimension_for_version();
|
|
let bit_matrix: BitMatrix = BitMatrix::new(dimension);
|
|
// Top left finder pattern + separator + format
|
|
bit_matrix.set_region(0, 0, 9, 9);
|
|
// Top right finder pattern + separator + format
|
|
bit_matrix.set_region(dimension - 8, 0, 8, 9);
|
|
// Bottom left finder pattern + separator + format
|
|
bit_matrix.set_region(0, dimension - 8, 9, 8);
|
|
// Alignment patterns
|
|
let max: i32 = self.alignment_pattern_centers.len();
|
|
{
|
|
let mut x: i32 = 0;
|
|
while x < max {
|
|
{
|
|
let i: i32 = self.alignment_pattern_centers[x] - 2;
|
|
{
|
|
let mut y: i32 = 0;
|
|
while y < max {
|
|
{
|
|
if (x != 0 || (y != 0 && y != max - 1)) && (x != max - 1 || y != 0) {
|
|
bit_matrix.set_region(self.alignment_pattern_centers[y] - 2, i, 5, 5);
|
|
}
|
|
// else no o alignment patterns near the three finder patterns
|
|
}
|
|
y += 1;
|
|
}
|
|
}
|
|
|
|
}
|
|
x += 1;
|
|
}
|
|
}
|
|
|
|
// Vertical timing pattern
|
|
bit_matrix.set_region(6, 9, 1, dimension - 17);
|
|
// Horizontal timing pattern
|
|
bit_matrix.set_region(9, 6, dimension - 17, 1);
|
|
if self.version_number > 6 {
|
|
// Version info, top right
|
|
bit_matrix.set_region(dimension - 11, 0, 3, 6);
|
|
// Version info, bottom left
|
|
bit_matrix.set_region(0, dimension - 11, 6, 3);
|
|
}
|
|
return bit_matrix;
|
|
}
|
|
|
|
/**
|
|
* <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
|
|
* use blocks of differing sizes within one version, so, this encapsulates the parameters for
|
|
* each set of blocks. It also holds the number of error-correction codewords per block since it
|
|
* will be the same across all blocks within one version.</p>
|
|
*/
|
|
pub struct ECBlocks {
|
|
|
|
let ec_codewords_per_block: i32;
|
|
|
|
let ec_blocks: Vec<ECB>;
|
|
}
|
|
|
|
impl ECBlocks {
|
|
|
|
fn new( ec_codewords_per_block: i32, ec_blocks: &ECB) -> ECBlocks {
|
|
let .ecCodewordsPerBlock = ec_codewords_per_block;
|
|
let .ecBlocks = ec_blocks;
|
|
}
|
|
|
|
pub fn get_e_c_codewords_per_block(&self) -> i32 {
|
|
return self.ec_codewords_per_block;
|
|
}
|
|
|
|
pub fn get_num_blocks(&self) -> i32 {
|
|
let mut total: i32 = 0;
|
|
for let ec_block: ECB in self.ec_blocks {
|
|
total += ec_block.get_count();
|
|
}
|
|
return total;
|
|
}
|
|
|
|
pub fn get_total_e_c_codewords(&self) -> i32 {
|
|
return self.ec_codewords_per_block * self.get_num_blocks();
|
|
}
|
|
|
|
pub fn get_e_c_blocks(&self) -> Vec<ECB> {
|
|
return self.ec_blocks;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* <p>Encapsulates the parameters for one error-correction block in one symbol version.
|
|
* This includes the number of data codewords, and the number of times a block with these
|
|
* parameters is used consecutively in the QR code version's format.</p>
|
|
*/
|
|
pub struct ECB {
|
|
|
|
let count: i32;
|
|
|
|
let data_codewords: i32;
|
|
}
|
|
|
|
impl ECB {
|
|
|
|
fn new( count: i32, data_codewords: i32) -> ECB {
|
|
let .count = count;
|
|
let .dataCodewords = data_codewords;
|
|
}
|
|
|
|
pub fn get_count(&self) -> i32 {
|
|
return self.count;
|
|
}
|
|
|
|
pub fn get_data_codewords(&self) -> i32 {
|
|
return self.data_codewords;
|
|
}
|
|
}
|
|
|
|
|
|
pub fn to_string(&self) -> String {
|
|
return String::value_of(self.version_number);
|
|
}
|
|
|
|
/**
|
|
* See ISO 18004:2006 6.5.1 Table 9
|
|
*/
|
|
fn build_versions() -> Vec<Version> {
|
|
return : vec![Version; 40] = vec![Version::new(1, , ECBlocks::new(7, ECB::new(1, 19)), ECBlocks::new(10, ECB::new(1, 16)), ECBlocks::new(13, ECB::new(1, 13)), ECBlocks::new(17, ECB::new(1, 9))), Version::new(2, : vec![i32; 2] = vec![6, 18, ]
|
|
, ECBlocks::new(10, ECB::new(1, 34)), ECBlocks::new(16, ECB::new(1, 28)), ECBlocks::new(22, ECB::new(1, 22)), ECBlocks::new(28, ECB::new(1, 16))), Version::new(3, : vec![i32; 2] = vec![6, 22, ]
|
|
, ECBlocks::new(15, ECB::new(1, 55)), ECBlocks::new(26, ECB::new(1, 44)), ECBlocks::new(18, ECB::new(2, 17)), ECBlocks::new(22, ECB::new(2, 13))), Version::new(4, : vec![i32; 2] = vec![6, 26, ]
|
|
, ECBlocks::new(20, ECB::new(1, 80)), ECBlocks::new(18, ECB::new(2, 32)), ECBlocks::new(26, ECB::new(2, 24)), ECBlocks::new(16, ECB::new(4, 9))), Version::new(5, : vec![i32; 2] = vec![6, 30, ]
|
|
, ECBlocks::new(26, ECB::new(1, 108)), ECBlocks::new(24, ECB::new(2, 43)), ECBlocks::new(18, ECB::new(2, 15), ECB::new(2, 16)), ECBlocks::new(22, ECB::new(2, 11), ECB::new(2, 12))), Version::new(6, : vec![i32; 2] = vec![6, 34, ]
|
|
, ECBlocks::new(18, ECB::new(2, 68)), ECBlocks::new(16, ECB::new(4, 27)), ECBlocks::new(24, ECB::new(4, 19)), ECBlocks::new(28, ECB::new(4, 15))), Version::new(7, : vec![i32; 3] = vec![6, 22, 38, ]
|
|
, ECBlocks::new(20, ECB::new(2, 78)), ECBlocks::new(18, ECB::new(4, 31)), ECBlocks::new(18, ECB::new(2, 14), ECB::new(4, 15)), ECBlocks::new(26, ECB::new(4, 13), ECB::new(1, 14))), Version::new(8, : vec![i32; 3] = vec![6, 24, 42, ]
|
|
, ECBlocks::new(24, ECB::new(2, 97)), ECBlocks::new(22, ECB::new(2, 38), ECB::new(2, 39)), ECBlocks::new(22, ECB::new(4, 18), ECB::new(2, 19)), ECBlocks::new(26, ECB::new(4, 14), ECB::new(2, 15))), Version::new(9, : vec![i32; 3] = vec![6, 26, 46, ]
|
|
, ECBlocks::new(30, ECB::new(2, 116)), ECBlocks::new(22, ECB::new(3, 36), ECB::new(2, 37)), ECBlocks::new(20, ECB::new(4, 16), ECB::new(4, 17)), ECBlocks::new(24, ECB::new(4, 12), ECB::new(4, 13))), Version::new(10, : vec![i32; 3] = vec![6, 28, 50, ]
|
|
, ECBlocks::new(18, ECB::new(2, 68), ECB::new(2, 69)), ECBlocks::new(26, ECB::new(4, 43), ECB::new(1, 44)), ECBlocks::new(24, ECB::new(6, 19), ECB::new(2, 20)), ECBlocks::new(28, ECB::new(6, 15), ECB::new(2, 16))), Version::new(11, : vec![i32; 3] = vec![6, 30, 54, ]
|
|
, ECBlocks::new(20, ECB::new(4, 81)), ECBlocks::new(30, ECB::new(1, 50), ECB::new(4, 51)), ECBlocks::new(28, ECB::new(4, 22), ECB::new(4, 23)), ECBlocks::new(24, ECB::new(3, 12), ECB::new(8, 13))), Version::new(12, : vec![i32; 3] = vec![6, 32, 58, ]
|
|
, ECBlocks::new(24, ECB::new(2, 92), ECB::new(2, 93)), ECBlocks::new(22, ECB::new(6, 36), ECB::new(2, 37)), ECBlocks::new(26, ECB::new(4, 20), ECB::new(6, 21)), ECBlocks::new(28, ECB::new(7, 14), ECB::new(4, 15))), Version::new(13, : vec![i32; 3] = vec![6, 34, 62, ]
|
|
, ECBlocks::new(26, ECB::new(4, 107)), ECBlocks::new(22, ECB::new(8, 37), ECB::new(1, 38)), ECBlocks::new(24, ECB::new(8, 20), ECB::new(4, 21)), ECBlocks::new(22, ECB::new(12, 11), ECB::new(4, 12))), Version::new(14, : vec![i32; 4] = vec![6, 26, 46, 66, ]
|
|
, ECBlocks::new(30, ECB::new(3, 115), ECB::new(1, 116)), ECBlocks::new(24, ECB::new(4, 40), ECB::new(5, 41)), ECBlocks::new(20, ECB::new(11, 16), ECB::new(5, 17)), ECBlocks::new(24, ECB::new(11, 12), ECB::new(5, 13))), Version::new(15, : vec![i32; 4] = vec![6, 26, 48, 70, ]
|
|
, ECBlocks::new(22, ECB::new(5, 87), ECB::new(1, 88)), ECBlocks::new(24, ECB::new(5, 41), ECB::new(5, 42)), ECBlocks::new(30, ECB::new(5, 24), ECB::new(7, 25)), ECBlocks::new(24, ECB::new(11, 12), ECB::new(7, 13))), Version::new(16, : vec![i32; 4] = vec![6, 26, 50, 74, ]
|
|
, ECBlocks::new(24, ECB::new(5, 98), ECB::new(1, 99)), ECBlocks::new(28, ECB::new(7, 45), ECB::new(3, 46)), ECBlocks::new(24, ECB::new(15, 19), ECB::new(2, 20)), ECBlocks::new(30, ECB::new(3, 15), ECB::new(13, 16))), Version::new(17, : vec![i32; 4] = vec![6, 30, 54, 78, ]
|
|
, ECBlocks::new(28, ECB::new(1, 107), ECB::new(5, 108)), ECBlocks::new(28, ECB::new(10, 46), ECB::new(1, 47)), ECBlocks::new(28, ECB::new(1, 22), ECB::new(15, 23)), ECBlocks::new(28, ECB::new(2, 14), ECB::new(17, 15))), Version::new(18, : vec![i32; 4] = vec![6, 30, 56, 82, ]
|
|
, ECBlocks::new(30, ECB::new(5, 120), ECB::new(1, 121)), ECBlocks::new(26, ECB::new(9, 43), ECB::new(4, 44)), ECBlocks::new(28, ECB::new(17, 22), ECB::new(1, 23)), ECBlocks::new(28, ECB::new(2, 14), ECB::new(19, 15))), Version::new(19, : vec![i32; 4] = vec![6, 30, 58, 86, ]
|
|
, ECBlocks::new(28, ECB::new(3, 113), ECB::new(4, 114)), ECBlocks::new(26, ECB::new(3, 44), ECB::new(11, 45)), ECBlocks::new(26, ECB::new(17, 21), ECB::new(4, 22)), ECBlocks::new(26, ECB::new(9, 13), ECB::new(16, 14))), Version::new(20, : vec![i32; 4] = vec![6, 34, 62, 90, ]
|
|
, ECBlocks::new(28, ECB::new(3, 107), ECB::new(5, 108)), ECBlocks::new(26, ECB::new(3, 41), ECB::new(13, 42)), ECBlocks::new(30, ECB::new(15, 24), ECB::new(5, 25)), ECBlocks::new(28, ECB::new(15, 15), ECB::new(10, 16))), Version::new(21, : vec![i32; 5] = vec![6, 28, 50, 72, 94, ]
|
|
, ECBlocks::new(28, ECB::new(4, 116), ECB::new(4, 117)), ECBlocks::new(26, ECB::new(17, 42)), ECBlocks::new(28, ECB::new(17, 22), ECB::new(6, 23)), ECBlocks::new(30, ECB::new(19, 16), ECB::new(6, 17))), Version::new(22, : vec![i32; 5] = vec![6, 26, 50, 74, 98, ]
|
|
, ECBlocks::new(28, ECB::new(2, 111), ECB::new(7, 112)), ECBlocks::new(28, ECB::new(17, 46)), ECBlocks::new(30, ECB::new(7, 24), ECB::new(16, 25)), ECBlocks::new(24, ECB::new(34, 13))), Version::new(23, : vec![i32; 5] = vec![6, 30, 54, 78, 102, ]
|
|
, ECBlocks::new(30, ECB::new(4, 121), ECB::new(5, 122)), ECBlocks::new(28, ECB::new(4, 47), ECB::new(14, 48)), ECBlocks::new(30, ECB::new(11, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(16, 15), ECB::new(14, 16))), Version::new(24, : vec![i32; 5] = vec![6, 28, 54, 80, 106, ]
|
|
, ECBlocks::new(30, ECB::new(6, 117), ECB::new(4, 118)), ECBlocks::new(28, ECB::new(6, 45), ECB::new(14, 46)), ECBlocks::new(30, ECB::new(11, 24), ECB::new(16, 25)), ECBlocks::new(30, ECB::new(30, 16), ECB::new(2, 17))), Version::new(25, : vec![i32; 5] = vec![6, 32, 58, 84, 110, ]
|
|
, ECBlocks::new(26, ECB::new(8, 106), ECB::new(4, 107)), ECBlocks::new(28, ECB::new(8, 47), ECB::new(13, 48)), ECBlocks::new(30, ECB::new(7, 24), ECB::new(22, 25)), ECBlocks::new(30, ECB::new(22, 15), ECB::new(13, 16))), Version::new(26, : vec![i32; 5] = vec![6, 30, 58, 86, 114, ]
|
|
, ECBlocks::new(28, ECB::new(10, 114), ECB::new(2, 115)), ECBlocks::new(28, ECB::new(19, 46), ECB::new(4, 47)), ECBlocks::new(28, ECB::new(28, 22), ECB::new(6, 23)), ECBlocks::new(30, ECB::new(33, 16), ECB::new(4, 17))), Version::new(27, : vec![i32; 5] = vec![6, 34, 62, 90, 118, ]
|
|
, ECBlocks::new(30, ECB::new(8, 122), ECB::new(4, 123)), ECBlocks::new(28, ECB::new(22, 45), ECB::new(3, 46)), ECBlocks::new(30, ECB::new(8, 23), ECB::new(26, 24)), ECBlocks::new(30, ECB::new(12, 15), ECB::new(28, 16))), Version::new(28, : vec![i32; 6] = vec![6, 26, 50, 74, 98, 122, ]
|
|
, ECBlocks::new(30, ECB::new(3, 117), ECB::new(10, 118)), ECBlocks::new(28, ECB::new(3, 45), ECB::new(23, 46)), ECBlocks::new(30, ECB::new(4, 24), ECB::new(31, 25)), ECBlocks::new(30, ECB::new(11, 15), ECB::new(31, 16))), Version::new(29, : vec![i32; 6] = vec![6, 30, 54, 78, 102, 126, ]
|
|
, ECBlocks::new(30, ECB::new(7, 116), ECB::new(7, 117)), ECBlocks::new(28, ECB::new(21, 45), ECB::new(7, 46)), ECBlocks::new(30, ECB::new(1, 23), ECB::new(37, 24)), ECBlocks::new(30, ECB::new(19, 15), ECB::new(26, 16))), Version::new(30, : vec![i32; 6] = vec![6, 26, 52, 78, 104, 130, ]
|
|
, ECBlocks::new(30, ECB::new(5, 115), ECB::new(10, 116)), ECBlocks::new(28, ECB::new(19, 47), ECB::new(10, 48)), ECBlocks::new(30, ECB::new(15, 24), ECB::new(25, 25)), ECBlocks::new(30, ECB::new(23, 15), ECB::new(25, 16))), Version::new(31, : vec![i32; 6] = vec![6, 30, 56, 82, 108, 134, ]
|
|
, ECBlocks::new(30, ECB::new(13, 115), ECB::new(3, 116)), ECBlocks::new(28, ECB::new(2, 46), ECB::new(29, 47)), ECBlocks::new(30, ECB::new(42, 24), ECB::new(1, 25)), ECBlocks::new(30, ECB::new(23, 15), ECB::new(28, 16))), Version::new(32, : vec![i32; 6] = vec![6, 34, 60, 86, 112, 138, ]
|
|
, ECBlocks::new(30, ECB::new(17, 115)), ECBlocks::new(28, ECB::new(10, 46), ECB::new(23, 47)), ECBlocks::new(30, ECB::new(10, 24), ECB::new(35, 25)), ECBlocks::new(30, ECB::new(19, 15), ECB::new(35, 16))), Version::new(33, : vec![i32; 6] = vec![6, 30, 58, 86, 114, 142, ]
|
|
, ECBlocks::new(30, ECB::new(17, 115), ECB::new(1, 116)), ECBlocks::new(28, ECB::new(14, 46), ECB::new(21, 47)), ECBlocks::new(30, ECB::new(29, 24), ECB::new(19, 25)), ECBlocks::new(30, ECB::new(11, 15), ECB::new(46, 16))), Version::new(34, : vec![i32; 6] = vec![6, 34, 62, 90, 118, 146, ]
|
|
, ECBlocks::new(30, ECB::new(13, 115), ECB::new(6, 116)), ECBlocks::new(28, ECB::new(14, 46), ECB::new(23, 47)), ECBlocks::new(30, ECB::new(44, 24), ECB::new(7, 25)), ECBlocks::new(30, ECB::new(59, 16), ECB::new(1, 17))), Version::new(35, : vec![i32; 7] = vec![6, 30, 54, 78, 102, 126, 150, ]
|
|
, ECBlocks::new(30, ECB::new(12, 121), ECB::new(7, 122)), ECBlocks::new(28, ECB::new(12, 47), ECB::new(26, 48)), ECBlocks::new(30, ECB::new(39, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(22, 15), ECB::new(41, 16))), Version::new(36, : vec![i32; 7] = vec![6, 24, 50, 76, 102, 128, 154, ]
|
|
, ECBlocks::new(30, ECB::new(6, 121), ECB::new(14, 122)), ECBlocks::new(28, ECB::new(6, 47), ECB::new(34, 48)), ECBlocks::new(30, ECB::new(46, 24), ECB::new(10, 25)), ECBlocks::new(30, ECB::new(2, 15), ECB::new(64, 16))), Version::new(37, : vec![i32; 7] = vec![6, 28, 54, 80, 106, 132, 158, ]
|
|
, ECBlocks::new(30, ECB::new(17, 122), ECB::new(4, 123)), ECBlocks::new(28, ECB::new(29, 46), ECB::new(14, 47)), ECBlocks::new(30, ECB::new(49, 24), ECB::new(10, 25)), ECBlocks::new(30, ECB::new(24, 15), ECB::new(46, 16))), Version::new(38, : vec![i32; 7] = vec![6, 32, 58, 84, 110, 136, 162, ]
|
|
, ECBlocks::new(30, ECB::new(4, 122), ECB::new(18, 123)), ECBlocks::new(28, ECB::new(13, 46), ECB::new(32, 47)), ECBlocks::new(30, ECB::new(48, 24), ECB::new(14, 25)), ECBlocks::new(30, ECB::new(42, 15), ECB::new(32, 16))), Version::new(39, : vec![i32; 7] = vec![6, 26, 54, 82, 110, 138, 166, ]
|
|
, ECBlocks::new(30, ECB::new(20, 117), ECB::new(4, 118)), ECBlocks::new(28, ECB::new(40, 47), ECB::new(7, 48)), ECBlocks::new(30, ECB::new(43, 24), ECB::new(22, 25)), ECBlocks::new(30, ECB::new(10, 15), ECB::new(67, 16))), Version::new(40, : vec![i32; 7] = vec![6, 30, 58, 86, 114, 142, 170, ]
|
|
, ECBlocks::new(30, ECB::new(19, 118), ECB::new(6, 119)), ECBlocks::new(28, ECB::new(18, 47), ECB::new(31, 48)), ECBlocks::new(30, ECB::new(34, 24), ECB::new(34, 25)), ECBlocks::new(30, ECB::new(20, 15), ECB::new(61, 16))), ]
|
|
;
|
|
}
|
|
}
|
|
|