The problem is:
Memory is never released; potential leak of memory pointed to by 'p'
In Code it occurs on the return of this single line method:
- (NSString *)encodeBase64:(const uint8_t *)input length:(NSInteger)length
{
return [NSString stringWithUTF8String:base64_encode(input, (size_t)length)];
}
base64_encode function:
char* base64_encode(const void* buf, size_t size)
{
static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char* str = (char*) malloc((size+3)*4/3 + 1);
char* p = str;
unsigned char* q = (unsigned char*) buf;
size_t i = 0;
while(i < size) {
int c = q[i++];
c *= 256;
if (i < size) c += q[i];
i++;
c *= 256;
if (i < size) c += q[i];
i++;
*p++ = base64[(c & 0x00fc0000) >> 18];
*p++ = base64[(c & 0x0003f000) >> 12];
if (i > size + 1)
*p++ = '=';
else
*p++ = base64[(c & 0x00000fc0) >> 6];
if (i > size)
*p++ = '=';
else
*p++ = base64[c & 0x0000003f];
}
*p = 0;
return str;
}
You should free(str) after converting the char * to NSString:
- (NSString *)encodeBase64:(const uint8_t *)input length:(NSInteger)length
{
char *base64 = base64_encode(input, length);
NSString *ret = [NSString stringWithUTF8String:base64];
free(base64);
return ret;
}
the memory allocated with the malloc function has to be released with free, you has to change the line
*p = 0;
to
free(p);
i am converting image from picker into nsdata(jpeg representation) and then converting it into nsstring using the following code
NSData *data=UIImageJPEGRepresentation(image,1.0);
NSString *imageString=[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
[[NSUserDefaults standardUserDefaults] setObject:imageString forKey:#"image_name"];
and at the other end where i need to display the image the uiimage is formed as follows.
NSString *imageString=[[NSString alloc] init];
imageString=[[NSUserDefaults standardUserDefaults] objectForKey:#"image_name"];
UIImage *image=[UIImage imageWithData:[imageString dataUsingEncoding:NSUTF8StringEncoding]];
the image variable used in the top code is not nil ,but the image formed from data is getting nil...when i nslogged userdefaults some string is present for the key mentioned above .can anyone explain why is this so..what is the right way to do this
If it goes through a web server or the like, you could encapsulate it with base64 enc/decoding or some other plain encoder.
It removes "bad" char, ie that screw up the string during transformation, and change them to generic alphabetical chars and then back again.
if this is the reason to your issues, here is a short one i use (which I most probably stole and adapted, but do not remember from whom. Sorry! :-) )
base64helper.h
#import <Foundation/Foundation.h>
#interface NSData (MBBase64)
base64helper.m
#import "base64helper.h"
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#implementation NSData (MBBase64)
+ (id)dataWithBase64EncodedString:(NSString *)string;
{
if (string == nil)
[NSException raise:NSInvalidArgumentException format:nil];
if ([string length] == 0)
return [NSData data];
static char *decodingTable = NULL;
if (decodingTable == NULL)
{
decodingTable = malloc(256);
if (decodingTable == NULL)
return nil;
memset(decodingTable, CHAR_MAX, 256);
NSUInteger i;
for (i = 0; i < 64; i++)
decodingTable[(short)encodingTable[i]] = i;
}
const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
if (characters == NULL) // Not an ASCII string!
return nil;
char *bytes = malloc((([string length] + 3) / 4) * 3);
if (bytes == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (YES)
{
char buffer[4];
short bufferLength;
for (bufferLength = 0; bufferLength < 4; i++)
{
if (characters[i] == '\0')
break;
if (isspace(characters[i]) || characters[i] == '=')
continue;
buffer[bufferLength] = decodingTable[(short)characters[i]];
if (buffer[bufferLength++] == CHAR_MAX) // Illegal character!
{
free(bytes);
return nil;
}
}
if (bufferLength == 0)
break;
if (bufferLength == 1) // At least two characters are needed to produce one byte!
{
free(bytes);
return nil;
}
// Decode the characters in the buffer to bytes.
bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
if (bufferLength > 2)
bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
if (bufferLength > 3)
bytes[length++] = (buffer[2] << 6) | buffer[3];
}
realloc(bytes, length);
return [NSData dataWithBytesNoCopy:bytes length:length];
}
- (NSString *)base64Encoding;
{
if ([self length] == 0)
return #"";
char *characters = malloc((([self length] + 2) / 3) * 4);
if (characters == NULL)
return nil;
NSUInteger length = 0;
NSUInteger i = 0;
while (i < [self length])
{
char buffer[3] = {0,0,0};
short bufferLength = 0;
while (bufferLength < 3 && i < [self length])
buffer[bufferLength++] = ((char *)[self bytes])[i++];
// Encode the bytes in the buffer to four characters, including padding "=" characters if necessary.
characters[length++] = encodingTable[(buffer[0] & 0xFC) >> 2];
characters[length++] = encodingTable[((buffer[0] & 0x03) << 4) | ((buffer[1] & 0xF0) >> 4)];
if (bufferLength > 1)
characters[length++] = encodingTable[((buffer[1] & 0x0F) << 2) | ((buffer[2] & 0xC0) >> 6)];
else characters[length++] = '=';
if (bufferLength > 2)
characters[length++] = encodingTable[buffer[2] & 0x3F];
else characters[length++] = '=';
}
return [[[NSString alloc] initWithBytesNoCopy:characters length:length encoding:NSASCIIStringEncoding freeWhenDone:YES] autorelease];
}
#end
I have the next problem with this code:
NSDictionary * imagen = [[NSDictionary alloc] initWithDictionary:[envio resultValue]];
NSString *imagenS = [imagen valueForKey:#"/Result"];
[Base64 initialize];
NSData * imagenDecode = [Base64 decode:imagenS];
NSLog(#"%#", [imagenS length]);
//SAVE IMAGE
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *docDirectory = [sysPaths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#david.png",docDirectory];
[imagenDecode writeToFile:filePath atomically:YES];
[envio resultValue] --> return a NSDictionary with one image in Base 64 codification.
I want decoder and save this image but in my console I have showed this message:
2011-08-23 20:15:36.539 WSStub[39226:a0f] -[NSCFDictionary length]: unrecognized selector sent to instance 0xd00ee0
The Base 64 code is:
//
// Base64.m
// CryptTest
//
// Created by Kiichi Takeuchi on 4/20/10.
// Copyright 2010 ObjectGraph LLC. All rights reserved.
//
#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;
}
}
}
+ (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
The line
NSString *imagenS = [imagen valueForKey:#"/Result"];
is returning a dictionary, not a string. You'll have to inspect your data source to determine whether this is correct or not.
Your NSLog() call is wrong. To show a length, it should be:
NSLog(#"%lu", [imagenS length]);
But that is probably not the problem.
You seem to be invoking length on an NSDictionary. Hard to tell where you do that, since you don't show the piece of code where that happens. It could be that imagenS is not an NSString, but an NSDictionary instead.
Try to do:
NSLog(#"%#", [imagenS class]);
and see what is displayed. If probably tells you that imagenS is not a string, but an NSCFDictionary or similar instead.
FWIW, NSCFDictionary is one of the subclasses of NSDictionary that actually implement the different versions of the main class. This is called a class cluster.
I have a piece of code in vb. I need to convert array of bytes to base 64 string. Following is the vb code.
If arrLicence.Count > 0 Then
LicenceBytes = CType(Array.CreateInstance(GetType(Byte),6), Byte())
LicenceBytes(0) = Convert.ToByte(arrLicence(0).ToString(), 16)
LicenceBytes(1) = Convert.ToByte(arrLicence(1).ToString(), 16)
LicenceBytes(2) = Convert.ToByte(arrLicence(2).ToString(), 16)
LicenceBytes(3) = Convert.ToByte(arrLicence(3).ToString(), 16)
LicenceBytes(4) = Convert.ToByte(arrLicence(4).ToString(), 16)
LicenceBytes(5) = Convert.ToByte(arrLicence(5).ToString(), 16)
LicenceString = Convert.ToBase64String(LicenceBytes) '6 byteArray - passed by the user - Base64Encoded
I need its equivalent in iphone. I tried with NSData and base64 conversion but result defers.
I have used this link for conversion.
http://www.cocoadev.com/index.pl?BaseSixtyFour
I tried by creating individual bytes using memcpy and then creating an array but with no success.
What I have tried is as follows:
NSData *d1 =[#"64" dataUsingEncoding:NSUTF16StringEncoding];
NSData *d2 = [#"37" dataUsingEncoding:NSUTF16StringEncoding];
NSData *d3 = [#"81" dataUsingEncoding:NSUTF16StringEncoding];
NSData *d4 = [#"d4" dataUsingEncoding:NSUTF16StringEncoding];
unsigned char *buffer = (unsigned char*)malloc(8);
buffer[0] = [d1 bytes] ;
buffer[1] = [d2 bytes] ;
buffer[2] = [d3 bytes] ;
buffer[3] = [d4 bytes] ;
NSData *data = [NSData dataWithBytes:buffer length:4];
NSString *str = [self encodeBase64WithData:data];
free(buffer);
This results in IJCgkA== while code in .NET returns ZDeB1A==
Please note that the conversion is for first four bytes of arrLicence and the input is 64, 37, 81, d4
Try this one, i hope this will surely help you.
get-base64-nsstring-from-nsdata
unsigned char *buffer = (unsigned char*)malloc(8);
buffer[0] = [d1 bytes] ;
buffer[1] = [d2 bytes] ;
buffer[2] = [d3 bytes] ;
buffer[3] = [d4 bytes] ;
Not sure what you expect this to do. bytes return an array, and you are assigning the addresses of the arrays to char elements of your buffer. This buffer won't be filled with any of the data you expect, and the "data" from d2 will partially overwrite those from d1 etc.
Also, you shouldn't make much assumptions about the lengths of your byte arrays, especially not if using UTF-16.
In a word: You don't throw the data you expect at your conversion routine. Maybe check that in the debugger.
See code sample, Very self-explained ...
http://www.cocoadev.com/index.pl?BaseSixtyFour
Also check below SO post .
How do I do base64 encoding on iphone-sdk?
//strBusiCode = #"64-37-81-d4-39-6d";
NSArray *tmp_arr = [strBusiCode componentsSeparatedByString:#"-"];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [tmp_arr count]; i++) {
byte_chars[0] = [[tmp_arr objectAtIndex:i] characterAtIndex:0];
byte_chars[1] = [[tmp_arr objectAtIndex:i] characterAtIndex:1];
whole_byte = strtol(byte_chars, NULL, 16);
[commandToSend appendBytes:&whole_byte length:1];
}
return commandToSend;
This commandToSend is then converted to base64 data.
If you look at the 2 last numbers you give as example, you will notice conversion match. Because the hi and low parts are the same.
Just swap the hi and low words.
You can use this base64.h and base64.m class to decode to base64 string.
base64.h
#import <Foundation/Foundation.h>
#interface NSData (Base64)
+ (NSData *)dataWithBase64EncodedString:(NSString *)string;
- (id)initWithBase64EncodedString:(NSString *)string;
- (NSString *) base64Encoding;
- (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength;
#end
base64.m
#import "base64.h"
static char encodingTable[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' };
#implementation NSData (VQBase64)
- (id)initWithString:(NSString *)string {
if (self = [super init]) {
[self initWithBase64EncodedString:string];
}
return self;
}
+ (NSData *) dataWithBase64EncodedString:(NSString *) string {
return [[[NSData allocWithZone:nil] initWithBase64EncodedString:string] autorelease];
}
- (id) initWithBase64EncodedString:(NSString *) string {
NSMutableData *mutableData = nil;
if( string ) {
unsigned long ixtext = 0;
unsigned long lentext = 0;
unsigned char ch = 0;
unsigned char inbuf[4], outbuf[3];
short i = 0, ixinbuf = 0;
BOOL flignore = NO;
BOOL flendtext = NO;
NSData *base64Data = nil;
const unsigned char *base64Bytes = nil;
// Convert the string to ASCII data.
base64Data = [string dataUsingEncoding:NSASCIIStringEncoding];
base64Bytes = [base64Data bytes];
mutableData = [NSMutableData dataWithCapacity:[base64Data length]];
lentext = [base64Data length];
while( YES ) {
if( ixtext >= lentext ) break;
ch = base64Bytes[ixtext++];
flignore = NO;
if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A';
else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26;
else if( ( ch >= '0' ) && ( ch <= '9' ) ) ch = ch - '0' + 52;
else if( ch == '+' ) ch = 62;
else if( ch == '=' ) flendtext = YES;
else if( ch == '/' ) ch = 63;
else flignore = YES;
if( ! flignore ) {
short ctcharsinbuf = 3;
BOOL flbreak = NO;
if( flendtext ) {
if( ! ixinbuf ) break;
if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1;
else ctcharsinbuf = 2;
ixinbuf = 3;
flbreak = YES;
}
inbuf [ixinbuf++] = ch;
if( ixinbuf == 4 ) {
ixinbuf = 0;
outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 );
outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 );
outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F );
for( i = 0; i < ctcharsinbuf; i++ )
[mutableData appendBytes:&outbuf[i] length:1];
}
if( flbreak ) break;
}
}
}
self = [self initWithData:mutableData];
return self;
}
- (NSString *) base64Encoding {
return [self base64EncodingWithLineLength:0];
}
- (NSString *) base64EncodingWithLineLength:(unsigned int) lineLength {
const unsigned char *bytes = [self bytes];
NSMutableString *result = [NSMutableString stringWithCapacity:[self length]];
unsigned long ixtext = 0;
unsigned long lentext = [self length];
long ctremaining = 0;
unsigned char inbuf[3], outbuf[4];
unsigned short i = 0;
unsigned short charsonline = 0, ctcopy = 0;
unsigned long ix = 0;
while( YES ) {
ctremaining = lentext - ixtext;
if( ctremaining <= 0 ) break;
for( i = 0; i < 3; i++ ) {
ix = ixtext + i;
if( ix < lentext ) inbuf[i] = bytes[ix];
else inbuf [i] = 0;
}
outbuf [0] = (inbuf [0] & 0xFC) >> 2;
outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
outbuf [3] = inbuf [2] & 0x3F;
ctcopy = 4;
switch( ctremaining ) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for( i = 0; i < ctcopy; i++ )
[result appendFormat:#"%c", encodingTable[outbuf[i]]];
for( i = ctcopy; i < 4; i++ )
[result appendString:#"="];
ixtext += 3;
charsonline += 4;
if( lineLength > 0 ) {
if( charsonline >= lineLength ) {
charsonline = 0;
[result appendString:#"\n"];
}
}
}
return [NSString stringWithString:result];
}
#end
Please check and let me know if any issue.
my convert code is all i have, but it converts a string to sha-1 to hex format. how can i convert sha-1 to base64 ?
-(NSString *)digest:(NSString*)input
int i;
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, data.length, digest);
output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
length:CC_SHA1_DIGEST_LENGTH];
for(i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
{
[output appendFormat:#"%02x", digest[i]];
}
return output;
}
There's no built-in hashing or Base64 in iOS. You'll have to roll your own. Find a C implementation of SHA1 in Google; as for Base64, I've got one for you:
NSString *ToBase64(NSData *d)
{
static const char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const NSString *PAD1 = #"=", *PAD2 = #"==";
int l = [d length];
unsigned char *p = (unsigned char*)[d bytes];
unichar Chunk[4];
NSMutableString *s = [NSMutableString stringWithCapacity:(l+3)*4/3];
int i;
int mod = l % 3;
int ll = l - mod;
unsigned int triad;
NSString *sChunk;
for(i=0;i<ll;i+=3)
{
triad = (p[i]<<16) | (p[i+1]<<8) | p[i+2];
Chunk[0] = ALPHABET[(triad >> 18) & 0x3f];
Chunk[1] = ALPHABET[(triad >> 12) & 0x3f];
Chunk[2] = ALPHABET[(triad >> 6) & 0x3f];
Chunk[3] = ALPHABET[triad & 0x3f];
sChunk = [[NSString alloc] initWithCharacters:Chunk length:4];
[s appendString:sChunk];
[sChunk release];
}
if(mod == 1)
{
Chunk[0] = ALPHABET[(p[i] >> 2) & 0x3f];
Chunk[1] = ALPHABET[(p[i] << 4) & 0x3f];
sChunk = [[NSString alloc] initWithCharacters:Chunk length:2];
[s appendString:sChunk];
[sChunk release];
[s appendString: PAD2];
}
if(mod == 2)
{
triad = (p[i]<<8) | p[i+1];
Chunk[0] = ALPHABET[(triad >> 10) & 0x3f];
Chunk[1] = ALPHABET[(triad >> 4) & 0x3f];
Chunk[2] = ALPHABET[(triad << 2) & 0x3f];
sChunk = [[NSString alloc] initWithCharacters:Chunk length:3];
[s appendString:sChunk];
[sChunk release];
[s appendString: PAD1];
}
return s;
}