JLChen
2021-11-04 1443556e9ccb1a19ed8e6710c16c8adc4d4f4fb3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * 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 "ZXBoolArray.h"
#import "ZXCode128Reader.h"
#import "ZXCode128Writer.h"
 
// Dummy characters used to specify control characters in input
const unichar ZX_CODE128_ESCAPE_FNC_1 = L'\u00f1';
const unichar ZX_CODE128_ESCAPE_FNC_2 = L'\u00f2';
const unichar ZX_CODE128_ESCAPE_FNC_3 = L'\u00f3';
const unichar ZX_CODE128_ESCAPE_FNC_4 = L'\u00f4';
 
@implementation ZXCode128Writer
 
- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error {
  if (format != kBarcodeFormatCode128) {
    [NSException raise:NSInvalidArgumentException format:@"Can only encode CODE_128"];
  }
  return [super encode:contents format:format width:width height:height hints:hints error:error];
}
 
- (ZXBoolArray *)encode:(NSString *)contents {
  int length = (int)[contents length];
  // Check length
  if (length < 1 || length > 80) {
    [NSException raise:NSInvalidArgumentException format:@"Contents length should be between 1 and 80 characters, but got %d", length];
  }
  // Check content
  for (int i = 0; i < length; i++) {
    unichar c = [contents characterAtIndex:i];
    if (c < ' ' || c > '~') {
      switch (c) {
        case ZX_CODE128_ESCAPE_FNC_1:
        case ZX_CODE128_ESCAPE_FNC_2:
        case ZX_CODE128_ESCAPE_FNC_3:
        case ZX_CODE128_ESCAPE_FNC_4:
          break;
        default:
          [NSException raise:NSInvalidArgumentException format:@"Bad character in input: %C", c];
      }
    }
  }
 
  NSMutableArray *patterns = [NSMutableArray array]; // temporary storage for patterns
  int checkSum = 0;
  int checkWeight = 1;
  int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
  int position = 0; // position in contents
 
  while (position < length) {
    //Select code to use
    int requiredDigitCount = codeSet == ZX_CODE128_CODE_CODE_C ? 2 : 4;
    int newCodeSet;
    if ([self isDigits:contents start:position length:requiredDigitCount]) {
      newCodeSet = ZX_CODE128_CODE_CODE_C;
    } else {
      newCodeSet = ZX_CODE128_CODE_CODE_B;
    }
 
    //Get the pattern index
    int patternIndex;
    if (newCodeSet == codeSet) {
      // Encode the current character
      // First handle escapes
      switch ([contents characterAtIndex:position]) {
        case ZX_CODE128_ESCAPE_FNC_1:
          patternIndex = ZX_CODE128_CODE_FNC_1;
          break;
        case ZX_CODE128_ESCAPE_FNC_2:
          patternIndex = ZX_CODE128_CODE_FNC_2;
          break;
        case ZX_CODE128_ESCAPE_FNC_3:
          patternIndex = ZX_CODE128_CODE_FNC_3;
          break;
        case ZX_CODE128_ESCAPE_FNC_4:
          patternIndex = ZX_CODE128_CODE_FNC_4_B; // FIXME if this ever outputs Code A
          break;
        default:
          // Then handle normal characters otherwise
          if (codeSet == ZX_CODE128_CODE_CODE_B) {
            patternIndex = [contents characterAtIndex:position] - ' ';
          } else { // CODE_CODE_C
            patternIndex = [[contents substringWithRange:NSMakeRange(position, 2)] intValue];
            position++; // Also incremented below
          }
      }
      position++;
    } else {
      // Should we change the current code?
      // Do we have a code set?
      if (codeSet == 0) {
        // No, we don't have a code set
        if (newCodeSet == ZX_CODE128_CODE_CODE_B) {
          patternIndex = ZX_CODE128_CODE_START_B;
        } else {
          // CODE_CODE_C
          patternIndex = ZX_CODE128_CODE_START_C;
        }
      } else {
        // Yes, we have a code set
        patternIndex = newCodeSet;
      }
      codeSet = newCodeSet;
    }
 
    // Get the pattern
    NSMutableArray *pattern = [NSMutableArray array];
    for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[patternIndex]) / sizeof(int); i++) {
      [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[patternIndex][i])];
    }
    [patterns addObject:pattern];
 
    // Compute checksum
    checkSum += patternIndex * checkWeight;
    if (position != 0) {
      checkWeight++;
    }
  }
 
  // Compute and append checksum
  checkSum %= 103;
  NSMutableArray *pattern = [NSMutableArray array];
  for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[checkSum]) / sizeof(int); i++) {
    [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[checkSum][i])];
  }
  [patterns addObject:pattern];
 
  // Append stop code
  pattern = [NSMutableArray array];
  for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP]) / sizeof(int); i++) {
    [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP][i])];
  }
  [patterns addObject:pattern];
 
  // Compute code width
  int codeWidth = 0;
  for (pattern in patterns) {
    for (int i = 0; i < pattern.count; i++) {
      codeWidth += [pattern[i] intValue];
    }
  }
 
  // Compute result
  ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:codeWidth];
  int pos = 0;
  for (NSArray *patternArray in patterns) {
    int patternLen = (int)[patternArray count];
    int pattern[patternLen];
    for (int i = 0; i < patternLen; i++) {
      pattern[i] = [patternArray[i] intValue];
    }
 
    pos += [self appendPattern:result pos:pos pattern:pattern patternLen:patternLen startColor:YES];
  }
 
  return result;
}
 
- (BOOL)isDigits:(NSString *)value start:(int)start length:(unsigned int)length {
  int end = start + length;
  int last = (int)[value length];
  for (int i = start; i < end && i < last; i++) {
    unichar c = [value characterAtIndex:i];
    if (c < '0' || c > '9') {
      if (c != ZX_CODE128_ESCAPE_FNC_1) {
        return NO;
      }
      end++; // ignore FNC_1
    }
  }
  return end <= last; // end > last if we've run out of string
}
 
@end