#import "NSData+Speakable.h"
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
long int i, j;
for (i = size - 1; i >= 0; i--)
{
for (j = 7; j >= 0; j--)
{
byte = b[i] & (1 << j);
byte >>= j;
printf("%u", byte);
}
}
puts("");
}
@implementation NSData (Speakable)
static unsigned char highMask = 0xe0;
static unsigned char lowMask = 0x1f;
+ (NSArray *) brands
{
return @[@"Camry", @"Nikon", @"Apple", @"Ford", @"Audi", @"Google", @"Nike", @"Amazon",
@"Honda", @"Mazda", @"Buick", @"Fiat", @"Jeep", @"Lexus", @"Volvo", @"Fuji",
@"Sony", @"Delta", @"Focus", @"Puma", @"Samsung", @"Tivo", @"Halo", @"Sting",
@"Shrek", @"Avatar", @"Shell", @"Visa", @"Vogue", @"Twitter", @"Lego", @"Pepsi"];
}
- (NSString *)encodeAsSpeakableString
{
NSMutableString *speakable = [[NSMutableString alloc] init];
const unsigned char *data = [self bytes];
if(data) {
for (int i = 0; i < [self length]; i++) {
unsigned char lower = data[i] & lowMask;
unsigned char higher = ((data[i] & highMask) >> 5) + 2;
if ([speakable length]) {
[speakable appendString:@" "];
}
[speakable appendString:[NSString stringWithFormat:@"%d %@", higher, [NSData brands][lower]]];
}
}
return speakable;
}
+ (NSData *)dataWithSpeakableString:(NSString *)s error:(NSError **)e
{
BOOL success = YES;
BOOL continueParsing = YES;
NSRange searchRange = NSMakeRange(0, s.length);
NSCharacterSet *validDigits = [NSCharacterSet characterSetWithCharactersInString:@"23456789"];
NSCharacterSet *chars = [NSCharacterSet letterCharacterSet];
NSMutableData *data = [[NSMutableData alloc] init];
while (continueParsing) {
int8_t encodedByte = 0;
NSRange resultRange = [s rangeOfCharacterFromSet:validDigits options:NSLiteralSearch range:searchRange];
if (resultRange.location != NSNotFound) {
searchRange.location = resultRange.location + resultRange.length;
searchRange.length = s.length - searchRange.location;
encodedByte = ([[s substringWithRange:resultRange] integerValue] - 2) << 5;
printBits(sizeof(encodedByte), &encodedByte);
NSLog(@"1. Result %@ | Search %@", NSStringFromRange(resultRange), NSStringFromRange(searchRange));
NSLog(@"2. %@", [s substringWithRange:resultRange]);
} else {
success = YES;
NSLog(@"A. Breaking out");
break;
}
resultRange = [s rangeOfCharacterFromSet:chars options:NSCaseInsensitiveSearch range:searchRange];
if (resultRange.location != NSNotFound) {
NSScanner *scanner = [NSScanner scannerWithString:s];
scanner.caseSensitive = NO;
scanner.scanLocation = resultRange.location;
NSString *word = [[NSString alloc] init];
[scanner scanCharactersFromSet:chars intoString:&word];
searchRange.location = resultRange.location + word.length;
searchRange.length = s.length - searchRange.location;
NSUInteger wordIndex = [[NSData brands] indexOfObject:[word capitalizedString]];
if (wordIndex != NSNotFound) {
NSLog(@"3. wordIndex: %lu", (unsigned long)wordIndex);
encodedByte = encodedByte | wordIndex;
} else {
success = NO;
break;
}
[data appendBytes:&encodedByte length:1];
NSLog(@"4. Result %@ | Search %@", NSStringFromRange(resultRange), NSStringFromRange(searchRange));
NSLog(@"5. %@", word);
NSLog(@"6. %@", data);
}
else {
continueParsing = NO;
success = NO;
}
}
if (!success) {
if (e) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Unable to parse"};
*e = [NSError errorWithDomain:@"SpeakableBytes" code:1 userInfo:userInfo];
}
return nil;
}
return data;
}
@end