File output as .csv objective C - objective-c

Hello guys I'm writing a test file for a program. where all the possible numbers are tested and i want the result to be logged as a .csv file,so i can upload it into excel.
float calc (float i, float j , float p, float ex){
float nodalatio = (p/ex);
float ans = (0.68 *j + 1.22*nodalatio + 0.34*j -0.81);
return ans;
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
float stage , grade, pos, ex;
float resul;
for (int i=1;i<=3;i++){
stage = i;
for(int j=1;j<=3;j++){
grade = j;
for(int p=1;p<=60;p++){
pos = p;
for(int e=1;e<=60;e++){
ex=e;
resul = calc(stage, grade,pos,ex);
NSLog(#"stage is %f grade is %f,pos is %f ex is %f the result is %f",stage,grade,pos,ex,resul);
}
}
}
}
[pool drain];
return 0;
}
the above is the test code and i can't seem to figure how to output this in to a .csv file. does the code in the loop or after the loop. this is what i had but this did nothing !
NSString *file_path = #"test.csv";
NSString *test_1 = [NSString stringwithformat#"%f",resu];
[test_1 writeToFile:file_path atomically:YES encoding:NSUnicodeStringEncoding error:nil];
thank you

Try this:
float calc(float, float, float, float);
float calc (float i, float j , float p, float ex)
{
float nodalratio = (p / ex);
float ans = (0.68 * j + 1.22 * nodalratio + 0.34 * j - 0.81);
return ans;
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
float stage , grade, pos, ex;
float resul;
[[NSFileManager defaultManager] createFileAtPath: #"test.csv" contents: [#"" dataUsingEncoding: NSUnicodeStringEncoding] attributes: nil];
NSFileHandle *file = [NSFileHandle fileHandleForWritingAtPath: #"test.csv"];
[file seekToEndOfFile];
for (int i = 1; i <= 3; i++)
{
stage = i;
for(int j = 1; j <= 3; j++)
{
grade = j;
for(int p = 1; p <= 60; p++)
{
pos = p;
for(int e = 1; e <= 60; e++)
{
ex = e;
resul = calc(stage, grade, pos, ex);
NSString *str = [NSString stringWithFormat: #"%f, %f, %f, %f, %f\n", stage, grade, pos, ex, resul];
[file writeData: [str dataUsingEncoding: NSUTF16LittleEndianStringEncoding]];
}
}
}
}
[file closeFile];
[pool drain];
return 0;
}
That works for me. It will contain a proper BOM and write each string in UTF-16 (Unicode). Using other encodings, like NSUTF16StringEncoding, will write a BOM for each line, which is not really what you want.
FWIW, are you sure it is not 0.68 * j and 0.34 * i or vice versa?

Don't reinvent the wheel:
http://github.com/davedelong/CHCSVParser
My CSV parser class also includes a CSV writer for creating CSV files.

Related

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];

md5 a string multiple times

md5 a string multiple times in Python:
def md5(i):
return hashlib.md5(i).hexdigest().upper()
def md5x3(src):
f = hashlib.md5(src).digest()
s = hashlib.md5(f).digest()
t = md5(s)
return t
how to implement above in C with OpenSSL on MacOS/iOS or in Objective-C without OpenSSL on MacOS/iOS ?
I'm try following, but its result is different from python's.
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>
static char* hextostr(const unsigned char* in , int len)
{
char* res = (char*)malloc(len * 2 + 1);
int i = 0;
memset(res , 0 , len * 2 + 1);
while(i < len)
{
sprintf(res + i * 2 , "%02x" , in[i]);
i ++;
};
// i = 0;
// int reslength;
// reslength=(int)strlen(res);
// while(i < reslength)
// {
// res[i] = toupper(res[i]);
// i ++;
// };
return res;
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * foo = #"abcdefghij";
NSData * buf1 = [foo dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result1[CC_MD5_DIGEST_LENGTH];
CC_MD5([buf1 bytes], (unsigned int)[buf1 length], result1);
NSData * buf2 = [[[NSString alloc] initWithFormat:#"%s", result1] dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result2[CC_MD5_DIGEST_LENGTH];
CC_MD5(result1, (unsigned int)strlen(result1), result2);
NSData * buf3 = [[[NSString alloc] initWithFormat:#"%s", result2] dataUsingEncoding:NSUTF8StringEncoding];
unsigned char result3[CC_MD5_DIGEST_LENGTH];
CC_MD5(result2, (unsigned int)strlen(result2), result3);
NSString * res = [[NSString alloc] initWithFormat:
#"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
result3[0], result3[1], result3[2], result3[3], result3[4], result3[5], result3[6], result3[7],
result3[8], result3[9], result3[10], result3[11], result3[12], result3[13], result3[14], result3[15]
];
NSLog(#"%s", hextostr(result1, CC_MD5_DIGEST_LENGTH));
NSLog(#"%s", hextostr(result2, CC_MD5_DIGEST_LENGTH));
NSLog(#"%s", hextostr(result3, CC_MD5_DIGEST_LENGTH));
[pool drain];
return 0;
}
Use a digest library, such as OpenSSL, which you probably have installed already. See http://www.openssl.org/docs/crypto/md5.html. Source code for MD5 is available at http://userpages.umbc.edu/~mabzug1/cs/md5/md5.html.

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;
}