FWIW My Solution to Speakable

#1

[code]static const NSArray *brandNames = nil;
static NSCharacterSet *validEncodedDigit = nil;

NSString *encodeByte(char byte)
{
char index = 0x1F & byte;
NSString *brandName = brandNames[index];
char encodedDigit =((0xe0 & byte) >> 5) + 2;
return [NSString stringWithFormat:@"%d %@ ", encodedDigit, brandName];
}

BOOL decodeByte(NSString *encodedDigit, NSString *brandName, char * byte, NSError **error)
{
// Check if encodedDigit is valid
if ([encodedDigit rangeOfCharacterFromSet:validEncodedDigit
options:NSLiteralSearch].location == NSNotFound) {
if(error) {
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : [NSString stringWithFormat:@“Invalid digit ‘%@’”, encodedDigit]};
*error = [NSError errorWithDomain:@“Speakable” code:1 userInfo];
}
return NO;
}
int digit = [encodedDigit intValue];

// Check if brandName is valid;
NSUInteger index = [brandNames indexOfObject:brandName];
if (index == NSNotFound) {
    if (error) {
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Invalid brandname '%@'",  brandName]};
        *error = [NSError errorWithDomain:@"Speakable" code:1 userInfo];
    }
    return NO;
}

*byte = (digit - 2) << 5 | (index & 0x1f);

return YES;

}

@implementation NSData (Speakable)

  • (void)initialize {
    brandNames = @[ @“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”];

    validEncodedDigit = [NSCharacterSet characterSetWithCharactersInString:@“23456789”];

}

  • (NSString *)encodeAsSpeakableString
    {

    // Copy bytes into buffer.
    const NSUInteger numBytes = self.length;
    char buffer[numBytes];
    [self getBytes:buffer length];
    NSMutableString *rtnValue = [[NSMutableString alloc] init];

    for (int i = 0; i < numBytes; i++) {
    char byte = buffer[i];
    [rtnValue appendString:encodeByte(byte)];
    }
    return rtnValue;
    }

  • (NSData *)dataWithSpeakableString:(NSString *)s
    error:(NSError **)e
    {

    NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    NSArray<NSString > words = [s componentsSeparatedByCharactersInSet:whitespace];

    long numBytes = words.count / 2;
    char bytes[numBytes];

    for (int i = 0; i < numBytes; i++) {
    NSString *encodedDigit = words[2 * i];
    NSString *brandName = words[(2 * i) + 1];

      if (!decodeByte(encodedDigit, brandName, &bytes[i], e)) {
          return nil;
      }
    

    }

    return [NSData dataWithBytes:bytes length];
    }

@end
[/code]