You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * Copyright 2012 ZXing authors
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "ZXBarcodeFormat.h"
  17. #import "ZXBitArray.h"
  18. #import "ZXErrors.h"
  19. #import "ZXIntArray.h"
  20. #import "ZXResult.h"
  21. #import "ZXResultMetadataType.h"
  22. #import "ZXResultPoint.h"
  23. #import "ZXUPCEANExtension2Support.h"
  24. #import "ZXUPCEANReader.h"
  25. @interface ZXUPCEANExtension2Support ()
  26. @property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters;
  27. @end
  28. @implementation ZXUPCEANExtension2Support
  29. - (id)init {
  30. if (self = [super init]) {
  31. _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4];
  32. }
  33. return self;
  34. }
  35. - (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row extensionStartRange:(NSRange)extensionStartRange error:(NSError **)error {
  36. NSMutableString *resultString = [NSMutableString string];
  37. int end = [self decodeMiddle:row startRange:extensionStartRange result:resultString error:error];
  38. if (end == -1) {
  39. return nil;
  40. }
  41. NSMutableDictionary *extensionData = [self parseExtensionString:resultString];
  42. ZXResult *extensionResult = [[ZXResult alloc] initWithText:resultString
  43. rawBytes:nil
  44. resultPoints:@[[[ZXResultPoint alloc] initWithX:(extensionStartRange.location + NSMaxRange(extensionStartRange)) / 2.0f y:rowNumber],
  45. [[ZXResultPoint alloc] initWithX:end y:rowNumber]]
  46. format:kBarcodeFormatUPCEANExtension];
  47. if (extensionData != nil) {
  48. [extensionResult putAllMetadata:extensionData];
  49. }
  50. return extensionResult;
  51. }
  52. - (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error {
  53. ZXIntArray *counters = self.decodeMiddleCounters;
  54. [counters clear];
  55. int end = [row size];
  56. int rowOffset = (int)NSMaxRange(startRange);
  57. int checkParity = 0;
  58. for (int x = 0; x < 2 && rowOffset < end; x++) {
  59. int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error];
  60. if (bestMatch == -1) {
  61. return -1;
  62. }
  63. [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)];
  64. rowOffset += [counters sum];
  65. if (bestMatch >= 10) {
  66. checkParity |= 1 << (1 - x);
  67. }
  68. if (x != 1) {
  69. // Read off separator if not last
  70. rowOffset = [row nextSet:rowOffset];
  71. rowOffset = [row nextUnset:rowOffset];
  72. }
  73. }
  74. if (result.length != 2) {
  75. if (error) *error = ZXNotFoundErrorInstance();
  76. return -1;
  77. }
  78. if ([result intValue] % 4 != checkParity) {
  79. if (error) *error = ZXNotFoundErrorInstance();
  80. return -1;
  81. }
  82. return rowOffset;
  83. }
  84. /**
  85. * @param raw raw content of extension
  86. * @return formatted interpretation of raw content as a NSDictionary mapping
  87. * one ZXResultMetadataType to appropriate value, or nil if not known
  88. */
  89. - (NSMutableDictionary *)parseExtensionString:(NSString *)raw {
  90. if (raw.length != 2) {
  91. return nil;
  92. }
  93. return [NSMutableDictionary dictionaryWithObject:@([raw intValue])
  94. forKey:@(kResultMetadataTypeIssueNumber)];
  95. }
  96. @end