begin port of rss_expanded

This commit is contained in:
Henry Schimke
2022-12-14 17:52:11 -06:00
parent dd82274ad1
commit 2de4061f8b
36 changed files with 1691 additions and 1672 deletions

View File

@@ -18,7 +18,7 @@ use one_d_reader_derive::OneDReader;
use crate::{common::BitArray, BarcodeFormat, Exceptions, RXingResult};
use super::{OneDReader, one_d_reader};
use super::{one_d_reader, OneDReader};
/**
* <p>Decodes Code 128 barcodes.</p>
@@ -434,7 +434,8 @@ impl Code128Reader {
for d in 0..CODE_PATTERNS.len() {
// for (int d = 0; d < CODE_PATTERNS.len(); d++) {
let pattern = &CODE_PATTERNS[d];
let variance = one_d_reader::patternMatchVariance(counters, &pattern, MAX_INDIVIDUAL_VARIANCE);
let variance =
one_d_reader::patternMatchVariance(counters, &pattern, MAX_INDIVIDUAL_VARIANCE);
if variance < bestVariance {
bestVariance = variance;
bestMatch = d as isize;

View File

@@ -19,7 +19,7 @@ use one_d_reader_derive::OneDReader;
use crate::common::BitArray;
use crate::{BarcodeFormat, Exceptions, RXingResult};
use super::{OneDReader, one_d_reader};
use super::{one_d_reader, OneDReader};
/**
* <p>Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if USE_CODE_39_EXTENDED_MODE is set.</p>

View File

@@ -18,7 +18,7 @@ use one_d_reader_derive::OneDReader;
use crate::{common::BitArray, BarcodeFormat, Exceptions, RXingResult};
use super::{OneDReader, one_d_reader};
use super::{one_d_reader, OneDReader};
/**
* <p>Decodes Code 93 barcodes.</p>

View File

@@ -18,7 +18,7 @@ use one_d_reader_derive::OneDReader;
use crate::{common::BitArray, BarcodeFormat, DecodeHintValue, Exceptions, RXingResult};
use super::{OneDReader, one_d_reader};
use super::{one_d_reader, OneDReader};
const MAX_AVG_VARIANCE: f32 = 0.38;
const MAX_INDIVIDUAL_VARIANCE: f32 = 0.5;
@@ -375,8 +375,11 @@ impl ITFReader {
counters[counterPosition] += 1;
} else {
if counterPosition == patternLength - 1 {
if one_d_reader::patternMatchVariance(&counters, pattern, MAX_INDIVIDUAL_VARIANCE)
< MAX_AVG_VARIANCE
if one_d_reader::patternMatchVariance(
&counters,
pattern,
MAX_INDIVIDUAL_VARIANCE,
) < MAX_AVG_VARIANCE
{
return Ok([patternStart, x]);
}
@@ -412,7 +415,8 @@ impl ITFReader {
for i in 0..max {
// for (int i = 0; i < max; i++) {
let pattern = &PATTERNS[i];
let variance = one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
let variance =
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
if variance < bestVariance {
bestVariance = variance;
bestMatch = i as isize;

View File

@@ -166,7 +166,6 @@ pub trait OneDReader: Reader {
) -> Result<RXingResult, Exceptions>;
}
/**
* Determines how closely a set of observed counts of runs of black/white values matches a given
* target pattern. This is reported as the ratio of the total variance from the expected pattern
@@ -177,11 +176,7 @@ pub trait OneDReader: Reader {
* @param maxIndividualVariance The most any counter can differ before we give up
* @return ratio of total variance between counters and pattern compared to total pattern size
*/
pub fn patternMatchVariance(
counters: &[u32],
pattern: &[u32],
maxIndividualVariance: f32,
) -> f32 {
pub fn patternMatchVariance(counters: &[u32], pattern: &[u32], maxIndividualVariance: f32) -> f32 {
let mut maxIndividualVariance = maxIndividualVariance;
let numCounters = counters.len();
let mut total = 0.0;
@@ -218,76 +213,72 @@ pub fn patternMatchVariance(
return totalVariance / total;
}
/**
* Records the size of successive runs of white and black pixels in a row, starting at a given point.
* The values are recorded in the given array, and the number of runs recorded is equal to the size
* of the array. If the row starts on a white pixel at the given start point, then the first count
* recorded is the run of white pixels starting from that point; likewise it is the count of a run
* of black pixels if the row begin on a black pixels at that point.
*
* @param row row to count from
* @param start offset into row to start at
* @param counters array into which to record counts
* @throws NotFoundException if counters cannot be filled entirely from row before running out
* of pixels
*/
pub fn recordPattern(
row: &BitArray,
start: usize,
counters: &mut [u32],
) -> Result<(), Exceptions> {
let numCounters = counters.len();
// Arrays.fill(counters, 0, numCounters, 0);
counters.fill(0);
let end = row.getSize();
if start >= end {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let mut isWhite = !row.get(start);
let mut counterPosition = 0;
let mut i = start;
while i < end {
if row.get(i) != isWhite {
counters[counterPosition] += 1;
} else {
counterPosition += 1;
if counterPosition == numCounters {
break;
} else {
counters[counterPosition] = 1;
isWhite = !isWhite;
}
}
i += 1;
}
// If we read fully the last section of pixels and filled up our counters -- or filled
// the last counter but ran off the side of the image, OK. Otherwise, a problem.
if !(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end)) {
return Err(Exceptions::NotFoundException("".to_owned()));
}
Ok(())
/**
* Records the size of successive runs of white and black pixels in a row, starting at a given point.
* The values are recorded in the given array, and the number of runs recorded is equal to the size
* of the array. If the row starts on a white pixel at the given start point, then the first count
* recorded is the run of white pixels starting from that point; likewise it is the count of a run
* of black pixels if the row begin on a black pixels at that point.
*
* @param row row to count from
* @param start offset into row to start at
* @param counters array into which to record counts
* @throws NotFoundException if counters cannot be filled entirely from row before running out
* of pixels
*/
pub fn recordPattern(row: &BitArray, start: usize, counters: &mut [u32]) -> Result<(), Exceptions> {
let numCounters = counters.len();
// Arrays.fill(counters, 0, numCounters, 0);
counters.fill(0);
let end = row.getSize();
if start >= end {
return Err(Exceptions::NotFoundException("".to_owned()));
}
pub fn recordPatternInReverse(
row: &BitArray,
start: usize,
counters: &mut [u32],
) -> Result<(), Exceptions> {
let mut start = start;
// This could be more efficient I guess
let mut numTransitionsLeft = counters.len() as isize;
let mut last = row.get(start);
while start > 0 && numTransitionsLeft >= 0 {
start -= 1;
if row.get(start) != last {
numTransitionsLeft -= 1;
last = !last;
let mut isWhite = !row.get(start);
let mut counterPosition = 0;
let mut i = start;
while i < end {
if row.get(i) != isWhite {
counters[counterPosition] += 1;
} else {
counterPosition += 1;
if counterPosition == numCounters {
break;
} else {
counters[counterPosition] = 1;
isWhite = !isWhite;
}
}
if numTransitionsLeft >= 0 {
return Err(Exceptions::NotFoundException("".to_owned()));
}
recordPattern(row, start + 1, counters)?;
i += 1;
}
// If we read fully the last section of pixels and filled up our counters -- or filled
// the last counter but ran off the side of the image, OK. Otherwise, a problem.
if !(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end)) {
return Err(Exceptions::NotFoundException("".to_owned()));
}
Ok(())
}
Ok(())
}
pub fn recordPatternInReverse(
row: &BitArray,
start: usize,
counters: &mut [u32],
) -> Result<(), Exceptions> {
let mut start = start;
// This could be more efficient I guess
let mut numTransitionsLeft = counters.len() as isize;
let mut last = row.get(start);
while start > 0 && numTransitionsLeft >= 0 {
start -= 1;
if row.get(start) != last {
numTransitionsLeft -= 1;
last = !last;
}
}
if numTransitionsLeft >= 0 {
return Err(Exceptions::NotFoundException("".to_owned()));
}
recordPattern(row, start + 1, counters)?;
Ok(())
}

View File

@@ -14,7 +14,10 @@
* limitations under the License.
*/
use crate::{oned::{OneDReader, one_d_reader}, Exceptions};
use crate::{
oned::{one_d_reader, OneDReader},
Exceptions,
};
/**
* Superclass of {@link OneDReader} implementations that read barcodes in the RSS family
@@ -97,7 +100,7 @@ pub trait AbstractRSSReaderTrait: OneDReader {
array[index] -= 1;
}
fn isFinderPattern( counters: &[u32]) -> bool {
fn isFinderPattern(counters: &[u32]) -> bool {
let firstTwoSum = counters[0] + counters[1];
let sum = firstTwoSum + counters[2] + counters[3];
let ratio: f32 = (firstTwoSum as f32) / (sum as f32);

View File

@@ -25,7 +25,7 @@ pub(crate) trait DataCharacterTrait: Display + Eq + PartialEq + Hash {
/**
* Encapsulates a since character value in an RSS barcode, including its checksum information.
*/
#[derive(Hash, PartialEq, Eq)]
#[derive(Hash, PartialEq, Eq, Debug)]
pub struct DataCharacter {
value: u32,
checksumPortion: u32,

View File

@@ -1,84 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded;
import com.google.zxing.common.BitArray;
import java.util.regex.Pattern;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
public final class BinaryUtil {
private static final Pattern ONE = Pattern.compile("1");
private static final Pattern ZERO = Pattern.compile("0");
private static final Pattern SPACE = Pattern.compile(" ");
private BinaryUtil() {
}
/*
* Constructs a BitArray from a String like the one returned from BitArray.toString()
*/
public static BitArray buildBitArrayFromString(CharSequence data) {
CharSequence dotsAndXs = ZERO.matcher(ONE.matcher(data).replaceAll("X")).replaceAll(".");
BitArray binary = new BitArray(SPACE.matcher(dotsAndXs).replaceAll("").length());
int counter = 0;
for (int i = 0; i < dotsAndXs.length(); ++i) {
if (i % 9 == 0) { // spaces
if (dotsAndXs.charAt(i) != ' ') {
throw new IllegalStateException("space expected");
}
continue;
}
char currentChar = dotsAndXs.charAt(i);
if (currentChar == 'X' || currentChar == 'x') {
binary.set(counter);
}
counter++;
}
return binary;
}
public static BitArray buildBitArrayFromStringWithoutSpaces(CharSequence data) {
StringBuilder sb = new StringBuilder();
CharSequence dotsAndXs = ZERO.matcher(ONE.matcher(data).replaceAll("X")).replaceAll(".");
int current = 0;
while (current < dotsAndXs.length()) {
sb.append(' ');
for (int i = 0; i < 8 && current < dotsAndXs.length(); ++i) {
sb.append(dotsAndXs.charAt(current));
current++;
}
}
return buildBitArrayFromString(sb.toString());
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded;
import com.google.zxing.common.BitArray;
import org.junit.Assert;
import org.junit.Test;
import java.util.regex.Pattern;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
public final class BinaryUtilTest extends Assert {
private static final Pattern SPACE = Pattern.compile(" ");
@Test
public void testBuildBitArrayFromString() {
CharSequence data = " ..X..X.. ..XXX... XXXXXXXX ........";
check(data);
data = " XXX..X..";
check(data);
data = " XX";
check(data);
data = " ....XX.. ..XX";
check(data);
data = " ....XX.. ..XX..XX ....X.X. ........";
check(data);
}
private static void check(CharSequence data) {
BitArray binary = BinaryUtil.buildBitArrayFromString(data);
assertEquals(data, binary.toString());
}
@Test
public void testBuildBitArrayFromStringWithoutSpaces() {
CharSequence data = " ..X..X.. ..XXX... XXXXXXXX ........";
checkWithoutSpaces(data);
data = " XXX..X..";
checkWithoutSpaces(data);
data = " XX";
checkWithoutSpaces(data);
data = " ....XX.. ..XX";
checkWithoutSpaces(data);
data = " ....XX.. ..XX..XX ....X.X. ........";
checkWithoutSpaces(data);
}
private static void checkWithoutSpaces(CharSequence data) {
CharSequence dataWithoutSpaces = SPACE.matcher(data).replaceAll("");
BitArray binary = BinaryUtil.buildBitArrayFromStringWithoutSpaces(dataWithoutSpaces);
assertEquals(data, binary.toString());
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded;
import com.google.zxing.common.BitArray;
import java.util.List;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class BitArrayBuilder {
private BitArrayBuilder() {
}
static BitArray buildBitArray(List<ExpandedPair> pairs) {
int charNumber = (pairs.size() * 2) - 1;
if (pairs.get(pairs.size() - 1).getRightChar() == null) {
charNumber -= 1;
}
int size = 12 * charNumber;
BitArray binary = new BitArray(size);
int accPos = 0;
ExpandedPair firstPair = pairs.get(0);
int firstValue = firstPair.getRightChar().getValue();
for (int i = 11; i >= 0; --i) {
if ((firstValue & (1 << i)) != 0) {
binary.set(accPos);
}
accPos++;
}
for (int i = 1; i < pairs.size(); ++i) {
ExpandedPair currentPair = pairs.get(i);
int leftValue = currentPair.getLeftChar().getValue();
for (int j = 11; j >= 0; --j) {
if ((leftValue & (1 << j)) != 0) {
binary.set(accPos);
}
accPos++;
}
if (currentPair.getRightChar() != null) {
int rightValue = currentPair.getRightChar().getValue();
for (int j = 11; j >= 0; --j) {
if ((rightValue & (1 << j)) != 0) {
binary.set(accPos);
}
accPos++;
}
}
}
return binary;
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded;
import com.google.zxing.common.BitArray;
import com.google.zxing.oned.rss.DataCharacter;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
public final class BitArrayBuilderTest extends Assert {
@Test
public void testBuildBitArray1() {
int[][] pairValues = {{19}, {673, 16}};
String expected = " .......X ..XX..X. X.X....X .......X ....";
checkBinary(pairValues, expected);
}
private static void checkBinary(int[][] pairValues, String expected) {
BitArray binary = buildBitArray(pairValues);
assertEquals(expected, binary.toString());
}
private static BitArray buildBitArray(int[][] pairValues) {
List<ExpandedPair> pairs = new ArrayList<>();
for (int i = 0; i < pairValues.length; ++i) {
int [] pair = pairValues[i];
DataCharacter leftChar;
if (i == 0) {
leftChar = null;
} else {
leftChar = new DataCharacter(pair[0], 0);
}
DataCharacter rightChar;
if (i == 0) {
rightChar = new DataCharacter(pair[0], 0);
} else if (pair.length == 2) {
rightChar = new DataCharacter(pair[1], 0);
} else {
rightChar = null;
}
ExpandedPair expandedPair = new ExpandedPair(leftChar, rightChar, null);
pairs.add(expandedPair);
}
return BitArrayBuilder.buildBitArray(pairs);
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded;
import com.google.zxing.oned.rss.DataCharacter;
import com.google.zxing.oned.rss.FinderPattern;
import java.util.Objects;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class ExpandedPair {
private final DataCharacter leftChar;
private final DataCharacter rightChar;
private final FinderPattern finderPattern;
ExpandedPair(DataCharacter leftChar,
DataCharacter rightChar,
FinderPattern finderPattern) {
this.leftChar = leftChar;
this.rightChar = rightChar;
this.finderPattern = finderPattern;
}
DataCharacter getLeftChar() {
return this.leftChar;
}
DataCharacter getRightChar() {
return this.rightChar;
}
FinderPattern getFinderPattern() {
return this.finderPattern;
}
boolean mustBeLast() {
return this.rightChar == null;
}
@Override
public String toString() {
return
"[ " + leftChar + " , " + rightChar + " : " +
(finderPattern == null ? "null" : finderPattern.getValue()) + " ]";
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ExpandedPair)) {
return false;
}
ExpandedPair that = (ExpandedPair) o;
return Objects.equals(leftChar, that.leftChar) &&
Objects.equals(rightChar, that.rightChar) &&
Objects.equals(finderPattern, that.finderPattern);
}
@Override
public int hashCode() {
return Objects.hashCode(leftChar) ^ Objects.hashCode(rightChar) ^ Objects.hashCode(finderPattern);
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
use lazy_static::lazy_static;
use regex::Regex;
use crate::{common::BitArray, Exceptions};
lazy_static! {
static ref ONE: Regex = Regex::new("1").unwrap();
static ref ZERO: Regex = Regex::new("0").unwrap();
static ref SPACE: Regex = Regex::new(" ").unwrap();
}
/*
* Constructs a BitArray from a String like the one returned from BitArray.toString()
*/
pub fn buildBitArrayFromString(data: &str) -> Result<BitArray, Exceptions> {
let dotsAndXs = ZERO
.replace_all(&ONE.replace_all(data, "X"), ".")
.to_string();
let mut binary = BitArray::with_size(SPACE.replace_all(&dotsAndXs, "").chars().count());
let mut counter = 0;
for i in 0..dotsAndXs.chars().count() {
// for (int i = 0; i < dotsAndXs.length(); ++i) {
if i % 9 == 0 {
// spaces
if dotsAndXs.chars().nth(i).unwrap() != ' ' {
return Err(Exceptions::IllegalStateException(
"space expected".to_owned(),
));
}
continue;
}
let currentChar = dotsAndXs.chars().nth(i).unwrap();
if currentChar == 'X' || currentChar == 'x' {
binary.set(counter);
}
counter += 1;
}
Ok(binary)
}
pub fn buildBitArrayFromStringWithoutSpaces(data: &str) -> Result<BitArray, Exceptions> {
let mut sb = String::new();
// let dotsAndXs = ZERO.matcher(ONE.matcher(data).replaceAll("X")).replaceAll(".");
let dotsAndXs = ZERO
.replace_all(&ONE.replace_all(data, "X"), ".")
.to_string();
let mut current = 0;
while current < dotsAndXs.chars().count() {
sb.push(' ');
let mut i = 0;
while i < 8 && current < dotsAndXs.chars().count() {
// for (int i = 0; i < 8 && current < dotsAndXs.length(); ++i) {
sb.push(dotsAndXs.chars().nth(current).unwrap());
current += 1;
i += 1;
}
}
buildBitArrayFromString(&sb)
}
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
#[cfg(test)]
mod BinaryUtilTest {
#[test]
fn testBuildBitArrayFromString() {
let data = " ..X..X.. ..XXX... XXXXXXXX ........";
check(data);
let data = " XXX..X..";
check(data);
let data = " XX";
check(data);
let data = " ....XX.. ..XX";
check(data);
let data = " ....XX.. ..XX..XX ....X.X. ........";
check(data);
}
fn check(data: &str) {
let binary = super::buildBitArrayFromString(data).expect("check");
assert_eq!(data, binary.to_string());
}
#[test]
fn testBuildBitArrayFromStringWithoutSpaces() {
let data = " ..X..X.. ..XXX... XXXXXXXX ........";
checkWithoutSpaces(data);
let data = " XXX..X..";
checkWithoutSpaces(data);
let data = " XX";
checkWithoutSpaces(data);
let data = " ....XX.. ..XX";
checkWithoutSpaces(data);
let data = " ....XX.. ..XX..XX ....X.X. ........";
checkWithoutSpaces(data);
}
fn checkWithoutSpaces(data: &str) {
let dataWithoutSpaces = super::SPACE.replace_all(data, "");
let binary =
super::buildBitArrayFromStringWithoutSpaces(&dataWithoutSpaces).expect("success");
assert_eq!(data, binary.to_string());
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use crate::{common::BitArray, oned::rss::DataCharacterTrait};
use super::ExpandedPair;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
pub fn buildBitArray(pairs: &Vec<ExpandedPair>) -> BitArray {
let mut charNumber = (pairs.len() * 2) - 1;
if pairs.get(pairs.len() - 1).unwrap().getRightChar().is_none() {
charNumber -= 1;
}
let size = 12 * charNumber;
let mut binary = BitArray::with_size(size);
let mut accPos = 0;
let firstPair = pairs.get(0).unwrap();
let Some(rp) = firstPair.getRightChar() else { panic!("first char must exist");};
let firstValue = rp.getValue();
let mut i = 11;
while i >= 0 {
// for (int i = 11; i >= 0; --i) {
if (firstValue & (1 << i)) != 0 {
binary.set(accPos);
}
accPos += 1;
i -= 1;
}
for i in 1..pairs.len() {
// for (int i = 1; i < pairs.size(); ++i) {
let currentPair = pairs.get(i).unwrap();
let Some(lv) = currentPair.getLeftChar() else { panic!("I'm not sure how we get here ");};
let leftValue = lv.getValue();
let mut j = 11;
while j >= 0 {
// for (int j = 11; j >= 0; --j) {
if (leftValue & (1 << j)) != 0 {
binary.set(accPos);
}
accPos += 1;
j -= 1;
}
if let Some(rc) = currentPair.getRightChar() {
let rightValue = rc.getValue(); //currentPair.getRightChar().getValue();
let mut j = 11;
while j >= 0 {
// for (int j = 11; j >= 0; --j) {
if (rightValue & (1 << j)) != 0 {
binary.set(accPos);
}
accPos += 1;
j -= 1;
}
}
}
return binary;
}
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
#[cfg(test)]
mod BitArrayBuilderTest {
use crate::{
common::BitArray,
oned::rss::{expanded::ExpandedPair, DataCharacter},
};
#[test]
fn testBuildBitArray1() {
let pairValues = vec![vec![19], vec![673, 16]];
let expected = " .......X ..XX..X. X.X....X .......X ....";
checkBinary(&pairValues, expected);
}
fn checkBinary(pairValues: &Vec<Vec<u32>>, expected: &str) {
let binary = buildBitArray(pairValues);
assert_eq!(expected, binary.to_string());
}
fn buildBitArray(pairValues: &Vec<Vec<u32>>) -> BitArray {
let mut pairs = Vec::new(); //new ArrayList<>();
for i in 0..pairValues.len() {
// for (int i = 0; i < pairValues.length; ++i) {
let pair = &pairValues[i];
let leftChar = if i == 0 {
None
} else {
Some(DataCharacter::new(pair[0], 0))
};
let rightChar = if i == 0 {
Some(DataCharacter::new(pair[0], 0))
} else if pair.len() == 2 {
Some(DataCharacter::new(pair[1], 0))
} else {
None
};
let expandedPair = ExpandedPair::new(leftChar, rightChar, None);
pairs.push(expandedPair);
}
super::buildBitArray(&pairs)
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
public abstract class AbstractExpandedDecoder {
private final BitArray information;
private final GeneralAppIdDecoder generalDecoder;
AbstractExpandedDecoder(BitArray information) {
this.information = information;
this.generalDecoder = new GeneralAppIdDecoder(information);
}
protected final BitArray getInformation() {
return information;
}
protected final GeneralAppIdDecoder getGeneralDecoder() {
return generalDecoder;
}
public abstract String parseInformation() throws NotFoundException, FormatException;
public static AbstractExpandedDecoder createDecoder(BitArray information) {
if (information.get(1)) {
return new AI01AndOtherAIs(information);
}
if (!information.get(2)) {
return new AnyAIDecoder(information);
}
int fourBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 4);
switch (fourBitEncodationMethod) {
case 4: return new AI013103decoder(information);
case 5: return new AI01320xDecoder(information);
}
int fiveBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 5);
switch (fiveBitEncodationMethod) {
case 12: return new AI01392xDecoder(information);
case 13: return new AI01393xDecoder(information);
}
int sevenBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 7);
switch (sevenBitEncodationMethod) {
case 56: return new AI013x0x1xDecoder(information, "310", "11");
case 57: return new AI013x0x1xDecoder(information, "320", "11");
case 58: return new AI013x0x1xDecoder(information, "310", "13");
case 59: return new AI013x0x1xDecoder(information, "320", "13");
case 60: return new AI013x0x1xDecoder(information, "310", "15");
case 61: return new AI013x0x1xDecoder(information, "320", "15");
case 62: return new AI013x0x1xDecoder(information, "310", "17");
case 63: return new AI013x0x1xDecoder(information, "320", "17");
}
throw new IllegalStateException("unknown decoder: " + information);
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class DecodedInformation extends DecodedObject {
private final String newString;
private final int remainingValue;
private final boolean remaining;
DecodedInformation(int newPosition, String newString) {
super(newPosition);
this.newString = newString;
this.remaining = false;
this.remainingValue = 0;
}
DecodedInformation(int newPosition, String newString, int remainingValue) {
super(newPosition);
this.remaining = true;
this.remainingValue = remainingValue;
this.newString = newString;
}
String getNewString() {
return this.newString;
}
boolean isRemaining() {
return this.remaining;
}
int getRemainingValue() {
return this.remainingValue;
}
}

View File

@@ -1,239 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
import com.google.zxing.NotFoundException;
import java.util.HashMap;
import java.util.Map;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class FieldParser {
private static final Map<String,DataLength> TWO_DIGIT_DATA_LENGTH = new HashMap<>();
static {
TWO_DIGIT_DATA_LENGTH.put("00", DataLength.fixed(18));
TWO_DIGIT_DATA_LENGTH.put("01", DataLength.fixed(14));
TWO_DIGIT_DATA_LENGTH.put("02", DataLength.fixed(14));
TWO_DIGIT_DATA_LENGTH.put("10", DataLength.variable(20));
TWO_DIGIT_DATA_LENGTH.put("11", DataLength.fixed(6));
TWO_DIGIT_DATA_LENGTH.put("12", DataLength.fixed(6));
TWO_DIGIT_DATA_LENGTH.put("13", DataLength.fixed(6));
TWO_DIGIT_DATA_LENGTH.put("15", DataLength.fixed(6));
TWO_DIGIT_DATA_LENGTH.put("17", DataLength.fixed(6));
TWO_DIGIT_DATA_LENGTH.put("20", DataLength.fixed(2));
TWO_DIGIT_DATA_LENGTH.put("21", DataLength.variable(20));
TWO_DIGIT_DATA_LENGTH.put("22", DataLength.variable(29));
TWO_DIGIT_DATA_LENGTH.put("30", DataLength.variable(8));
TWO_DIGIT_DATA_LENGTH.put("37", DataLength.variable(8));
//internal company codes
for (int i = 90; i <= 99; i++) {
TWO_DIGIT_DATA_LENGTH.put(String.valueOf(i), DataLength.variable(30));
}
}
private static final Map<String,DataLength> THREE_DIGIT_DATA_LENGTH = new HashMap<>();
static {
THREE_DIGIT_DATA_LENGTH.put("240", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("241", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("242", DataLength.variable(6));
THREE_DIGIT_DATA_LENGTH.put("250", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("251", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("253", DataLength.variable(17));
THREE_DIGIT_DATA_LENGTH.put("254", DataLength.variable(20));
THREE_DIGIT_DATA_LENGTH.put("400", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("401", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("402", DataLength.fixed(17));
THREE_DIGIT_DATA_LENGTH.put("403", DataLength.variable(30));
THREE_DIGIT_DATA_LENGTH.put("410", DataLength.fixed(13));
THREE_DIGIT_DATA_LENGTH.put("411", DataLength.fixed(13));
THREE_DIGIT_DATA_LENGTH.put("412", DataLength.fixed(13));
THREE_DIGIT_DATA_LENGTH.put("413", DataLength.fixed(13));
THREE_DIGIT_DATA_LENGTH.put("414", DataLength.fixed(13));
THREE_DIGIT_DATA_LENGTH.put("420", DataLength.variable(20));
THREE_DIGIT_DATA_LENGTH.put("421", DataLength.variable(15));
THREE_DIGIT_DATA_LENGTH.put("422", DataLength.fixed(3));
THREE_DIGIT_DATA_LENGTH.put("423", DataLength.variable(15));
THREE_DIGIT_DATA_LENGTH.put("424", DataLength.fixed(3));
THREE_DIGIT_DATA_LENGTH.put("425", DataLength.fixed(3));
THREE_DIGIT_DATA_LENGTH.put("426", DataLength.fixed(3));
}
private static final Map<String,DataLength> THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = new HashMap<>();
static {
for (int i = 310; i <= 316; i++) {
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put(String.valueOf(i), DataLength.fixed(6));
}
for (int i = 320; i <= 336; i++) {
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put(String.valueOf(i), DataLength.fixed(6));
}
for (int i = 340; i <= 357; i++) {
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put(String.valueOf(i), DataLength.fixed(6));
}
for (int i = 360; i <= 369; i++) {
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put(String.valueOf(i), DataLength.fixed(6));
}
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put("390", DataLength.variable(15));
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put("391", DataLength.variable(18));
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put("392", DataLength.variable(15));
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put("393", DataLength.variable(18));
THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.put("703", DataLength.variable(30));
}
private static final Map<String,DataLength> FOUR_DIGIT_DATA_LENGTH = new HashMap<>();
static {
FOUR_DIGIT_DATA_LENGTH.put("7001", DataLength.fixed(13));
FOUR_DIGIT_DATA_LENGTH.put("7002", DataLength.variable(30));
FOUR_DIGIT_DATA_LENGTH.put("7003", DataLength.fixed(10));
FOUR_DIGIT_DATA_LENGTH.put("8001", DataLength.fixed(14));
FOUR_DIGIT_DATA_LENGTH.put("8002", DataLength.variable(20));
FOUR_DIGIT_DATA_LENGTH.put("8003", DataLength.variable(30));
FOUR_DIGIT_DATA_LENGTH.put("8004", DataLength.variable(30));
FOUR_DIGIT_DATA_LENGTH.put("8005", DataLength.fixed(6));
FOUR_DIGIT_DATA_LENGTH.put("8006", DataLength.fixed(18));
FOUR_DIGIT_DATA_LENGTH.put("8007", DataLength.variable(30));
FOUR_DIGIT_DATA_LENGTH.put("8008", DataLength.variable(12));
FOUR_DIGIT_DATA_LENGTH.put("8018", DataLength.fixed(18));
FOUR_DIGIT_DATA_LENGTH.put("8020", DataLength.variable(25));
FOUR_DIGIT_DATA_LENGTH.put("8100", DataLength.fixed(6));
FOUR_DIGIT_DATA_LENGTH.put("8101", DataLength.fixed(10));
FOUR_DIGIT_DATA_LENGTH.put("8102", DataLength.fixed(2));
FOUR_DIGIT_DATA_LENGTH.put("8110", DataLength.variable(70));
FOUR_DIGIT_DATA_LENGTH.put("8200", DataLength.variable(70));
}
private FieldParser() {
}
static String parseFieldsInGeneralPurpose(String rawInformation) throws NotFoundException {
if (rawInformation.isEmpty()) {
return null;
}
// Processing 2-digit AIs
if (rawInformation.length() < 2) {
throw NotFoundException.getNotFoundInstance();
}
DataLength twoDigitDataLength = TWO_DIGIT_DATA_LENGTH.get(rawInformation.substring(0, 2));
if (twoDigitDataLength != null) {
if (twoDigitDataLength.variable) {
return processVariableAI(2, twoDigitDataLength.length, rawInformation);
}
return processFixedAI(2, twoDigitDataLength.length, rawInformation);
}
if (rawInformation.length() < 3) {
throw NotFoundException.getNotFoundInstance();
}
String firstThreeDigits = rawInformation.substring(0, 3);
DataLength threeDigitDataLength = THREE_DIGIT_DATA_LENGTH.get(firstThreeDigits);
if (threeDigitDataLength != null) {
if (threeDigitDataLength.variable) {
return processVariableAI(3, threeDigitDataLength.length, rawInformation);
}
return processFixedAI(3, threeDigitDataLength.length, rawInformation);
}
if (rawInformation.length() < 4) {
throw NotFoundException.getNotFoundInstance();
}
DataLength threeDigitPlusDigitDataLength = THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.get(firstThreeDigits);
if (threeDigitPlusDigitDataLength != null) {
if (threeDigitPlusDigitDataLength.variable) {
return processVariableAI(4, threeDigitPlusDigitDataLength.length, rawInformation);
}
return processFixedAI(4, threeDigitPlusDigitDataLength.length, rawInformation);
}
DataLength firstFourDigitLength = FOUR_DIGIT_DATA_LENGTH.get(rawInformation.substring(0, 4));
if (firstFourDigitLength != null) {
if (firstFourDigitLength.variable) {
return processVariableAI(4, firstFourDigitLength.length, rawInformation);
}
return processFixedAI(4, firstFourDigitLength.length, rawInformation);
}
throw NotFoundException.getNotFoundInstance();
}
private static String processFixedAI(int aiSize, int fieldSize, String rawInformation) throws NotFoundException {
if (rawInformation.length() < aiSize) {
throw NotFoundException.getNotFoundInstance();
}
String ai = rawInformation.substring(0, aiSize);
if (rawInformation.length() < aiSize + fieldSize) {
throw NotFoundException.getNotFoundInstance();
}
String field = rawInformation.substring(aiSize, aiSize + fieldSize);
String remaining = rawInformation.substring(aiSize + fieldSize);
String result = '(' + ai + ')' + field;
String parsedAI = parseFieldsInGeneralPurpose(remaining);
return parsedAI == null ? result : result + parsedAI;
}
private static String processVariableAI(int aiSize, int variableFieldSize, String rawInformation)
throws NotFoundException {
String ai = rawInformation.substring(0, aiSize);
int maxSize = Math.min(rawInformation.length(), aiSize + variableFieldSize);
String field = rawInformation.substring(aiSize, maxSize);
String remaining = rawInformation.substring(maxSize);
String result = '(' + ai + ')' + field;
String parsedAI = parseFieldsInGeneralPurpose(remaining);
return parsedAI == null ? result : result + parsedAI;
}
private static final class DataLength {
final boolean variable;
final int length;
private DataLength(boolean variable, int length) {
this.variable = variable;
this.length = length;
}
static DataLength fixed(int length) {
return new DataLength(false, length);
}
static DataLength variable(int length) {
return new DataLength(true, length);
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
import com.google.zxing.NotFoundException;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
public final class FieldParserTest extends Assert {
private static void checkFields(String expected) throws NotFoundException {
String field = expected.replace("(", "").replace(")","");
String actual = FieldParser.parseFieldsInGeneralPurpose(field);
assertEquals(expected, actual);
}
@Test
public void testParseField() throws Exception {
checkFields("(15)991231(3103)001750(10)12A");
}
@Test
public void testParseField2() throws Exception {
checkFields("(15)991231(15)991231(3103)001750(10)12A");
}
}

View File

@@ -1,470 +0,0 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class GeneralAppIdDecoder {
private final BitArray information;
private final CurrentParsingState current = new CurrentParsingState();
private final StringBuilder buffer = new StringBuilder();
GeneralAppIdDecoder(BitArray information) {
this.information = information;
}
String decodeAllCodes(StringBuilder buff, int initialPosition) throws NotFoundException, FormatException {
int currentPosition = initialPosition;
String remaining = null;
do {
DecodedInformation info = this.decodeGeneralPurposeField(currentPosition, remaining);
String parsedFields = FieldParser.parseFieldsInGeneralPurpose(info.getNewString());
if (parsedFields != null) {
buff.append(parsedFields);
}
if (info.isRemaining()) {
remaining = String.valueOf(info.getRemainingValue());
} else {
remaining = null;
}
if (currentPosition == info.getNewPosition()) { // No step forward!
break;
}
currentPosition = info.getNewPosition();
} while (true);
return buff.toString();
}
private boolean isStillNumeric(int pos) {
// It's numeric if it still has 7 positions
// and one of the first 4 bits is "1".
if (pos + 7 > this.information.getSize()) {
return pos + 4 <= this.information.getSize();
}
for (int i = pos; i < pos + 3; ++i) {
if (this.information.get(i)) {
return true;
}
}
return this.information.get(pos + 3);
}
private DecodedNumeric decodeNumeric(int pos) throws FormatException {
if (pos + 7 > this.information.getSize()) {
int numeric = extractNumericValueFromBitArray(pos, 4);
if (numeric == 0) {
return new DecodedNumeric(this.information.getSize(), DecodedNumeric.FNC1, DecodedNumeric.FNC1);
}
return new DecodedNumeric(this.information.getSize(), numeric - 1, DecodedNumeric.FNC1);
}
int numeric = extractNumericValueFromBitArray(pos, 7);
int digit1 = (numeric - 8) / 11;
int digit2 = (numeric - 8) % 11;
return new DecodedNumeric(pos + 7, digit1, digit2);
}
int extractNumericValueFromBitArray(int pos, int bits) {
return extractNumericValueFromBitArray(this.information, pos, bits);
}
static int extractNumericValueFromBitArray(BitArray information, int pos, int bits) {
int value = 0;
for (int i = 0; i < bits; ++i) {
if (information.get(pos + i)) {
value |= 1 << (bits - i - 1);
}
}
return value;
}
DecodedInformation decodeGeneralPurposeField(int pos, String remaining) throws FormatException {
this.buffer.setLength(0);
if (remaining != null) {
this.buffer.append(remaining);
}
this.current.setPosition(pos);
DecodedInformation lastDecoded = parseBlocks();
if (lastDecoded != null && lastDecoded.isRemaining()) {
return new DecodedInformation(this.current.getPosition(),
this.buffer.toString(), lastDecoded.getRemainingValue());
}
return new DecodedInformation(this.current.getPosition(), this.buffer.toString());
}
private DecodedInformation parseBlocks() throws FormatException {
boolean isFinished;
BlockParsedRXingResult result;
do {
int initialPosition = current.getPosition();
if (current.isAlpha()) {
result = parseAlphaBlock();
isFinished = result.isFinished();
} else if (current.isIsoIec646()) {
result = parseIsoIec646Block();
isFinished = result.isFinished();
} else { // it must be numeric
result = parseNumericBlock();
isFinished = result.isFinished();
}
boolean positionChanged = initialPosition != current.getPosition();
if (!positionChanged && !isFinished) {
break;
}
} while (!isFinished);
return result.getDecodedInformation();
}
private BlockParsedRXingResult parseNumericBlock() throws FormatException {
while (isStillNumeric(current.getPosition())) {
DecodedNumeric numeric = decodeNumeric(current.getPosition());
current.setPosition(numeric.getNewPosition());
if (numeric.isFirstDigitFNC1()) {
DecodedInformation information;
if (numeric.isSecondDigitFNC1()) {
information = new DecodedInformation(current.getPosition(), buffer.toString());
} else {
information = new DecodedInformation(current.getPosition(), buffer.toString(), numeric.getSecondDigit());
}
return new BlockParsedRXingResult(information, true);
}
buffer.append(numeric.getFirstDigit());
if (numeric.isSecondDigitFNC1()) {
DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.toString());
return new BlockParsedRXingResult(information, true);
}
buffer.append(numeric.getSecondDigit());
}
if (isNumericToAlphaNumericLatch(current.getPosition())) {
current.setAlpha();
current.incrementPosition(4);
}
return new BlockParsedRXingResult();
}
private BlockParsedRXingResult parseIsoIec646Block() throws FormatException {
while (isStillIsoIec646(current.getPosition())) {
DecodedChar iso = decodeIsoIec646(current.getPosition());
current.setPosition(iso.getNewPosition());
if (iso.isFNC1()) {
DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.toString());
return new BlockParsedRXingResult(information, true);
}
buffer.append(iso.getValue());
}
if (isAlphaOr646ToNumericLatch(current.getPosition())) {
current.incrementPosition(3);
current.setNumeric();
} else if (isAlphaTo646ToAlphaLatch(current.getPosition())) {
if (current.getPosition() + 5 < this.information.getSize()) {
current.incrementPosition(5);
} else {
current.setPosition(this.information.getSize());
}
current.setAlpha();
}
return new BlockParsedRXingResult();
}
private BlockParsedRXingResult parseAlphaBlock() {
while (isStillAlpha(current.getPosition())) {
DecodedChar alpha = decodeAlphanumeric(current.getPosition());
current.setPosition(alpha.getNewPosition());
if (alpha.isFNC1()) {
DecodedInformation information = new DecodedInformation(current.getPosition(), buffer.toString());
return new BlockParsedRXingResult(information, true); //end of the char block
}
buffer.append(alpha.getValue());
}
if (isAlphaOr646ToNumericLatch(current.getPosition())) {
current.incrementPosition(3);
current.setNumeric();
} else if (isAlphaTo646ToAlphaLatch(current.getPosition())) {
if (current.getPosition() + 5 < this.information.getSize()) {
current.incrementPosition(5);
} else {
current.setPosition(this.information.getSize());
}
current.setIsoIec646();
}
return new BlockParsedRXingResult();
}
private boolean isStillIsoIec646(int pos) {
if (pos + 5 > this.information.getSize()) {
return false;
}
int fiveBitValue = extractNumericValueFromBitArray(pos, 5);
if (fiveBitValue >= 5 && fiveBitValue < 16) {
return true;
}
if (pos + 7 > this.information.getSize()) {
return false;
}
int sevenBitValue = extractNumericValueFromBitArray(pos, 7);
if (sevenBitValue >= 64 && sevenBitValue < 116) {
return true;
}
if (pos + 8 > this.information.getSize()) {
return false;
}
int eightBitValue = extractNumericValueFromBitArray(pos, 8);
return eightBitValue >= 232 && eightBitValue < 253;
}
private DecodedChar decodeIsoIec646(int pos) throws FormatException {
int fiveBitValue = extractNumericValueFromBitArray(pos, 5);
if (fiveBitValue == 15) {
return new DecodedChar(pos + 5, DecodedChar.FNC1);
}
if (fiveBitValue >= 5 && fiveBitValue < 15) {
return new DecodedChar(pos + 5, (char) ('0' + fiveBitValue - 5));
}
int sevenBitValue = extractNumericValueFromBitArray(pos, 7);
if (sevenBitValue >= 64 && sevenBitValue < 90) {
return new DecodedChar(pos + 7, (char) (sevenBitValue + 1));
}
if (sevenBitValue >= 90 && sevenBitValue < 116) {
return new DecodedChar(pos + 7, (char) (sevenBitValue + 7));
}
int eightBitValue = extractNumericValueFromBitArray(pos, 8);
char c;
switch (eightBitValue) {
case 232:
c = '!';
break;
case 233:
c = '"';
break;
case 234:
c = '%';
break;
case 235:
c = '&';
break;
case 236:
c = '\'';
break;
case 237:
c = '(';
break;
case 238:
c = ')';
break;
case 239:
c = '*';
break;
case 240:
c = '+';
break;
case 241:
c = ',';
break;
case 242:
c = '-';
break;
case 243:
c = '.';
break;
case 244:
c = '/';
break;
case 245:
c = ':';
break;
case 246:
c = ';';
break;
case 247:
c = '<';
break;
case 248:
c = '=';
break;
case 249:
c = '>';
break;
case 250:
c = '?';
break;
case 251:
c = '_';
break;
case 252:
c = ' ';
break;
default:
throw FormatException.getFormatInstance();
}
return new DecodedChar(pos + 8, c);
}
private boolean isStillAlpha(int pos) {
if (pos + 5 > this.information.getSize()) {
return false;
}
// We now check if it's a valid 5-bit value (0..9 and FNC1)
int fiveBitValue = extractNumericValueFromBitArray(pos, 5);
if (fiveBitValue >= 5 && fiveBitValue < 16) {
return true;
}
if (pos + 6 > this.information.getSize()) {
return false;
}
int sixBitValue = extractNumericValueFromBitArray(pos, 6);
return sixBitValue >= 16 && sixBitValue < 63; // 63 not included
}
private DecodedChar decodeAlphanumeric(int pos) {
int fiveBitValue = extractNumericValueFromBitArray(pos, 5);
if (fiveBitValue == 15) {
return new DecodedChar(pos + 5, DecodedChar.FNC1);
}
if (fiveBitValue >= 5 && fiveBitValue < 15) {
return new DecodedChar(pos + 5, (char) ('0' + fiveBitValue - 5));
}
int sixBitValue = extractNumericValueFromBitArray(pos, 6);
if (sixBitValue >= 32 && sixBitValue < 58) {
return new DecodedChar(pos + 6, (char) (sixBitValue + 33));
}
char c;
switch (sixBitValue) {
case 58:
c = '*';
break;
case 59:
c = ',';
break;
case 60:
c = '-';
break;
case 61:
c = '.';
break;
case 62:
c = '/';
break;
default:
throw new IllegalStateException("Decoding invalid alphanumeric value: " + sixBitValue);
}
return new DecodedChar(pos + 6, c);
}
private boolean isAlphaTo646ToAlphaLatch(int pos) {
if (pos + 1 > this.information.getSize()) {
return false;
}
for (int i = 0; i < 5 && i + pos < this.information.getSize(); ++i) {
if (i == 2) {
if (!this.information.get(pos + 2)) {
return false;
}
} else if (this.information.get(pos + i)) {
return false;
}
}
return true;
}
private boolean isAlphaOr646ToNumericLatch(int pos) {
// Next is alphanumeric if there are 3 positions and they are all zeros
if (pos + 3 > this.information.getSize()) {
return false;
}
for (int i = pos; i < pos + 3; ++i) {
if (this.information.get(i)) {
return false;
}
}
return true;
}
private boolean isNumericToAlphaNumericLatch(int pos) {
// Next is alphanumeric if there are 4 positions and they are all zeros, or
// if there is a subset of this just before the end of the symbol
if (pos + 1 > this.information.getSize()) {
return false;
}
for (int i = 0; i < 4 && i + pos < this.information.getSize(); ++i) {
if (this.information.get(pos + i)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use crate::{Exceptions, common::BitArray};
use super::GeneralAppIdDecoder;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
pub trait AbstractExpandedDecoder {
// private final BitArray information;
// private final GeneralAppIdDecoder generalDecoder;
// AbstractExpandedDecoder(BitArray information) {
// this.information = information;
// this.generalDecoder = new GeneralAppIdDecoder(information);
// }
// protected final BitArray getInformation() {
// return information;
// }
// protected final GeneralAppIdDecoder getGeneralDecoder() {
// return generalDecoder;
// }
fn parseInformation(&mut self) -> Result<String,Exceptions>;
fn getGeneralDecoder(&self) -> &GeneralAppIdDecoder;
// fn new(information:&BitArray) -> Self where Self:Sized;
}
// pub fn createDecoder( information:&BitArray) -> Box<dyn AbstractExpandedDecoder>{
// if information.get(1) {
// return new AI01AndOtherAIs(information);
// }
// if !information.get(2) {
// return new AnyAIDecoder(information);
// }
// let fourBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 4);
// switch (fourBitEncodationMethod) {
// case 4: return new AI013103decoder(information);
// case 5: return new AI01320xDecoder(information);
// }
// int fiveBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 5);
// switch (fiveBitEncodationMethod) {
// case 12: return new AI01392xDecoder(information);
// case 13: return new AI01393xDecoder(information);
// }
// int sevenBitEncodationMethod = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 7);
// switch (sevenBitEncodationMethod) {
// case 56: return new AI013x0x1xDecoder(information, "310", "11");
// case 57: return new AI013x0x1xDecoder(information, "320", "11");
// case 58: return new AI013x0x1xDecoder(information, "310", "13");
// case 59: return new AI013x0x1xDecoder(information, "320", "13");
// case 60: return new AI013x0x1xDecoder(information, "310", "15");
// case 61: return new AI013x0x1xDecoder(information, "320", "15");
// case 62: return new AI013x0x1xDecoder(information, "310", "17");
// case 63: return new AI013x0x1xDecoder(information, "320", "17");
// }
// throw new IllegalStateException("unknown decoder: " + information);
// }

View File

@@ -24,35 +24,42 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
use crate::common::BitArray;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.common.BitArray;
use super::{AI01decoder, AbstractExpandedDecoder, GeneralAppIdDecoder};
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class AI01AndOtherAIs extends AI01decoder {
pub struct AI01AndOtherAIs<'a>(&'a BitArray,GeneralAppIdDecoder<'a>);
impl<'a> AI01decoder for AI01AndOtherAIs<'_> {}
impl AbstractExpandedDecoder for AI01AndOtherAIs<'_> {
fn parseInformation(&mut self) -> Result<String,crate::Exceptions> {
let mut buff = String::new();//new StringBuilder();
private static final int HEADER_SIZE = 1 + 1 + 2; //first bit encodes the linkage flag,
//the second one is the encodation method, and the other two are for the variable length
AI01AndOtherAIs(BitArray information) {
super(information);
}
buff.push_str("(01)");
let initialGtinPosition = buff.chars().count();
let firstGtinDigit = self.getGeneralDecoder().extractNumericValueFromBitArray(Self::HEADER_SIZE, 4);
buff.push_str(&firstGtinDigit.to_string());
self.encodeCompressedGtinWithoutAI(&mut buff, Self::HEADER_SIZE + 4, initialGtinPosition);
self.1.decodeAllCodes(buff, Self::HEADER_SIZE + 44)
}
@Override
public String parseInformation() throws NotFoundException, FormatException {
StringBuilder buff = new StringBuilder();
buff.append("(01)");
int initialGtinPosition = buff.length();
int firstGtinDigit = this.getGeneralDecoder().extractNumericValueFromBitArray(HEADER_SIZE, 4);
buff.append(firstGtinDigit);
this.encodeCompressedGtinWithoutAI(buff, HEADER_SIZE + 4, initialGtinPosition);
return this.getGeneralDecoder().decodeAllCodes(buff, HEADER_SIZE + 44);
}
fn getGeneralDecoder(&self) -> &super::GeneralAppIdDecoder {
&self.1
}
}
impl<'a> AI01AndOtherAIs<'_> {
fn new(information:&'a BitArray) -> AI01AndOtherAIs<'a> {
AI01AndOtherAIs( information,GeneralAppIdDecoder::new(information))
}
const HEADER_SIZE : usize = 1 + 1 + 2; //first bit encodes the linkage flag,
//the second one is the encodation method, and the other two are for the variable length
// AI01AndOtherAIs(BitArray information) {
// super(information);
// }
}

View File

@@ -24,58 +24,57 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
use super::AbstractExpandedDecoder;
import com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
abstract class AI01decoder extends AbstractExpandedDecoder {
pub trait AI01decoder : AbstractExpandedDecoder {
static final int GTIN_SIZE = 40;
const GTIN_SIZE : u32 = 40;
AI01decoder(BitArray information) {
super(information);
fn encodeCompressedGtin(&self, buf:&mut String, currentPos:usize) {
buf.push_str("(01)");
let initialPosition = buf.chars().count();
buf.push('9');
self.encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition);
}
final void encodeCompressedGtin(StringBuilder buf, int currentPos) {
buf.append("(01)");
int initialPosition = buf.length();
buf.append('9');
encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition);
}
final void encodeCompressedGtinWithoutAI(StringBuilder buf, int currentPos, int initialBufferPosition) {
for (int i = 0; i < 4; ++i) {
int currentBlock = this.getGeneralDecoder().extractNumericValueFromBitArray(currentPos + 10 * i, 10);
if (currentBlock / 100 == 0) {
buf.append('0');
fn encodeCompressedGtinWithoutAI(&self, buf:&mut String, currentPos:usize, initialBufferPosition:usize) {
for i in 0..4 {
// for (int i = 0; i < 4; ++i) {
let currentBlock = self.getGeneralDecoder().extractNumericValueFromBitArray(currentPos + 10 * i, 10);
if currentBlock / 100 == 0 {
buf.push('0');
}
if (currentBlock / 10 == 0) {
buf.append('0');
if currentBlock / 10 == 0 {
buf.push('0');
}
buf.append(currentBlock);
buf.push_str(&currentBlock.to_string());
}
appendCheckDigit(buf, initialBufferPosition);
}
private static void appendCheckDigit(StringBuilder buf, int currentPos) {
int checkDigit = 0;
for (int i = 0; i < 13; i++) {
int digit = buf.charAt(i + currentPos) - '0';
checkDigit += (i & 0x01) == 0 ? 3 * digit : digit;
}
checkDigit = 10 - (checkDigit % 10);
if (checkDigit == 10) {
checkDigit = 0;
}
buf.append(checkDigit);
}
}
pub(super) fn appendCheckDigit( buf:&mut String, currentPos:usize) {
let mut checkDigit = 0;
for i in 0..13 {
// for (int i = 0; i < 13; i++) {
let digit = buf.chars().nth(i + currentPos).unwrap() as u32 - '0' as u32;
checkDigit += if (i & 0x01) == 0 {3 * digit} else {digit};
}
checkDigit = 10 - (checkDigit % 10);
if checkDigit == 10 {
checkDigit = 0;
}
buf.push_str(&checkDigit.to_string());
}

View File

@@ -24,31 +24,33 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
use super::DecodedInformation;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class BlockParsedRXingResult {
private final DecodedInformation decodedInformation;
private final boolean finished;
BlockParsedRXingResult() {
this(null, false);
}
BlockParsedRXingResult(DecodedInformation information, boolean finished) {
this.finished = finished;
this.decodedInformation = information;
}
DecodedInformation getDecodedInformation() {
return this.decodedInformation;
}
boolean isFinished() {
return this.finished;
}
pub struct BlockParsedRXingResult {
decodedInformation: Option<DecodedInformation>,
finished: bool,
}
impl BlockParsedRXingResult {
pub fn new() -> Self {
Self::with_information(None, false)
}
pub fn with_information(information: Option<DecodedInformation>, finished: bool) -> Self {
Self {
decodedInformation: information,
finished,
}
}
pub fn getDecodedInformation(&self) -> &Option<DecodedInformation> {
&self.decodedInformation
}
pub fn isFinished(&self) -> bool {
self.finished
}
}

View File

@@ -23,61 +23,62 @@
*
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum State {
NUMERIC,
ALPHA,
ISO_IEC_646,
}
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class CurrentParsingState {
private int position;
private State encoding;
private enum State {
NUMERIC,
ALPHA,
ISO_IEC_646
}
CurrentParsingState() {
this.position = 0;
this.encoding = State.NUMERIC;
}
int getPosition() {
return position;
}
void setPosition(int position) {
this.position = position;
}
void incrementPosition(int delta) {
position += delta;
}
boolean isAlpha() {
return this.encoding == State.ALPHA;
}
boolean isNumeric() {
return this.encoding == State.NUMERIC;
}
boolean isIsoIec646() {
return this.encoding == State.ISO_IEC_646;
}
void setNumeric() {
this.encoding = State.NUMERIC;
}
void setAlpha() {
this.encoding = State.ALPHA;
}
void setIsoIec646() {
this.encoding = State.ISO_IEC_646;
}
pub struct CurrentParsingState {
position: usize,
encoding: State,
}
impl CurrentParsingState {
pub fn new() -> Self {
Self {
position: 0,
encoding: State::NUMERIC,
}
}
pub fn getPosition(&self) -> usize {
self.position
}
pub fn setPosition(&mut self, position: usize) {
self.position = position
}
pub fn incrementPosition(&mut self, delta: usize) {
self.position += delta;
}
pub fn isAlpha(&self) -> bool {
self.encoding == State::ALPHA
}
pub fn isNumeric(&self) -> bool {
self.encoding == State::NUMERIC
}
pub fn isIsoIec646(&self) -> bool {
self.encoding == State::ISO_IEC_646
}
pub fn setNumeric(&mut self) {
self.encoding = State::NUMERIC;
}
pub fn setAlpha(&mut self) {
self.encoding = State::ALPHA;
}
pub fn setIsoIec646(&mut self) {
self.encoding = State::ISO_IEC_646;
}
}

View File

@@ -24,29 +24,33 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
use super::DecodedObject;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class DecodedChar extends DecodedObject {
private final char value;
static final char FNC1 = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset
DecodedChar(int newPosition, char value) {
super(newPosition);
this.value = value;
}
char getValue() {
return this.value;
}
boolean isFNC1() {
return this.value == FNC1;
}
pub struct DecodedChar {
value: char,
newPosition: usize,
}
impl DecodedObject for DecodedChar {
fn getNewPosition(&self) -> usize {
self.newPosition
}
}
impl DecodedChar {
pub const FNC1: char = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset
pub fn new(newPosition: usize, value: char) -> Self {
Self { value, newPosition }
}
pub fn getValue(&self) -> char {
self.value
}
pub fn isFNC1(&self) -> bool {
self.value == Self::FNC1
}
}

View File

@@ -24,50 +24,57 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
import com.google.zxing.FormatException;
use super::DecodedObject;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
final class DecodedNumeric extends DecodedObject {
#[derive(Clone)]
pub struct DecodedInformation {
newPosition: usize,
newString: String,
remainingValue: u32,
remaining: bool,
}
private final int firstDigit;
private final int secondDigit;
static final int FNC1 = 10;
DecodedNumeric(int newPosition, int firstDigit, int secondDigit) throws FormatException {
super(newPosition);
if (firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10) {
throw FormatException.getFormatInstance();
impl DecodedObject for DecodedInformation {
fn getNewPosition(&self) -> usize {
self.newPosition
}
}
impl DecodedInformation {
pub fn new(newPosition: usize, newString: String) -> Self {
Self {
newPosition,
newString,
remainingValue: 0,
remaining: false,
}
}
this.firstDigit = firstDigit;
this.secondDigit = secondDigit;
}
pub fn with_remaining_value(
newPosition: usize,
newString: String,
remainingValue: u32,
) -> Self {
Self {
newPosition,
newString,
remainingValue,
remaining: true,
}
}
int getFirstDigit() {
return this.firstDigit;
}
pub fn getNewString(&self) -> &str {
&self.newString
}
int getSecondDigit() {
return this.secondDigit;
}
int getValue() {
return this.firstDigit * 10 + this.secondDigit;
}
boolean isFirstDigitFNC1() {
return this.firstDigit == FNC1;
}
boolean isSecondDigitFNC1() {
return this.secondDigit == FNC1;
}
pub fn isRemaining(&self) -> bool {
self.remaining
}
pub fn getRemainingValue(&self) -> u32 {
self.remainingValue
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use crate::Exceptions;
use super::DecodedObject;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
pub struct DecodedNumeric {
newPosition: usize,
firstDigit: u32,
secondDigit: u32,
}
impl DecodedObject for DecodedNumeric {
fn getNewPosition(&self) -> usize {
self.newPosition
}
}
impl DecodedNumeric {
pub const FNC1: u32 = 10;
pub fn new(newPosition: usize, firstDigit: u32, secondDigit: u32) -> Result<Self, Exceptions> {
// super(newPosition);
if firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10 {
return Err(Exceptions::FormatException(
".getFormatInstance();".to_owned(),
));
}
Ok(Self {
newPosition,
firstDigit,
secondDigit,
})
}
pub fn getFirstDigit(&self) -> u32 {
self.firstDigit
}
pub fn getSecondDigit(&self) -> u32 {
self.secondDigit
}
pub fn getValue(&self) -> u32 {
self.firstDigit * 10 + self.secondDigit
}
pub fn isFirstDigitFNC1(&self) -> bool {
self.firstDigit == Self::FNC1
}
pub fn isSecondDigitFNC1(&self) -> bool {
self.secondDigit == Self::FNC1
}
}

View File

@@ -24,21 +24,13 @@
* http://www.piramidepse.com/
*/
package com.google.zxing.oned.rss.expanded.decoders;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
abstract class DecodedObject {
pub trait DecodedObject {
private final int newPosition;
DecodedObject(int newPosition) {
this.newPosition = newPosition;
}
final int getNewPosition() {
return this.newPosition;
}
fn getNewPosition(&self) -> usize;
}

View File

@@ -0,0 +1,308 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use std::collections::HashMap;
use crate::Exceptions;
use lazy_static::lazy_static;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
lazy_static! {
static ref TWO_DIGIT_DATA_LENGTH : HashMap<String,DataLength> = {
let mut hm = HashMap::new();
hm.insert("00".to_owned(), DataLength::fixed(18));
hm.insert("01".to_owned(), DataLength::fixed(14));
hm.insert("02".to_owned(), DataLength::fixed(14));
hm.insert("10".to_owned(), DataLength::variable(20));
hm.insert("11".to_owned(), DataLength::fixed(6));
hm.insert("12".to_owned(), DataLength::fixed(6));
hm.insert("13".to_owned(), DataLength::fixed(6));
hm.insert("15".to_owned(), DataLength::fixed(6));
hm.insert("17".to_owned(), DataLength::fixed(6));
hm.insert("20".to_owned(), DataLength::fixed(2));
hm.insert("21".to_owned(), DataLength::variable(20));
hm.insert("22".to_owned(), DataLength::variable(29));
hm.insert("30".to_owned(), DataLength::variable(8));
hm.insert("37".to_owned(), DataLength::variable(8));
//internal company codes
for i in 90..=99 {
// for (int i = 90; i <= 99; i++) {
hm.insert(i.to_string(), DataLength::variable(30));
}
hm
};
static ref THREE_DIGIT_DATA_LENGTH : HashMap<String,DataLength>=
{
let mut hm = HashMap::new();
hm.insert("240".to_owned(), DataLength::variable(30));
hm.insert("241".to_owned(), DataLength::variable(30));
hm.insert("242".to_owned(), DataLength::variable(6));
hm.insert("250".to_owned(), DataLength::variable(30));
hm.insert("251".to_owned(), DataLength::variable(30));
hm.insert("253".to_owned(), DataLength::variable(17));
hm.insert("254".to_owned(), DataLength::variable(20));
hm.insert("400".to_owned(), DataLength::variable(30));
hm.insert("401".to_owned(), DataLength::variable(30));
hm.insert("402".to_owned(), DataLength::fixed(17));
hm.insert("403".to_owned(), DataLength::variable(30));
hm.insert("410".to_owned(), DataLength::fixed(13));
hm.insert("411".to_owned(), DataLength::fixed(13));
hm.insert("412".to_owned(), DataLength::fixed(13));
hm.insert("413".to_owned(), DataLength::fixed(13));
hm.insert("414".to_owned(), DataLength::fixed(13));
hm.insert("420".to_owned(), DataLength::variable(20));
hm.insert("421".to_owned(), DataLength::variable(15));
hm.insert("422".to_owned(), DataLength::fixed(3));
hm.insert("423".to_owned(), DataLength::variable(15));
hm.insert("424".to_owned(), DataLength::fixed(3));
hm.insert("425".to_owned(), DataLength::fixed(3));
hm.insert("426".to_owned(), DataLength::fixed(3));
hm
};
static ref THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH:HashMap<String,DataLength> = {
let mut hm = HashMap::new();
for i in 310..=316 {
// for (int i = 310; i <= 316; i++) {
hm.insert(i.to_string(), DataLength::fixed(6));
}
for i in 320..=336 {
// for (int i = 320; i <= 336; i++) {
hm.insert(i.to_string(), DataLength::fixed(6));
}
for i in 340..=357 {
// for (int i = 340; i <= 357; i++) {
hm.insert(i.to_string(), DataLength::fixed(6));
}
for i in 360..=369 {
// for (int i = 360; i <= 369; i++) {
hm.insert(i.to_string(), DataLength::fixed(6));
}
hm.insert("390".to_owned(), DataLength::variable(15));
hm.insert("391".to_owned(), DataLength::variable(18));
hm.insert("392".to_owned(), DataLength::variable(15));
hm.insert("393".to_owned(), DataLength::variable(18));
hm.insert("703".to_owned(), DataLength::variable(30));
hm
};
static ref FOUR_DIGIT_DATA_LENGTH : HashMap<String,DataLength>={
let mut hm = HashMap::new();
hm.insert("7001".to_owned(), DataLength::fixed(13));
hm.insert("7002".to_owned(), DataLength::variable(30));
hm.insert("7003".to_owned(), DataLength::fixed(10));
hm.insert("8001".to_owned(), DataLength::fixed(14));
hm.insert("8002".to_owned(), DataLength::variable(20));
hm.insert("8003".to_owned(), DataLength::variable(30));
hm.insert("8004".to_owned(), DataLength::variable(30));
hm.insert("8005".to_owned(), DataLength::fixed(6));
hm.insert("8006".to_owned(), DataLength::fixed(18));
hm.insert("8007".to_owned(), DataLength::variable(30));
hm.insert("8008".to_owned(), DataLength::variable(12));
hm.insert("8018".to_owned(), DataLength::fixed(18));
hm.insert("8020".to_owned(), DataLength::variable(25));
hm.insert("8100".to_owned(), DataLength::fixed(6));
hm.insert("8101".to_owned(), DataLength::fixed(10));
hm.insert("8102".to_owned(), DataLength::fixed(2));
hm.insert("8110".to_owned(), DataLength::variable(70));
hm.insert("8200".to_owned(), DataLength::variable(70));
hm
};
}
pub fn parseFieldsInGeneralPurpose(rawInformation: &str) -> Result<String, Exceptions> {
if rawInformation.is_empty() {
return Ok("".to_owned());
}
// Processing 2-digit AIs
if rawInformation.chars().count() < 2 {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let lookup: String = rawInformation.chars().take(2).collect();
let twoDigitDataLength = TWO_DIGIT_DATA_LENGTH.get(&lookup);
if let Some(tddl) = twoDigitDataLength {
if tddl.variable {
return processVariableAI(2, tddl.length, rawInformation);
}
return processFixedAI(2, tddl.length, rawInformation);
}
if rawInformation.chars().count() < 3 {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let firstThreeDigits: String = rawInformation.chars().take(3).collect(); //rawInformation.substring(0, 3);
let threeDigitDataLength = THREE_DIGIT_DATA_LENGTH.get(&firstThreeDigits);
if let Some(tddl) = threeDigitDataLength {
if tddl.variable {
return processVariableAI(3, tddl.length, rawInformation);
}
return processFixedAI(3, tddl.length, rawInformation);
}
if rawInformation.chars().count() < 4 {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let threeDigitPlusDigitDataLength = THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.get(&firstThreeDigits);
if let Some(tdpddl) = threeDigitPlusDigitDataLength {
if tdpddl.variable {
return processVariableAI(4, tdpddl.length, rawInformation);
}
return processFixedAI(4, tdpddl.length, rawInformation);
}
let lookup: String = rawInformation.chars().take(4).collect();
let firstFourDigitLength = FOUR_DIGIT_DATA_LENGTH.get(&lookup /*(0, 4)*/);
if let Some(ffdl) = firstFourDigitLength {
if ffdl.variable {
return processVariableAI(4, ffdl.length, rawInformation);
}
return processFixedAI(4, ffdl.length, rawInformation);
}
return Err(Exceptions::NotFoundException("".to_owned()));
}
fn processFixedAI(
aiSize: usize,
fieldSize: usize,
rawInformation: &str,
) -> Result<String, Exceptions> {
if rawInformation.chars().count() < aiSize {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let ai: String = rawInformation.chars().take(aiSize).collect();
if rawInformation.chars().count() < aiSize + fieldSize {
return Err(Exceptions::NotFoundException("".to_owned()));
}
let field: String = rawInformation
.chars()
.skip(aiSize)
.take(fieldSize)
.collect(); //rawInformation.substring(aiSize, aiSize + fieldSize);
let remaining: String = rawInformation.chars().skip(aiSize + fieldSize).collect(); // rawInformation.substring(aiSize + fieldSize);
let result = format!("({}){}", ai, field);
let parsedAI = parseFieldsInGeneralPurpose(&remaining)?;
Ok(if parsedAI.is_empty() {
result
} else {
format!("{}{}", result, parsedAI)
})
}
fn processVariableAI(
aiSize: usize,
variableFieldSize: usize,
rawInformation: &str,
) -> Result<String, Exceptions> {
let ai: String = rawInformation.chars().take(aiSize as usize).collect(); //rawInformation.substring(0, aiSize);
let maxSize = rawInformation
.chars()
.count()
.min(aiSize + variableFieldSize);
let field: String = rawInformation
.chars()
.skip(aiSize as usize)
.take(maxSize)
.collect(); // (aiSize, maxSize);
let remaining: String = rawInformation.chars().skip(maxSize).collect();
let result = format!("({}){}", ai, field); //'(' + ai + ')' + field;
let parsedAI = parseFieldsInGeneralPurpose(&remaining)?;
Ok(if parsedAI.is_empty() {
result
} else {
format!("{}{}", result, parsedAI)
})
}
struct DataLength {
pub variable: bool,
pub length: usize,
}
impl DataLength {
// fn new( variable:bool, length:u32) -> Self{
// Self(variable,length)
// }
pub fn fixed(length: usize) -> Self {
Self {
variable: false,
length,
}
}
pub fn variable(length: usize) -> Self {
Self {
variable: true,
length,
}
}
}
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
#[cfg(test)]
mod FieldParserTest {
fn checkFields( expected:&str) {
let field = expected.replace("(", "").replace(")","");
let actual = super::parseFieldsInGeneralPurpose(&field).expect("parse");
assert_eq!(expected, actual);
}
#[test]
fn testParseField() {
checkFields("(15)991231(3103)001750(10)12A");
}
#[test]
fn testParseField2() {
checkFields("(15)991231(15)991231(3103)001750(10)12A");
}
}

View File

@@ -0,0 +1,469 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use crate::{common::BitArray, Exceptions};
use super::{CurrentParsingState, DecodedChar, DecodedNumeric, DecodedInformation, BlockParsedRXingResult, DecodedObject, field_parser};
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
pub struct GeneralAppIdDecoder<'a> {
information:&'a BitArray,
current : CurrentParsingState, //= new CurrentParsingState();
buffer :String, //= new StringBuilder();
}
impl<'a> GeneralAppIdDecoder<'_> {
pub fn new( information:&'a BitArray) -> GeneralAppIdDecoder<'a>{
GeneralAppIdDecoder{
information,
current: CurrentParsingState::new(),
buffer: String::new(),
}
}
pub fn decodeAllCodes(&mut self, buff:String, initialPosition:usize) -> Result<String,Exceptions> {
let mut buff = buff;
let mut currentPosition = initialPosition;
let mut remaining = "".to_owned();
loop {
let info = self.decodeGeneralPurposeField(currentPosition, &remaining)?;
let parsedFields =field_parser::parseFieldsInGeneralPurpose(info.getNewString())?;
if !parsedFields.is_empty() {
buff.push_str(&parsedFields);
}
if info.isRemaining() {
remaining = info.getRemainingValue().to_string();
} else {
remaining = "".to_owned();
}
if currentPosition == info.getNewPosition() { // No step forward!
break;
}
currentPosition = info.getNewPosition();
}
Ok(buff)
}
fn isStillNumeric(&self, pos:usize) -> bool{
// It's numeric if it still has 7 positions
// and one of the first 4 bits is "1".
if pos + 7 > self.information.getSize() {
return pos + 4 <= self.information.getSize();
}
for i in pos..pos+3 {
// for (int i = pos; i < pos + 3; ++i) {
if self.information.get(i) {
return true;
}
}
self.information.get(pos + 3)
}
fn decodeNumeric(&self, pos:usize) -> Result<DecodedNumeric,Exceptions> {
if pos + 7 > self.information.getSize() {
let numeric = self.extractNumericValueFromBitArray(pos, 4);
if numeric == 0 {
return DecodedNumeric::new(self.information.getSize(), DecodedNumeric::FNC1, DecodedNumeric::FNC1);
}
return DecodedNumeric::new(self.information.getSize(), numeric - 1, DecodedNumeric::FNC1);
}
let numeric = self.extractNumericValueFromBitArray(pos, 7);
let digit1 = (numeric - 8) / 11;
let digit2 = (numeric - 8) % 11;
DecodedNumeric::new(pos + 7, digit1, digit2)
}
pub fn extractNumericValueFromBitArray(&self, pos:usize, bits:u32) -> u32{
Self::extractNumericValueFromBitArrayWithInformation(&self.information, pos, bits)
}
pub fn extractNumericValueFromBitArrayWithInformation( information:&BitArray, pos:usize, bits:u32) ->u32{
let mut value = 0;
for i in 0..bits {
// for (int i = 0; i < bits; ++i) {
if information.get(pos + i as usize) {
value |= 1 << (bits - i - 1);
}
}
value
}
pub fn decodeGeneralPurposeField(&mut self, pos:usize, remaining:&str) -> Result<DecodedInformation,Exceptions> {
self.buffer.clear();
if !remaining.is_empty() {
self.buffer.push_str(remaining);
}
self.current.setPosition(pos);
if let Ok(lastDecoded) = self.parseBlocks(){
if lastDecoded.isRemaining() {
return Ok(DecodedInformation::with_remaining_value(self.current.getPosition(),
self.buffer.clone(), lastDecoded.getRemainingValue()));
}}
Ok(DecodedInformation::new(self.current.getPosition(), self.buffer.clone()))
}
fn parseBlocks(&mut self) -> Result<DecodedInformation,Exceptions> {
let mut isFinished;
let mut result:BlockParsedRXingResult;
loop {
let initialPosition = self.current.getPosition();
if self.current.isAlpha() {
result =self. parseAlphaBlock()?;
isFinished = result.isFinished();
} else if self.current.isIsoIec646() {
result = self.parseIsoIec646Block()?;
isFinished = result.isFinished();
} else { // it must be numeric
result = self.parseNumericBlock()?;
isFinished = result.isFinished();
}
let positionChanged = initialPosition != self.current.getPosition();
if !positionChanged && !isFinished {
break;
}
if !(!isFinished) { break; }
} //while (!isFinished);
Ok(result.getDecodedInformation().as_ref().unwrap().clone())
}
fn parseNumericBlock(&mut self) -> Result<BlockParsedRXingResult,Exceptions> {
while self.isStillNumeric(self.current.getPosition()) {
let numeric = self.decodeNumeric(self.current.getPosition())?;
self.current.setPosition(numeric.getNewPosition());
if numeric.isFirstDigitFNC1() {
let information=
if numeric.isSecondDigitFNC1() {
DecodedInformation::new(self.current.getPosition(), self.buffer.clone())
} else {
DecodedInformation::with_remaining_value(self.current.getPosition(), self.buffer.clone(), numeric.getSecondDigit())
};
return Ok(BlockParsedRXingResult::with_information(Some(information), true));
}
self.buffer.push_str(&numeric.getFirstDigit().to_string());
if numeric.isSecondDigitFNC1() {
let information = DecodedInformation::new(self.current.getPosition(), self.buffer.clone());
return Ok(BlockParsedRXingResult::with_information(Some(information), true));
}
self.buffer.push_str(&numeric.getSecondDigit().to_string());
}
if self.isNumericToAlphaNumericLatch(self.current.getPosition()) {
self.current.setAlpha();
self.current.incrementPosition(4);
}
Ok(BlockParsedRXingResult::new())
}
fn parseIsoIec646Block(&mut self) -> Result<BlockParsedRXingResult,Exceptions> {
while self.isStillIsoIec646(self.current.getPosition()) {
let iso = self.decodeIsoIec646(self.current.getPosition())?;
self.current.setPosition(iso.getNewPosition());
if iso.isFNC1() {
let information = DecodedInformation::new(self.current.getPosition(), self.buffer.clone());
return Ok(BlockParsedRXingResult::with_information(Some(information), true));
}
self.buffer.push_str(&iso.getValue().to_string());
}
if self.isAlphaOr646ToNumericLatch(self.current.getPosition()) {
self.current.incrementPosition(3);
self.current.setNumeric();
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
if self.current.getPosition() + 5 < self.information.getSize() {
self. current.incrementPosition(5);
} else {
self.current.setPosition(self.information.getSize());
}
self.current.setAlpha();
}
Ok(BlockParsedRXingResult::new())
}
fn parseAlphaBlock(&mut self) -> Result<BlockParsedRXingResult,Exceptions> {
while self.isStillAlpha(self.current.getPosition()) {
let alpha = self.decodeAlphanumeric(self.current.getPosition())?;
self.current.setPosition(alpha.getNewPosition());
if alpha.isFNC1() {
let information = DecodedInformation::new(self.current.getPosition(), self.buffer.clone());
return Ok(BlockParsedRXingResult::with_information(Some(information), true)); //end of the char block
}
self.buffer.push_str(&alpha.getValue().to_string());
}
if self.isAlphaOr646ToNumericLatch(self.current.getPosition()) {
self.current.incrementPosition(3);
self.current.setNumeric();
} else if self.isAlphaTo646ToAlphaLatch(self.current.getPosition()) {
if self.current.getPosition() + 5 < self.information.getSize() {
self.current.incrementPosition(5);
} else {
self.current.setPosition(self.information.getSize());
}
self.current.setIsoIec646();
}
Ok(BlockParsedRXingResult::new())
}
fn isStillIsoIec646(&self, pos:usize) -> bool{
if pos + 5 > self.information.getSize() {
return false;
}
let fiveBitValue =self. extractNumericValueFromBitArray(pos, 5);
if fiveBitValue >= 5 && fiveBitValue < 16 {
return true;
}
if pos + 7 > self.information.getSize() {
return false;
}
let sevenBitValue = self.extractNumericValueFromBitArray(pos, 7);
if sevenBitValue >= 64 && sevenBitValue < 116 {
return true;
}
if pos + 8 > self.information.getSize() {
return false;
}
let eightBitValue = self.extractNumericValueFromBitArray(pos, 8);
eightBitValue >= 232 && eightBitValue < 253
}
fn decodeIsoIec646(&self, pos:usize) -> Result<DecodedChar,Exceptions> {
let fiveBitValue = self.extractNumericValueFromBitArray(pos, 5);
if fiveBitValue == 15 {
return Ok(DecodedChar::new(pos + 5, DecodedChar::FNC1));
}
if fiveBitValue >= 5 && fiveBitValue < 15 {
return Ok(DecodedChar::new(pos + 5, char::from_u32 ('0' as u32 + fiveBitValue - 5).unwrap()));
}
let sevenBitValue = self.extractNumericValueFromBitArray(pos, 7);
if sevenBitValue >= 64 && sevenBitValue < 90 {
return Ok(DecodedChar::new(pos + 7, char::from_u32 (sevenBitValue + 1).unwrap()));
}
if sevenBitValue >= 90 && sevenBitValue < 116 {
return Ok(DecodedChar::new(pos + 7, char::from_u32 (sevenBitValue + 7).unwrap()));
}
let eightBitValue = self.extractNumericValueFromBitArray(pos, 8);
let c=
match eightBitValue {
232=>
'!',
233=>
'"',
234=>
'%',
235=>
'&',
236=>
'\'',
237=>
'(',
238=>
')',
239=>
'*',
240=>
'+',
241=>
',',
242=>
'-',
243=>
'.',
244=>
'/',
245=>
':',
246=>
';',
247=>
'<',
248=>
'=',
249=>
'>',
250=>
'?',
251=>
'_',
252=>
' ',
_=>
return Err(Exceptions::FormatException("".to_owned())),
};
Ok(DecodedChar::new(pos + 8, c))
}
fn isStillAlpha(&self, pos:usize) -> bool{
if pos + 5 > self.information.getSize() {
return false;
}
// We now check if it's a valid 5-bit value (0..9 and FNC1)
let fiveBitValue = self.extractNumericValueFromBitArray(pos, 5);
if fiveBitValue >= 5 && fiveBitValue < 16 {
return true;
}
if pos + 6 > self.information.getSize() {
return false;
}
let sixBitValue = self.extractNumericValueFromBitArray(pos, 6);
sixBitValue >= 16 && sixBitValue < 63 // 63 not included
}
fn decodeAlphanumeric(&self, pos:usize) -> Result<DecodedChar,Exceptions> {
let fiveBitValue = self.extractNumericValueFromBitArray(pos, 5);
if fiveBitValue == 15 {
return Ok(DecodedChar::new(pos + 5, DecodedChar::FNC1));
}
if fiveBitValue >= 5 && fiveBitValue < 15 {
return Ok(DecodedChar::new(pos + 5, char::from_u32 ('0' as u32 + fiveBitValue - 5).unwrap()));
}
let sixBitValue = self.extractNumericValueFromBitArray(pos, 6);
if sixBitValue >= 32 && sixBitValue < 58 {
return Ok(DecodedChar::new(pos + 6, char::from_u32 (sixBitValue + 33).unwrap()));
}
let c =
match sixBitValue {
58=>
'*',
59=>
',',
60=>
'-',
61=>
'.',
62=>
'/',
_=>
return Err(Exceptions::IllegalStateException(format!("Decoding invalid alphanumeric value: {}" , sixBitValue))),
};
Ok(DecodedChar::new(pos + 6, c))
}
fn isAlphaTo646ToAlphaLatch(&self, pos:usize)-> bool {
if pos + 1 > self.information.getSize() {
return false;
}
let mut i = 0;
while i < 5 && i + pos < self.information.getSize() {
// for (int i = 0; i < 5 && i + pos < this.information.getSize(); ++i) {
if i == 2 {
if !self.information.get(pos + 2) {
return false;
}
} else if self.information.get(pos + i) {
return false;
}
i+=1;
}
true
}
fn isAlphaOr646ToNumericLatch(&self, pos:usize) -> bool{
// Next is alphanumeric if there are 3 positions and they are all zeros
if pos + 3 > self.information.getSize() {
return false;
}
for i in pos..pos+3 {
// for (int i = pos; i < pos + 3; ++i) {
if self.information.get(i) {
return false;
}
}
true
}
fn isNumericToAlphaNumericLatch(&self, pos:usize) -> bool{
// Next is alphanumeric if there are 4 positions and they are all zeros, or
// if there is a subset of this just before the end of the symbol
if pos + 1 > self.information.getSize() {
return false;
}
let mut i = 0;
while i < 4 && pos < self.information.getSize() {
// for (int i = 0; i < 4 && i + pos < this.information.getSize(); ++i) {
if self.information.get(pos + i) {
return false;
}
i+=1;
}
true
}
}

View File

@@ -1 +1,27 @@
pub mod abstract_expanded_decoder;
pub use abstract_expanded_decoder::AbstractExpandedDecoder;
mod ai_01_and_other_ais;
pub use ai_01_and_other_ais::*;
mod ai_01_decoder;
pub use ai_01_decoder::*;
mod general_app_id_decoder;
pub use general_app_id_decoder::*;
mod current_parsing_state;
pub use current_parsing_state::*;
mod decoded_object;
pub use decoded_object::*;
mod decoded_char;
pub use decoded_char::*;
mod decoded_information;
pub use decoded_information::*;
mod decoded_numeric;
pub use decoded_numeric::*;
mod block_parsed_result;
pub use block_parsed_result::*;
pub mod field_parser;

View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2010 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.
*/
/*
* These authors would like to acknowledge the Spanish Ministry of Industry,
* Tourism and Trade, for the support in the project TSI020301-2008-2
* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled
* Mobile Dynamic Environments", led by Treelogic
* ( http://www.treelogic.com/ ):
*
* http://www.piramidepse.com/
*/
use std::fmt::Display;
use crate::oned::rss::{DataCharacter, FinderPattern};
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
#[derive(PartialEq, Eq, Hash)]
pub struct ExpandedPair {
leftChar: Option<DataCharacter>,
rightChar: Option<DataCharacter>,
finderPattern: Option<FinderPattern>,
}
impl ExpandedPair {
pub fn new(
leftChar: Option<DataCharacter>,
rightChar: Option<DataCharacter>,
finderPattern: Option<FinderPattern>,
) -> Self {
Self {
leftChar,
rightChar,
finderPattern,
}
}
pub fn getLeftChar(&self) -> &Option<DataCharacter> {
&self.leftChar
}
pub fn getRightChar(&self) -> &Option<DataCharacter> {
&self.rightChar
}
pub fn getFinderPattern(&self) -> &Option<FinderPattern> {
&self.finderPattern
}
pub fn mustBeLast(&self) -> bool {
self.rightChar.is_none()
}
}
impl Display for ExpandedPair {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[ {:?} , {:?} : {} ]",
self.leftChar,
self.rightChar,
if let Some(fp) = &self.finderPattern {
fp.getValue().to_string()
} else {
"null".to_owned()
}
)
}
}

View File

@@ -1 +1,7 @@
pub mod decoders;
pub mod binary_util;
pub mod bit_array_builder;
mod expanded_pair;
pub use expanded_pair::*;

View File

@@ -18,7 +18,7 @@ use std::collections::HashMap;
use crate::{
common::{detector::MathUtils, BitArray},
oned::{OneDReader, one_d_reader},
oned::{one_d_reader, OneDReader},
BarcodeFormat, DecodeHintType, DecodingHintDictionary, Exceptions, RXingResult,
RXingResultMetadataType, RXingResultMetadataValue, RXingResultPoint, Reader, ResultPoint,
};
@@ -293,11 +293,10 @@ impl RSS14Reader {
pattern: &FinderPattern,
outsideChar: bool,
) -> Result<DataCharacter, Exceptions> {
let counters = &mut self.dataCharacterCounters; //[0_u32; 8]; //self.getDataCharacterCounters();
//Arrays.fill(counters, 0);
// counters.fill(0);
counters.fill(0);
let counters = &mut self.dataCharacterCounters; //[0_u32; 8]; //self.getDataCharacterCounters();
//Arrays.fill(counters, 0);
// counters.fill(0);
counters.fill(0);
if outsideChar {
one_d_reader::recordPatternInReverse(row, pattern.getStartEnd()[0], &mut counters[..])?;
@@ -305,7 +304,7 @@ impl RSS14Reader {
one_d_reader::recordPattern(row, pattern.getStartEnd()[1], &mut counters[..])?;
// reverse it
let mut i = 0;
let mut j = counters.len() -1;
let mut j = counters.len() - 1;
while i < j {
// for (int i = 0, j = counters.length - 1; i < j; i++, j--) {
let temp = counters[i];
@@ -468,13 +467,13 @@ impl RSS14Reader {
let firstCounter = startEnd[0] - firstElementStart as usize;
let mut counters = &mut self.decodeFinderCounters;
let counter_len = counters.len();
let slc = counters[0..counter_len-1].to_vec();
let slc = counters[0..counter_len - 1].to_vec();
counters[1..counter_len].copy_from_slice(&slc);
// Make 'counters' hold 1-4
// let counters = self.getDecodeFinderCounters();
// System.arraycopy(counters, 0, counters, 1, counters.length - 1);
// counters.fill(0);
counters[0] = firstCounter as u32;
let value = Self::parseFinderValue(counters, &Self::FINDER_PATTERNS)?;
let mut start = firstElementStart as usize;

View File

@@ -19,7 +19,7 @@ use crate::{
RXingResultMetadataType, RXingResultMetadataValue, RXingResultPoint, Reader,
};
use super::{EANManufacturerOrgSupport, OneDReader, UPCEANExtensionSupport, one_d_reader};
use super::{one_d_reader, EANManufacturerOrgSupport, OneDReader, UPCEANExtensionSupport};
use lazy_static::lazy_static;
@@ -433,8 +433,11 @@ pub trait UPCEANReader: OneDReader {
counters[counterPosition] += 1;
} else {
if counterPosition == patternLength - 1 {
if one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE)
< MAX_AVG_VARIANCE
if one_d_reader::patternMatchVariance(
counters,
pattern,
MAX_INDIVIDUAL_VARIANCE,
) < MAX_AVG_VARIANCE
{
return Ok([patternStart, x]);
}
@@ -483,7 +486,7 @@ pub trait UPCEANReader: OneDReader {
// for (int i = 0; i < max; i++) {
let pattern = &patterns[i];
let variance: f32 =
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
one_d_reader::patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE);
if variance < bestVariance {
bestVariance = variance;
bestMatch = i as isize;

View File

@@ -1,4 +1,3 @@
/*
* Copyright 2008 ZXing authors
*
@@ -15,15 +14,15 @@
* limitations under the License.
*/
use rxing::{maxicode::MaxiCodeReader, BarcodeFormat, DecodeHintType, MultiFormatReader};
use rxing::{maxicode::MaxiCodeReader, BarcodeFormat, DecodeHintType, MultiFormatReader};
mod common;
/**
* @author Sean Owen
*/
#[test]
fn rss14_black_box1_test_case() {
mod common;
/**
* @author Sean Owen
*/
#[test]
fn rss14_black_box1_test_case() {
let mut tester = common::AbstractBlackBoxTestCase::new(
"test_resources/blackbox/rss14-1",
MultiFormatReader::default(),
@@ -31,15 +30,13 @@
);
// super("src/test/resources/blackbox/rss14-1", new MultiFormatReader(), BarcodeFormat.RSS_14);
tester.add_test(6, 6, 0.0);
tester.add_test(6, 6, 180.0);
tester.add_test(6, 6, 0.0);
tester.add_test(6, 6, 180.0);
tester.test_black_box()
}
tester.test_black_box()
}
/**
/**
* @author Sean Owen
*/
#[test]
@@ -55,6 +52,4 @@ fn rss14_black_box2_test_case() {
tester.add_test_complex(3, 8, 0, 1, 180.0);
tester.test_black_box()
}
}