blob: 48027717be5d32d310c6f6366a09fcdfd0f02b20 [file] [log] [blame]
/*
* Copyright 2013 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 "ZXEdifactEncoder.h"
#import "ZXEncoderContext.h"
#import "ZXHighLevelEncoder.h"
#import "ZXSymbolInfo.h"
@implementation ZXEdifactEncoder
- (int)encodingMode {
return [ZXHighLevelEncoder edifactEncodation];
}
- (void)encode:(ZXEncoderContext *)context {
//step F
NSMutableString *buffer = [NSMutableString string];
while ([context hasMoreCharacters]) {
unichar c = [context currentChar];
[self encodeChar:c buffer:buffer];
context.pos++;
NSUInteger count = buffer.length;
if (count >= 4) {
[context writeCodewords:[self encodeToCodewords:buffer startpos:0]];
[buffer deleteCharactersInRange:NSMakeRange(0, 4)];
int newMode = [ZXHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]];
if (newMode != [self encodingMode]) {
[context signalEncoderChange:[ZXHighLevelEncoder asciiEncodation]];
break;
}
}
}
[buffer appendFormat:@"%C", (unichar) 31]; //Unlatch
[self handleEOD:context buffer:buffer];
}
/**
* Handle "end of data" situations
*/
- (void)handleEOD:(ZXEncoderContext *)context buffer:(NSMutableString *)buffer {
@try {
NSUInteger count = buffer.length;
if (count == 0) {
return; //Already finished
}
if (count == 1) {
//Only an unlatch at the end
[context updateSymbolInfo];
int available = context.symbolInfo.dataCapacity - context.codewordCount;
int remaining = [context remainingCharacters];
if (remaining == 0 && available <= 2) {
return; //No unlatch
}
}
if (count > 4) {
@throw [NSException exceptionWithName:@"IllegalStateException"
reason:@"Count must not exceed 4"
userInfo:nil];
}
int restChars = (int)count - 1;
NSString *encoded = [self encodeToCodewords:buffer startpos:0];
BOOL endOfSymbolReached = ![context hasMoreCharacters];
BOOL restInAscii = endOfSymbolReached && restChars <= 2;
if (restChars <= 2) {
[context updateSymbolInfoWithLength:context.codewordCount + restChars];
int available = context.symbolInfo.dataCapacity - context.codewordCount;
if (available >= 3) {
restInAscii = NO;
[context updateSymbolInfoWithLength:context.codewordCount + (int)encoded.length];
//available = context.symbolInfo.dataCapacity - context.codewordCount;
}
}
if (restInAscii) {
[context resetSymbolInfo];
context.pos -= restChars;
} else {
[context writeCodewords:encoded];
}
} @finally {
[context signalEncoderChange:[ZXHighLevelEncoder asciiEncodation]];
}
}
- (void)encodeChar:(unichar)c buffer:(NSMutableString *)sb {
if (c >= ' ' && c <= '?') {
[sb appendFormat:@"%C", c];
} else if (c >= '@' && c <= '^') {
[sb appendFormat:@"%C", (unichar) (c - 64)];
} else {
[ZXHighLevelEncoder illegalCharacter:c];
}
}
- (NSString *)encodeToCodewords:(NSMutableString *)sb startpos:(int)startPos {
int len = (int)sb.length - startPos;
if (len == 0) {
@throw [NSException exceptionWithName:@"IllegalStateException"
reason:@"Buffer must not be empty"
userInfo:nil];
}
unichar c1 = [sb characterAtIndex:startPos];
unichar c2 = len >= 2 ? [sb characterAtIndex:startPos + 1] : 0;
unichar c3 = len >= 3 ? [sb characterAtIndex:startPos + 2] : 0;
unichar c4 = len >= 4 ? [sb characterAtIndex:startPos + 3] : 0;
int v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4;
unichar cw1 = (unichar) ((v >> 16) & 255);
unichar cw2 = (unichar) ((v >> 8) & 255);
unichar cw3 = (unichar) (v & 255);
NSMutableString *res = [NSMutableString stringWithCapacity:3];
[res appendFormat:@"%C", cw1];
if (len >= 2) {
[res appendFormat:@"%C", cw2];
}
if (len >= 3) {
[res appendFormat:@"%C", cw3];
}
return [NSString stringWithString:res];
}
@end