0

In Objective-C, how can i decode a string that was encoded in C# using HttpServerUtility.UrlTokenEncode?

In Java, i was able to use this method suggested by @Gideon.

I tried to convert that method from Java to Objective-C and this is what i got so far.

- (NSData *)URLTokenDecode:(NSString *)input {

NSData *result;
NSUInteger len = [input length];
NSUInteger numPadChars = (int)[input characterAtIndex:len-1] - (int)'0';

if(numPadChars >10)
    return nil;

char base64Chars[len - 1 + numPadChars];

for(int iter = 0; iter < len-1 ; iter++){
    char c = [input characterAtIndex:iter];
    switch (c) {
        case '-':
            base64Chars[iter] = '+';
            break;

        case '_':
            base64Chars[iter] = '/';
            break;

        default:
            base64Chars[iter] = c;
            break;
    }
}

for(int iter = len-1; iter < strlen(base64Chars); iter++){
    base64Chars[iter] = '=';
}

NSString* assembledString = [NSString stringWithCString:base64Chars encoding:NSASCIIStringEncoding];
result = [[NSData alloc] initWithBase64EncodedString:assembledString options:0];

return result;
}

result should be a NSData which then can be used to populate an ImageView using [UIImage imageWithData:result];

I tried to debug this method with the same data from Java method but for some reason result always becomes nil here.

I noticed in the Objective-C version, size of the base64Chars array strlen(base64Chars) is always one less than the Java version base64Chars.length, i tried to tweak around it but it didn't work out.

Thanks in advance for any help.

Community
  • 1
  • 1
Sobhan
  • 1,051
  • 2
  • 13
  • 29

2 Answers2

0

You use strlen() to get length, it's the already fill length, not the size of base64Chars, nor the len - 1 + numPadChars in java implementation. so the = padding may not fill.

you can try my fixed method:

- (NSData *)UrlTokenDecode:(NSString *)input {

NSData *result;
NSUInteger len = [input length];
NSUInteger numPadChars = (int)[input characterAtIndex:len-1] - (int)'0';

if(numPadChars >10)
    return nil;

char* base64Chars = malloc(len+numPadChars); // no -1 because need a '\0' end
memset(base64Chars, 0, len+numPadChars);

for(int iter = 0 ; iter < len-1 ; iter++){
    char myChar = [input characterAtIndex:iter];
    switch (myChar) {
        case '-':
            base64Chars[iter] = '+';
            break;

        case '_':
            base64Chars[iter] = '/';
            break;

        default:
            base64Chars[iter] = myChar;
            break;
    }
}

for(int iter = len-1 ; iter < len+numPadChars-1; iter++){
    base64Chars[iter] = '=';
}

NSString* assembledString = [NSString stringWithCString:base64Chars encoding:NSASCIIStringEncoding];
result = [[NSData alloc] initWithBase64EncodedString:assembledString options:0];
free(base64Chars);

return result;
}
SolaWing
  • 1,652
  • 12
  • 14
0

As an alternate approach. I made the whole method more Objective-C friendly.

NSData *URLTokenDecode(NSString *token)
{
    if (token.length == 0) return nil;

    // The last character in the token is the number of padding characters.
    NSUInteger numberOfPaddingCharacters = [token characterAtIndex:token.length - 1] - '0';
    if (numberOfPaddingCharacters > 10) return nil;

    // The Base64 string is the token without the last character.
    NSString *base64 = [token substringWithRange:NSMakeRange(0, token.length - 1)];

    // '-'s are '+'s and '_'s are '/'s.
    base64 = [base64 stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
    base64 = [base64 stringByReplacingOccurrencesOfString:@"_" withString:@"/"];

    // Pad the Base64 string out with '='s
    NSUInteger paddedLength = base64.length + numberOfPaddingCharacters;
    base64 = [base64 stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:0];

    NSData *result = [[NSData alloc] initWithBase64EncodedString:base64 options:kNilOptions];
    return result;
}
Jeffery Thomas
  • 42,202
  • 8
  • 92
  • 117
  • Thanks for the quick answer, i'm receiving an exception at line `base64 = [base64 stringByPaddingToLength:paddedLength withString:@"=" startingAtIndex:base64.length];` because _'NSInvalidArgumentException', reason: '*** -[__NSCFString stringByPaddingToLength:withString:startingAtIndex:]: out of range padIndex_ is there a reason it goes out of range? – Sobhan May 24 '15 at 03:51
  • @Sobhan sorry, I had a thinko with the last parameter of `-stringByPaddingToLength:withString:startingAtIndex:`. It should have been `0` not `base64.length`. I updated my code. – Jeffery Thomas May 24 '15 at 14:04
  • Ahh yes, thanks @Jeffery, now it works. I have a question, knowing that this method is more Objective-C friendly, does that mean its performance is going to be more efficient than the method described in the question? – Sobhan May 25 '15 at 06:27
  • No. I didn't do it this way for performance reasons. Readability, modularity, and leveraging the standard library were my goals. I would only optimize for performance if I had a performance issues. – Jeffery Thomas May 25 '15 at 15:55