I have a UIImage and I want to encode it using base 64. I then send the string to our server.
Our server decodes it using btoa(). It can't do so properly.
After debugging, we found out that the result of encoding/decoding using btoa()/atob() does not match NSData's base64EncodedStringWithOptions when I convert from UIImage to NSData and then encode.
What's weird is they do match when I read the UIImage directly as NSData using dataWithContentsOfFile: instead of converting from UIImage to NSData using UIImagePNGRepresentation()
My problem is that I'm supposed to use an imagepicker that returns a UIImage. I don't want to write the image to file and then read it directly as NSData. it's not efficient. Is there a way to solve this?
Try this for base64 encoding:
+ (NSString*)base64forData:(NSData*)theData
{
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] ;
}
I would like to extract all the bits in the following bits from NSData byte :
status Data byte : <0011...
Result turns all are 0000 0000 0000 0000 . Could you please tell me how to ?
NSData *aData = [valueData subdataWithRange:NSMakeRange(0, 2)]; //16 bit status
status= [self bitsToInt:aData];
NSString *aString = [NSString stringWithFormat:#"%d", status];
int value = [aString intValue];
NSlog(#"sadasd value : ,%d" ,value );
unsigned thbit0 = (1 << 0) & value;
unsigned thbit1 = (1 << 1) & value;
unsigned thbit2 = (1 << 2) & value;
unsigned thbit3 = (1 << 3) & value;
unsigned thbit4 = (1 << 4) & value;
unsigned thbit5 = (1 << 5) & value;
unsigned thbit6 = (1 << 6) & value;
unsigned thbit7 = (1 << 7) & value;
unsigned thbit8 = (1 << 8) & value;
unsigned thbit9 = (1 << 9) & value;
unsigned thbit10 = (1 << 10) & value;
unsigned thbit11= (1 << 11) & value;
unsigned thbit12 = (1 << 12) & value;
..
- (int) bitsToInt : (NSData *) valueDa {
uint8_t * bytePtr = (uint8_t * )[valueDa bytes];
int high = bytePtr[1] >= 0 ? bytePtr[1] : 256 + bytePtr[1];
int low = bytePtr[0] >= 0 ? bytePtr[0] : 256 + bytePtr[0];
return low | (high << 8);
}
You could try to work with bit string instead of integer values with additional bit extracting.
Here is simple decoder:
- (NSString *)getBitsFromData:(NSData *)data
{
NSMutableString *result = [NSMutableString string];
const uint8_t *bytes = [data bytes];
for (NSUInteger i = 0; i < data.length; i++)
{
uint8_t byte = bytes[i];
for (int j = 0; j < 8; j++)
{
((byte >> j) & 1) == 0 ? [result appendString:#"0"] : [result appendString:#"1"];
}
}
return result;
}
Test:
NSString *test = #"test";
NSLog(#"%#", [self getBitsFromData:[test dataUsingEncoding:NSUTF8StringEncoding]]);
Result:
2015-07-29 11:37:31.768 Test[18342:9947704] 00101110101001101100111000101110
In Objective C is there a way to convert a multi-byte unicode byte array into an NSString, where it will allow the conversion to succeed even if the array data is a partial buffer (not on a complete character boundary)?
The application of this is when receiving byte buffers in a stream, and you want to parse the string version of the data buffer (but there is more data to come, and your buffer data doesn't have complete multi-byte unicode).
NSString's initWithData:encoding: method does not work for this purpose, as shown here...
Test code:
- (void)test {
char myArray[] = {'f', 'o', 'o', (char) 0xc3, (char) 0x97, 'b', 'a', 'r'};
size_t sizeOfMyArray = sizeof(myArray);
[self dump:myArray sizeOfMyArray:sizeOfMyArray];
[self dump:myArray sizeOfMyArray:sizeOfMyArray - 1];
[self dump:myArray sizeOfMyArray:sizeOfMyArray - 2];
[self dump:myArray sizeOfMyArray:sizeOfMyArray - 3];
[self dump:myArray sizeOfMyArray:sizeOfMyArray - 4];
[self dump:myArray sizeOfMyArray:sizeOfMyArray - 5];
}
- (void)dump:(char[])myArray sizeOfMyArray:(size_t)sourceLength {
NSString *string = [[NSString alloc] initWithData:[NSData dataWithBytes:myArray length:sourceLength] encoding:NSUTF8StringEncoding];
NSLog(#"sourceLength: %lu bytes, string.length: %i bytes, string :'%#'", sourceLength, string.length, string);
}
Output:
sourceLength: 8 bytes, string.length: 7 bytes, string :'foo×bar'
sourceLength: 7 bytes, string.length: 6 bytes, string :'foo×ba'
sourceLength: 6 bytes, string.length: 5 bytes, string :'foo×b'
sourceLength: 5 bytes, string.length: 4 bytes, string :'foo×'
sourceLength: 4 bytes, string.length: 0 bytes, string :'(null)'
sourceLength: 3 bytes, string.length: 3 bytes, string :'foo'
As can be seen, converting the "sourceLength: 4 bytes" byte array fails, and returns (null). This is because the UTF-8 unicode '×' character (0xc3 0x97) is only partially included.
Ideally there would be a function that I can use that would return the correct NString, and tell me how many bytes are "left over".
You largely have your own answer. If the initWithData:dataWithBytes:encoding: method returns nil, then you know the buffer has a partial (invalid) character at the end.
Modify dump to return an int. Then have it attempt to create the NSString in a loop. Each time you get nil, reduce the length and try again. Once you get a valid NSString, return the difference between the used length and the passed length.
I had this problem before and forget it for a while. It was an opportunity to do it. The code below is done with informations from the utf-8 page on wikipedia. It is a category on NSData.
It check the data from the end and only the four last bytes because the OP said that it can be giga byte of data. Otherwise with utf-8 it's simpler to run through the bytes from the beginning.
/*
Return the range of a valid utf-8 encoded text by
removing partial trailing multi-byte char.
It assumes that all the bytes are valid utf-8 encoded char,
e.g. it don't raise a flag if a continuation byte is preceded
by a single char byte.
*/
- (NSRange)rangeOfUTF8WithoutPartialTrailingMultibytes
{
NSRange validRange = {0, 0};
NSUInteger trailLength = MIN([self length], 4U);
unsigned char trail[4];
[self getBytes:&trail
range:NSMakeRange([self length] - trailLength, trailLength)];
unsigned multibyteCount = 0;
for (NSInteger i = trailLength - 1; i >= 0; i--) {
if (isUTF8SingleByte(trail[i])) {
validRange = NSMakeRange(0, [self length] - trailLength + i + 1);
break;
}
if (isUTF8ContinuationByte(trail[i])) {
multibyteCount++;
continue;
}
if (isUTF8StartByte(trail[i])) {
multibyteCount++;
if (multibyteCount == lengthForUTF8StartByte(trail[i])) {
validRange = NSMakeRange(0, [self length] - trailLength + i + multibyteCount);
}
else {
validRange = NSMakeRange(0, [self length] - trailLength + i);
}
break;
}
}
return validRange;
}
Here is the static functions used in the method:
static BOOL isUTF8SingleByte(const unsigned char c)
{
return c <= 0x7f;
}
static BOOL isUTF8ContinuationByte(const unsigned char c)
{
return (c >= 0x80) && (c <= 0xbf);
}
static BOOL isUTF8StartByte(const unsigned char c)
{
return (c >= 0xc2) && (c <= 0xf4);
}
static BOOL isUTF8InvalidByte(const unsigned char c)
{
return (c == 0xc0) || (c == 0xc1) || (c > 0xf4);
}
static unsigned lengthForUTF8StartByte(const unsigned char c)
{
if ((c >= 0xc2) && (c <= 0xdf)) {
return 2;
}
else if ((c >= 0xe0) && (c <= 0xef)) {
return 3;
}
else if ((c >= 0xf0) && (c <= 0xf4)) {
return 4;
}
return 1;
}
Here is my inefficient implementation, which I don't consider to be a correct answer. I'll leave it here in case others find it useful (and in the hope that someone else will give a better answer than this!)
It's in a category on NSMutableData...
/**
* Removes the biggest string possible from this NSMutableData, leaving any remainder unicode half-characters behind.
*
* NOTE: This is a very inefficient implementation, it may require multiple parsing of the complete NSMutableData buffer,
* it is especially inefficient when the data buffer does not contain a valid string encoding, as all lengths will be
* attempted.
*/
- (NSString *)removeMaximumStringUsingEncoding:(NSStringEncoding)encoding {
if (self.length > 0) {
// Quick test for the case where the whole buffer can be used (is common case, and doesn't require NSData manipulation).
NSString *result = [[NSString alloc] initWithData:self encoding:encoding];
if (result != Nil) {
self.length = 0; // Simple case, we used the whole buffer.
return result;
}
// Try to find the largest subData that is a valid string.
for (NSUInteger subDataLength = self.length - 1; subDataLength > 0; subDataLength--) {
NSRange subDataRange = NSMakeRange(0, subDataLength);
result = [[NSString alloc] initWithData:[self subdataWithRange:subDataRange] encoding:encoding];
if (result != Nil) {
// Delete the bytes we used from our buffer, leave the remainder.
[self replaceBytesInRange:subDataRange withBytes:Nil length:0];
return result;
}
}
}
return #"";
}
Just started learning objective-c and was trying to convert a byte array into UTF8 NSString but have been getting nil/null.
Here is the abbreviated code sample.
enum {
TMessageType_CALL = 1,
TMessageType_REPLY = 2,
TMessageType_EXCEPTION = 3,
TMessageType_ONEWAY = 4
};
int32_t VERSION_1 = 0x80010000;
int value = VERSION_1 | TMessageType_CALL;
uint8_t buff[4];
buff[0] = 0xFF & (value >> 24);
buff[1] = 0xFF & (value >> 16);
buff[2] = 0xFF & (value >> 8);
buff[3] = 0xFF & value;
//Convert buff to NSString with offset =0, length =4
I tried the following.
NSString *t = [[NSString alloc] initWithBytes:buff length:4 encoding:NSUTF8StringEncoding];
NSString *t1 = [NSString stringWithUTF8String:(char *)buff];
But both t and t1 return nil.
What is the right API to convert it correctly?
This conversion needs to be generic across WriteI32() writeI64(), writeString(), writeDouble(). Here is the code for the rest.
- (void) writeI16: (short) value
{
uint8_t buff[2];
buff[0] = 0xff & (value >> 8);
buff[1] = 0xff & value;
[mTransport write: buff offset: 0 length: 2];
}
- (void) writeI64: (int64_t) value
{
uint8_t buff[8];
buff[0] = 0xFF & (value >> 56);
buff[1] = 0xFF & (value >> 48);
buff[2] = 0xFF & (value >> 40);
buff[3] = 0xFF & (value >> 32);
buff[4] = 0xFF & (value >> 24);
buff[5] = 0xFF & (value >> 16);
buff[6] = 0xFF & (value >> 8);
buff[7] = 0xFF & value;
[mTransport write: buff offset: 0 length: 8];
}
- (void) writeDouble: (double) value
{
// spit out IEEE 754 bits - FIXME - will this get us in trouble on
// PowerPC?
[self writeI64: *((int64_t *) &value)];
}
- (void) writeString: (NSString *) value
{
if (value != nil) {
const char * utf8Bytes = [value UTF8String];
size_t length = strlen(utf8Bytes);
[self writeI32: length];
[mTransport write: (uint8_t *) utf8Bytes offset: 0 length: length];
} else {
// instead of crashing when we get null, let's write out a zero
// length string
[self writeI32: 0];
}
}
buff is an array of unsigned chars, so you could use this:
NSString *t = [NSString stringWithFormat:#"%s", buff];
As an alternative, you can get each character explicitly:
NSMutableString *t = [NSMutableString stringWithCapacity:4];
for (NSUInteger i = 0; i < 4; ++i)
[t appendFormat:#"%c", buff[i]];
NSLog(#"%#", t);
The first option does a conversion to a valid string. The second option gives you each character, regardless of any terminating characters ('\0').
I'm not sure what useful information this will give you, but there you have it.
I am trying to convert an NSData object that has been encrypted with AES256 encryption to base64 NSData object. I am under the impression that I can not directly convert a NSData object that has been encrypted with AES256 encryption to a NSString, and that I must first convert it to base64.
So how would I convert a NSData object to a base64 data object? And bonus I need to convert the base64 data object to a NSString.
I found this method, but I am not sure how I convert my NSData object to base64 using the method below.
- (NSString*)base64forData:(NSData*)theData {
const uint8_t* input = (const uint8_t*)[theData bytes];
NSInteger length = [theData length];
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t* output = (uint8_t*)data.mutableBytes;
NSInteger i;
for (i=0; i < length; i += 3) {
NSInteger value = 0;
NSInteger j;
for (j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger theIndex = (i / 3) * 4;
output[theIndex + 0] = table[(value >> 18) & 0x3F];
output[theIndex + 1] = table[(value >> 12) & 0x3F];
output[theIndex + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[theIndex + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
The method that you provided in your post should work (cocoadev has relevant discussion).
Here is how you use this method:
NSString *b64 = [self base64forData:myNsData];