Big RSS Expanded changelist -- thank you authors

git-svn-id: https://zxing.googlecode.com/svn/trunk@1350 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2010-05-10 19:18:50 +00:00
parent 0ab1caee3e
commit 74c8744e8c
398 changed files with 5120 additions and 98 deletions

View file

@ -1,11 +1,14 @@
This project consists of contributions from several people, recognized here for convenience, This project consists of contributions from several people, recognized here for convenience,
in alphabetical order. in alphabetical order.
Agustín Delgado (Servinform S.A.)
Aitor Almeida (University of Deusto)
Alasdair Mackintosh (Google) Alasdair Mackintosh (Google)
Alexander Martin (Haase & Martin GmbH) Alexander Martin (Haase & Martin GmbH)
Andreas Pillath Andreas Pillath
Andrey Sitnik Andrey Sitnik
Androida.hu / http://www.androida.hu/ Androida.hu / http://www.androida.hu/
Antonio Manuel Benjumea (Servinform S.A.)
Brian Brown (Google) Brian Brown (Google)
Christian Brunschen (Google) Christian Brunschen (Google)
Daniel Switkin (Google) Daniel Switkin (Google)
@ -13,6 +16,7 @@ Dave MacLachlan (Google)
David Phillip Oster (Google) David Phillip Oster (Google)
David Albert (Bug Labs) David Albert (Bug Labs)
Diego Pierotto Diego Pierotto
Eduardo Castillejo (University of Deusto)
Eric Kobrin (Velocitude) Eric Kobrin (Velocitude)
Erik Barbara Erik Barbara
Fred Lin (Anobiit) Fred Lin (Anobiit)
@ -32,6 +36,7 @@ Matthew Schulkind (Google)
Matt York (LifeMarks) Matt York (LifeMarks)
Mohamad Fairol Mohamad Fairol
Nikolaos Ftylitakis Nikolaos Ftylitakis
Pablo Orduña (University of Deusto)
Paul Hackenberger Paul Hackenberger
Randy Shen (Acer) Randy Shen (Acer)
Rasmus Schrøder Sørensen Rasmus Schrøder Sørensen

View file

@ -62,6 +62,9 @@ public final class BarcodeFormat {
/** PDF417 format. */ /** PDF417 format. */
public static final BarcodeFormat PDF417 = new BarcodeFormat("PDF417"); public static final BarcodeFormat PDF417 = new BarcodeFormat("PDF417");
/** RSS EXPANDED */
public static final BarcodeFormat RSS_EXPANDED = new BarcodeFormat("RSS_EXPANDED");
private final String name; private final String name;
private BarcodeFormat(String name) { private BarcodeFormat(String name) {

View file

@ -102,7 +102,8 @@ public final class MultiFormatReader implements Reader {
formats.contains(BarcodeFormat.CODE_39) || formats.contains(BarcodeFormat.CODE_39) ||
formats.contains(BarcodeFormat.CODE_128) || formats.contains(BarcodeFormat.CODE_128) ||
formats.contains(BarcodeFormat.ITF) || formats.contains(BarcodeFormat.ITF) ||
formats.contains(BarcodeFormat.RSS14); formats.contains(BarcodeFormat.RSS14) ||
formats.contains(BarcodeFormat.RSS_EXPANDED);
// Put 1D readers upfront in "normal" mode // Put 1D readers upfront in "normal" mode
if (addOneDReader && !tryHarder) { if (addOneDReader && !tryHarder) {
readers.addElement(new MultiFormatOneDReader(hints)); readers.addElement(new MultiFormatOneDReader(hints));

View file

@ -0,0 +1,195 @@
/*
* 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.client.result;
import java.util.Hashtable;
/**
* @author Antonio Manuel Benjumea Conde, Servinform, S.A.
* @author Agustín Delgado, Servinform, S.A.
*/
public class ExpandedProductParsedResult extends ParsedResult {
public static final String KILOGRAM = "KG";
public static final String POUND = "LB";
private final String productID;
private final String sscc;
private final String lotNumber;
private final String productionDate;
private final String packagingDate;
private final String bestBeforeDate;
private final String expirationDate;
private final String weight;
private final String weightType;
private final String weightIncrement;
private final String price;
private final String priceIncrement;
private final String priceCurrency;
// For AIS that not exist in this object
private final Hashtable uncommonAIs;
ExpandedProductParsedResult() {
super(ParsedResultType.PRODUCT);
this.productID = "";
this.sscc = "";
this.lotNumber = "";
this.productionDate = "";
this.packagingDate = "";
this.bestBeforeDate = "";
this.expirationDate = "";
this.weight = "";
this.weightType = "";
this.weightIncrement = "";
this.price = "";
this.priceIncrement = "";
this.priceCurrency = "";
this.uncommonAIs = new Hashtable();
}
public ExpandedProductParsedResult(String productID, String sscc,
String lotNumber, String productionDate, String packagingDate,
String bestBeforeDate, String expirationDate, String weight,
String weightType, String weightIncrement, String price,
String priceIncrement, String priceCurrency, Hashtable uncommonAIs) {
super(ParsedResultType.PRODUCT);
this.productID = productID;
this.sscc = sscc;
this.lotNumber = lotNumber;
this.productionDate = productionDate;
this.packagingDate = packagingDate;
this.bestBeforeDate = bestBeforeDate;
this.expirationDate = expirationDate;
this.weight = weight;
this.weightType = weightType;
this.weightIncrement = weightIncrement;
this.price = price;
this.priceIncrement = priceIncrement;
this.priceCurrency = priceCurrency;
this.uncommonAIs = uncommonAIs;
}
public boolean equals(Object o){
if (!(o instanceof ExpandedProductParsedResult)) {
return false;
}
ExpandedProductParsedResult other = (ExpandedProductParsedResult)o;
return this.productID.equals( other.productID)
&& this.sscc.equals( other.sscc)
&& this.lotNumber.equals( other.lotNumber)
&& this.productionDate.equals( other.productionDate)
&& this.bestBeforeDate.equals( other.bestBeforeDate)
&& this.expirationDate.equals( other.expirationDate)
&& this.weight.equals( other.weight)
&& this.weightType.equals( other.weightType)
&& this.weightIncrement.equals( other.weightIncrement)
&& this.price.equals( other.price)
&& this.priceIncrement.equals( other.priceIncrement)
&& this.priceCurrency.equals( other.priceCurrency)
&& this.uncommonAIs.equals( other.uncommonAIs);
}
public int hashCode(){
int hash1 = this.productID.hashCode();
hash1 = 31 * hash1 + this.sscc.hashCode();
hash1 = 31 * hash1 + this.lotNumber.hashCode();
hash1 = 31 * hash1 + this.productionDate.hashCode();
hash1 = 31 * hash1 + this.bestBeforeDate.hashCode();
hash1 = 31 * hash1 + this.expirationDate.hashCode();
hash1 = 31 * hash1 + this.weight.hashCode();
int hash2 = this.weightType.hashCode();
hash2 = 31 * hash2 + this.weightIncrement.hashCode();
hash2 = 31 * hash2 + this.price.hashCode();
hash2 = 31 * hash2 + this.priceIncrement.hashCode();
hash2 = 31 * hash2 + this.priceCurrency.hashCode();
hash2 = 31 * hash2 + this.uncommonAIs.hashCode();
return hash1 ^ hash2;
}
public String getProductID() {
return productID;
}
public String getSscc() {
return sscc;
}
public String getLotNumber() {
return lotNumber;
}
public String getProductionDate() {
return productionDate;
}
public String getPackagingDate() {
return packagingDate;
}
public String getBestBeforeDate() {
return bestBeforeDate;
}
public String getExpirationDate() {
return expirationDate;
}
public String getWeight() {
return weight;
}
public String getWeightType() {
return weightType;
}
public String getWeightIncrement() {
return weightIncrement;
}
public String getPrice() {
return price;
}
public String getPriceIncrement() {
return priceIncrement;
}
public String getPriceCurrency() {
return priceCurrency;
}
public Hashtable getUncommonAIs() {
return uncommonAIs;
}
public String getDisplayResult() {
return productID;
}
}

View file

@ -0,0 +1,199 @@
/*
* 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.client.result;
import java.util.Hashtable;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
/**
* Parses strings of digits that represent a RSS Extended code.
*
* @author Antonio Manuel Benjumea Conde, Servinform, S.A.
* @author Agustín Delgado, Servinform, S.A.
*/
final class ExpandedProductResultParser extends ResultParser {
private ExpandedProductResultParser() {
}
// Treat all RSS EXPANDED, in the sense that they are all
// product barcodes with complementary data.
public static ExpandedProductParsedResult parse(Result result) {
BarcodeFormat format = result.getBarcodeFormat();
if (!(BarcodeFormat.RSS_EXPANDED.equals(format))) {
// ExtendedProductParsedResult NOT created. Not a RSS Expanded barcode
return null;
}
// Really neither of these should happen:
String rawText = result.getText();
if (rawText == null) {
// ExtendedProductParsedResult NOT created. Input text is NULL
return null;
}
String productID = "-";
String sscc = "-";
String lotNumber = "-";
String productionDate = "-";
String packagingDate = "-";
String bestBeforeDate = "-";
String expirationDate = "-";
String weight = "-";
String weightType = "-";
String weightIncrement = "-";
String price = "-";
String priceIncrement = "-";
String priceCurrency = "-";
Hashtable uncommonAIs = new Hashtable();
int i = 0;
while (i < rawText.length()) {
String ai = findAIvalue(i, rawText);
if ("ERROR".equals(ai)) {
// Error. Code doesn't match with RSS expanded pattern
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
return null;
}
i += ai.length() + 2;
String value = findValue(i, rawText);
i += value.length();
if ("00".equals(ai)) {
sscc = value;
} else if ("01".equals(ai)) {
productID = value;
} else if ("10".equals(ai)) {
lotNumber = value;
} else if ("11".equals(ai)) {
productionDate = value;
} else if ("13".equals(ai)) {
packagingDate = value;
} else if ("15".equals(ai)) {
bestBeforeDate = value;
} else if ("17".equals(ai)) {
expirationDate = value;
} else if ("3100".equals(ai) || "3101".equals(ai)
|| "3102".equals(ai) || "3103".equals(ai)
|| "3104".equals(ai) || "3105".equals(ai)
|| "3106".equals(ai) || "3107".equals(ai)
|| "3108".equals(ai) || "3109".equals(ai)) {
weight = value;
weightType = ExpandedProductParsedResult.KILOGRAM;
weightIncrement = ai.substring(3);
} else if ("3200".equals(ai) || "3201".equals(ai)
|| "3202".equals(ai) || "3203".equals(ai)
|| "3204".equals(ai) || "3205".equals(ai)
|| "3206".equals(ai) || "3207".equals(ai)
|| "3208".equals(ai) || "3209".equals(ai)) {
weight = value;
weightType = ExpandedProductParsedResult.POUND;
weightIncrement = ai.substring(3);
} else if ("3920".equals(ai) || "3921".equals(ai)
|| "3922".equals(ai) || "3923".equals(ai)) {
price = value;
priceIncrement = ai.substring(3);
} else if ("3930".equals(ai) || "3931".equals(ai)
|| "3932".equals(ai) || "3933".equals(ai)) {
if (value.length() < 4) {
// The value must have more of 3 symbols (3 for currency and
// 1 at least for the price)
// ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern
return null;
}
price = value.substring(3);
priceCurrency = value.substring(0, 3);
priceIncrement = ai.substring(3);
} else {
// No match with common AIs
uncommonAIs.put(ai, value);
}
}
return new ExpandedProductParsedResult(productID, sscc, lotNumber,
productionDate, packagingDate, bestBeforeDate, expirationDate,
weight, weightType, weightIncrement, price, priceIncrement,
priceCurrency, uncommonAIs);
}
private static String findAIvalue(int i, String rawText) {
StringBuffer buf = new StringBuffer();
char c = rawText.charAt(i);
// First character must be a open parenthesis.If not, ERROR
if (c != '(') {
return "ERROR";
}
String rawTextAux = rawText.substring(i + 1);
for (int index = 0; index < rawTextAux.length(); index++) {
char currentChar = rawTextAux.charAt(index);
switch (currentChar){
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
buf.append(currentChar);
break;
case ')':
return buf.toString();
default:
return "ERROR";
}
}
return buf.toString();
}
private static String findValue(int i, String rawText) {
StringBuffer buf = new StringBuffer();
String rawTextAux = rawText.substring(i);
for (int index = 0; index < rawTextAux.length(); index++) {
char c = rawTextAux.charAt(index);
if (c == '(') {
// We look for a new AI. If it doesn't exist (ERROR), we coninue
// with the iteration
if ("ERROR".equals(findAIvalue(index, rawTextAux))) {
buf.append(c);
} else {
break;
}
} else {
buf.append(c);
}
}
return buf.toString();
}
}

View file

@ -72,6 +72,8 @@ public abstract class ResultParser {
return result; return result;
} else if ((result = ProductResultParser.parse(theResult)) != null) { } else if ((result = ProductResultParser.parse(theResult)) != null) {
return result; return result;
} else if ((result = ExpandedProductResultParser.parse(theResult)) != null) {
return result;
} }
return new TextParsedResult(theResult.getText(), null); return new TextParsedResult(theResult.getText(), null);
} }

View file

@ -24,6 +24,7 @@ import com.google.zxing.ReaderException;
import com.google.zxing.Result; import com.google.zxing.Result;
import com.google.zxing.common.BitArray; import com.google.zxing.common.BitArray;
import com.google.zxing.oned.rss.RSS14Reader; import com.google.zxing.oned.rss.RSS14Reader;
import com.google.zxing.oned.rss.expanded.RSSExpandedReader;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Vector; import java.util.Vector;
@ -61,6 +62,9 @@ public final class MultiFormatOneDReader extends OneDReader {
if (possibleFormats.contains(BarcodeFormat.RSS14)) { if (possibleFormats.contains(BarcodeFormat.RSS14)) {
readers.addElement(new RSS14Reader()); readers.addElement(new RSS14Reader());
} }
if (possibleFormats.contains(BarcodeFormat.RSS_EXPANDED)){
readers.addElement(new RSSExpandedReader());
}
} }
if (readers.isEmpty()) { if (readers.isEmpty()) {
readers.addElement(new MultiFormatUPCEANReader(hints)); readers.addElement(new MultiFormatUPCEANReader(hints));
@ -68,6 +72,7 @@ public final class MultiFormatOneDReader extends OneDReader {
readers.addElement(new Code128Reader()); readers.addElement(new Code128Reader());
readers.addElement(new ITFReader()); readers.addElement(new ITFReader());
readers.addElement(new RSS14Reader()); readers.addElement(new RSS14Reader());
readers.addElement(new RSSExpandedReader());
} }
} }

View file

@ -0,0 +1,110 @@
/*
* 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.
*/
package com.google.zxing.oned.rss;
import com.google.zxing.NotFoundException;
import com.google.zxing.oned.OneDReader;
public abstract class AbstractRSSReader extends OneDReader {
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.2f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.4f);
private static final float MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f;
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;
protected final int[] decodeFinderCounters;
protected final int[] dataCharacterCounters;
protected final float[] oddRoundingErrors;
protected final float[] evenRoundingErrors;
protected final int[] oddCounts;
protected final int[] evenCounts;
protected AbstractRSSReader(){
decodeFinderCounters = new int[4];
dataCharacterCounters = new int[8];
oddRoundingErrors = new float[4];
evenRoundingErrors = new float[4];
oddCounts = new int[dataCharacterCounters.length / 2];
evenCounts = new int[dataCharacterCounters.length / 2];
}
protected static int parseFinderValue(int[] counters, int [][] finderPatterns) throws NotFoundException {
for (int value = 0; value < finderPatterns.length; value++) {
if (patternMatchVariance(counters, finderPatterns[value], MAX_INDIVIDUAL_VARIANCE) <
MAX_AVG_VARIANCE) {
return value;
}
}
throw NotFoundException.getNotFoundInstance();
}
protected static int count(int[] array) {
int count = 0;
for (int i = 0; i < array.length; i++) {
count += array[i];
}
return count;
}
protected static void increment(int[] array, float[] errors) {
int index = 0;
float biggestError = errors[0];
for (int i = 1; i < array.length; i++) {
if (errors[i] > biggestError) {
biggestError = errors[i];
index = i;
}
}
array[index]++;
}
protected static void decrement(int[] array, float[] errors) {
int index = 0;
float biggestError = errors[0];
for (int i = 1; i < array.length; i++) {
if (errors[i] < biggestError) {
biggestError = errors[i];
index = i;
}
}
array[index]--;
}
protected static boolean isFinderPattern(int[] counters) {
int firstTwoSum = counters[0] + counters[1];
int sum = firstTwoSum + counters[2] + counters[3];
float ratio = (float) firstTwoSum / (float) sum;
if (ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO) {
// passes ratio test in spec, but see if the counts are unreasonable
int minCounter = Integer.MAX_VALUE;
int maxCounter = Integer.MIN_VALUE;
for (int i = 0; i < counters.length; i++) {
int counter = counters[i];
if (counter > maxCounter) {
maxCounter = counter;
}
if (counter < minCounter) {
minCounter = counter;
}
}
return maxCounter < 10 * minCounter;
}
return false;
}
}

View file

@ -16,21 +16,21 @@
package com.google.zxing.oned.rss; package com.google.zxing.oned.rss;
class DataCharacter { public class DataCharacter {
private final int value; private final int value;
private final int checksumPortion; private final int checksumPortion;
DataCharacter(int value, int checksumPortion) { public DataCharacter(int value, int checksumPortion) {
this.value = value; this.value = value;
this.checksumPortion = checksumPortion; this.checksumPortion = checksumPortion;
} }
int getValue() { public int getValue() {
return value; return value;
} }
int getChecksumPortion() { public int getChecksumPortion() {
return checksumPortion; return checksumPortion;
} }

View file

@ -18,13 +18,13 @@ package com.google.zxing.oned.rss;
import com.google.zxing.ResultPoint; import com.google.zxing.ResultPoint;
final class FinderPattern { public final class FinderPattern {
private final int value; private final int value;
private final int[] startEnd; private final int[] startEnd;
private final ResultPoint[] resultPoints; private final ResultPoint[] resultPoints;
FinderPattern(int value, int[] startEnd, int start, int end, int rowNumber) { public FinderPattern(int value, int[] startEnd, int start, int end, int rowNumber) {
this.value = value; this.value = value;
this.startEnd = startEnd; this.startEnd = startEnd;
this.resultPoints = new ResultPoint[] { this.resultPoints = new ResultPoint[] {
@ -33,15 +33,15 @@ final class FinderPattern {
}; };
} }
int getValue() { public int getValue() {
return value; return value;
} }
int[] getStartEnd() { public int[] getStartEnd() {
return startEnd; return startEnd;
} }
ResultPoint[] getResultPoints() { public ResultPoint[] getResultPoints() {
return resultPoints; return resultPoints;
} }

View file

@ -23,7 +23,6 @@ import com.google.zxing.Result;
import com.google.zxing.ResultPoint; import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback; import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.BitArray; import com.google.zxing.common.BitArray;
import com.google.zxing.oned.OneDReader;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Hashtable; import java.util.Hashtable;
@ -32,13 +31,7 @@ import java.util.Vector;
/** /**
* Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006. * Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006.
*/ */
public final class RSS14Reader extends OneDReader { public final class RSS14Reader extends AbstractRSSReader {
private static final int MAX_AVG_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.2f);
private static final int MAX_INDIVIDUAL_VARIANCE = (int) (PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.4f);
private static final float MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f;
private static final float MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f;
private static final int[] OUTSIDE_EVEN_TOTAL_SUBSET = {1,10,34,70,126}; private static final int[] OUTSIDE_EVEN_TOTAL_SUBSET = {1,10,34,70,126};
private static final int[] INSIDE_ODD_TOTAL_SUBSET = {4,20,48,81}; private static final int[] INSIDE_ODD_TOTAL_SUBSET = {4,20,48,81};
@ -59,22 +52,10 @@ public final class RSS14Reader extends OneDReader {
{1,3,9,1}, {1,3,9,1},
}; };
private final int[] decodeFinderCounters;
private final int[] dataCharacterCounters;
private final float[] oddRoundingErrors;
private final float[] evenRoundingErrors;
private final int[] oddCounts;
private final int[] evenCounts;
private final Vector possibleLeftPairs; private final Vector possibleLeftPairs;
private final Vector possibleRightPairs; private final Vector possibleRightPairs;
public RSS14Reader() { public RSS14Reader() {
decodeFinderCounters = new int[4];
dataCharacterCounters = new int[8];
oddRoundingErrors = new float[4];
evenRoundingErrors = new float[4];
oddCounts = new int[dataCharacterCounters.length / 2];
evenCounts = new int[dataCharacterCounters.length / 2];
possibleLeftPairs = new Vector(); possibleLeftPairs = new Vector();
possibleRightPairs = new Vector(); possibleRightPairs = new Vector();
} }
@ -348,28 +329,6 @@ public final class RSS14Reader extends OneDReader {
} }
private static boolean isFinderPattern(int[] counters) {
int firstTwoSum = counters[0] + counters[1];
int sum = firstTwoSum + counters[2] + counters[3];
float ratio = (float) firstTwoSum / (float) sum;
if (ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO) {
// passes ratio test in spec, but see if the counts are unreasonable
int minCounter = Integer.MAX_VALUE;
int maxCounter = Integer.MIN_VALUE;
for (int i = 0; i < counters.length; i++) {
int counter = counters[i];
if (counter > maxCounter) {
maxCounter = counter;
}
if (counter < minCounter) {
minCounter = counter;
}
}
return maxCounter < 10 * minCounter;
}
return false;
}
private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, boolean right, int[] startEnd) private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, boolean right, int[] startEnd)
throws NotFoundException { throws NotFoundException {
// Actually we found elements 2-5 // Actually we found elements 2-5
@ -387,7 +346,7 @@ public final class RSS14Reader extends OneDReader {
counters[i] = counters[i-1]; counters[i] = counters[i-1];
} }
counters[0] = firstCounter; counters[0] = firstCounter;
int value = parseFinderValue(counters); int value = parseFinderValue(counters, FINDER_PATTERNS);
int start = firstElementStart; int start = firstElementStart;
int end = startEnd[1]; int end = startEnd[1];
if (right) { if (right) {
@ -398,16 +357,6 @@ public final class RSS14Reader extends OneDReader {
return new FinderPattern(value, new int[] {firstElementStart, startEnd[1]}, start, end, rowNumber); return new FinderPattern(value, new int[] {firstElementStart, startEnd[1]}, start, end, rowNumber);
} }
private static int parseFinderValue(int[] counters) throws NotFoundException {
for (int value = 0; value < FINDER_PATTERNS.length; value++) {
if (patternMatchVariance(counters, FINDER_PATTERNS[value], MAX_INDIVIDUAL_VARIANCE) <
MAX_AVG_VARIANCE) {
return value;
}
}
throw NotFoundException.getNotFoundInstance();
}
/* /*
private static int[] normalizeE2SEValues(int[] counters) { private static int[] normalizeE2SEValues(int[] counters) {
int p = 0; int p = 0;
@ -425,38 +374,6 @@ public final class RSS14Reader extends OneDReader {
} }
*/ */
private static int count(int[] array) {
int count = 0;
for (int i = 0; i < array.length; i++) {
count += array[i];
}
return count;
}
private static void increment(int[] array, float[] errors) {
int index = 0;
float biggestError = errors[0];
for (int i = 1; i < array.length; i++) {
if (errors[i] > biggestError) {
biggestError = errors[i];
index = i;
}
}
array[index]++;
}
private static void decrement(int[] array, float[] errors) {
int index = 0;
float biggestError = errors[0];
for (int i = 1; i < array.length; i++) {
if (errors[i] < biggestError) {
biggestError = errors[i];
index = i;
}
}
array[index]--;
}
private void adjustOddEvenCounts(boolean outsideChar, int numModules) throws NotFoundException { private void adjustOddEvenCounts(boolean outsideChar, int numModules) throws NotFoundException {
int oddSum = count(oddCounts); int oddSum = count(oddCounts);

View file

@ -61,7 +61,7 @@ public final class RSSUtils {
return widths; return widths;
} }
static int getRSSvalue(int[] widths, int maxWidth, boolean noNarrow) { public static int getRSSvalue(int[] widths, int maxWidth, boolean noNarrow) {
int elements = widths.length; int elements = widths.length;
int n = 0; int n = 0;
for (int i = 0; i < elements; i++) { for (int i = 0; i < elements; i++) {

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/
*/
package com.google.zxing.oned.rss.expanded;
import java.util.Vector;
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 BitArrayBuilder {
private BitArrayBuilder() {
}
static BitArray buildBitArray(Vector pairs) {
int charNumber = (pairs.size() << 1) - 1;
if ((((ExpandedPair)pairs.lastElement()).getRightChar()) == null) {
charNumber -= 1;
}
int size = 12 * charNumber;
BitArray binary = new BitArray(size);
int accPos = 0;
ExpandedPair firstPair = (ExpandedPair)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 = (ExpandedPair)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

@ -0,0 +1,68 @@
/*
* 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;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class ExpandedPair {
private final boolean mayBeLast;
private final DataCharacter leftChar;
private final DataCharacter rightChar;
private final FinderPattern finderPattern;
ExpandedPair(DataCharacter leftChar, DataCharacter rightChar, FinderPattern finderPattern, boolean mayBeLast) {
this.leftChar = leftChar;
this.rightChar = rightChar;
this.finderPattern = finderPattern;
this.mayBeLast = mayBeLast;
}
boolean mayBeLast(){
return this.mayBeLast;
}
DataCharacter getLeftChar() {
return this.leftChar;
}
DataCharacter getRightChar() {
return this.rightChar;
}
FinderPattern getFinderPattern() {
return this.finderPattern;
}
public boolean mustBeLast() {
return this.rightChar == null;
}
}

View file

@ -0,0 +1,578 @@
/*
* 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 java.util.Hashtable;
import java.util.Vector;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.BitArray;
import com.google.zxing.oned.rss.AbstractRSSReader;
import com.google.zxing.oned.rss.DataCharacter;
import com.google.zxing.oned.rss.FinderPattern;
import com.google.zxing.oned.rss.RSSUtils;
import com.google.zxing.oned.rss.expanded.decoders.AbstractExpandedDecoder;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es)
*/
public final class RSSExpandedReader extends AbstractRSSReader{
private static final int[] SYMBOL_WIDEST = {7, 5, 4, 3, 1};
private static final int[] EVEN_TOTAL_SUBSET = {4, 20, 52, 104, 204};
private static final int[] GSUM = {0, 348, 1388, 2948, 3988};
private static final int[][] FINDER_PATTERNS = {
{1,8,4,1}, // A
{3,6,4,1}, // B
{3,4,6,1}, // C
{3,2,8,1}, // D
{2,6,5,1}, // E
{2,2,9,1} // F
};
private static final int[][] WEIGHTS = {
{ 1, 3, 9, 27, 81, 32, 96, 77},
{ 20, 60, 180, 118, 143, 7, 21, 63},
{189, 145, 13, 39, 117, 140, 209, 205},
{193, 157, 49, 147, 19, 57, 171, 91},
{ 62, 186, 136, 197, 169, 85, 44, 132},
{185, 133, 188, 142, 4, 12, 36, 108},
{113, 128, 173, 97, 80, 29, 87, 50},
{150, 28, 84, 41, 123, 158, 52, 156},
{ 46, 138, 203, 187, 139, 206, 196, 166},
{ 76, 17, 51, 153, 37, 111, 122, 155},
{ 43, 129, 176, 106, 107, 110, 119, 146},
{ 16, 48, 144, 10, 30, 90, 59, 177},
{109, 116, 137, 200, 178, 112, 125, 164},
{ 70, 210, 208, 202, 184, 130, 179, 115},
{134, 191, 151, 31, 93, 68, 204, 190},
{148, 22, 66, 198, 172, 94, 71, 2},
{ 6, 18, 54, 162, 64, 192,154, 40},
{120, 149, 25, 75, 14, 42,126, 167},
{ 79, 26, 78, 23, 69, 207,199, 175},
{103, 98, 83, 38, 114, 131, 182, 124},
{161, 61, 183, 127, 170, 88, 53, 159},
{ 55, 165, 73, 8, 24, 72, 5, 15},
{ 45, 135, 194, 160, 58, 174, 100, 89}
};
private static final int FINDER_PAT_A = 0;
private static final int FINDER_PAT_B = 1;
private static final int FINDER_PAT_C = 2;
private static final int FINDER_PAT_D = 3;
private static final int FINDER_PAT_E = 4;
private static final int FINDER_PAT_F = 5;
private static final int [][] FINDER_PATTERN_SEQUENCES = {
{ FINDER_PAT_A, FINDER_PAT_A },
{ FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B },
{ FINDER_PAT_A, FINDER_PAT_C, FINDER_PAT_B, FINDER_PAT_D },
{ FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_C },
{ FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_F },
{ FINDER_PAT_A, FINDER_PAT_E, FINDER_PAT_B, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F },
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D },
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E },
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F },
{ FINDER_PAT_A, FINDER_PAT_A, FINDER_PAT_B, FINDER_PAT_B, FINDER_PAT_C, FINDER_PAT_D, FINDER_PAT_D, FINDER_PAT_E, FINDER_PAT_E, FINDER_PAT_F, FINDER_PAT_F },
};
private static final int LONGEST_SEQUENCE_SIZE = FINDER_PATTERN_SEQUENCES[FINDER_PATTERN_SEQUENCES.length - 1].length;
private static final int MAX_PAIRS = 11;
private final Vector pairs = new Vector(MAX_PAIRS);
private final int [] startEnd = new int[2];
private final int [] currentSequence = new int[LONGEST_SEQUENCE_SIZE];
public Result decodeRow(int rowNumber, BitArray row, Hashtable hints) throws NotFoundException {
this.reset();
decodeRow2pairs(rowNumber, row);
return constructResult(this.pairs);
}
public void reset() {
this.pairs.setSize(0);
}
// Not private for testing
Vector decodeRow2pairs(int rowNumber, BitArray row) throws NotFoundException {
while(true){
ExpandedPair nextPair = retrieveNextPair(row, this.pairs, rowNumber);
this.pairs.add(nextPair);
if(nextPair.mayBeLast()){
if(checkChecksum()) {
return this.pairs;
}
if(nextPair.mustBeLast()) {
throw NotFoundException.getNotFoundInstance();
}
}
}
}
private static Result constructResult(Vector pairs) throws NotFoundException{
BitArray binary = BitArrayBuilder.buildBitArray(pairs);
AbstractExpandedDecoder decoder = AbstractExpandedDecoder.createDecoder(binary);
String resultingString = decoder.parseInformation();
ResultPoint [] firstPoints = ((ExpandedPair)pairs.get(0)).getFinderPattern().getResultPoints();
ResultPoint [] lastPoints = ((ExpandedPair)pairs.lastElement()).getFinderPattern().getResultPoints();
return new Result(
resultingString,
null,
new ResultPoint[]{firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1]},
BarcodeFormat.RSS_EXPANDED
);
}
private boolean checkChecksum(){
ExpandedPair firstPair = (ExpandedPair)this.pairs.get(0);
DataCharacter checkCharacter = firstPair.getLeftChar();
DataCharacter firstCharacter = firstPair.getRightChar();
int checksum = firstCharacter.getChecksumPortion();
int S = 2;
for(int i = 1; i < this.pairs.size(); ++i){
ExpandedPair currentPair = (ExpandedPair)this.pairs.get(i);
checksum += currentPair.getLeftChar().getChecksumPortion();
S++;
if(currentPair.getRightChar() != null){
checksum += currentPair.getRightChar().getChecksumPortion();
S++;
}
}
checksum %= 211;
int checkCharacterValue = 211 * (S - 4) + checksum;
return checkCharacterValue == checkCharacter.getValue();
}
private static int getNextSecondBar(BitArray row, int initialPos){
int currentPos = initialPos;
boolean current = row.get(currentPos);
while(currentPos < row.size && row.get(currentPos) == current) {
currentPos++;
}
current = !current;
while(currentPos < row.size && row.get(currentPos) == current) {
currentPos++;
}
return currentPos;
}
// not private for testing
ExpandedPair retrieveNextPair(BitArray row, Vector previousPairs, int rowNumber) throws NotFoundException{
boolean isOddPattern = previousPairs.size() % 2 == 0;
FinderPattern pattern;
boolean keepFinding = true;
int forcedOffset = -1;
do{
this.findNextPair(row, previousPairs, forcedOffset);
pattern = parseFoundFinderPattern(row, rowNumber, isOddPattern);
if(pattern == null){
forcedOffset = getNextSecondBar(row, this.startEnd[0]);
}else {
keepFinding = false;
}
}while(keepFinding);
boolean mayBeLast = checkPairSequence(previousPairs, pattern);
DataCharacter leftChar = this.decodeDataCharacter(row, pattern, isOddPattern, true);
DataCharacter rightChar;
try{
rightChar = this.decodeDataCharacter(row, pattern, isOddPattern, false);
}catch(NotFoundException nfe){
if(mayBeLast) {
rightChar = null;
} else {
throw nfe;
}
}
return new ExpandedPair(leftChar, rightChar, pattern, mayBeLast);
}
private boolean checkPairSequence(Vector previousPairs, FinderPattern pattern) throws NotFoundException{
int currentSequenceLength = previousPairs.size() + 1;
if(currentSequenceLength > this.currentSequence.length) {
throw NotFoundException.getNotFoundInstance();
}
for(int pos = 0; pos < previousPairs.size(); ++pos) {
this.currentSequence[pos] = ((ExpandedPair) previousPairs.get(pos)).getFinderPattern().getValue();
}
this.currentSequence[currentSequenceLength - 1] = pattern.getValue();
for(int i = 0; i < FINDER_PATTERN_SEQUENCES.length; ++i){
int [] validSequence = FINDER_PATTERN_SEQUENCES[i];
if(validSequence.length >= currentSequenceLength){
boolean valid = true;
for(int pos = 0; pos < currentSequenceLength; ++pos) {
if (this.currentSequence[pos] != validSequence[pos]) {
valid = false;
break;
}
}
if(valid) {
return currentSequenceLength == validSequence.length;
}
}
}
throw NotFoundException.getNotFoundInstance();
}
private void findNextPair(BitArray row, Vector previousPairs, int forcedOffset) throws NotFoundException{
int[] counters = this.decodeFinderCounters;
counters[0] = 0;
counters[1] = 0;
counters[2] = 0;
counters[3] = 0;
int width = row.getSize();
int rowOffset;
if (forcedOffset >= 0) {
rowOffset = forcedOffset;
} else if (previousPairs.isEmpty()) {
rowOffset = 0;
} else{
ExpandedPair lastPair = ((ExpandedPair)previousPairs.lastElement());
rowOffset = lastPair.getFinderPattern().getStartEnd()[1];
}
boolean searchingEvenPair = previousPairs.size() % 2 != 0;
boolean isWhite = false;
while (rowOffset < width) {
isWhite = !row.get(rowOffset);
if (!isWhite) {
break;
}
rowOffset++;
}
int counterPosition = 0;
int patternStart = rowOffset;
for (int x = rowOffset; x < width; x++) {
boolean pixel = row.get(x);
if (pixel ^ isWhite) {
counters[counterPosition]++;
} else {
if (counterPosition == 3) {
if (searchingEvenPair) {
reverseCounters(counters);
}
if (isFinderPattern(counters)){
this.startEnd[0] = patternStart;
this.startEnd[1] = x;
return;
}
if (searchingEvenPair) {
reverseCounters(counters);
}
patternStart += counters[0] + counters[1];
counters[0] = counters[2];
counters[1] = counters[3];
counters[2] = 0;
counters[3] = 0;
counterPosition--;
} else {
counterPosition++;
}
counters[counterPosition] = 1;
isWhite = !isWhite;
}
}
throw NotFoundException.getNotFoundInstance();
}
private static void reverseCounters(int [] counters){
int length = counters.length;
for(int i = 0; i < length / 2; ++i){
int tmp = counters[i];
counters[i] = counters[length - i - 1];
counters[length - i - 1] = tmp;
}
}
private FinderPattern parseFoundFinderPattern(BitArray row, int rowNumber, boolean oddPattern) {
// Actually we found elements 2-5.
int firstCounter;
int start;
int end;
if(oddPattern){
// If pattern number is odd, we need to locate element 1 *before* the current block.
int firstElementStart = this.startEnd[0] - 1;
// Locate element 1
while (firstElementStart >= 0 && !row.get(firstElementStart)) {
firstElementStart--;
}
firstElementStart++;
firstCounter = this.startEnd[0] - firstElementStart;
start = firstElementStart;
end = this.startEnd[1];
}else{
// If pattern number is even, the pattern is reversed, so we need to locate element 1 *after* the current block.
start = this.startEnd[0];
int firstElementStart = this.startEnd[1] + 1;
while(row.get(firstElementStart) && firstElementStart < row.size) {
firstElementStart++;
}
end = firstElementStart;
firstCounter = end - this.startEnd[1];
}
// Make 'counters' hold 1-4
int [] counters = this.decodeFinderCounters;
for (int i = counters.length - 1; i > 0; i--) {
counters[i] = counters[i - 1];
}
counters[0] = firstCounter;
int value;
try {
value = parseFinderValue(counters, FINDER_PATTERNS);
} catch (NotFoundException nfe) {
return null;
}
return new FinderPattern(value, new int[] {start, end}, start, end, rowNumber);
}
DataCharacter decodeDataCharacter(BitArray row, FinderPattern pattern, boolean isOddPattern, boolean leftChar)
throws NotFoundException {
int[] counters = this.dataCharacterCounters;
counters[0] = 0;
counters[1] = 0;
counters[2] = 0;
counters[3] = 0;
counters[4] = 0;
counters[5] = 0;
counters[6] = 0;
counters[7] = 0;
if (leftChar) {
recordPatternInReverse(row, pattern.getStartEnd()[0], counters);
} else {
recordPattern(row, pattern.getStartEnd()[1] + 1, counters);
// reverse it
for (int i = 0, j = counters.length - 1; i < j; i++, j--) {
int temp = counters[i];
counters[i] = counters[j];
counters[j] = temp;
}
}//counters[] has the pixels of the module
int numModules = 17; //left and right data characters have all the same length
float elementWidth = (float) count(counters) / (float) numModules;
int[] oddCounts = this.oddCounts;
int[] evenCounts = this.evenCounts;
float[] oddRoundingErrors = this.oddRoundingErrors;
float[] evenRoundingErrors = this.evenRoundingErrors;
for (int i = 0; i < counters.length; i++) {
float value = 1.0f * counters[i] / elementWidth;
int count = (int) (value + 0.5f); // Round
if (count < 1) {
count = 1;
} else if (count > 8) {
count = 8;
}
int offset = i >> 1;
if ((i & 0x01) == 0) {
oddCounts[offset] = count;
oddRoundingErrors[offset] = value - count;
} else {
evenCounts[offset] = count;
evenRoundingErrors[offset] = value - count;
}
}
adjustOddEvenCounts(numModules);
int weightRowNumber = 4 * pattern.getValue() + (isOddPattern?0:2) + (leftChar?0:1) - 1;
int oddSum = 0;
int oddChecksumPortion = 0;
for (int i = oddCounts.length - 1; i >= 0; i--) {
if(isNotA1left(pattern, isOddPattern, leftChar)){
int weight = WEIGHTS[weightRowNumber][2 * i];
oddChecksumPortion += oddCounts[i] * weight;
}
oddSum += oddCounts[i];
}
int evenChecksumPortion = 0;
int evenSum = 0;
for (int i = evenCounts.length - 1; i >= 0; i--) {
if(isNotA1left(pattern, isOddPattern, leftChar)){
int weight = WEIGHTS[weightRowNumber][2 * i + 1];
evenChecksumPortion += evenCounts[i] * weight;
}
evenSum += evenCounts[i];
}
int checksumPortion = oddChecksumPortion + evenChecksumPortion;
if ((oddSum & 0x01) != 0 || oddSum > 13 || oddSum < 4) {
throw NotFoundException.getNotFoundInstance();
}
int group = (13 - oddSum) / 2;
int oddWidest = SYMBOL_WIDEST[group];
int evenWidest = 9 - oddWidest;
int vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true);
int vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false);
int tEven = EVEN_TOTAL_SUBSET[group];
int gSum = GSUM[group];
int value = vOdd * tEven + vEven + gSum;
return new DataCharacter(value, checksumPortion);
}
private static boolean isNotA1left(FinderPattern pattern, boolean isOddPattern, boolean leftChar) {
// A1: pattern.getValue is 0 (A), and it's an oddPattern, and it is a left char
return !(pattern.getValue() == 0 && isOddPattern && leftChar);
}
private void adjustOddEvenCounts(int numModules) throws NotFoundException {
int oddSum = count(this.oddCounts);
int evenSum = count(this.evenCounts);
int mismatch = oddSum + evenSum - numModules;
boolean oddParityBad = (oddSum & 0x01) == 1;
boolean evenParityBad = (evenSum & 0x01) == 0;
boolean incrementOdd = false;
boolean decrementOdd = false;
if (oddSum > 13) {
decrementOdd = true;
} else if (oddSum < 4) {
incrementOdd = true;
}
boolean incrementEven = false;
boolean decrementEven = false;
if (evenSum > 13) {
decrementEven = true;
} else if (evenSum < 4) {
incrementEven = true;
}
if (mismatch == 1) {
if (oddParityBad) {
if (evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
decrementOdd = true;
} else {
if (!evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
decrementEven = true;
}
} else if (mismatch == -1) {
if (oddParityBad) {
if (evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
incrementOdd = true;
} else {
if (!evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
incrementEven = true;
}
} else if (mismatch == 0) {
if (oddParityBad) {
if (!evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
// Both bad
if (oddSum < evenSum) {
incrementOdd = true;
decrementEven = true;
} else {
decrementOdd = true;
incrementEven = true;
}
} else {
if (evenParityBad) {
throw NotFoundException.getNotFoundInstance();
}
// Nothing to do!
}
} else {
throw NotFoundException.getNotFoundInstance();
}
if (incrementOdd) {
if (decrementOdd) {
throw NotFoundException.getNotFoundInstance();
}
increment(this.oddCounts, this.oddRoundingErrors);
}
if (decrementOdd) {
decrement(this.oddCounts, this.oddRoundingErrors);
}
if (incrementEven) {
if (decrementEven) {
throw NotFoundException.getNotFoundInstance();
}
increment(this.evenCounts, this.oddRoundingErrors);
}
if (decrementEven) {
decrement(this.evenCounts, this.evenRoundingErrors);
}
}
}

View file

@ -0,0 +1,47 @@
/*
* 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.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class AI013103decoder extends AI013x0xDecoder {
AI013103decoder(BitArray information) {
super(information);
}
protected void addWeightCode(StringBuffer buf, int weight) {
buf.append("(3103)");
}
protected int checkWeight(int weight) {
return weight;
}
}

View file

@ -0,0 +1,55 @@
/*
* 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.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class AI01320xDecoder extends AI013x0xDecoder {
AI01320xDecoder(BitArray information) {
super(information);
}
protected void addWeightCode(StringBuffer buf, int weight) {
if (weight < 10000) {
buf.append("(3202)");
} else {
buf.append("(3203)");
}
}
protected int checkWeight(int weight) {
if(weight < 10000) {
return weight;
}
return weight - 10000;
}
}

View file

@ -0,0 +1,66 @@
/*
* 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 com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class AI01392xDecoder extends AI01decoder {
private static final int headerSize = 5 + 1 + 2;
private static final int lastDigitSize = 2;
AI01392xDecoder(BitArray information) {
super(information);
}
public String parseInformation() throws NotFoundException {
if (this.information.size < headerSize + gtinSize) {
throw NotFoundException.getNotFoundInstance();
}
StringBuffer buf = new StringBuffer();
encodeCompressedGtin(buf, headerSize);
int lastAIdigit =
this.generalDecoder.extractNumericValueFromBitArray(headerSize + gtinSize, lastDigitSize);
buf.append("(392");
buf.append(lastAIdigit);
buf.append(')');
DecodedInformation decodedInformation =
this.generalDecoder.decodeGeneralPurposeField(headerSize + gtinSize + lastDigitSize, null);
buf.append(decodedInformation.getNewString());
return buf.toString();
}
}

View file

@ -0,0 +1,76 @@
/*
* 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 com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
final class AI01393xDecoder extends AI01decoder {
private static final int headerSize = 5 + 1 + 2;
private static final int lastDigitSize = 2;
private static final int firstThreeDigitsSize = 10;
AI01393xDecoder(BitArray information) {
super(information);
}
public String parseInformation() throws NotFoundException {
if(this.information.size < headerSize + gtinSize) {
throw NotFoundException.getNotFoundInstance();
}
StringBuffer buf = new StringBuffer();
encodeCompressedGtin(buf, headerSize);
int lastAIdigit =
this.generalDecoder.extractNumericValueFromBitArray(headerSize + gtinSize, lastDigitSize);
buf.append("(393");
buf.append(lastAIdigit);
buf.append(')');
int firstThreeDigits =
this.generalDecoder.extractNumericValueFromBitArray(headerSize + gtinSize + lastDigitSize, firstThreeDigitsSize);
if(firstThreeDigits / 100 == 0) {
buf.append('0');
}
if(firstThreeDigits / 10 == 0) {
buf.append('0');
}
buf.append(firstThreeDigits);
DecodedInformation generalInformation =
this.generalDecoder.decodeGeneralPurposeField(headerSize + gtinSize + lastDigitSize + firstThreeDigitsSize, null);
buf.append(generalInformation.getNewString());
return buf.toString();
}
}

View file

@ -0,0 +1,106 @@
/*
* 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 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 AI013x0x1xDecoder extends AI01weightDecoder {
private static final int headerSize = 7 + 1;
private static final int weightSize = 20;
private static final int dateSize = 16;
private final String dateCode;
private final String firstAIdigits;
AI013x0x1xDecoder(BitArray information, String firstAIdigits, String dateCode) {
super(information);
this.dateCode = dateCode;
this.firstAIdigits = firstAIdigits;
}
public String parseInformation() throws NotFoundException {
if (this.information.size != headerSize + gtinSize + weightSize + dateSize) {
throw NotFoundException.getNotFoundInstance();
}
StringBuffer buf = new StringBuffer();
encodeCompressedGtin(buf, headerSize);
encodeCompressedWeight(buf, headerSize + gtinSize, weightSize);
encodeCompressedDate(buf, headerSize + gtinSize + weightSize);
return buf.toString();
}
private void encodeCompressedDate(StringBuffer buf, int currentPos) {
int numericDate = this.generalDecoder.extractNumericValueFromBitArray(currentPos, dateSize);
if(numericDate == 38400) {
return;
}
buf.append('(');
buf.append(this.dateCode);
buf.append(')');
int day = numericDate % 32;
numericDate /= 32;
int month = numericDate % 12 + 1;
numericDate /= 12;
int year = numericDate;
if (year / 10 == 0) {
buf.append('0');
}
buf.append(year);
if (month / 10 == 0) {
buf.append('0');
}
buf.append(month);
if (day / 10 == 0) {
buf.append('0');
}
buf.append(day);
}
protected void addWeightCode(StringBuffer buf, int weight) {
int lastAI = weight / 100000;
buf.append('(');
buf.append(this.firstAIdigits);
buf.append(lastAI);
buf.append(')');
}
protected int checkWeight(int weight) {
return weight % 100000;
}
}

View file

@ -0,0 +1,56 @@
/*
* 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 com.google.zxing.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
abstract class AI013x0xDecoder extends AI01weightDecoder {
private static final int headerSize = 4 + 1;
private static final int weightSize = 15;
AI013x0xDecoder(BitArray information) {
super(information);
}
public String parseInformation() throws NotFoundException {
if (this.information.size != headerSize + gtinSize + weightSize) {
throw NotFoundException.getNotFoundInstance();
}
StringBuffer buf = new StringBuffer();
encodeCompressedGtin(buf, headerSize);
encodeCompressedWeight(buf, headerSize + gtinSize, weightSize);
return buf.toString();
}
}

View file

@ -0,0 +1,56 @@
/*
* 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 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 AI01AndOtherAIs extends AI01decoder {
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);
}
public String parseInformation() throws NotFoundException {
StringBuffer buff = new StringBuffer();
buff.append("(01)");
int initialGtinPosition = buff.length();
int firstGtinDigit = this.generalDecoder.extractNumericValueFromBitArray(HEADER_SIZE, 4);
buff.append(firstGtinDigit);
this.encodeCompressedGtinWithoutAI(buff, HEADER_SIZE + 4, initialGtinPosition);
return this.generalDecoder.decodeAllCodes(buff, HEADER_SIZE + 44);
}
}

View file

@ -0,0 +1,81 @@
/*
* 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.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 {
protected static final int gtinSize = 40;
AI01decoder(BitArray information) {
super(information);
}
protected void encodeCompressedGtin(StringBuffer buf, int currentPos) {
buf.append("(01)");
int initialPosition = buf.length();
buf.append('9');
encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition);
}
protected void encodeCompressedGtinWithoutAI(StringBuffer buf, int currentPos, int initialBufferPosition) {
for(int i = 0; i < 4; ++i){
int currentBlock = this.generalDecoder.extractNumericValueFromBitArray(currentPos + 10 * i, 10);
if (currentBlock / 100 == 0) {
buf.append('0');
}
if (currentBlock / 10 == 0) {
buf.append('0');
}
buf.append(currentBlock);
}
appendCheckDigit(buf, initialBufferPosition);
}
private static void appendCheckDigit(StringBuffer 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);
}
}

View file

@ -0,0 +1,58 @@
/*
* 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.common.BitArray;
/**
* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es)
*/
abstract class AI01weightDecoder extends AI01decoder {
AI01weightDecoder(BitArray information) {
super(information);
}
protected void encodeCompressedWeight(StringBuffer buf, int currentPos, int weightSize) {
int originalWeightNumeric = this.generalDecoder.extractNumericValueFromBitArray(currentPos, weightSize);
addWeightCode(buf, originalWeightNumeric);
int weightNumeric = checkWeight(originalWeightNumeric);
int currentDivisor = 100000;
for(int i = 0; i < 5; ++i){
if (weightNumeric / currentDivisor == 0) {
buf.append('0');
}
currentDivisor /= 10;
}
buf.append(weightNumeric);
}
protected abstract void addWeightCode(StringBuffer buf, int weight);
protected abstract int checkWeight(int weight);
}

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/
*/
package com.google.zxing.oned.rss.expanded.decoders;
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 {
protected final BitArray information;
protected final GeneralAppIdDecoder generalDecoder;
AbstractExpandedDecoder(BitArray information){
this.information = information;
this.generalDecoder = new GeneralAppIdDecoder(information);
}
public abstract String parseInformation() throws NotFoundException;
public static AbstractExpandedDecoder createDecoder(BitArray information){
if (information.get(1)) {
return new AI01AndOtherAIs(information);
} else 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

@ -0,0 +1,48 @@
/*
* 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 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 AnyAIDecoder extends AbstractExpandedDecoder {
private static final int HEADER_SIZE = 2 + 1 + 2;
AnyAIDecoder(BitArray information) {
super(information);
}
public String parseInformation() throws NotFoundException {
StringBuffer buf = new StringBuffer();
return this.generalDecoder.decodeAllCodes(buf, HEADER_SIZE);
}
}

View file

@ -0,0 +1,60 @@
/*
* 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 BlockParsedResult {
private final DecodedInformation decodedInformation;
private final boolean finished;
BlockParsedResult() {
this.finished = true;
this.decodedInformation = null;
}
BlockParsedResult(boolean finished) {
this.finished = finished;
this.decodedInformation = null;
}
BlockParsedResult(DecodedInformation information, boolean finished) {
this.finished = finished;
this.decodedInformation = information;
}
DecodedInformation getDecodedInformation() {
return this.decodedInformation;
}
boolean isFinished() {
return this.finished;
}
}

View file

@ -0,0 +1,69 @@
/*
* 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)
*/
final class CurrentParsingState {
int position;
private int encoding;
private static final int NUMERIC = 1;
private static final int ALPHA = 2;
private static final int ISO_IEC_646 = 4;
CurrentParsingState(){
this.position = 0;
this.encoding = NUMERIC;
}
boolean isAlpha(){
return this.encoding == ALPHA;
}
boolean isNumeric(){
return this.encoding == NUMERIC;
}
boolean isIsoIec646(){
return this.encoding == ISO_IEC_646;
}
void setNumeric(){
this.encoding = NUMERIC;
}
void setAlpha(){
this.encoding = ALPHA;
}
void setIsoIec646(){
this.encoding = ISO_IEC_646;
}
}

View file

@ -0,0 +1,52 @@
/*
* 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 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;
}
}

View file

@ -0,0 +1,63 @@
/*
* 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

@ -0,0 +1,79 @@
/*
* 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 DecodedNumeric extends DecodedObject {
private final int firstDigit;
private final int secondDigit;
static final int FNC1 = 10;
DecodedNumeric(int newPosition, int firstDigit, int secondDigit){
super(newPosition);
this.firstDigit = firstDigit;
this.secondDigit = secondDigit;
if (this.firstDigit < 0 || this.firstDigit > 10) {
throw new IllegalArgumentException("Invalid firstDigit: " + firstDigit);
}
if (this.secondDigit < 0 || this.secondDigit > 10) {
throw new IllegalArgumentException("Invalid secondDigit: " + secondDigit);
}
}
int getFirstDigit(){
return this.firstDigit;
}
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;
}
boolean isAnyFNC1(){
return this.firstDigit == FNC1 || this.secondDigit == FNC1;
}
}

View file

@ -0,0 +1,44 @@
/*
* 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)
*/
abstract class DecodedObject {
protected final int newPosition;
DecodedObject(int newPosition){
this.newPosition = newPosition;
}
int getNewPosition() {
return this.newPosition;
}
}

View file

@ -0,0 +1,285 @@
/*
* 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;
/**
* @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 Object VARIABLE_LENGTH = new Object();
private static final Object [][] TWO_DIGIT_DATA_LENGTH = {
// "DIGITS", new Integer(LENGTH)
// or
// "DIGITS", VARIABLE_LENGTH, new Integer(MAX_SIZE)
{ "00", new Integer(18) },
{ "01", new Integer(14) },
{ "02", new Integer(14) },
{ "10", VARIABLE_LENGTH, new Integer(20) },
{ "11", new Integer(6) },
{ "12", new Integer(6) },
{ "13", new Integer(6) },
{ "15", new Integer(6) },
{ "17", new Integer(6) },
{ "20", new Integer(2) },
{ "21", VARIABLE_LENGTH, new Integer(20) },
{ "22", VARIABLE_LENGTH, new Integer(29) },
{ "30", VARIABLE_LENGTH, new Integer( 8) },
{ "37", VARIABLE_LENGTH, new Integer( 8) },
//internal company codes
{ "90", VARIABLE_LENGTH, new Integer(30) },
{ "91", VARIABLE_LENGTH, new Integer(30) },
{ "92", VARIABLE_LENGTH, new Integer(30) },
{ "93", VARIABLE_LENGTH, new Integer(30) },
{ "94", VARIABLE_LENGTH, new Integer(30) },
{ "95", VARIABLE_LENGTH, new Integer(30) },
{ "96", VARIABLE_LENGTH, new Integer(30) },
{ "97", VARIABLE_LENGTH, new Integer(30) },
{ "98", VARIABLE_LENGTH, new Integer(30) },
{ "99", VARIABLE_LENGTH, new Integer(30) },
};
private static final Object [][] THREE_DIGIT_DATA_LENGTH = {
// Same format as above
{ "240", VARIABLE_LENGTH, new Integer(30) },
{ "241", VARIABLE_LENGTH, new Integer(30) },
{ "242", VARIABLE_LENGTH, new Integer( 6) },
{ "250", VARIABLE_LENGTH, new Integer(30) },
{ "251", VARIABLE_LENGTH, new Integer(30) },
{ "253", VARIABLE_LENGTH, new Integer(17) },
{ "254", VARIABLE_LENGTH, new Integer(20) },
{ "400", VARIABLE_LENGTH, new Integer(30) },
{ "401", VARIABLE_LENGTH, new Integer(30) },
{ "402", new Integer(17) },
{ "403", VARIABLE_LENGTH, new Integer(30) },
{ "410", new Integer(13) },
{ "411", new Integer(13) },
{ "412", new Integer(13) },
{ "413", new Integer(13) },
{ "414", new Integer(13) },
{ "420", VARIABLE_LENGTH, new Integer(20) },
{ "421", VARIABLE_LENGTH, new Integer(15) },
{ "422", new Integer( 3) },
{ "423", VARIABLE_LENGTH, new Integer(15) },
{ "424", new Integer(3) },
{ "425", new Integer(3) },
{ "426", new Integer(3) },
};
private static final Object [][] THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = {
// Same format as above
{ "310", new Integer(6) },
{ "311", new Integer(6) },
{ "312", new Integer(6) },
{ "313", new Integer(6) },
{ "314", new Integer(6) },
{ "315", new Integer(6) },
{ "316", new Integer(6) },
{ "320", new Integer(6) },
{ "321", new Integer(6) },
{ "322", new Integer(6) },
{ "323", new Integer(6) },
{ "324", new Integer(6) },
{ "325", new Integer(6) },
{ "326", new Integer(6) },
{ "327", new Integer(6) },
{ "328", new Integer(6) },
{ "329", new Integer(6) },
{ "330", new Integer(6) },
{ "331", new Integer(6) },
{ "332", new Integer(6) },
{ "333", new Integer(6) },
{ "334", new Integer(6) },
{ "335", new Integer(6) },
{ "336", new Integer(6) },
{ "340", new Integer(6) },
{ "341", new Integer(6) },
{ "342", new Integer(6) },
{ "343", new Integer(6) },
{ "344", new Integer(6) },
{ "345", new Integer(6) },
{ "346", new Integer(6) },
{ "347", new Integer(6) },
{ "348", new Integer(6) },
{ "349", new Integer(6) },
{ "350", new Integer(6) },
{ "351", new Integer(6) },
{ "352", new Integer(6) },
{ "353", new Integer(6) },
{ "354", new Integer(6) },
{ "355", new Integer(6) },
{ "356", new Integer(6) },
{ "357", new Integer(6) },
{ "360", new Integer(6) },
{ "361", new Integer(6) },
{ "362", new Integer(6) },
{ "363", new Integer(6) },
{ "364", new Integer(6) },
{ "365", new Integer(6) },
{ "366", new Integer(6) },
{ "367", new Integer(6) },
{ "368", new Integer(6) },
{ "369", new Integer(6) },
{ "390", VARIABLE_LENGTH, new Integer(15) },
{ "391", VARIABLE_LENGTH, new Integer(18) },
{ "392", VARIABLE_LENGTH, new Integer(15) },
{ "393", VARIABLE_LENGTH, new Integer(18) },
{ "703", VARIABLE_LENGTH, new Integer(30) }
};
private static final Object [][] FOUR_DIGIT_DATA_LENGTH = {
// Same format as above
{ "7001", new Integer(13) },
{ "7002", VARIABLE_LENGTH, new Integer(30) },
{ "7003", new Integer(10) },
{ "8001", new Integer(14) },
{ "8002", VARIABLE_LENGTH, new Integer(20) },
{ "8003", VARIABLE_LENGTH, new Integer(30) },
{ "8004", VARIABLE_LENGTH, new Integer(30) },
{ "8005", new Integer(6) },
{ "8006", new Integer(18) },
{ "8007", VARIABLE_LENGTH, new Integer(30) },
{ "8008", VARIABLE_LENGTH, new Integer(12) },
{ "8018", new Integer(18) },
{ "8020", VARIABLE_LENGTH, new Integer(25) },
{ "8100", new Integer(6) },
{ "8101", new Integer(10) },
{ "8102", new Integer(2) },
{ "8110", VARIABLE_LENGTH, new Integer(30) },
};
private FieldParser() {
}
static String parseFieldsInGeneralPurpose(String rawInformation) throws NotFoundException{
if(rawInformation.length() == 0) {
return "";
}
// Processing 2-digit AIs
if(rawInformation.length() < 2) {
throw NotFoundException.getNotFoundInstance();
}
String firstTwoDigits = rawInformation.substring(0, 2);
for (int i=0; i<TWO_DIGIT_DATA_LENGTH.length; ++i){
if (TWO_DIGIT_DATA_LENGTH[i][0].equals(firstTwoDigits)){
if(TWO_DIGIT_DATA_LENGTH[i][1] == VARIABLE_LENGTH) {
return processVariableAI(2, ((Integer) TWO_DIGIT_DATA_LENGTH[i][2]).intValue(), rawInformation);
}
return processFixedAI(2, ((Integer)TWO_DIGIT_DATA_LENGTH[i][1]).intValue(), rawInformation);
}
}
if(rawInformation.length() < 3) {
throw NotFoundException.getNotFoundInstance();
}
String firstThreeDigits = rawInformation.substring(0, 3);
for (int i=0; i<THREE_DIGIT_DATA_LENGTH.length; ++i){
if (THREE_DIGIT_DATA_LENGTH[i][0].equals(firstThreeDigits)){
if (THREE_DIGIT_DATA_LENGTH[i][1] == VARIABLE_LENGTH) {
return processVariableAI(3, ((Integer) THREE_DIGIT_DATA_LENGTH[i][2]).intValue(), rawInformation);
}
return processFixedAI(3, ((Integer)THREE_DIGIT_DATA_LENGTH[i][1]).intValue(), rawInformation);
}
}
for (int i=0; i<THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH.length; ++i){
if (THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][0].equals(firstThreeDigits)){
if (THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][1] == VARIABLE_LENGTH) {
return processVariableAI(4, ((Integer) THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][2]).intValue(), rawInformation);
}
return processFixedAI(4, ((Integer)THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][1]).intValue(), rawInformation);
}
}
if(rawInformation.length() < 4) {
throw NotFoundException.getNotFoundInstance();
}
String firstFourDigits = rawInformation.substring(0, 4);
for (int i=0; i<FOUR_DIGIT_DATA_LENGTH.length; ++i){
if (FOUR_DIGIT_DATA_LENGTH[i][0].equals(firstFourDigits)){
if (FOUR_DIGIT_DATA_LENGTH[i][1] == VARIABLE_LENGTH) {
return processVariableAI(4, ((Integer) FOUR_DIGIT_DATA_LENGTH[i][2]).intValue(), rawInformation);
}
return processFixedAI(4, ((Integer)FOUR_DIGIT_DATA_LENGTH[i][1]).intValue(), 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);
return '(' + ai + ')' + field + parseFieldsInGeneralPurpose(remaining);
}
private static String processVariableAI(int aiSize, int variableFieldSize, String rawInformation) throws NotFoundException {
String ai = rawInformation.substring(0, aiSize);
int maxSize;
if (rawInformation.length() < aiSize + variableFieldSize) {
maxSize = rawInformation.length();
} else {
maxSize = aiSize + variableFieldSize;
}
String field = rawInformation.substring(aiSize, maxSize);
String remaining = rawInformation.substring(maxSize);
return '(' + ai + ')' + field + parseFieldsInGeneralPurpose(remaining);
}
}

View file

@ -0,0 +1,414 @@
/*
* 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 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 StringBuffer buffer = new StringBuffer();
GeneralAppIdDecoder(BitArray information){
this.information = information;
}
String decodeAllCodes(StringBuffer buff, int initialPosition) throws NotFoundException {
int currentPosition = initialPosition;
String remaining = null;
do{
DecodedInformation info = this.decodeGeneralPurposeField(currentPosition, remaining);
String parsedFields = FieldParser.parseFieldsInGeneralPurpose(info.getNewString());
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.size){
return pos + 4 <= this.information.size;
}
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) {
if(pos + 7 > this.information.size){
int numeric = extractNumericValueFromBitArray(pos, 4);
if(numeric == 0) {
return new DecodedNumeric(this.information.size, DecodedNumeric.FNC1, DecodedNumeric.FNC1);
}
return new DecodedNumeric(this.information.size, 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) {
if(bits > 32) {
throw new IllegalArgumentException("extractNumberValueFromBitArray can't handle more than 32 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) {
this.buffer.setLength(0);
if(remaining != null) {
this.buffer.append(remaining);
}
this.current.position = pos;
DecodedInformation lastDecoded = parseBlocks();
if(lastDecoded != null && lastDecoded.isRemaining()) {
return new DecodedInformation(this.current.position, this.buffer.toString(), lastDecoded.getRemainingValue());
}
return new DecodedInformation(this.current.position, this.buffer.toString());
}
private DecodedInformation parseBlocks() {
boolean isFinished;
BlockParsedResult result;
do{
int initialPosition = current.position;
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.position;
if(!positionChanged && !isFinished) {
break;
}
} while (!isFinished);
return result.getDecodedInformation();
}
private BlockParsedResult parseNumericBlock() {
while(isStillNumeric(current.position)){
DecodedNumeric numeric = decodeNumeric(current.position);
current.position = numeric.getNewPosition();
if(numeric.isFirstDigitFNC1()){
DecodedInformation information;
if (numeric.isSecondDigitFNC1()) {
information = new DecodedInformation(current.position, buffer.toString());
} else {
information = new DecodedInformation(current.position, buffer.toString(), numeric.getSecondDigit());
}
return new BlockParsedResult(information, true);
}
buffer.append(numeric.getFirstDigit());
if(numeric.isSecondDigitFNC1()){
DecodedInformation information = new DecodedInformation(current.position, buffer.toString());
return new BlockParsedResult(information, true);
}
buffer.append(numeric.getSecondDigit());
}
if(isNumericToAlphaNumericLatch(current.position)){
current.setAlpha();
current.position += 4;
}
return new BlockParsedResult(false);
}
private BlockParsedResult parseIsoIec646Block() {
while (isStillIsoIec646(current.position)) {
DecodedChar iso = decodeIsoIec646(current.position);
current.position = iso.getNewPosition();
if (iso.isFNC1()) {
DecodedInformation information = new DecodedInformation(current.position, buffer.toString());
return new BlockParsedResult(information, true);
}
buffer.append(iso.getValue());
}
if (isAlphaOr646ToNumericLatch(current.position)) {
current.position += 3;
current.setNumeric();
} else if (isAlphaTo646ToAlphaLatch(current.position)) {
if (current.position + 5 < this.information.size) {
current.position += 5;
} else {
current.position = this.information.size;
}
current.setAlpha();
}
return new BlockParsedResult(false);
}
private BlockParsedResult parseAlphaBlock() {
while (isStillAlpha(current.position)) {
DecodedChar alpha = decodeAlphanumeric(current.position);
current.position = alpha.getNewPosition();
if(alpha.isFNC1()) {
DecodedInformation information = new DecodedInformation(current.position, buffer.toString());
return new BlockParsedResult(information, true); //end of the char block
}
buffer.append(alpha.getValue());
}
if (isAlphaOr646ToNumericLatch(current.position)) {
current.position += 3;
current.setNumeric();
} else if (isAlphaTo646ToAlphaLatch(current.position)) {
if (current.position + 5 < this.information.size) {
current.position += 5;
} else {
current.position = this.information.size;
}
current.setIsoIec646();
}
return new BlockParsedResult(false);
}
private boolean isStillIsoIec646(int pos) {
if(pos + 5 > this.information.size) {
return false;
}
int fiveBitValue = extractNumericValueFromBitArray(pos, 5);
if(fiveBitValue >= 5 && fiveBitValue < 16) {
return true;
}
if(pos + 7 > this.information.size) {
return false;
}
int sevenBitValue = extractNumericValueFromBitArray(pos, 7);
if(sevenBitValue >= 64 && sevenBitValue < 116) {
return true;
}
if(pos + 8 > this.information.size) {
return false;
}
int eightBitValue = extractNumericValueFromBitArray(pos, 8);
return eightBitValue >= 232 && eightBitValue < 253;
}
private DecodedChar decodeIsoIec646(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 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);
switch (eightBitValue){
case 232: return new DecodedChar(pos + 8, '!');
case 233: return new DecodedChar(pos + 8, '"');
case 234: return new DecodedChar(pos + 8, '%');
case 235: return new DecodedChar(pos + 8, '&');
case 236: return new DecodedChar(pos + 8, '\'');
case 237: return new DecodedChar(pos + 8, '(');
case 238: return new DecodedChar(pos + 8, ')');
case 239: return new DecodedChar(pos + 8, '*');
case 240: return new DecodedChar(pos + 8, '+');
case 241: return new DecodedChar(pos + 8, ',');
case 242: return new DecodedChar(pos + 8, '-');
case 243: return new DecodedChar(pos + 8, '.');
case 244: return new DecodedChar(pos + 8, '/');
case 245: return new DecodedChar(pos + 8, ':');
case 246: return new DecodedChar(pos + 8, ';');
case 247: return new DecodedChar(pos + 8, '<');
case 248: return new DecodedChar(pos + 8, '=');
case 249: return new DecodedChar(pos + 8, '>');
case 250: return new DecodedChar(pos + 8, '?');
case 251: return new DecodedChar(pos + 8, '_');
case 252: return new DecodedChar(pos + 8, ' ');
}
throw new RuntimeException("Decoding invalid ISO/IEC 646 value: " + eightBitValue);
}
private boolean isStillAlpha(int pos) {
if(pos + 5 > this.information.size) {
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.size) {
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));
}
switch(sixBitValue){
case 58: return new DecodedChar(pos + 6, '*');
case 59: return new DecodedChar(pos + 6, ',');
case 60: return new DecodedChar(pos + 6, '-');
case 61: return new DecodedChar(pos + 6, '.');
case 62: return new DecodedChar(pos + 6, '/');
}
throw new RuntimeException("Decoding invalid alphanumeric value: " + sixBitValue);
}
private boolean isAlphaTo646ToAlphaLatch(int pos) {
if(pos + 1 > this.information.size) {
return false;
}
for(int i = 0; i < 5 && i + pos < this.information.size; ++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.size) {
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.size) {
return false;
}
for (int i = 0; i < 4 && i + pos < this.information.size; ++i) {
if (this.information.get(pos + i)) {
return false;
}
}
return true;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1 @@
(11)100224(17)110224(3102)000100

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

View file

@ -0,0 +1 @@
(01)98898765432106(15)991231(3103)001750(10)12A(422)123(21)123456(423)012345678901

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

View file

@ -0,0 +1 @@
(01)98898765432106(15)991231(3103)001750(10)12A(422)123(21)123456

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View file

@ -0,0 +1 @@
(01)98898765432106(3103)001750

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

View file

@ -0,0 +1 @@
(01)90012345678908(3922)795

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

View file

@ -0,0 +1 @@
(01)90012345678908(3932)0401234

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3102)001750(11)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3202)001750(11)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3102)001750(13)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3202)001750(13)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3102)001750(15)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3103)001750

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3202)001750(15)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3102)001750(17)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1 @@
(01)90012345678908(3202)001750(17)100312

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

View file

@ -0,0 +1 @@
(10)56789(11)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

View file

@ -0,0 +1 @@
(10)567890(11)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

View file

@ -0,0 +1 @@
(10)123

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

View file

@ -0,0 +1 @@
(10)5678(11)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

View file

@ -0,0 +1 @@
(10)1098-1234

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

View file

@ -0,0 +1 @@
(10)1098/1234

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

View file

@ -0,0 +1 @@
(10)1098.1234

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -0,0 +1 @@
(10)12A

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

View file

@ -0,0 +1 @@
(10)1098*1234

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

View file

@ -0,0 +1 @@
(10)1098,1234

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

View file

@ -0,0 +1 @@
(15)991231(3103)001750(10)12A(422)123(21)123456(423)0123456789012

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1 @@
(01)98898765432106(3202)012345(15)991231

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -0,0 +1 @@
(01)90614141000015(3202)000150

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

View file

@ -0,0 +1 @@
(10)567(01)90012345678908(11)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

View file

@ -0,0 +1 @@
(10)567(11)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

View file

@ -0,0 +1 @@
(10)567(11)010101(13)010101

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

View file

@ -0,0 +1 @@
(10)567(3102)123456

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

View file

@ -0,0 +1 @@
(01)98898765432106(3103)001750

Some files were not shown because too many files have changed in this diff Show more