diff --git a/actionscript/core/src/com/google/zxing/oned/rss/AbstractRSSReader.as b/actionscript/core/src/com/google/zxing/oned/rss/AbstractRSSReader.as new file mode 100644 index 000000000..3597068aa --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/AbstractRSSReader.as @@ -0,0 +1,112 @@ +/* + * 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 class AbstractRSSReader extends OneDReader { + + private static var MAX_AVG_VARIANCE:int = Math.round(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.2); + private static var MAX_INDIVIDUAL_VARIANCE:int = Math.round(PATTERN_MATCH_RESULT_SCALE_FACTOR * 0.4); + + private static var MIN_FINDER_PATTERN_RATIO:Number = 9.5 / 12.0; + private static var MAX_FINDER_PATTERN_RATIO:Number = 12.5 / 14.0; + + protected var decodeFinderCounters:Array; + protected var dataCharacterCounters:Array; + protected var oddRoundingErrors:Array; + protected var evenRoundingErrors:Array; + protected var oddCounts:Array; + protected var evenCounts:Array; + + public function AbstractRSSReader(){ + decodeFinderCounters = new Array(4); + dataCharacterCounters = new Array(8); + oddRoundingErrors = new Array(4); + evenRoundingErrors = new Array(4); + oddCounts = new Array(dataCharacterCounters.length / 2); + evenCounts = new Array(dataCharacterCounters.length / 2); + } + + + protected static function parseFinderValue(counters:Array, finderPatterns:Array):int { + for (var value:int = 0; value < finderPatterns.length; value++) { + if (patternMatchVariance(counters, finderPatterns[value], MAX_INDIVIDUAL_VARIANCE) < + MAX_AVG_VARIANCE) { + return value; + } + } + throw NotFoundException.getNotFoundInstance(); + } + + protected static function count(array:Array):int { + var count:int = 0; + for (var i:int = 0; i < array.length; i++) { + count += array[i]; + } + return count; + } + + protected static function increment(array:Array, errors:Array):void { + var index:int = 0; + var biggestError:Number = errors[0]; + for (var i:int = 1; i < array.length; i++) { + if (errors[i] > biggestError) { + biggestError = errors[i]; + index = i; + } + } + array[index]++; + } + + protected static function decrement(array:Array, errors:Array):void { + var index:int = 0; + var biggestError:Array = errors[0]; + for (var i:int = 1; i < array.length; i++) { + if (errors[i] < biggestError) { + biggestError = errors[i]; + index = i; + } + } + array[index]--; + } + + protected static function isFinderPattern(counters:Array):Boolean { + var firstTwoSum:int = counters[0] + counters[1]; + var sum:int = firstTwoSum + counters[2] + counters[3]; + var ratio:Number = firstTwoSum / sum; + if (ratio >= MIN_FINDER_PATTERN_RATIO && ratio <= MAX_FINDER_PATTERN_RATIO) { + // passes ratio test in spec, but see if the counts are unreasonable + var minCounter:int = int.MAX_VALUE; + var maxCounter:int = int.MIN_VALUE; + for (var i:int = 0; i < counters.length; i++) { + var counter:int = counters[i]; + if (counter > maxCounter) { + maxCounter = counter; + } + if (counter < minCounter) { + minCounter = counter; + } + } + return maxCounter < 10 * minCounter; + } + return false; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/DataCharacter.as b/actionscript/core/src/com/google/zxing/oned/rss/DataCharacter.as new file mode 100644 index 000000000..a2ff13a6b --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/DataCharacter.as @@ -0,0 +1,39 @@ +/* + * Copyright 2009 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 +{ + +public class DataCharacter { + + private var value:int; + private var checksumPortion:int; + + public function DataCharacter(value:int, checksumPortion:int) { + this.value = value; + this.checksumPortion = checksumPortion; + } + + public function getValue():int { + return value; + } + + public function getChecksumPortion():int { + return checksumPortion; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/FinderPattern.as b/actionscript/core/src/com/google/zxing/oned/rss/FinderPattern.as new file mode 100644 index 000000000..f5b68b1f3 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/FinderPattern.as @@ -0,0 +1,51 @@ +/* + * Copyright 2009 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.ResultPoint; + +public class FinderPattern { + + + protected var value:int; + protected var startEnd:Array; + protected var resultPoints:Array; + + public function FinderPattern( value:int, startEnd:Array, start:int, end:int, rowNumber:int) { + this.value = value; + this.startEnd = startEnd; + this.resultPoints = [ + new ResultPoint( start as Number, rowNumber as Number), + new ResultPoint( end as Number, rowNumber as Number), + ]; + } + + public function getValue():int { + return value; + } + + public function getStartEnd():Array { + return startEnd; + } + + public function getResultPoints():Array { + return resultPoints; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/Pair.as b/actionscript/core/src/com/google/zxing/oned/rss/Pair.as new file mode 100644 index 000000000..b3cb0e31a --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/Pair.as @@ -0,0 +1,42 @@ +/* + * Copyright 2009 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 +{ + +public class Pair extends DataCharacter { + + protected var finderPattern:FinderPattern; + protected var count:int; + + public function Pair(value:int, checksumPortion:int, finderPattern:FinderPattern) { + super(value, checksumPortion); + this.finderPattern = finderPattern; + } + + public function getFinderPattern():FinderPattern { + return finderPattern; + } + + public function getCount():int { + return count; + } + + public function incrementCount():void { + count++; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/RSS14Reader.as b/actionscript/core/src/com/google/zxing/oned/rss/RSS14Reader.as new file mode 100644 index 000000000..d3dffbd72 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/RSS14Reader.as @@ -0,0 +1,509 @@ +/* + * Copyright 2009 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.BarcodeFormat; + import com.google.zxing.DecodeHintType; + import com.google.zxing.NotFoundException; + import com.google.zxing.Result; + import com.google.zxing.ResultPoint; + import com.google.zxing.ResultPointCallback; + import com.google.zxing.common.BitArray; + import com.google.zxing.common.flexdatatypes.ArrayList; + import com.google.zxing.common.flexdatatypes.Enumeration; + import com.google.zxing.common.flexdatatypes.HashTable; + import com.google.zxing.common.flexdatatypes.StringBuilder; + + /** + * Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006. + */ + public class RSS14Reader extends AbstractRSSReader + { + + private static var OUTSIDE_EVEN_TOTAL_SUBSET:Array = [1,10,34,70,126]; + private static var INSIDE_ODD_TOTAL_SUBSET:Array = [4,20,48,81]; + private static var OUTSIDE_GSUM:Array = [0,161,961,2015,2715]; + private static var INSIDE_GSUM:Array = [0,336,1036,1516]; + private static var OUTSIDE_ODD_WIDEST:Array = [8,6,4,3,1]; + private static var INSIDE_ODD_WIDEST:Array = [2,4,6,8]; + + private static var FINDER_PATTERNS:Array = [ + [3,8,2,1], + [3,5,5,1], + [3,3,7,1], + [3,1,9,1], + [2,7,4,1], + [2,5,6,1], + [2,3,8,1], + [1,5,7,1], + [1,3,9,1], + ]; + + private var possibleLeftPairs:ArrayList; + private var possibleRightPairs:ArrayList; + + public function RSS14Reader() + { + possibleLeftPairs = new ArrayList(); + possibleRightPairs = new ArrayList(); + } + + public override function decodeRow(rowNumber:Object , row:BitArray , o:Object ):Result + { + var leftPair:Pair = decodePair(row, false, rowNumber as int, o as HashTable); + + addOrTally(possibleLeftPairs, leftPair); + row.reverse(); + var rightPair:Pair = decodePair(row, true, rowNumber as int, o as HashTable); + addOrTally(possibleRightPairs, rightPair); + row.reverse(); + var numLeftPairs:int = possibleLeftPairs.size(); + var numRightPairs:int = possibleRightPairs.size(); + for (var l:int = 0; l < numLeftPairs; l++) { + var left:Pair = possibleLeftPairs.elementAt(l) as Pair; + if (left.getCount() > 1) { + for (var r:int = 0; r < numRightPairs; r++) { + var right:Pair = possibleRightPairs.elementAt(r) as Pair; + if (right.getCount() > 1) { + if (checkChecksum(left, right)) { + return constructResult(left, right); + } + } + } + } + } + throw NotFoundException.getNotFoundInstance(); + } + + private static function addOrTally(possiblePairs:ArrayList, pair:Pair):void + { + if (pair != null) + { + //var e:Enumeration = new Enumeration(possiblePairs.elements()); + var found:Boolean = false; + var cntr:int = 0; + var max:int = possiblePairs.Count; + + for(var i:int=0;i 0; i--) { + buffer.Append('0'); + } + buffer.Append(text); + + var checkDigit:int = 0; + for (i = 0; i < 13; i++) { + var digit:int = (buffer.charAt(i)).charCodeAt(0) - ('0' as String).charCodeAt(0); + checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; + } + checkDigit = 10 - (checkDigit % 10); + if (checkDigit == 10) { + checkDigit = 0; + } + buffer.Append(checkDigit); + + var leftPoints:Array = leftPair.getFinderPattern().getResultPoints(); + var rightPoints:Array = rightPair.getFinderPattern().getResultPoints(); + return new Result( + buffer.toString(), + null, + [ leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1], ], + BarcodeFormat.RSS_14); + } + + private static function checkChecksum(leftPair:Pair, rightPair:Pair):Boolean { + var leftFPValue:int = leftPair.getFinderPattern().getValue(); + var rightFPValue:int = rightPair.getFinderPattern().getValue(); + if ((leftFPValue == 0 && rightFPValue == 8) || + (leftFPValue == 8 && rightFPValue == 0)) { + } + var checkValue:int = (leftPair.getChecksumPortion() + 16 * rightPair.getChecksumPortion()) % 79; + var targetCheckValue:int = + 9 * leftPair.getFinderPattern().getValue() + rightPair.getFinderPattern().getValue(); + if (targetCheckValue > 72) { + targetCheckValue--; + } + if (targetCheckValue > 8) { + targetCheckValue--; + } + return checkValue == targetCheckValue; + } + + private function decodePair( row:BitArray, right:Boolean, rowNumber:int, hints:HashTable):Pair + { + try { + var startEnd:Array = findFinderPattern(row, 0, right); + var pattern:FinderPattern = parseFoundFinderPattern(row, rowNumber, right, startEnd); + + var resultPointCallback:ResultPointCallback = hints == null ? null : + (hints._get(DecodeHintType.NEED_RESULT_POINT_CALLBACK) as ResultPointCallback); + + if (resultPointCallback != null) { + var center:Number = (startEnd[0] + startEnd[1]) / 2.0; + if (right) { + // row is actually reversed + center = row.getSize() - 1 - center; + } + resultPointCallback.foundPossibleResultPoint(new ResultPoint(center, rowNumber)); + } + + var outside:DataCharacter = decodeDataCharacter(row, pattern, true); + var inside:DataCharacter = decodeDataCharacter(row, pattern, false); + return new Pair(1597 * outside.getValue() + inside.getValue(), + outside.getChecksumPortion() + 4 * inside.getChecksumPortion(), + pattern); + } catch (re:NotFoundException) { + return null; + } + return null;// + } + + private function decodeDataCharacter(row:BitArray, pattern:FinderPattern , outsideChar:Boolean ):DataCharacter { + + var counters:Array = 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 (outsideChar) { + recordPatternInReverse(row, pattern.getStartEnd()[0], counters); + } else { + recordPattern(row, pattern.getStartEnd()[1] + 1, counters); + // reverse it + var j:int; + for (i = 0, j = counters.length - 1; i < j; i++, j--) { + var temp:int = counters[i]; + counters[i] = counters[j]; + counters[j] = temp; + } + } + + var numModules:int = outsideChar ? 16 : 15; + var elementWidth:Number = count(counters) / numModules; + + var oddCounts:Array = this.oddCounts; + var evenCounts:Array = this.evenCounts; + var oddRoundingErrors:Array = this.oddRoundingErrors; + var evenRoundingErrors:Array = this.evenRoundingErrors; + + for (var i:int = 0; i < counters.length; i++) + { + var value:Number = counters[i] / elementWidth; + var count:int = int(value + 0.5); // Round + if (count < 1) { + count = 1; + } else if (count > 8) { + count = 8; + } + var offset:int = i >> 1; + if ((i & 0x01) == 0) { + oddCounts[offset] = count; + oddRoundingErrors[offset] = value - count; + } else { + evenCounts[offset] = count; + evenRoundingErrors[offset] = value - count; + } + } + + adjustOddEvenCounts(outsideChar, numModules); + + var oddSum:int = 0; + var oddChecksumPortion:int = 0; + for (i = oddCounts.length - 1; i >= 0; i--) { + oddChecksumPortion *= 9; + oddChecksumPortion += oddCounts[i]; + oddSum += oddCounts[i]; + } + var evenChecksumPortion:int = 0; + var evenSum:int = 0; + for (i = evenCounts.length - 1; i >= 0; i--) { + evenChecksumPortion *= 9; + evenChecksumPortion += evenCounts[i]; + evenSum += evenCounts[i]; + } + var checksumPortion:int = oddChecksumPortion + 3*evenChecksumPortion; + + if (outsideChar) { + if ((oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4) { + throw NotFoundException.getNotFoundInstance(); + } + var group:int = (12 - oddSum) / 2; + var oddWidest:int = OUTSIDE_ODD_WIDEST[group]; + var evenWidest:int = 9 - oddWidest; + var vOdd:int = RSSUtils.getRSSvalue(oddCounts, oddWidest, false); + var vEven:int = RSSUtils.getRSSvalue(evenCounts, evenWidest, true); + var tEven:int = OUTSIDE_EVEN_TOTAL_SUBSET[group]; + var gSum:int = OUTSIDE_GSUM[group]; + return new DataCharacter(vOdd * tEven + vEven + gSum, checksumPortion); + } else { + if ((evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4) { + throw NotFoundException.getNotFoundInstance(); + } + group = (10 - evenSum) / 2; + oddWidest = INSIDE_ODD_WIDEST[group]; + evenWidest = 9 - oddWidest; + vOdd = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); + vEven = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); + var tOdd:int = INSIDE_ODD_TOTAL_SUBSET[group]; + gSum = INSIDE_GSUM[group]; + return new DataCharacter(vEven * tOdd + vOdd + gSum, checksumPortion); + } + + } + + private function findFinderPattern(row:BitArray , rowOffset:int, rightFinderPattern:Boolean ):Array + { + + var counters:Array = decodeFinderCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + + var width:int = row.getSize(); + var isWhite:Boolean = false; + while (rowOffset < width) { + isWhite = !row._get(rowOffset); + if (rightFinderPattern == isWhite) { + // Will encounter white first when searching for right finder pattern + break; + } + rowOffset++; + } + + var counterPosition:int = 0; + var patternStart:int = rowOffset; + for (var x:int = rowOffset; x < width; x++) { + var pixel:Boolean = row._get(x); + if (pixel != isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == 3) { + if (isFinderPattern(counters)) { + return [patternStart, x]; + } + 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 function parseFoundFinderPattern(row:BitArray, rowNumber:int, right:Boolean, startEnd:Array):FinderPattern { + // Actually we found elements 2-5 + var firstIsBlack:Boolean = row._get(startEnd[0]); + var firstElementStart:int = startEnd[0] - 1; + // Locate element 1 + while (firstElementStart >= 0 && (firstIsBlack != row._get(firstElementStart))) { + firstElementStart--; + } + firstElementStart++; + var firstCounter:int = startEnd[0] - firstElementStart; + // Make 'counters' hold 1-4 + var counters:Array = decodeFinderCounters; + for (var i:int = counters.length - 1; i > 0; i--) { + counters[i] = counters[i-1]; + } + counters[0] = firstCounter; + var value:int = parseFinderValue(counters, FINDER_PATTERNS); + var start :int= firstElementStart; + var end:int = startEnd[1]; + if (right) { + // row is actually reversed + start = row.getSize() - 1 - start; + end = row.getSize() - 1 - end; + } + return new FinderPattern(value, [firstElementStart, startEnd[1]], start, end, rowNumber); + } + + /* + private static int[] normalizeE2SEValues(int[] counters) { + int p = 0; + for (int i = 0; i < counters.length; i++) { + p += counters[i]; + } + int[] normalized = new int[counters.length - 2]; + for (int i = 0; i < normalized.length; i++) { + int e = counters[i] + counters[i+1]; + float eRatio = (float) e / (float) p; + float E = ((eRatio * 32.0f) + 1.0f) / 2.0f; + normalized[i] = (int) E; + } + return normalized; + } + */ + + private function adjustOddEvenCounts(outsideChar:Boolean, numModules:int):void { + + var oddSum:int = count(oddCounts); + var evenSum:int = count(evenCounts); + var mismatch:int = oddSum + evenSum - numModules; + var oddParityBad:Boolean = (oddSum & 0x01) == (outsideChar ? 1 : 0); + var evenParityBad:Boolean = (evenSum & 0x01) == 1; + + var incrementOdd:Boolean = false; + var decrementOdd:Boolean = false; + var incrementEven:Boolean = false; + var decrementEven:Boolean = false; + + if (outsideChar) { + if (oddSum > 12) { + decrementOdd = true; + } else if (oddSum < 4) { + incrementOdd = true; + } + if (evenSum > 12) { + decrementEven = true; + } else if (evenSum < 4) { + incrementEven = true; + } + } else { + if (oddSum > 11) { + decrementOdd = true; + } else if (oddSum < 5) { + incrementOdd = true; + } + if (evenSum > 10) { + decrementEven = true; + } else if (evenSum < 4) { + incrementEven = true; + } + } + + /*if (mismatch == 2) { + if (!(oddParityBad && evenParityBad)) { + throw ReaderException.getInstance(); + } + decrementOdd = true; + decrementEven = true; + } else if (mismatch == -2) { + if (!(oddParityBad && evenParityBad)) { + throw ReaderException.getInstance(); + } + incrementOdd = true; + incrementEven = true; + } else */ + 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(oddCounts, oddRoundingErrors); + } + if (decrementOdd) { + decrement(oddCounts, oddRoundingErrors); + } + if (incrementEven) { + if (decrementEven) { + throw NotFoundException.getNotFoundInstance(); + } + increment(evenCounts, oddRoundingErrors); + } + if (decrementEven) { + decrement(evenCounts, evenRoundingErrors); + } + + } + + } +} diff --git a/actionscript/core/src/com/google/zxing/oned/rss/RSSUtils.as b/actionscript/core/src/com/google/zxing/oned/rss/RSSUtils.as new file mode 100644 index 000000000..f9d9749dd --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/RSSUtils.as @@ -0,0 +1,159 @@ +/* + * Copyright 2009 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 +{ + +/** Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. */ +public class RSSUtils { + + public function RSSUtils() {} + + public static function getRSSwidths(val:int, n:int, elements:int,maxWidth:int, noNarrow:Boolean):Array + { + var widths:Array = new Array(elements); + var bar:int; + var narrowMask:int = 0; + for (bar = 0; bar < elements - 1; bar++) { + narrowMask |= (1 << bar); + var elmWidth:int = 1; + var subVal:int; + while (true) { + subVal = combins(n - elmWidth - 1, elements - bar - 2); + if (noNarrow && (narrowMask == 0) && + (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { + subVal -= combins(n - elmWidth - (elements - bar), elements - bar - 2); + } + if (elements - bar - 1 > 1) { + var lessVal:int = 0; + for (var mxwElement:int = n - elmWidth - (elements - bar - 2); + mxwElement > maxWidth; + mxwElement--) { + lessVal += combins(n - elmWidth - mxwElement - 1, elements - bar - 3); + } + subVal -= lessVal * (elements - 1 - bar); + } else if (n - elmWidth > maxWidth) { + subVal--; + } + val -= subVal; + if (val < 0) { + break; + } + elmWidth++; + narrowMask &= ~(1 << bar); + } + val += subVal; + n -= elmWidth; + widths[bar] = elmWidth; + } + widths[bar] = n; + return widths; + } + + public static function getRSSvalue(widths:Array, maxWidth:int, noNarrow:Boolean):int { + var elements:int = widths.length; + var n:int = 0; + for (var i:int = 0; i < elements; i++) { + n += widths[i]; + } + var val:int = 0; + var narrowMask:int = 0; + for (var bar:int = 0; bar < elements - 1; bar++) { + var elmWidth:int; + for (elmWidth = 1, narrowMask |= (1 << bar); + elmWidth < widths[bar]; + elmWidth++, narrowMask &= ~(1 << bar)) { + var subVal:int = combins(n - elmWidth - 1, elements - bar - 2); + if (noNarrow && (narrowMask == 0) && + (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { + subVal -= combins(n - elmWidth - (elements - bar), + elements - bar - 2); + } + if (elements - bar - 1 > 1) { + var lessVal:int = 0; + for (var mxwElement:int = n - elmWidth - (elements - bar - 2); + mxwElement > maxWidth; mxwElement--) { + lessVal += combins(n - elmWidth - mxwElement - 1, + elements - bar - 3); + } + subVal -= lessVal * (elements - 1 - bar); + } else if (n - elmWidth > maxWidth) { + subVal--; + } + val += subVal; + } + n -= elmWidth; + } + return val; + } + + public static function combins(n:int, r:int):int { + var maxDenom:int; + var minDenom:int; + if (n - r > r) { + minDenom = r; + maxDenom = n - r; + } else { + minDenom = n - r; + maxDenom = r; + } + var val:int = 1; + var j:int = 1; + for (var i:int = n; i > maxDenom; i--) { + val *= i; + if (j <= minDenom) { + val /= j; + j++; + } + } + while (j <= minDenom) { + val /= j; + j++; + } + return val; + } + + public static function elements(eDist:Array, N:int, K:int):Array { + var widths:Array = new Array(eDist.length + 2); + var twoK:int = K << 1; + widths[0] = 1; + var i:int; + var minEven:int = 10; + var barSum:int = 1; + for (i = 1; i < twoK - 2; i += 2) { + widths[i] = eDist[i - 1] - widths[i - 1]; + widths[i + 1] = eDist[i] - widths[i]; + barSum += widths[i] + widths[i + 1]; + if (widths[i] < minEven) { + minEven = widths[i]; + } + } + widths[twoK - 1] = N - barSum; + if (widths[twoK - 1] < minEven) { + minEven = widths[twoK - 1]; + } + if (minEven > 1) { + for (i = 0; i < twoK; i += 2) { + widths[i] += minEven - 1; + widths[i + 1] -= minEven - 1; + } + } + return widths; + } + + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/BitArrayBuilder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/BitArrayBuilder.as new file mode 100644 index 000000000..6891dfc2c --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/BitArrayBuilder.as @@ -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 com.google.zxing.common.BitArray; + import com.google.zxing.common.flexdatatypes.ArrayList; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class BitArrayBuilder { + + public function BitArrayBuilder() { + } + + public static function buildBitArray(pairs:ArrayList):BitArray { + var charNumber:int = (pairs.size() << 1) - 1; + if ((pairs.lastElement() as ExpandedPair).getRightChar() == null) { + charNumber -= 1; + } + + var size:int = 12 * charNumber; + + var binary:BitArray = new BitArray(size); + var accPos:int = 0; + + var firstPair:ExpandedPair = pairs.elementAt(0) as ExpandedPair; + var firstValue:int = firstPair.getRightChar().getValue(); + for(var i:int = 11; i >= 0; --i){ + if ((firstValue & (1 << i)) != 0) { + binary._set(accPos); + } + accPos++; + } + + for(i = 1; i < pairs.size(); ++i){ + var currentPair:ExpandedPair = pairs.elementAt(i) as ExpandedPair; + + var leftValue:int = currentPair.getLeftChar().getValue(); + for(var j:int = 11; j >= 0; --j){ + if ((leftValue & (1 << j)) != 0) { + binary._set(accPos); + } + accPos++; + } + + if(currentPair.getRightChar() != null){ + var rightValue:int = currentPair.getRightChar().getValue(); + for(j = 11; j >= 0; --j){ + if ((rightValue & (1 << j)) != 0) { + binary._set(accPos); + } + accPos++; + } + } + } + return binary; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/ExpandedPair.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/ExpandedPair.as new file mode 100644 index 000000000..fb3993dee --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/ExpandedPair.as @@ -0,0 +1,71 @@ +/* + * 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) + */ +public class ExpandedPair { + + protected var _mayBeLast:Boolean; + protected var leftChar:DataCharacter; + protected var rightChar:DataCharacter; + protected var finderPattern:FinderPattern; + + public function ExpandedPair(leftChar:DataCharacter, rightChar:DataCharacter, finderPattern:FinderPattern, mayBeLast:Boolean) + { + this.leftChar = leftChar; + this.rightChar = rightChar; + this.finderPattern = finderPattern; + this._mayBeLast = mayBeLast; + } + + public function mayBeLast():Boolean{ + return this._mayBeLast; + } + + public function getLeftChar():DataCharacter { + return this.leftChar; + } + + public function getRightChar():DataCharacter { + return this.rightChar; + } + + public function getFinderPattern():FinderPattern { + return this.finderPattern; + } + + public function mustBeLast():Boolean { + return this.rightChar == null; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/RSSExpandedReader.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/RSSExpandedReader.as new file mode 100644 index 000000000..861a16364 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/RSSExpandedReader.as @@ -0,0 +1,582 @@ +/* + * 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.BarcodeFormat; + import com.google.zxing.NotFoundException; + import com.google.zxing.Result; + import com.google.zxing.common.BitArray; + import com.google.zxing.common.flexdatatypes.ArrayList; + 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 class RSSExpandedReader extends AbstractRSSReader{ + + private static var SYMBOL_WIDEST:Array = [7, 5, 4, 3, 1]; + private static var EVEN_TOTAL_SUBSET:Array = [4, 20, 52, 104, 204]; + private static var GSUM:Array = [0, 348, 1388, 2948, 3988]; + + private static var FINDER_PATTERNS:Array = [ + [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 var WEIGHTS:Array = [ + [ 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 var FINDER_PAT_A:int = 0; + private static var FINDER_PAT_B:int = 1; + private static var FINDER_PAT_C:int = 2; + private static var FINDER_PAT_D:int = 3; + private static var FINDER_PAT_E:int = 4; + private static var FINDER_PAT_F:int = 5; + + private static var FINDER_PATTERN_SEQUENCES:Array = [ + [ 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 var LONGEST_SEQUENCE_SIZE:int = FINDER_PATTERN_SEQUENCES[FINDER_PATTERN_SEQUENCES.length - 1].length; + + private static var MAX_PAIRS:int = 11; + private var pairs:ArrayList = new ArrayList(MAX_PAIRS); + private var startEnd:Array = new Array(2); + private var currentSequence:Array = new Array(LONGEST_SEQUENCE_SIZE); + + public override function decodeRow(rowNumber:Object , row:BitArray , o:Object ):Result { + this.reset(); + decodeRow2pairs(rowNumber as int, row); + return constructResult(this.pairs); + } + + public override function reset():void { + this.pairs.clearAll();//.setSize(0); + } + + // Not private for testing + public function decodeRow2pairs(rowNumber:int , row:BitArray ): ArrayList { + while(true){ + var nextPair:ExpandedPair = retrieveNextPair(row, this.pairs, rowNumber); + this.pairs.addElement(nextPair); + + if (nextPair.mayBeLast()) + { + if (checkChecksum()) { + return this.pairs; + } + if (nextPair.mustBeLast()) { + throw NotFoundException.getNotFoundInstance(); + } + } + } + throw NotFoundException.getNotFoundInstance + } + + + private static function constructResult(pairs:ArrayList):Result{ + var binary:BitArray = BitArrayBuilder.buildBitArray(pairs); + + var decoder:AbstractExpandedDecoder = AbstractExpandedDecoder.createDecoder(binary); + var resultingString:String = decoder.parseInformation(); + + var firstPoints:Array = (pairs.elementAt(0) as ExpandedPair).getFinderPattern().getResultPoints(); + var lastPoints:Array = (pairs.lastElement() as ExpandedPair).getFinderPattern().getResultPoints(); + + return new Result( + resultingString, + null, + [firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1]], + BarcodeFormat.RSS_EXPANDED + ); + } + + private function checkChecksum():Boolean + { + var firstPair:ExpandedPair = this.pairs.elementAt(0) as ExpandedPair; + var checkCharacter:DataCharacter = firstPair.getLeftChar(); + var firstCharacter:DataCharacter = firstPair.getRightChar(); + + var checksum:int = firstCharacter.getChecksumPortion(); + var S:int = 2; + + for(var i:int = 1; i < this.pairs.size(); ++i){ + var currentPair:ExpandedPair = this.pairs.elementAt(i) as ExpandedPair; + checksum += currentPair.getLeftChar().getChecksumPortion(); + S++; + if(currentPair.getRightChar() != null){ + checksum += currentPair.getRightChar().getChecksumPortion(); + S++; + } + } + + checksum %= 211; + + var checkCharacterValue:int = 211 * (S - 4) + checksum; + + return checkCharacterValue == checkCharacter.getValue(); + } + + private static function getNextSecondBar(row:BitArray, initialPos:int):int{ + var currentPos:int = initialPos; + var current:Boolean = 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 + public function retrieveNextPair(row:BitArray, previousPairs:ArrayList, rowNumber:int):ExpandedPair{ + var isOddPattern:Boolean = previousPairs.size() % 2 == 0; + + var pattern:FinderPattern; + + var keepFinding:Boolean = true; + var forcedOffset:int = -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); + + var mayBeLast:Boolean = checkPairSequence(previousPairs, pattern); + + var leftChar:DataCharacter = this.decodeDataCharacter(row, pattern, isOddPattern, true); + var rightChar:DataCharacter; + try{ + rightChar = this.decodeDataCharacter(row, pattern, isOddPattern, false); + }catch(nfe:NotFoundException){ + if(mayBeLast) { + rightChar = null; + } else { + throw nfe; + } + } + + return new ExpandedPair(leftChar, rightChar, pattern, mayBeLast); + } + + private function checkPairSequence(previousPairs:ArrayList, pattern:FinderPattern):Boolean{ + var currentSequenceLength:int = previousPairs.size() + 1; + if(currentSequenceLength > this.currentSequence.length) { + throw NotFoundException.getNotFoundInstance(); + } + + for(var pos:int = 0; pos < previousPairs.size(); ++pos) { + this.currentSequence[pos] = (previousPairs.elementAt(pos) as ExpandedPair).getFinderPattern().getValue(); + } + + this.currentSequence[currentSequenceLength - 1] = pattern.getValue(); + + for(var i:int = 0; i < FINDER_PATTERN_SEQUENCES.length; ++i){ + var validSequence:Array = FINDER_PATTERN_SEQUENCES[i]; + if(validSequence.length >= currentSequenceLength){ + var valid:Boolean = true; + for(pos = 0; pos < currentSequenceLength; ++pos) { + if (this.currentSequence[pos] != validSequence[pos]) { + valid = false; + break; + } + } + + if(valid) { + return currentSequenceLength == validSequence.length; + } + } + } + + throw NotFoundException.getNotFoundInstance(); + } + + private function findNextPair(row:BitArray, previousPairs:ArrayList, forcedOffset:int):void{ + var counters:Array = this.decodeFinderCounters; + counters[0] = 0; + counters[1] = 0; + counters[2] = 0; + counters[3] = 0; + + var width:int = row.getSize(); + + var rowOffset:int; + if (forcedOffset >= 0) { + rowOffset = forcedOffset; + } else if (previousPairs.isEmpty()) { + rowOffset = 0; + } else{ + var lastPair:ExpandedPair = previousPairs.lastElement() as ExpandedPair; + rowOffset = lastPair.getFinderPattern().getStartEnd()[1]; + } + var searchingEvenPair:Boolean = ((previousPairs.size() % 2) != 0); + + var isWhite:Boolean = false; + while (rowOffset < width) { + isWhite = !row._get(rowOffset); + if (!isWhite) { + break; + } + rowOffset++; + } + + var counterPosition:int = 0; + var patternStart:int = rowOffset; + for (var x:int = rowOffset; x < width; x++) { + var pixel:Boolean = row._get(x); + if (pixel != isWhite) { + counters[counterPosition]++; + } else { + if (counterPosition == 3) { + if (searchingEvenPair) { + reverseCounters(counters); + } + var ifp:Boolean = isFinderPattern(counters); + if (ifp) + { + 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 function reverseCounters(counters:Array):void{ + var length:int = counters.length; + for(var i:int = 0; i < int(length / 2); ++i){ + var tmp:int = counters[i]; + counters[i] = counters[length - i - 1]; + counters[length - i - 1] = tmp; + } + } + + private function parseFoundFinderPattern(row:BitArray, rowNumber:int, oddPattern:Boolean):FinderPattern { + // Actually we found elements 2-5. + var firstCounter:int; + var start:int; + var end:int; + + if(oddPattern){ + // If pattern number is odd, we need to locate element 1 *before* the current block. + + var firstElementStart:int = 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]; + + firstElementStart = this.startEnd[1] + 1; + while (firstElementStart < row.Size && row._get(firstElementStart)) { + firstElementStart++; + } + + end = firstElementStart; + firstCounter = end - this.startEnd[1]; + } + + // Make 'counters' hold 1-4 + var counters:Array = this.decodeFinderCounters; + for (var i:int = counters.length - 1; i > 0; i--) { + counters[i] = counters[i - 1]; + } + + counters[0] = firstCounter; + var value:int; + try { + value = parseFinderValue(counters, FINDER_PATTERNS); + } catch (nfe:NotFoundException) { + return null; + } + return new FinderPattern(value, [start, end], start, end, rowNumber); + } + + public function decodeDataCharacter(row:BitArray, pattern:FinderPattern, isOddPattern:Boolean, leftChar:Boolean):DataCharacter + { + var counters:Array = 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 + var j:int = counters.length - 1; + for (var i:int = 0; i < j; i++, j--) { + var temp:int = counters[i]; + counters[i] = counters[j]; + counters[j] = temp; + } + }//counters[] has the pixels of the module + + var numModules:int = 17; //left and right data characters have all the same length + var elementWidth:Number = count(counters) / numModules; + + var oddCounts:Array = this.oddCounts; + var evenCounts:Array = this.evenCounts; + var oddRoundingErrors:Array = this.oddRoundingErrors; + var evenRoundingErrors:Array = this.evenRoundingErrors; + + for (i = 0; i < counters.length; i++) { + var value1:Number = 1.0 * counters[i] / elementWidth; + var count:int = int(value1 + 0.5); + if (count < 1) { + count = 1; + } else if (count > 8) { + count = 8; + } + var offset:int = i >> 1; + if ((i & 0x01) == 0) { + oddCounts[offset] = count; + oddRoundingErrors[offset] = value1 - count; + } else { + evenCounts[offset] = count; + evenRoundingErrors[offset] = value1 - count; + } + } + + adjustOddEvenCounts(numModules); + + var weightRowNumber:int = 4 * pattern.getValue() + (isOddPattern?0:2) + (leftChar?0:1) - 1; + + var oddSum:int = 0; + var oddChecksumPortion:int = 0; + for (i = oddCounts.length - 1; i >= 0; i--) { + if(isNotA1left(pattern, isOddPattern, leftChar)){ + var weight:int = WEIGHTS[weightRowNumber][2 * i]; + oddChecksumPortion += oddCounts[i] * weight; + } + oddSum += oddCounts[i]; + } + var evenChecksumPortion:int = 0; + var evenSum:int = 0; + for (i = evenCounts.length - 1; i >= 0; i--) { + if(isNotA1left(pattern, isOddPattern, leftChar)){ + weight = WEIGHTS[weightRowNumber][2 * i + 1]; + evenChecksumPortion += evenCounts[i] * weight; + } + evenSum += evenCounts[i]; + } + var checksumPortion:int = oddChecksumPortion + evenChecksumPortion; + + if ((oddSum & 0x01) != 0 || oddSum > 13 || oddSum < 4) { + throw NotFoundException.getNotFoundInstance(); + } + + var group:int = int((13 - oddSum) / 2); + var oddWidest:int = SYMBOL_WIDEST[group]; + var evenWidest:int = 9 - oddWidest; + var vOdd:int = RSSUtils.getRSSvalue(oddCounts, oddWidest, true); + var vEven:int = RSSUtils.getRSSvalue(evenCounts, evenWidest, false); + var tEven:int = EVEN_TOTAL_SUBSET[group]; + var gSum:int = GSUM[group]; + var value2:int = vOdd * tEven + vEven + gSum; + + return new DataCharacter(value2, checksumPortion); + } + + private static function isNotA1left(pattern:FinderPattern, isOddPattern:Boolean, leftChar:Boolean):Boolean { + // A1: pattern.getValue is 0 (A), and it's an oddPattern, and it is a left char + return !(pattern.getValue() == 0 && isOddPattern && leftChar); + } + + private function adjustOddEvenCounts(numModules:int):void { + + var oddSum:int = count(this.oddCounts); + var evenSum:int = count(this.evenCounts); + var mismatch:int = oddSum + evenSum - numModules; + var oddParityBad:Boolean = (oddSum & 0x01) == 1; + var evenParityBad:Boolean = (evenSum & 0x01) == 0; + + var incrementOdd:Boolean = false; + var decrementOdd:Boolean = false; + + if (oddSum > 13) { + decrementOdd = true; + } else if (oddSum < 4) { + incrementOdd = true; + } + var incrementEven:Boolean = false; + var decrementEven:Boolean = 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); + } + } +} +} diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013103decoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013103decoder.as new file mode 100644 index 000000000..0c479ad34 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013103decoder.as @@ -0,0 +1,50 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI013103decoder extends AI013x0xDecoder { + + public function AI013103decoder(information:BitArray) { + super(information); + } + + protected override function addWeightCode(buf:StringBuilder, weight:int):void { + buf.Append("(3103)"); + } + + protected override function checkWeight(weight:int):int { + return weight; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01320xDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01320xDecoder.as new file mode 100644 index 000000000..8f02b95aa --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01320xDecoder.as @@ -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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI01320xDecoder extends AI013x0xDecoder { + + public function AI01320xDecoder(information:BitArray) { + super(information); + } + + protected override function addWeightCode(buf:StringBuilder , weight:int):void { + if (weight < 10000) { + buf.Append("(3202)"); + } else { + buf.Append("(3203)"); + } + } + + protected override function checkWeight(weight:int):int { + if(weight < 10000) { + return weight; + } + return weight - 10000; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01392xDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01392xDecoder.as new file mode 100644 index 000000000..cd9d809f7 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01392xDecoder.as @@ -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 +{ + +import com.google.zxing.NotFoundException; +import com.google.zxing.common.BitArray; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI01392xDecoder extends AI01decoder { + + private static var HEADER_SIZE:int = 5 + 1 + 2; + private static var LAST_DIGIT_SIZE:int = 2; + + public function AI01392xDecoder(information:BitArray) { + super(information); + } + + public override function parseInformation():String { + if (this.information.Size < HEADER_SIZE + GTIN_SIZE) { + throw NotFoundException.getNotFoundInstance(); + } + + var buf:StringBuilder = new StringBuilder(); + + encodeCompressedGtin(buf, HEADER_SIZE); + + var lastAIdigit:int = + this.generalDecoder.extractNumericValueFromBitArray2(HEADER_SIZE + GTIN_SIZE, LAST_DIGIT_SIZE); + buf.Append("(392"); + buf.Append(lastAIdigit); + buf.Append(')'); + + var decodedInformation:DecodedInformation = + this.generalDecoder.decodeGeneralPurposeField(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE, null); + buf.Append(decodedInformation.getNewString()); + + return buf.toString(); + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01393xDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01393xDecoder.as new file mode 100644 index 000000000..ac1d60156 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01393xDecoder.as @@ -0,0 +1,78 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI01393xDecoder extends AI01decoder { + + private static var HEADER_SIZE:int = 5 + 1 + 2; + private static var LAST_DIGIT_SIZE:int = 2; + private static var FIRST_THREE_DIGITS_SIZE:int = 10; + + public function AI01393xDecoder(information:BitArray) { + super(information); + } + + public override function parseInformation():String { + if(this.information.Size < HEADER_SIZE + GTIN_SIZE) { + throw NotFoundException.getNotFoundInstance(); + } + + var buf:StringBuilder = new StringBuilder(); + + encodeCompressedGtin(buf, HEADER_SIZE); + + var lastAIdigit:int = + this.generalDecoder.extractNumericValueFromBitArray2(HEADER_SIZE + GTIN_SIZE, LAST_DIGIT_SIZE); + + buf.Append("(393"); + buf.Append(lastAIdigit); + buf.Append(')'); + + var firstThreeDigits:int = + this.generalDecoder.extractNumericValueFromBitArray2(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE, FIRST_THREE_DIGITS_SIZE); + if(int(firstThreeDigits / 100) == 0) { + buf.Append('0'); + } + if(int(firstThreeDigits / 10) == 0) { + buf.Append('0'); + } + buf.Append(firstThreeDigits); + + var generalInformation:DecodedInformation = + this.generalDecoder.decodeGeneralPurposeField(HEADER_SIZE + GTIN_SIZE + LAST_DIGIT_SIZE + FIRST_THREE_DIGITS_SIZE, null); + buf.Append(generalInformation.getNewString()); + + return buf.toString(); + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0x1xDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0x1xDecoder.as new file mode 100644 index 000000000..965f9a66c --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0x1xDecoder.as @@ -0,0 +1,108 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class AI013x0x1xDecoder extends AI01weightDecoder { + + private static var HEADER_SIZE:int = 7 + 1; + private static var WEIGHT_SIZE:int = 20; + private static var DATE_SIZE:int = 16; + + private var dateCode:String; + private var firstAIdigits:String; + + public function AI013x0x1xDecoder(information:BitArray, firstAIdigits:String, dateCode:String) { + super(information); + this.dateCode = dateCode; + this.firstAIdigits = firstAIdigits; + } + + public override function parseInformation():String { + if (this.information.Size != HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE + DATE_SIZE) { + throw NotFoundException.getNotFoundInstance(); + } + + var buf:StringBuilder = new StringBuilder(); + + encodeCompressedGtin(buf, HEADER_SIZE); + encodeCompressedWeight(buf, HEADER_SIZE + GTIN_SIZE, WEIGHT_SIZE); + encodeCompressedDate(buf, HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE); + + return buf.toString(); + } + + private function encodeCompressedDate(buf:StringBuilder, currentPos:int):void { + var numericDate:int = this.generalDecoder.extractNumericValueFromBitArray2(currentPos, DATE_SIZE); + if(numericDate == 38400) { + return; + } + + buf.Append('('); + buf.Append(this.dateCode); + buf.Append(')'); + + var day:int = numericDate % 32; + numericDate = int(numericDate / 32); + var month:int = numericDate % 12 + 1; + numericDate = int(numericDate / 12); + var year:int = numericDate; + + if (int(year / 10) == 0) { + buf.Append('0'); + } + buf.Append(year); + if (int(month / 10) == 0) { + buf.Append('0'); + } + buf.Append(month); + if (day / 10 == 0) { + buf.Append('0'); + } + buf.Append(day); + } + + protected override function addWeightCode(buf:StringBuilder, weight:int):void { + var lastAI:int = int(weight / 100000); + buf.Append('('); + buf.Append(this.firstAIdigits); + buf.Append(lastAI); + buf.Append(')'); + } + + protected override function checkWeight(weight:int):int { + return weight % 100000; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0xDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0xDecoder.as new file mode 100644 index 000000000..c700db722 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI013x0xDecoder.as @@ -0,0 +1,59 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI013x0xDecoder extends AI01weightDecoder { + + private static var HEADER_SIZE:int = 4 + 1; + private static var WEIGHT_SIZE:int = 15; + + public function AI013x0xDecoder(information:BitArray) { + super(information); + } + + public override function parseInformation():String { + if (this.information.Size != HEADER_SIZE + GTIN_SIZE + WEIGHT_SIZE) { + throw NotFoundException.getNotFoundInstance(); + } + + var buf:StringBuilder = new StringBuilder(); + + encodeCompressedGtin(buf, HEADER_SIZE); + encodeCompressedWeight(buf, HEADER_SIZE + GTIN_SIZE, WEIGHT_SIZE); + + return buf.toString(); + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01AndOtherAIs.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01AndOtherAIs.as new file mode 100644 index 000000000..963ea9e74 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01AndOtherAIs.as @@ -0,0 +1,59 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class AI01AndOtherAIs extends AI01decoder { + + private static var HEADER_SIZE:int = 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 + public function AI01AndOtherAIs(information:BitArray) { + super(information); + } + + public override function parseInformation():String { + var buff:StringBuilder = new StringBuilder(); + + buff.Append("(01)"); + var initialGtinPosition:int = buff.length; + var firstGtinDigit:int = this.generalDecoder.extractNumericValueFromBitArray2(HEADER_SIZE, 4); + buff.Append(firstGtinDigit); + + this.encodeCompressedGtinWithoutAI(buff, HEADER_SIZE + 4, initialGtinPosition); + + return this.generalDecoder.decodeAllCodes(buff, HEADER_SIZE + 44); + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01decoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01decoder.as new file mode 100644 index 000000000..72ff95e61 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01decoder.as @@ -0,0 +1,84 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class AI01decoder extends AbstractExpandedDecoder { + + protected static var GTIN_SIZE:int = 40; + + public function AI01decoder(information:BitArray) { + super(information); + } + + protected function encodeCompressedGtin(buf:StringBuilder, currentPos:int):void { + buf.Append("(01)"); + var initialPosition:int = buf.length; + buf.Append('9'); + + encodeCompressedGtinWithoutAI(buf, currentPos, initialPosition); + } + + protected function encodeCompressedGtinWithoutAI(buf:StringBuilder , currentPos:int, initialBufferPosition:int):void { + for(var i:int = 0; i < 4; ++i){ + var currentBlock:int = this.generalDecoder.extractNumericValueFromBitArray2(currentPos + 10 * i, 10); + if (int(currentBlock / 100) == 0) { + buf.Append('0'); + } + if (int(currentBlock / 10) == 0) { + buf.Append('0'); + } + buf.Append(currentBlock); + } + + appendCheckDigit(buf, initialBufferPosition); + } + + private static function appendCheckDigit(buf:StringBuilder, currentPos:int):void{ + var checkDigit:int = 0; + for (var i:int = 0; i < 13; i++) { + var digit:int = (buf.charAt(i + currentPos)).charCodeAt(0) - ('0' as String).charCodeAt(0); + checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; + } + + checkDigit = 10 - (checkDigit % 10); + if (checkDigit == 10) { + checkDigit = 0; + } + + buf.Append(checkDigit); + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01weightDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01weightDecoder.as new file mode 100644 index 000000000..541064f07 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AI01weightDecoder.as @@ -0,0 +1,61 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + */ +public class AI01weightDecoder extends AI01decoder { + + public function AI01weightDecoder(information:BitArray) { + super(information); + } + + protected function encodeCompressedWeight(buf:StringBuilder, currentPos:int, weightSize:int):void { + var originalWeightNumeric:int = this.generalDecoder.extractNumericValueFromBitArray2(currentPos, weightSize); + addWeightCode(buf, originalWeightNumeric); + + var weightNumeric:int = checkWeight(originalWeightNumeric); + + var currentDivisor:int = 100000; + for(var i:int = 0; i < 5; ++i){ + if (int(weightNumeric / currentDivisor) == 0) { + buf.Append('0'); + } + currentDivisor = int(currentDivisor / 10); + } + buf.Append(weightNumeric); + } + + protected function addWeightCode(buf:StringBuilder, weight:int):void{} + protected function checkWeight(weight:int):int{ return 0;} +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AbstractExpandedDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AbstractExpandedDecoder.as new file mode 100644 index 000000000..da8facf31 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AbstractExpandedDecoder.as @@ -0,0 +1,87 @@ +/* + * 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 class AbstractExpandedDecoder { + + protected var information:BitArray; + protected var generalDecoder:GeneralAppIdDecoder; + + public function AbstractExpandedDecoder(information:BitArray){ + this.information = information; + this.generalDecoder = new GeneralAppIdDecoder(information); + } + + public function parseInformation():String{ return '';} + + public static function createDecoder(information:BitArray):AbstractExpandedDecoder{ + if (information._get(1)) { + return new AI01AndOtherAIs(information); + } + if (!information._get(2)) { + return new AnyAIDecoder(information); + } + + var fourBitEncodationMethod:int = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 4); + + switch(fourBitEncodationMethod){ + case 4: return new AI013103decoder(information); + case 5: return new AI01320xDecoder(information); + } + + var fiveBitEncodationMethod:int = GeneralAppIdDecoder.extractNumericValueFromBitArray(information, 1, 5); + switch(fiveBitEncodationMethod){ + case 12: return new AI01392xDecoder(information); + case 13: return new AI01393xDecoder(information); + } + + var sevenBitEncodationMethod:int = 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 Error("unknown decoder: " + information); + } +} + + +} diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AnyAIDecoder.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AnyAIDecoder.as new file mode 100644 index 000000000..a9a735a33 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/AnyAIDecoder.as @@ -0,0 +1,51 @@ +/* + * 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; +import com.google.zxing.common.flexdatatypes.StringBuilder; + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class AnyAIDecoder extends AbstractExpandedDecoder { + + private static var HEADER_SIZE:int = 2 + 1 + 2; + + public function AnyAIDecoder(information:BitArray) { + super(information); + } + + public override function parseInformation():String { + var buf:StringBuilder = new StringBuilder(); + return this.generalDecoder.decodeAllCodes(buf, HEADER_SIZE); + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/BlockParsedResult.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/BlockParsedResult.as new file mode 100644 index 000000000..422dd112e --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/BlockParsedResult.as @@ -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 +{ + +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + * */ +public class BlockParsedResult { + protected var decodedInformation:DecodedInformation; + protected var finished:Boolean; +/* + public function BlockParsedResult(finished:Boolean) { + this(null, finished); + } +*/ + public function BlockParsedResult(information:DecodedInformation, finished:Boolean) { + this.finished = finished; + this.decodedInformation = information; + } + + public function getDecodedInformation():DecodedInformation { + return this.decodedInformation; + } + + public function isFinished():Boolean { + return this.finished; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/CurrentParsingState.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/CurrentParsingState.as new file mode 100644 index 000000000..71843e7a1 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/CurrentParsingState.as @@ -0,0 +1,71 @@ +/* + * 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) + */ +public class CurrentParsingState { + + public var position:int; + protected var encoding:int; + + public static var NUMERIC:int = 1; + public static var ALPHA:int = 2; + static public var ISO_IEC_646:int = 4; + + public function CurrentParsingState(){ + this.position = 0; + this.encoding = NUMERIC; + } + + public function isAlpha():Boolean{ + return this.encoding == ALPHA; + } + + public function isNumeric():Boolean{ + return this.encoding == NUMERIC; + } + + public function isIsoIec646():Boolean{ + return this.encoding == ISO_IEC_646; + } + + public function setNumeric():void{ + this.encoding = NUMERIC; + } + + public function setAlpha():void{ + this.encoding = ALPHA; + } + + public function setIsoIec646():void{ + this.encoding = ISO_IEC_646; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedChar.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedChar.as new file mode 100644 index 000000000..32629fc28 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedChar.as @@ -0,0 +1,53 @@ +/* + * 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) + */ +public class DecodedChar extends DecodedObject { + + protected var value:String; + + public static var FNC1:String = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset + + public function DecodedChar(newPosition:int, value:String) { + super(newPosition); + this.value = value; + } + + public function getValue():String{ + return this.value; + } + + public function isFNC1():Boolean{ + return this.value == FNC1; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedInformation.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedInformation.as new file mode 100644 index 000000000..f6b12f000 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedInformation.as @@ -0,0 +1,67 @@ +/* + * 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) + */ +public class DecodedInformation extends DecodedObject { + + protected var newString:String; + protected var remainingValue:int; + protected var remaining:Boolean; + + + public function DecodedInformation(newPosition:int,newString:String, remainingValue:int=0){ + super(newPosition); + this.remainingValue = remainingValue; + if (remainingValue != 0) + { + this.remaining = true; + } + else + { + this.remaining = false; + } + this.newString = newString; + } + + public function getNewString():String{ + return this.newString; + } + + public function isRemaining():Boolean{ + return this.remaining; + } + + public function getRemainingValue():int{ + return this.remainingValue; + } +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedNumeric.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedNumeric.as new file mode 100644 index 000000000..646a90f85 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedNumeric.as @@ -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.flexdatatypes.IllegalArgumentException; +/** + * @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) + * @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) + */ +public class DecodedNumeric extends DecodedObject { + protected var firstDigit:int; + protected var secondDigit:int; + + public static var FNC1:int = 10; + + public function DecodedNumeric(newPosition:int, firstDigit:int, secondDigit:int){ + 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); + } + } + + public function getFirstDigit():int{ + return this.firstDigit; + } + + public function getSecondDigit():int{ + return this.secondDigit; + } + + public function getValue():int{ + return this.firstDigit * 10 + this.secondDigit; + } + + public function isFirstDigitFNC1():Boolean{ + return this.firstDigit == FNC1; + } + + public function isSecondDigitFNC1():Boolean{ + return this.secondDigit == FNC1; + } + + public function isAnyFNC1():Boolean{ + return this.firstDigit == FNC1 || this.secondDigit == FNC1; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedObject.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedObject.as new file mode 100644 index 000000000..ab72d10c8 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/DecodedObject.as @@ -0,0 +1,45 @@ +/* + * 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) + */ +public class DecodedObject { + protected var newPosition:int; + + public function DecodedObject(newPosition:int):void{ + this.newPosition = newPosition; + } + + public function getNewPosition():int { + return this.newPosition; + } + +} +} \ No newline at end of file diff --git a/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/FieldParser.as b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/FieldParser.as new file mode 100644 index 000000000..36da50508 --- /dev/null +++ b/actionscript/core/src/com/google/zxing/oned/rss/expanded/decoders/FieldParser.as @@ -0,0 +1,304 @@ +/* + * 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) + */ +public class FieldParser { + + protected static var VARIABLE_LENGTH:Object = new Object(); + + private static var TWO_DIGIT_DATA_LENGTH:Array = [ + // "DIGITS", new Integer(LENGTH) + // or + // "DIGITS", VARIABLE_LENGTH, new Integer(MAX_SIZE) + + [ "00", new Array(18) ], + [ "01", new Array(14) ], + [ "02", new Array(14) ], + + [ "10", VARIABLE_LENGTH, new Array(20) ], + [ "11", new Array(6) ], + [ "12", new Array(6) ], + [ "13", new Array(6) ], + [ "15", new Array(6) ], + [ "17", new Array(6) ], + + [ "20", new Array(2) ], + [ "21", VARIABLE_LENGTH, new Array(20) ], + [ "22", VARIABLE_LENGTH, new Array(29) ], + + [ "30", VARIABLE_LENGTH, new Array( 8) ], + [ "37", VARIABLE_LENGTH, new Array( 8) ], + + //internal company codes + [ "90", VARIABLE_LENGTH, new Array(30) ], + [ "91", VARIABLE_LENGTH, new Array(30) ], + [ "92", VARIABLE_LENGTH, new Array(30) ], + [ "93", VARIABLE_LENGTH, new Array(30) ], + [ "94", VARIABLE_LENGTH, new Array(30) ], + [ "95", VARIABLE_LENGTH, new Array(30) ], + [ "96", VARIABLE_LENGTH, new Array(30) ], + [ "97", VARIABLE_LENGTH, new Array(30) ], + [ "98", VARIABLE_LENGTH, new Array(30) ], + [ "99", VARIABLE_LENGTH, new Array(30) ], + ]; + + private static var THREE_DIGIT_DATA_LENGTH:Array = [ + // Same format as above + + [ "240", VARIABLE_LENGTH, new Array(30) ], + [ "241", VARIABLE_LENGTH, new Array(30) ], + [ "242", VARIABLE_LENGTH, new Array( 6) ], + [ "250", VARIABLE_LENGTH, new Array(30) ], + [ "251", VARIABLE_LENGTH, new Array(30) ], + [ "253", VARIABLE_LENGTH, new Array(17) ], + [ "254", VARIABLE_LENGTH, new Array(20) ], + + [ "400", VARIABLE_LENGTH, new Array(30) ], + [ "401", VARIABLE_LENGTH, new Array(30) ], + [ "402", new Array(17) ], + [ "403", VARIABLE_LENGTH, new Array(30) ], + [ "410", new Array(13) ], + [ "411", new Array(13) ], + [ "412", new Array(13) ], + [ "413", new Array(13) ], + [ "414", new Array(13) ], + [ "420", VARIABLE_LENGTH, new Array(20) ], + [ "421", VARIABLE_LENGTH, new Array(15) ], + [ "422", new Array( 3) ], + [ "423", VARIABLE_LENGTH, new Array(15) ], + [ "424", new Array(3) ], + [ "425", new Array(3) ], + [ "426", new Array(3) ], + ]; + + private static var THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH:Array = [ + // Same format as above + + [ "310", new Array(6) ], + [ "311", new Array(6) ], + [ "312", new Array(6) ], + [ "313", new Array(6) ], + [ "314", new Array(6) ], + [ "315", new Array(6) ], + [ "316", new Array(6) ], + [ "320", new Array(6) ], + [ "321", new Array(6) ], + [ "322", new Array(6) ], + [ "323", new Array(6) ], + [ "324", new Array(6) ], + [ "325", new Array(6) ], + [ "326", new Array(6) ], + [ "327", new Array(6) ], + [ "328", new Array(6) ], + [ "329", new Array(6) ], + [ "330", new Array(6) ], + [ "331", new Array(6) ], + [ "332", new Array(6) ], + [ "333", new Array(6) ], + [ "334", new Array(6) ], + [ "335", new Array(6) ], + [ "336", new Array(6) ], + [ "340", new Array(6) ], + [ "341", new Array(6) ], + [ "342", new Array(6) ], + [ "343", new Array(6) ], + [ "344", new Array(6) ], + [ "345", new Array(6) ], + [ "346", new Array(6) ], + [ "347", new Array(6) ], + [ "348", new Array(6) ], + [ "349", new Array(6) ], + [ "350", new Array(6) ], + [ "351", new Array(6) ], + [ "352", new Array(6) ], + [ "353", new Array(6) ], + [ "354", new Array(6) ], + [ "355", new Array(6) ], + [ "356", new Array(6) ], + [ "357", new Array(6) ], + [ "360", new Array(6) ], + [ "361", new Array(6) ], + [ "362", new Array(6) ], + [ "363", new Array(6) ], + [ "364", new Array(6) ], + [ "365", new Array(6) ], + [ "366", new Array(6) ], + [ "367", new Array(6) ], + [ "368", new Array(6) ], + [ "369", new Array(6) ], + [ "390", VARIABLE_LENGTH, new Array(15) ], + [ "391", VARIABLE_LENGTH, new Array(18) ], + [ "392", VARIABLE_LENGTH, new Array(15) ], + [ "393", VARIABLE_LENGTH, new Array(18) ], + [ "703", VARIABLE_LENGTH, new Array(30) ] + ]; + + private static var FOUR_DIGIT_DATA_LENGTH:Array = [ + // Same format as above + + [ "7001", new Array(13) ], + [ "7002", VARIABLE_LENGTH, new Array(30) ], + [ "7003", new Array(10) ], + + [ "8001", new Array(14) ], + [ "8002", VARIABLE_LENGTH, new Array(20) ], + [ "8003", VARIABLE_LENGTH, new Array(30) ], + [ "8004", VARIABLE_LENGTH, new Array(30) ], + [ "8005", new Array(6) ], + [ "8006", new Array(18) ], + [ "8007", VARIABLE_LENGTH, new Array(30) ], + [ "8008", VARIABLE_LENGTH, new Array(12) ], + [ "8018", new Array(18) ], + [ "8020", VARIABLE_LENGTH, new Array(25) ], + [ "8100", new Array(6) ], + [ "8101", new Array(10) ], + [ "8102", new Array(2) ], + [ "8110", VARIABLE_LENGTH, new Array(30) ], + ]; + + public function FieldParser() { + } + + public static function parseFieldsInGeneralPurpose(rawInformation:String):String{ + if(rawInformation.length == 0) { + return null; + } + + // Processing 2-digit AIs + + if(rawInformation.length < 2) + { + throw NotFoundException.getNotFoundInstance(); + } + + var firstTwoDigits:String = rawInformation.substring(0, 2); + for (var i:int=0; i this.information.Size){ + return pos + 4 <= this.information.Size; + } + + for(var i:int = pos; i < pos + 3; ++i) { + if (this.information._get(i)) { + return true; + } + } + + return this.information._get(pos + 3); + } + + private function decodeNumeric(pos:int):DecodedNumeric { + if(pos + 7 > this.information.Size){ + var numeric:int = extractNumericValueFromBitArray2(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); + } + numeric = extractNumericValueFromBitArray2(pos, 7); + + var digit1:int = int((numeric - 8) / 11); + var digit2:int = (numeric - 8) % 11; + + return new DecodedNumeric(pos + 7, digit1, digit2); + } + + public function extractNumericValueFromBitArray2(pos:int, bits:int):int{ + return extractNumericValueFromBitArray(this.information, pos, bits); + } + + public static function extractNumericValueFromBitArray(information:BitArray, pos:int, bits:int):int { + + if(bits > 32) { + throw new IllegalArgumentException("extractNumberValueFromBitArray can't handle more than 32 bits"); + } + + var value:int = 0; + for(var i:int = 0; i < bits; ++i) { + if (information._get(pos + i)) { + value |= (1 << (bits - i - 1)); + } + } + + return value; + } + + public function decodeGeneralPurposeField(pos:int, remaining:String):DecodedInformation { + this.buffer.setLength(0); + + if(remaining != null) { + this.buffer.Append(remaining); + } + + this.current.position = pos; + + var lastDecoded:DecodedInformation = 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 function parseBlocks():DecodedInformation { + var isFinished:Boolean; + var result:BlockParsedResult; + do{ + var initialPosition:int = 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(); + } + + var positionChanged:Boolean = initialPosition != current.position; + if(!positionChanged && !isFinished) { + break; + } + } while (!isFinished); + + return result.getDecodedInformation(); + } + + private function parseNumericBlock():BlockParsedResult { + while(isStillNumeric(current.position)){ + var numeric:DecodedNumeric = decodeNumeric(current.position); + current.position = numeric.getNewPosition(); + + if(numeric.isFirstDigitFNC1()){ + var information:DecodedInformation; + 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(String.fromCharCode(48+numeric.getFirstDigit())); + + if(numeric.isSecondDigitFNC1()){ + information = new DecodedInformation(current.position, buffer.toString()); + return new BlockParsedResult(information, true); + } + buffer.Append(String.fromCharCode(48+numeric.getSecondDigit())); + } + + if(isNumericToAlphaNumericLatch(current.position)){ + current.setAlpha(); + current.position += 4; + } + return new BlockParsedResult(null,false); + } + + private function parseIsoIec646Block():BlockParsedResult { + while (isStillIsoIec646(current.position)) { + var iso:DecodedChar = decodeIsoIec646(current.position); + current.position = iso.getNewPosition(); + + if (iso.isFNC1()) { + var information:DecodedInformation = 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(null,false); + } + + private function parseAlphaBlock():BlockParsedResult { + while (isStillAlpha(current.position)) { + var alpha:DecodedChar = decodeAlphanumeric(current.position); + current.position = alpha.getNewPosition(); + + if(alpha.isFNC1()) { + var information:DecodedInformation = 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(null,false); + } + + private function isStillIsoIec646(pos:int):Boolean + { + if(pos + 5 > this.information.Size) { + return false; + } + + var fiveBitValue:int = extractNumericValueFromBitArray2(pos, 5); + if(fiveBitValue >= 5 && fiveBitValue < 16) { + return true; + } + + if(pos + 7 > this.information.Size) { + return false; + } + + var sevenBitValue:int = extractNumericValueFromBitArray2(pos, 7); + if(sevenBitValue >= 64 && sevenBitValue < 116) { + return true; + } + + if(pos + 8 > this.information.Size) { + return false; + } + + var eightBitValue:int = extractNumericValueFromBitArray2(pos, 8); + return eightBitValue >= 232 && eightBitValue < 253; + + } + + private function decodeIsoIec646(pos:int):DecodedChar { + var fiveBitValue:int = extractNumericValueFromBitArray2(pos, 5); + if(fiveBitValue == 15) { + return new DecodedChar(pos + 5, DecodedChar.FNC1); + } + + if(fiveBitValue >= 5 && fiveBitValue < 15) { + return new DecodedChar(pos + 5, String.fromCharCode((48 + fiveBitValue - 5) as int)); + } + + var sevenBitValue:int = extractNumericValueFromBitArray2(pos, 7); + + if(sevenBitValue >= 64 && sevenBitValue < 90) { + return new DecodedChar(pos + 7, (sevenBitValue + 1).toString()); + } + + if(sevenBitValue >= 90 && sevenBitValue < 116) { + return new DecodedChar(pos + 7, String.fromCharCode(sevenBitValue + 7)); + } + + var eightBitValue:int = extractNumericValueFromBitArray2(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 Error("Decoding invalid ISO/IEC 646 value: " + eightBitValue); + } + + private function isStillAlpha(pos:int):Boolean { + if(pos + 5 > this.information.Size) { + return false; + } + + // We now check if it's a valid 5-bit value (0..9 and FNC1) + var fiveBitValue:int = extractNumericValueFromBitArray2(pos, 5); + if(fiveBitValue >= 5 && fiveBitValue < 16) { + return true; + } + + if(pos + 6 > this.information.Size) { + return false; + } + + var sixBitValue:int = extractNumericValueFromBitArray2(pos, 6); + return sixBitValue >= 16 && sixBitValue < 63; // 63 not included + } + + private function decodeAlphanumeric(pos:int):DecodedChar { + var fiveBitValue:int = extractNumericValueFromBitArray2(pos, 5); + if(fiveBitValue == 15) { + return new DecodedChar(pos + 5, DecodedChar.FNC1); + } + + if(fiveBitValue >= 5 && fiveBitValue < 15) { + return new DecodedChar(pos + 5, String.fromCharCode((('0' as String).charCodeAt(0) + fiveBitValue - 5)as int)); + } + + var sixBitValue:int = extractNumericValueFromBitArray2(pos, 6); + + if(sixBitValue >= 32 && sixBitValue < 58) { + return new DecodedChar(pos + 6, String.fromCharCode(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 Error("Decoding invalid alphanumeric value: " + sixBitValue); + } + + private function isAlphaTo646ToAlphaLatch(pos:int):Boolean { + if(pos + 1 > this.information.Size) { + return false; + } + + for(var i:int = 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 function isAlphaOr646ToNumericLatch(pos:int):Boolean { + // Next is alphanumeric if there are 3 positions and they are all zeros + if (pos + 3 > this.information.Size) { + return false; + } + + for (var i:int = pos; i < pos + 3; ++i) { + if (this.information._get(i)) { + return false; + } + } + return true; + } + + private function isNumericToAlphaNumericLatch(pos:int):Boolean { + // 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 (var i:int = 0; i < 4 && i + pos < this.information.Size; ++i) { + if (this.information._get(pos + i)) { + return false; + } + } + return true; + } +} +} \ No newline at end of file