| /* |
| * Copyright 2012 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. |
| */ |
| |
| #import "ZXBitArray.h" |
| #import "ZXEAN13Reader.h" |
| #import "ZXErrors.h" |
| |
| // For an EAN-13 barcode, the first digit is represented by the parities used |
| // to encode the next six digits, according to the table below. For example, |
| // if the barcode is 5 123456 789012 then the value of the first digit is |
| // signified by using odd for '1', even for '2', even for '3', odd for '4', |
| // odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13 |
| // |
| // Parity of next 6 digits |
| // Digit 0 1 2 3 4 5 |
| // 0 Odd Odd Odd Odd Odd Odd |
| // 1 Odd Odd Even Odd Even Even |
| // 2 Odd Odd Even Even Odd Even |
| // 3 Odd Odd Even Even Even Odd |
| // 4 Odd Even Odd Odd Even Even |
| // 5 Odd Even Even Odd Odd Even |
| // 6 Odd Even Even Even Odd Odd |
| // 7 Odd Even Odd Even Odd Even |
| // 8 Odd Even Odd Even Even Odd |
| // 9 Odd Even Even Odd Even Odd |
| // |
| // Note that the encoding for '0' uses the same parity as a UPC barcode. Hence |
| // a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. |
| // |
| // The encoding is represented by the following array, which is a bit pattern |
| // using Odd = 0 and Even = 1. For example, 5 is represented by: |
| // |
| // Odd Even Even Odd Odd Even |
| // in binary: |
| // 0 1 1 0 0 1 == 0x19 |
| // |
| int FIRST_DIGIT_ENCODINGS[10] = { |
| 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A |
| }; |
| |
| @interface ZXEAN13Reader () |
| |
| @property (nonatomic, assign) int *decodeMiddleCounters; |
| |
| @end |
| |
| @implementation ZXEAN13Reader |
| |
| - (id)init { |
| if (self = [super init]) { |
| _decodeMiddleCounters = (int *)malloc(sizeof(4) * sizeof(int)); |
| _decodeMiddleCounters[0] = 0; |
| _decodeMiddleCounters[1] = 0; |
| _decodeMiddleCounters[2] = 0; |
| _decodeMiddleCounters[3] = 0; |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| if (_decodeMiddleCounters != NULL) { |
| free(_decodeMiddleCounters); |
| _decodeMiddleCounters = NULL; |
| } |
| } |
| |
| - (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { |
| int *counters = self.decodeMiddleCounters; |
| counters[0] = 0; |
| counters[1] = 0; |
| counters[2] = 0; |
| counters[3] = 0; |
| const int countersLen = 4; |
| int end = row.size; |
| int rowOffset = (int)NSMaxRange(startRange); |
| |
| int lgPatternFound = 0; |
| |
| for (int x = 0; x < 6 && rowOffset < end; x++) { |
| int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters countersLen:countersLen rowOffset:rowOffset patternType:UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error]; |
| if (bestMatch == -1) { |
| return -1; |
| } |
| [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)]; |
| for (int i = 0; i < countersLen; i++) { |
| rowOffset += counters[i]; |
| } |
| if (bestMatch >= 10) { |
| lgPatternFound |= 1 << (5 - x); |
| } |
| } |
| |
| if (![self determineFirstDigit:result lgPatternFound:lgPatternFound]) { |
| if (error) *error = NotFoundErrorInstance(); |
| return -1; |
| } |
| |
| NSRange middleRange = [[self class] findGuardPattern:row rowOffset:rowOffset whiteFirst:YES pattern:(int *)MIDDLE_PATTERN patternLen:MIDDLE_PATTERN_LEN error:error]; |
| if (middleRange.location == NSNotFound) { |
| return -1; |
| } |
| rowOffset = (int)NSMaxRange(middleRange); |
| |
| for (int x = 0; x < 6 && rowOffset < end; x++) { |
| int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters countersLen:countersLen rowOffset:rowOffset patternType:UPC_EAN_PATTERNS_L_PATTERNS error:error]; |
| if (bestMatch == -1) { |
| return -1; |
| } |
| [result appendFormat:@"%C", (unichar)('0' + bestMatch)]; |
| for (int i = 0; i < countersLen; i++) { |
| rowOffset += counters[i]; |
| } |
| } |
| |
| return rowOffset; |
| } |
| |
| - (ZXBarcodeFormat)barcodeFormat { |
| return kBarcodeFormatEan13; |
| } |
| |
| /** |
| * Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded |
| * digits in a barcode, determines the implicitly encoded first digit and adds it to the |
| * result string. |
| */ |
| - (BOOL)determineFirstDigit:(NSMutableString *)resultString lgPatternFound:(int)lgPatternFound { |
| for (int d = 0; d < 10; d++) { |
| if (lgPatternFound == FIRST_DIGIT_ENCODINGS[d]) { |
| [resultString insertString:[NSString stringWithFormat:@"%C", (unichar)('0' + d)] atIndex:0]; |
| return YES; |
| } |
| } |
| return NO; |
| } |
| |
| @end |