Skip to content

Instantly share code, notes, and snippets.

@johanhar
Last active November 13, 2017 07:33
Show Gist options
  • Save johanhar/a421a14bef2f06ee2340 to your computer and use it in GitHub Desktop.
Save johanhar/a421a14bef2f06ee2340 to your computer and use it in GitHub Desktop.
uic-918-3 aztec barcode decoding ios objective-c
// add this method to ZXAztecDecoder.m (ZXingObjC)
+ (NSString *)UIC9183TicketId:(ZXBoolArray *)correctedBits
{
NSMutableData *bytes = [[NSMutableData alloc] init];
int endIndex = (int)correctedBits.length;
ZXAztecTable latchTable = ZXAztecTableUpper; // table most recently latched to
ZXAztecTable shiftTable = ZXAztecTableUpper; // table to use for the next read
int index = 0;
int byteIndex = 0;
while (index < endIndex) {
if (shiftTable == ZXAztecTableBinary) {
if (endIndex - index < 5) {
break;
}
int length = [self readCode:correctedBits startIndex:index length:5];
index += 5;
if (length == 0) {
if (endIndex - index < 11) {
break;
}
length = [self readCode:correctedBits startIndex:index length:11] + 31;
index += 11;
}
for (int charCount = 0; charCount < length; charCount++) {
if (endIndex - index < 8) {
index = endIndex; // Force outer loop to exit
break;
}
int code = [self readCode:correctedBits startIndex:index length:8];
// deflated content starts from byte 68 according to UIC-918-3
if (byteIndex >= 68) {
unsigned char compressedBytes[1];
compressedBytes[0] = (unsigned char)code;
[bytes appendBytes:compressedBytes length:1];
}
index += 8;
byteIndex++;
}
// Go back to whatever mode we had been in
shiftTable = latchTable;
} else {
int size = shiftTable == ZXAztecTableDigit ? 4 : 5;
if (endIndex - index < size) {
break;
}
int code = [self readCode:correctedBits startIndex:index length:size];
index += size;
NSString *str = [self character:shiftTable code:code];
if ([str hasPrefix:@"CTRL_"]) {
// Table changes
shiftTable = [self table:[str characterAtIndex:5]];
if ([str characterAtIndex:6] == 'L') {
latchTable = shiftTable;
}
} else {
byteIndex++;
// Go back to whatever mode we had been in
shiftTable = latchTable;
}
}
}
NSData *inflated1 = [[bytes copy] inflateWithMissingHeader:YES];
NSData *inflated2 = [[bytes copy] inflateWithMissingHeader:NO];
NSString *inflatedString;
NSMutableString *ticketID = [[NSMutableString alloc] init];
if (inflated1.length > 0) {
inflatedString = [[NSString alloc] initWithData:inflated1 encoding:NSUTF8StringEncoding];
} else if (inflated2.length > 0) {
inflatedString = [[NSString alloc] initWithData:inflated2 encoding:NSUTF8StringEncoding];
}
// we find the UIC-918-3 ticket id in the inflated content from 16 to 35
// it will always be 20 bytes long, so we need to eliminate null-characters and whatnot
if (inflatedString.length > 36) {
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\w+"
options:0
error:nil];
NSRange textRange = NSMakeRange(16, 20);
NSRange matchRange = [regex rangeOfFirstMatchInString:inflatedString
options:NSMatchingReportProgress
range:textRange];
if (matchRange.location != NSNotFound) {
[ticketID appendString:[inflatedString substringWithRange:matchRange]];
}
}
return [ticketID copy];
}
// inflating (NSData category)
- (NSData *)inflateWithMissingHeader:(BOOL)missingHeader
{
if ([self length] == 0) return self;
NSInteger full_length = [self length];
NSInteger half_length = [self length] / 2;
NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
BOOL done = NO;
int status;
z_stream strm;
strm.next_in = (Bytef *)[self bytes];
strm.avail_in = (unsigned int)[self length];
strm.total_out = 0;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
if (missingHeader) {
if (inflateInit2(&strm, -15) != Z_OK) return nil;
} else {
if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
}
while (!done)
{
// Make sure we have enough room and reset the lengths.
if (strm.total_out >= [decompressed length])
[decompressed increaseLengthBy: half_length];
strm.next_out = [decompressed mutableBytes] + strm.total_out;
strm.avail_out = (unsigned int)([decompressed length] - strm.total_out);
// Inflate another chunk.
status = inflate (&strm, Z_SYNC_FLUSH);
if (status == Z_STREAM_END) done = YES;
else if (status != Z_OK) break;
}
if (inflateEnd (&strm) != Z_OK) return nil;
// Set real length.
if (done)
{
[decompressed setLength: strm.total_out];
return [NSData dataWithData: decompressed];
}
else return nil;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment