decode route from google API - objective-c

i am desperately trying to find a way on how to get an Array of all the Coordinates (or a Polyline) from the google API so that I can draw my route on the MKMapView.
( By the way, I don´t want to use the RegexKitLite)
As I found elsewhere, this should be the right way to call for the API.
NSString* apiUrlStr = [NSString stringWithFormat:#"http://maps.google.com/maps?output=dragdir&saddr=%#&daddr=%#", saddr, daddr];
NSURL* apiUrl = [NSURL URLWithString:apiUrlStr];
encodedString = ..... ???? // here i need some code before i can call the following Method
[self polylineWithEncodedString:encodedString];
and here is a method i found, to get a polyline.
+ (MKPolyline *)polylineWithEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}

Code from here works perfectly well:
https://gist.github.com/Muximize/3770235
+ (MKPolyline *)polylineWithGMEncodedString:(NSString *)encodedString {
const char *bytes = [encodedString UTF8String];
NSUInteger length = [encodedString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSUInteger idx = 0;
NSUInteger count = length / 4;
CLLocationCoordinate2D *coords = calloc(count, sizeof(CLLocationCoordinate2D));
NSUInteger coordIdx = 0;
float latitude = 0;
float longitude = 0;
while (idx < length) {
char byte = 0;
int res = 0;
char shift = 0;
do {
byte = bytes[idx++] - 63;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLat = ((res & 1) ? ~(res >> 1) : (res >> 1));
latitude += deltaLat;
shift = 0;
res = 0;
do {
byte = bytes[idx++] - 0x3F;
res |= (byte & 0x1F) << shift;
shift += 5;
} while (byte >= 0x20);
float deltaLon = ((res & 1) ? ~(res >> 1) : (res >> 1));
longitude += deltaLon;
float finalLat = latitude * 1E-5;
float finalLon = longitude * 1E-5;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(finalLat, finalLon);
coords[coordIdx++] = coord;
if (coordIdx == count) {
NSUInteger newCount = count + 10;
coords = realloc(coords, newCount * sizeof(CLLocationCoordinate2D));
count = newCount;
}
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:coordIdx];
free(coords);
return polyline;
}

Calling...
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%#,%#&destination=%f,%f&mode=driving&sensor=false",smAppDelegate.currPosition.latitude, smAppDelegate.currPosition.longitude, ((LocationItem*)selectedAnno).coordinate.latitude, ((LocationItem*)selectedAnno).coordinate.longitude]]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Response...
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[self.responseDirectionData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.responseDirectionData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
[connection release];
self.responseDirectionData =nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"connection established");
[connection release];
NSError *error = nil;
NSString *responseString=[[NSString alloc]initWithData:responseDirectionData encoding:NSUTF8StringEncoding];
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSDictionary *jsonObjects = [jsonParser objectWithString:responseString error:&error];
NSLog(#"responce = %#",jsonObjects);
NSMutableArray *ad = [jsonObjects objectForKey:#"routes"];
NSMutableArray *data2 = [[ad objectAtIndex:0] objectForKey:#"legs"];
NSMutableArray *data3 = [[data2 objectAtIndex:0] objectForKey:#"steps"];
NSLog(#"Data3 %#", data3);
NSMutableArray *polyLinesArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [data3 count]; i++)
{
NSString* encodedPoints = [[[data3 objectAtIndex:i] objectForKey:#"polyline"] valueForKey:#"points"];
MKPolyline *route = [self polylineWithEncodedString:encodedPoints];
[polyLinesArray addObject:route];
}
[self.mapView addOverlays:polyLinesArray];
[polyLinesArray release];
}

Related

myArray count isn't functioning as expected

The arrayTwelveLEngth variable isn't working as expected. When I placed a breakpoint on the amount = 1; line above, I hovered over arrayTwelve, and found that it was empty with 0 elements. Immediately after, I then hovered about arrayTwelveLength, expecting to see 0, but instead it seems that the arrayTwelveLength had a value of 1876662112. I don't know how it got that value, and I need to solve that problem. What am I doing wrong?
NSMutableArray *redValues = [NSMutableArray array];
NSMutableArray *arrayTwelve = [NSMutableArray array];
__block int counter = 0;
__block NSInteger u;
NSUInteger redValuesLength = [redValues count];
__block int arrayTwelveLength = 0;
__block float diffForAverage, fps, averageTime, bloodSpeed;
float average;
__block int amount = 1;
__block float totalTwelve, totalThirteen;
__block NSUInteger totalNumberOfFramesInSmallArrays = 0;
__block NSUInteger totalNumberOfFramesNotInSmallArrays;
for (u = (counter + 24); u < (redValuesLength - 24); u++)
{
diffForAverage = average - [redValues[u + 1] floatValue];
float test = [redValues[u] floatValue];
arrayTwelveLength = [arrayTwelve count];
if (diffForAverage > -1 && diffForAverage < 1)
{
totalTwelve += [redValues[u + 1] floatValue];
amount++;
[arrayTwelve addObject:#(test)];
counter++;
}
else
{
if (arrayTwelveLength >= 8)
{
counter++;
break;
}
else
{
[arrayTwelve removeAllObjects];
totalTwelve = [redValues[u + 1] floatValue];
counter++;
amount = 1;
}
}
}
amount = 1; // I added a breakpoint here
totalThirteen = [redValues[u + 1] floatValue];
average = totalThirteen / amount;
if (counter == redValuesLength)
{
totalNumberOfFramesNotInSmallArrays = redValuesLength - totalNumberOfFramesInSmallArrays - 25 - (redValuesLength - counter);
fps = redValuesLength / 30;
averageTime = totalNumberOfFramesNotInSmallArrays / fps;
bloodSpeed = 3 / averageTime;
[_BloodSpeedValue setText:[NSString stringWithFormat:#"%f", bloodSpeed]];
}
if (arrayTwelveLength == NULL)
{
arrayTwelveLength = 0;
}
totalNumberOfFramesInSmallArrays += arrayTwelveLength;
You have problems with unsigned/signed types and with your data set the first for loop should not even enter, because your for loop index variable u (== 24) < (redValuesLength (== 0) - 24) but, because redValuesLength being Unsigned type it wraps around and you get:
(unsigned long)0 - (unsigned long)24 = -24 modulo ULONG_MAX + 1= 18446744073709551592
Also, you are not initialising average before usage.

Objective-C RC4 Decryption

I am new to Objective-C, but am an experienced developer (C#), but I can't figure this out:
I have a string which is RC4 encrypted, and I need to decrypt it using Objective-C on the iPad (iOS 5.0). I have looked all over the net for a working example, but have had no luck finding an example that works end-to-end. Not only does the code below not return the decrypted string correctly, it returns something different every time it executes, which makes me thing a pointer is being released someplace.
Note: I do not know if it matters, but the string was encrypted using http://archive.plugins.jquery.com/project/RC4 and then stored as text in a Sqlite database, which I am now accessing from Objective-C (I know, the architecture sounds messy, but I can't change that at this point.)
The code I am using is (taken from RC4 encryption - CommonCrypto (Objective-C) vs PHP):
+ (NSString*)decryptData:(NSData*) dataToDecrypt
{
const void *vplainText;
size_t plainTextBufferSize;
plainTextBufferSize = [dataToDecrypt length];
vplainText = [dataToDecrypt bytes];
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x0, bufferPtrSize);
NSString *key = #"theKeyIUsedtoEncryptInTheFirstPlace";
const void *vkey = (const void *) [key UTF8String];
size_t keyLength = [[key dataUsingEncoding:NSUTF8StringEncoding] length];
ccStatus = CCCrypt(kCCDecrypt,
kCCAlgorithmRC4,
0,
vkey,
kCCKeySizeDES,
nil,
vplainText,
plainTextBufferSize,
(void *)bufferPtr,
bufferPtrSize,
&movedBytes);
if (ccStatus == kCCSuccess) NSLog(#"SUCCESS");
/*else*/ if (ccStatus == kCCParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED";
NSString *result = [[ NSString alloc ] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSASCIIStringEncoding];
NSLog(#"%#", result);
return result;
}
Use this function for encryption and decryption. (Just put in the encoded string with same key again to decode it).
-(NSString*) rc4Key:(NSString*) key str:(NSString*) str
{
int j = 0;
unichar res[str.length];
const unichar* buffer = res;
unsigned char s[256];
for (int i = 0; i < 256; i++)
{
s[i] = i;
}
for (int i = 0; i < 256; i++)
{
j = (j + s[i] + [key characterAtIndex:(i % key.length)]) % 256;
swap(s[i], s[j]);
}
int i = j = 0;
for (int y = 0; y < str.length; y++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
swap(s[i], s[j]);
unsigned char f = [str characterAtIndex:y] ^ s[ (s[i] + s[j]) % 256];
res[y] = f;
}
return [NSString stringWithCharacters:buffer length:str.length];
}
I see a couple of references to DES in your code (kCCKeySizeDES, kCCBlockSize3DES). That doesn't seem right -- at a minimum, kCCKeySizeDES should probably be replaced with keyLength.
If that doesn't solve it, I'd look next at possible text encoding issues. The data in SQLite might be UTF8-encoded binary data, in which case you'll probably have to "decode" it by converting from UTF8 to ISO8859-1.
RC4 implementation translated from .net:
+(NSString*)RC4:(NSString *)data key:(NSString *)key
{
id x;
int y = 0;
int i = 0;
int j = 0;
NSMutableArray *box = [[NSMutableArray alloc] initWithCapacity:256];
NSString *result = #"";
for (i = 0; i < 256; i++) {
[box addObject:[NSNumber numberWithInt:i]];
}
for (i = 0; i < 256; i++) {
j = ((int)[key characterAtIndex:(i % key.length)] + [[box objectAtIndex:i] intValue] + j) % 256;
x = [box objectAtIndex:i];
[box setObject:[box objectAtIndex:j] atIndexedSubscript:i];
[box setObject:x atIndexedSubscript:j];
}
for (i = 0; i < data.length; i++) {
y = i % 256;
j = ([[box objectAtIndex:y] intValue] + j) % 256;
x = [box objectAtIndex:y];
[box setObject:[box objectAtIndex:j] atIndexedSubscript:y];
[box setObject:x atIndexedSubscript:j];
NSString *c = [NSString stringWithFormat:#"%c", ([data characterAtIndex:i] ^ (char)[[box objectAtIndex:([[box objectAtIndex:y] intValue] + [[box objectAtIndex:j] intValue]) % 256] intValue])];
result = [result stringByAppendingString:c];
}
return result;
}

Converting binary bits to Hex value

How do I convert binary data to hex value in obj-c?
Example:
1111 = F,
1110 = E,
0001 = 1,
0011 = 3.
I have a NSString of 10010101010011110110110011010111, and i want to convert it to hex value.
Currently I'm doing in a manual way. Which is,
-(NSString*)convertToHex:(NSString*)hexString
{
NSMutableString *convertingString = [[NSMutableString alloc] init];
for (int x = 0; x < ([hexString length]/4); x++) {
int a = 0;
int b = 0;
int c = 0;
int d = 0;
NSString *A = [NSString stringWithFormat:#"%c", [hexString characterAtIndex:(x)]];
NSString *B = [NSString stringWithFormat:#"%c", [hexString characterAtIndex:(x*4+1)]];
NSString *C = [NSString stringWithFormat:#"%c", [hexString characterAtIndex:(x*4+2)]];
NSString *D = [NSString stringWithFormat:#"%c", [hexString characterAtIndex:(x*4+3)]];
if ([A isEqualToString:#"1"]) { a = 8;}
if ([B isEqualToString:#"1"]) { b = 4;}
if ([C isEqualToString:#"1"]) { c = 2;}
if ([D isEqualToString:#"1"]) { d = 1;}
int total = a + b + c + d;
if (total < 10) { [convertingString appendFormat:#"%i",total]; }
else if (total == 10) { [convertingString appendString:#"A"]; }
else if (total == 11) { [convertingString appendString:#"B"]; }
else if (total == 12) { [convertingString appendString:#"C"]; }
else if (total == 13) { [convertingString appendString:#"D"]; }
else if (total == 14) { [convertingString appendString:#"E"]; }
else if (total == 15) { [convertingString appendString:#"F"]; }
}
NSString *convertedHexString = convertingString;
return [convertedHexString autorelease];
[convertingString release];
}
Anyone have better suggestion? This is taking too long.
Thanks in advance.
I have never been much of a C hacker myself, but a problem like this is perfect for C, so here is my modest proposal - coded as test code to run on the Mac, but you should be able to copy the relevant bits out to use under iOS:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
NSString *str = #"10010101010011110110110011010111";
char* cstr = [str cStringUsingEncoding: NSASCIIStringEncoding];
NSUInteger len = strlen(cstr);
char* lastChar = cstr + len - 1;
NSUInteger curVal = 1;
NSUInteger result = 0;
while (lastChar >= cstr) {
if (*lastChar == '1')
{
result += curVal;
}
/*
else
{
// Optionally add checks for correct characters here
}
*/
lastChar--;
curVal <<= 1;
}
NSString *resultStr = [NSString stringWithFormat: #"%x", result];
NSLog(#"Result: %#", resultStr);
[p release];
}
It seems to work, but I am sure that there is still room for improvement.
#interface bin2hex : NSObject
+(NSString *)convertBin:(NSString *)bin;
#end
#implementation bin2hex
+(NSString*)convertBin:(NSString *)bin
{
if ([bin length] > 16) {
NSMutableArray *bins = [NSMutableArray array];
for (int i = 0;i < [bin length]; i += 16) {
[bins addObject:[bin substringWithRange:NSMakeRange(i, 16)]];
}
NSMutableString *ret = [NSMutableString string];
for (NSString *abin in bins) {
[ret appendString:[bin2hex convertBin:abin]];
}
return ret;
} else {
int value = 0;
for (int i = 0; i < [bin length]; i++) {
value += pow(2,i)*[[bin substringWithRange:NSMakeRange([bin length]-1-i, 1)] intValue];
}
return [NSString stringWithFormat:#"%X", value];
}
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
// insert code here...
NSLog(#"0x%#",[bin2hex convertBin:#"10010101010011110110110011010111"]);
}
return 0;
}
I get the result of 0x954F6CD7 for 10010101010011110110110011010111 and it seems to be instant
Maybe easiest would be to setup a NSDictionary for quick lookups?
[NSDictionary dictionaryWithObjects...]
since it is a limited number of entries.
"0000" -> 0
...
"1111" -> F

Insert a #"\n" in NSString

For example, if I start with this string:
NSString * labeltext = #"abcdefghijk";
I want this string change to #"abc\n def\n ghi \n jk".
I want #"\n" to be inserted at an interval of 3.
How can I accomplish this?
Use a NSMutableString and then for loop through the original NSString.
NSMutableString *buffer = [[NSMutableString alloc] init];
int len = [labelText length];
for (i = 0; i < len; i++) {
NSRange charAt = NSMakeRange(i,1);
[buffer appendString: [labelText substringWithRange: charAt]];
if ((i % 3) == 2) {
[buffer appendString: #"\n"];
}
}
labelText = (NSString *)buffer;
The above example is pure Objective-C. This can also be accomplished using C. Convert the NSString into a cstring and then loop through the array. For instance,
const char *str = [labelText UTF8String];
int len = strlen(str) - 1;
int pos = 0;
char buffer[(len * 2) + 1];
for (i = 0; i < len; i++) {
char ch = str[i];
buffer[pos] = ch;
pos++;
if ((i % 3) == 2) {
buffer[pos] = '\n';
pos++;
}
}
buffer[pos] = '\0';
labelText = [NSString stringWithFormat: #"%s", buffer];

How to Base64 encoding on the iPhone

How do I do Base64 encoding on the iPhone?
I have found a few examples that looked promising, but could never get any of them to work on the phone.
You can see an example here.
This is for iOS7+.
I copy the code here, just in case:
// Create NSData object
NSData *nsdata = [#"iOS Developer Tips encoded in Base64"
dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64Encoded = [nsdata base64EncodedStringWithOptions:0];
// Print the Base64 encoded string
NSLog(#"Encoded: %#", base64Encoded);
// Let's go the other way...
// NSData from the Base64 encoded str
NSData *nsdataFromBase64String = [[NSData alloc]
initWithBase64EncodedString:base64Encoded options:0];
// Decoded NSString from the NSData
NSString *base64Decoded = [[NSString alloc]
initWithData:nsdataFromBase64String encoding:NSUTF8StringEncoding];
NSLog(#"Decoded: %#", base64Decoded);
Use this library to encode Base64.
It also supports ARC
I also had trouble finding working code for the iPhone that I could understand.
I finally wrote this.
-(NSString *)Base64Encode:(NSData *)data;
-(NSString *)Base64Encode:(NSData *)data{
//Point to start of the data and set buffer sizes
int inLength = [data length];
int outLength = ((((inLength * 4)/3)/4)*4) + (((inLength * 4)/3)%4 ? 4 : 0);
const char *inputBuffer = [data bytes];
char *outputBuffer = malloc(outLength+1);
outputBuffer[outLength] = 0;
//64 digit code
static char Encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//Start the count
int cycle = 0;
int inpos = 0;
int outpos = 0;
char temp;
//Pad the last to bytes, the outbuffer must always be a multiple of 4.
outputBuffer[outLength-1] = '=';
outputBuffer[outLength-2] = '=';
/* http://en.wikipedia.org/wiki/Base64
Text content M a n
ASCII 77 97 110
8 Bit pattern 01001101 01100001 01101110
6 Bit pattern 010011 010110 000101 101110
Index 19 22 5 46
Base64-encoded T W F u
*/
while (inpos < inLength){
switch (cycle) {
case 0:
outputBuffer[outpos++] = Encode[(inputBuffer[inpos] & 0xFC) >> 2];
cycle = 1;
break;
case 1:
temp = (inputBuffer[inpos++] & 0x03) << 4;
outputBuffer[outpos] = Encode[temp];
cycle = 2;
break;
case 2:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xF0) >> 4];
temp = (inputBuffer[inpos++] & 0x0F) << 2;
outputBuffer[outpos] = Encode[temp];
cycle = 3;
break;
case 3:
outputBuffer[outpos++] = Encode[temp|(inputBuffer[inpos]&0xC0) >> 6];
cycle = 4;
break;
case 4:
outputBuffer[outpos++] = Encode[inputBuffer[inpos++] & 0x3f];
cycle = 0;
break;
default:
cycle = 0;
break;
}
}
NSString *pictemp = [NSString stringWithUTF8String:outputBuffer];
free(outputBuffer);
return pictemp;
}
Download following two files from GitHub
Base64.h
Base64.m
Add these files to your project
Import header file in desired file
#import "Base64.h"
And use as to encode
NSString *plainText = #"Your String";
NSString *base64String = [plainText base64EncodedStringWithWrapWidth:0];
Also you can decode it as
NSString *plainText = [base64String base64DecodedString];
Try this out...this worked perfectly for me.create a category Base64.h and Base 64.m,Import to any class you want to use and call it using single line for base 64 encoding to happen.
//
// Base64.h
// CryptTest
// Created by SURAJ K THOMAS on 02/05/2013.
#import <Foundation/Foundation.h>
#interface Base64 : NSObject {
}
+ (void) initialize;
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length;
+ (NSString*) encode:(NSData*) rawBytes;
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength;
+ (NSData*) decode:(NSString*) string;
#end
#import "Base64.h"
#implementation Base64
#define ArrayLength(x) (sizeof(x)/sizeof(*(x)))
static char encodingTable[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static char decodingTable[128];
+ (void) initialize {
if (self == [Base64 class]) {
memset(decodingTable, 0, ArrayLength(decodingTable));
for (NSInteger i = 0; i < ArrayLength(encodingTable); i++) {
decodingTable[encodingTable[i]] = i;
}
}
}
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
}
+ (NSString*) encode:(NSData*) rawBytes {
return [self encode:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSData*) decode:(const char*) string length:(NSInteger) inputLength {
if ((string == NULL) || (inputLength % 4 != 0)) {
return nil;
}
while (inputLength > 0 && string[inputLength - 1] == '=') {
inputLength--;
}
NSInteger outputLength = inputLength * 3 / 4;
NSMutableData* data = [NSMutableData dataWithLength:outputLength];
uint8_t* output = data.mutableBytes;
NSInteger inputPoint = 0;
NSInteger outputPoint = 0;
while (inputPoint < inputLength) {
char i0 = string[inputPoint++];
char i1 = string[inputPoint++];
char i2 = inputPoint < inputLength ? string[inputPoint++] : 'A'; /* 'A' will
decode to \0 */
char i3 = inputPoint < inputLength ? string[inputPoint++] : 'A';
output[outputPoint++] = (decodingTable[i0] << 2) | (decodingTable[i1] >> 4);
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i1] & 0xf) << 4) |
(decodingTable[i2] >> 2);
}
if (outputPoint < outputLength) {
output[outputPoint++] = ((decodingTable[i2] & 0x3) << 6) |
decodingTable[i3];
}
}
return data;
}
+ (NSData*) decode:(NSString*) string {
return [self decode:[string cStringUsingEncoding:NSASCIIStringEncoding]
length:string.length];
}
#end
now import the above category to any class and convert the string like below
NSString *authString = [[NSString stringWithFormat:#"OD0EK819OJFIFT6OJZZXT09Y1YUT1EJ2"]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSData *inputData = [authString dataUsingEncoding:NSUTF8StringEncoding];
NSString *finalAuth =[Base64 encode:inputData];
NSLog(#"Encoded string =%#", finalAuth);
reference
NSString *plainString = #"foo";
Encoding
NSData *plainData = [plainString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64String = [plainData base64EncodedStringWithOptions:0];
NSLog(#"%#", base64String); // Zm9v
Decoding
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"%#", decodedString); // foo
Seems as of iOS 7 you no longer need any libraries to encode in Base64. Following methods on NSData can be used to Base64 encode:
base64EncodedDataWithOptions:
– base64EncodedStringWithOptions:
I did my own implementation, where has been removed all checks inside the loop. So on big amount of data, it works faster. You can take it as a basis for own solution.
static char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ (NSString *)encodeString:(NSString *)data
{
const char *input = [data cStringUsingEncoding:NSUTF8StringEncoding];
unsigned long inputLength = [data length];
unsigned long modulo = inputLength % 3;
unsigned long outputLength = (inputLength / 3) * 4 + (modulo ? 4 : 0);
unsigned long j = 0;
// Do not forget about trailing zero
unsigned char *output = malloc(outputLength + 1);
output[outputLength] = 0;
// Here are no checks inside the loop, so it works much faster than other implementations
for (unsigned long i = 0; i < inputLength; i += 3) {
output[j++] = alphabet[ (input[i] & 0xFC) >> 2 ];
output[j++] = alphabet[ ((input[i] & 0x03) << 4) | ((input[i + 1] & 0xF0) >> 4) ];
output[j++] = alphabet[ ((input[i + 1] & 0x0F)) << 2 | ((input[i + 2] & 0xC0) >> 6) ];
output[j++] = alphabet[ (input[i + 2] & 0x3F) ];
}
// Padding in the end of encoded string directly depends of modulo
if (modulo > 0) {
output[outputLength - 1] = '=';
if (modulo == 1)
output[outputLength - 2] = '=';
}
NSString *s = [NSString stringWithUTF8String:(const char *)output];
free(output);
return s;
}
This answer is outdated, use https://stackoverflow.com/a/24468530/669586 since iOS 7.
A method in a NSData category
- (NSString*)encodeBase64 {
static char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
unsigned int length = self.length;
unsigned const char* rawData = self.bytes;
//empty data = empty output
if (length == 0) {
return #"";
}
unsigned int outputLength = (((length + 2) / 3) * 4);
//let's allocate buffer for the output
char* rawOutput = malloc(outputLength + 1);
//with each step we get 3 bytes from the input and write 4 bytes to the output
for (unsigned int i = 0, outputIndex = 0; i < length; i += 3, outputIndex += 4) {
BOOL triple = NO;
BOOL quad = NO;
//get 3 bytes (or only 1 or 2 when we have reached the end of input)
unsigned int value = rawData[i];
value <<= 8;
if (i + 1 < length) {
value |= rawData[i + 1];
triple = YES;
}
value <<= 8;
if (i + 2 < length) {
value |= rawData[i + 2];
quad = YES;
}
//3 * 8 bits written as 4 * 6 bits (indexing the 64 chars of the alphabet)
//write = if end of input reached
rawOutput[outputIndex + 3] = (quad) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 2] = (triple) ? alphabet[value & 0x3F] : '=';
value >>= 6;
rawOutput[outputIndex + 1] = alphabet[value & 0x3F];
value >>= 6;
rawOutput[outputIndex] = alphabet[value & 0x3F];
}
rawOutput[outputLength] = 0;
NSString* output = [NSString stringWithCString:rawOutput encoding:NSASCIIStringEncoding];
free(rawOutput);
return output;
}