/*
|
* 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 "ZXCodaBarReader.h"
|
#import "ZXCodaBarWriter.h"
|
|
const unichar ZX_CODA_START_END_CHARS[] = {'A', 'B', 'C', 'D'};
|
const unichar ZX_CODA_ALT_START_END_CHARS[] = {'T', 'N', '*', 'E'};
|
const unichar ZX_CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED[] = {'/', ':', '+', '.'};
|
static unichar ZX_CODA_DEFAULT_GUARD;
|
|
@implementation ZXCodaBarWriter
|
|
+ (void)initialize {
|
if ([self class] != [ZXCodaBarWriter class]) return;
|
|
ZX_CODA_DEFAULT_GUARD = ZX_CODA_START_END_CHARS[0];
|
}
|
|
- (ZXBoolArray *)encode:(NSString *)contents {
|
if ([contents length] < 2) {
|
// Can't have a start/end guard, so tentatively add default guards
|
contents = [NSString stringWithFormat:@"%C%@%C", ZX_CODA_DEFAULT_GUARD, contents, ZX_CODA_DEFAULT_GUARD];
|
} else {
|
// Verify input and calculate decoded length.
|
unichar firstChar = [[contents uppercaseString] characterAtIndex:0];
|
unichar lastChar = [[contents uppercaseString] characterAtIndex:contents.length - 1];
|
BOOL startsNormal = [ZXCodaBarReader arrayContains:ZX_CODA_START_END_CHARS length:sizeof(ZX_CODA_START_END_CHARS) / sizeof(unichar) key:firstChar];
|
BOOL endsNormal = [ZXCodaBarReader arrayContains:ZX_CODA_START_END_CHARS length:sizeof(ZX_CODA_START_END_CHARS) / sizeof(unichar) key:lastChar];
|
BOOL startsAlt = [ZXCodaBarReader arrayContains:ZX_CODA_ALT_START_END_CHARS length:sizeof(ZX_CODA_ALT_START_END_CHARS) / sizeof(unichar) key:firstChar];
|
BOOL endsAlt = [ZXCodaBarReader arrayContains:ZX_CODA_ALT_START_END_CHARS length:sizeof(ZX_CODA_ALT_START_END_CHARS) / sizeof(unichar) key:lastChar];
|
if (startsNormal) {
|
if (!endsNormal) {
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents]
|
userInfo:nil];
|
}
|
// else already has valid start/end
|
} else if (startsAlt) {
|
if (!endsAlt) {
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents]
|
userInfo:nil];
|
}
|
// else already has valid start/end
|
} else {
|
// Doesn't start with a guard
|
if (endsNormal || endsAlt) {
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents]
|
userInfo:nil];
|
}
|
// else doesn't end with guard either, so add a default
|
contents = [NSString stringWithFormat:@"%C%@%C", ZX_CODA_DEFAULT_GUARD, contents, ZX_CODA_DEFAULT_GUARD];
|
}
|
}
|
|
// The start character and the end character are decoded to 10 length each.
|
int resultLength = 20;
|
for (int i = 1; i < contents.length - 1; i++) {
|
if (([contents characterAtIndex:i] >= '0' && [contents characterAtIndex:i] <= '9') ||
|
[contents characterAtIndex:i] == '-' || [contents characterAtIndex:i] == '$') {
|
resultLength += 9;
|
} else if ([ZXCodaBarReader arrayContains:ZX_CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED length:4 key:[contents characterAtIndex:i]]) {
|
resultLength += 10;
|
} else {
|
@throw [NSException exceptionWithName:NSInvalidArgumentException
|
reason:[NSString stringWithFormat:@"Cannot encode : '%C'", [contents characterAtIndex:i]]
|
userInfo:nil];
|
}
|
}
|
// A blank is placed between each character.
|
resultLength += contents.length - 1;
|
|
ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:resultLength];
|
int position = 0;
|
for (int index = 0; index < contents.length; index++) {
|
unichar c = [[contents uppercaseString] characterAtIndex:index];
|
if (index == 0 || index == contents.length - 1) {
|
// The start/end chars are not in the CodaBarReader.ALPHABET.
|
switch (c) {
|
case 'T':
|
c = 'A';
|
break;
|
case 'N':
|
c = 'B';
|
break;
|
case '*':
|
c = 'C';
|
break;
|
case 'E':
|
c = 'D';
|
break;
|
}
|
}
|
int code = 0;
|
for (int i = 0; i < ZX_CODA_ALPHABET_LEN; i++) {
|
// Found any, because I checked above.
|
if (c == ZX_CODA_ALPHABET[i]) {
|
code = ZX_CODA_CHARACTER_ENCODINGS[i];
|
break;
|
}
|
}
|
BOOL color = YES;
|
int counter = 0;
|
int bit = 0;
|
while (bit < 7) { // A character consists of 7 digit.
|
result.array[position] = color;
|
position++;
|
if (((code >> (6 - bit)) & 1) == 0 || counter == 1) {
|
color = !color; // Flip the color.
|
bit++;
|
counter = 0;
|
} else {
|
counter++;
|
}
|
}
|
if (index < contents.length - 1) {
|
result.array[position] = NO;
|
position++;
|
}
|
}
|
return result;
|
}
|
|
@end
|