Pan Ziyue
Pan Ziyue

Reputation: 2287

Detecting if NSString is Base64

I was recently trying to make an iOS application that is able to encode and decode Base64, alongside with other 'languages' such as hexadecimal and binary. I was trying to make an automated decoder (which is capable of automatically detecting the 'language'). However, when I got to Base64, the automated decoder seems to be unable to detect valid Base64 as there are newline characters in the Base64 string. My Base64 detecting code is shown below:

-(BOOL)isBase64Data:(NSString *)input
{
    if ([input length] % 4 == 0) {
        static NSCharacterSet *invertedBase64CharacterSet = nil;
        if (invertedBase64CharacterSet == nil) {
            invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="]invertedSet];
        }
        return [input rangeOfCharacterFromSet:invertedBase64CharacterSet options:NSLiteralSearch].location == NSNotFound;
    }
    return NO;
}

And just for additional info, here's my method for detecting type of 'language' in an NSString.

-(NSInteger)detectType:(BOOL)base64 hexadecimal:(BOOL)hex binary:(BOOL)binary
{
    //Make sure the checking of characters are in this order!
    if (binary) {
        return 0; //Type 0 means binary
    }
    else if (hex) {
        return 1; //Type 1 means hexadecimal
    }
    else if (base64) {
        return 2; //Type 2 means base64
    }
    else {
        return 3; //Type 3 is error/invalid text
    }
}

I just call this method whenever I want to decode:

-(IBAction)decode:(id)sender
{
    //This is where I detect the type
    NSInteger type = [self detectType:[self isBase64Data:userInput.text] hexadecimal:[self isHexadecimal:userInput.text] binary:[self isBinary:userInput.text]];

    if ([userInput text].length<1) { //First, check if the text view is empty in the first place
        WCAlertView *alert=[[WCAlertView alloc]initWithTitle:@"Error: No input!" message:nil delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
        [alert show];
    }
    else if (type==0) {
        //Initiate the binary converter here
        TextBinViewController *binVC=[[TextBinViewController alloc]init];
        output.text=[binVC binToText:userInput.text];
    }
    else if (type==1) {
        //Initiate the hexadecimal converter here
        TextHexViewController *hexVC=[[TextHexViewController alloc]init];
        output.text=[hexVC hexToText:userInput.text];
    }
    else if (type==2) {
        //Initiate the base64 converter here
        TextBase64ViewController *baseVC=[[TextBase64ViewController alloc]init];
        output.text=[baseVC base64Decode:userInput.text];
    }
    else {
        //If the type matches none of the above, show an error (WCAlertView is a subclass of alertview that allows more styling)
        WCAlertView *alert=[[WCAlertView alloc]initWithTitle:@"Error: Invalid input!" message:nil delegate:nil cancelButtonTitle:@"Okay" otherButtonTitles:nil, nil];
        [alert show];
        output.text=@"";
    }

    [userInput resignFirstResponder];
}

Upvotes: 3

Views: 1645

Answers (2)

Pan Ziyue
Pan Ziyue

Reputation: 2287

Alright guys, I've realised that I can simply trim all the newline characters from the string. The updated -isBase64Data method is as below:

-(BOOL)isBase64Data:(NSString *)input
{

    input=[[input componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:@""];
    if ([input length] % 4 == 0) {
        static NSCharacterSet *invertedBase64CharacterSet = nil;
        if (invertedBase64CharacterSet == nil) {
            invertedBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="]invertedSet];
        }
        return [input rangeOfCharacterFromSet:invertedBase64CharacterSet options:NSLiteralSearch].location == NSNotFound;
    }
    return NO;
}

Now the detection of Base64 strings work correctly. I figured out that when the string has newline characters or such, the [input length] % 4 does not return 0. So, my current solution is simply to trim those characters away using the whitespaceAndNewlineCharacterSet.

Upvotes: 5

CRD
CRD

Reputation: 53010

Add a new line to the string of valid characters from which you make a set and take its inverse.

Upvotes: 0

Related Questions