How would I go about appending this binary string
111000111000111111000111000111
to an NSMutableData object that contains a png
(NSMutableData *dataForPNGFile = UIImagePNGRepresentation(p.Image);)
You'd need to parse the string into an NSData, then append that.
I'm not aware of anything built in, so e.g.
NSMutableData *data = [NSMutableData dataWithLength(string.length+7)/8];
uint8_t *mutableBytes = (uint8_t *)data.mutableBytes;
for(NSUinteger index = 0; index < string.length; index++)
{
unichar character = [string characterAtIndex:index];
mutableBytes[index >> 3] <<= 1;
if(character == '1') mutableBytes[index >> 3] |= 1;
}
if(string.length&7)
mutableBytes[string.length >> 3] <<= (7 - (string.length&7));
So assumptions are that your source string is only 1s and 0s, that it's written from most significant to least significant digit and that it's byte rather than word oriented.
Also, UIImagePNGRepresentation returns immutable data so you'll need to take a mutable copy of that.
Look at the NSMuteableData method appendBytes:length:
You will have to convert your bits to bytes as #Tommy says.
Related
I have an Uint8List data list, for example:
Uint8List uintList = Uint8List.fromList([10, 1]);
How can I convert these numbers to a decimal number?
int decimalValue = ??? // in this case 265
Mees' answer is the correct general method, and it's good to understand how to do bitwise operations manually.
However, Dart does have a ByteData class that has various functions to help parse byte data for you (e.g. getInt16, getUint16). In your case, you can do:
Uint8List uintList = Uint8List.fromList([10, 1]);
int decimalValue = ByteData.view(uintList.buffer).getInt16(0, Endian.little);
print(decimalValue); // Prints: 266.
From what I understand of your question, you want decimalValue to be an integer where the least significant byte is (decimal)10, and the byte after that to be 1. This would result in the value 1 * 256 + 10 = 266. If you meant the bytes the other way around, it would be 10 * 256 + 1 = 2560 + 1 = 2561.
I don't actually have any experience with dart, but I assume code similar to this would work:
int decimalValue = 0;
for (int i = 0; i < uintList.length; i++) {
decimalValue = decimalValue << 8; // shift everything one byte to the left
decimalValue = decimalValue | uintList[i]; // bitwise or operation
}
If it doesn't produce the number you want it to, you might have to iterate through the loop backwards instead, which requires changing one line of code:
for (int i = uintList.length-1; i >= 0; i--) {
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 #"";
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I am working on a app which sends data to server with user location info. Server accept this data based on checksum calculation, which is written in java.
Here is the code written in Java:
private static final String CHECKSUM_CONS = "1217278743473774374";
private static String createChecksum(double lat, double lon) {
int latLon = (int) ((lat + lon) * 1E6);
String checkSumStr = CHECKSUM_CONS + latLon;
byte buffer[] = checkSumStr.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
CheckedInputStream cis = new CheckedInputStream(bais, new Adler32());
byte readBuffer[] = new byte[50];
long value = 0;
try {
while (cis.read(readBuffer) >= 0) {
value = cis.getChecksum().getValue();
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
return String.valueOf(value);
}
I tried looking for help to find out how to write objective c equivalent of this. Above function uses adler32 and I don't have any clue about that. Please help.
Thanks for your time.
The answers shown here by #achievelimitless and #user3275097 are incorrect.
First off, signed integers should not be used. The modulo operator on negative numbers is defined differently in different languages, and should be avoided when possible. Simply use unsigned integers instead.
Second, the loops will quickly overflow the 16-bit accumulators, which will give the wrong answer. The modulo operations can be deferred, but they must be done before overflow. You can calculate how many loops you can do safely by assuming that all of the input bytes are 255.
Third, because of the second point, you should not use 16-bit types. You should use at least 32-bit types to avoid having to do the modulo operation very often. You still need to limit the number of loops, but the number gets much bigger. For 32-bit unsigned types, the maximum number of loops is 5552. So the basic code looks like:
#define MOD 65521
#define MAX 5552
unsigned long adler32(unsigned char *buf, size_t len)
{
unsigned long a = 1, b = 0;
size_t n;
while (len) {
n = len > MAX ? MAX : len;
len -= n;
do {
a += *buf++;
b += a;
} while (--n);
a %= MOD;
b %= MOD;
}
return a | (b << 16);
}
As noted by #Sulthan, you should simply use the adler32() function provided in zlib, which is already there on Mac OS X and iOS.
On basis of definition of adler32 checksum as mentioned in wikipedia,
Objective C implementation would be like this:
static NSNumber * adlerChecksumof(NSString *str)
{
NSMutableData *data= [[NSMutableData alloc]init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
for (int i = 0; i < ([str length] / 2); i++)
{
byte_chars[0] = [str characterAtIndex:i*2];
byte_chars[1] = [str characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[data appendBytes:&whole_byte length:1];
}
int16_t a=1;
int16_t b=0;
Byte * dataBytes= (Byte *)[data bytes];
for (int i=0; i<[data length]; i++)
{
a+= dataBytes[i];
b+=a;
}
a%= 65521;
b%= 65521;
int32_t adlerChecksum= b*65536+a;
return #(adlerChecksum);
}
Here str would be your string as mentioned in your question..
So when you want to calculate checksum of some string just do this:
NSNumber * calculatedChkSm= adlerChecksumof(#"1217278743473774374");
Please Let me know if more info needed
I'm translating a small Java library for using in an Objective-C application I'm writing.
char[] chars = sentence.toCharArray();
int i = 0;
while (i < chars.length) { ... }
Where sentence is an NSString.
I'd like to translate the above Java code to Objective-C. Here's what I have so far:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
const char *chars = [sentence UTF8String];
How do I the above while condition? I'm not sure of how I'm supposed to check the length of the the string after it was converted to a character array.
Your Objective-C string already holds a measure of its length, it's just a matter of retrieving it:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSUInteger length = sentence.length;
const char *chars = [sentence UTF8String];
But I would like to remember that even if you didn't know the length, you could use the C strlen function:
// trims sentence off white space
sentence = [sentence stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
const char *chars = [sentence UTF8String];
size_t length = strlen(chars);
Even there is already an accepted answer I want to warn of using strlen(), even in this case it might be without any problem. There are a differences between NSString and C-Strings.
A. -length (NSString) and strlen() has different semantics:
NSString is not(!) \0-terminated, but length based. It can store \0 characters. It is very easy to get different length, if there is a \0 character in the string instance:
NSString *sentence = #"Amin\0Negm";
NSLog( #"length %ld", [sentence length]); // 9
const char *chars = [sentence cStringUsingEncoding:NSUTF8StringEncoding];
size_t length= strlen(chars);
NSLog(#"strlen %ld", (long)length); // 4
length 9
strlen 4
But -UTF8String and even the used -cStringUsingEnocding: (both NSString) copy out the whole string stored in the string instance. (I think in case of -cStringUsingEncoding it is misleading, because standard string functions like strlen() always uses the first \0 as the termination of strings.)
B. In UTF8 a character can have multibytes. A char in C is one byte. (With byte not in the meaning of 8 bits, but smallest addressable unit.)
NSString *sentence = #"Αmin Negm";
NSLog( #"length %ld", [sentence length]);
const char *chars = [sentence UTF8String];
size_t length= strlen(chars);
NSLog(#"strlen %ld", (long)length);
length 9
strlen 10
WTF happened here? The "A" of Amin is no latin capital letter A but a greek capital letter Alpha. In UTF8 this takes two bytes and for pure C's strlen there are two characters!
NSLog(#"%x-%x %x-%x", 'A', 'm', (unsigned char)*chars, (unsigned char)*(chars+1) );
41-6d ce-91
The first two numbers are the codes for 'A', 'm', the second two numbers are the UTF8 code for greek capital letter Alpha (CE 91).
I do not think, that it is a good idea to simply change from NSString to char * without good reason and a complete understanding of the problems. If you do not expect such characters, use NSASCIIStringEncoding. If you expect such characters check your code again and again … or read C.
C. C supports wide characters. This is similiar to Mac OS' unichar, but typed wchar_t. There are string functions for wchar_t in wchar.h.
NSString *sentence = #"Αmin Negm";
NSLog( #"length %ld", [sentence length]);
wchar_t wchars[128]; // take care of the size
wchar_t *wchar = wchars;
for (NSUInteger index = 0; index < [sentence length]; index++)
{
*wchar++ = [sentence characterAtIndex:index];
}
*wchar = '\0';
NSLog(#"widestrlen %ld", wcslen(wchars));
length 9
widestrlen 9
D. Obviously you want to iterate through the string. The common pattern in pure C is not to use an index and to compare it to the length and definitly not to to strlen() in every loop, because it produces high costs. (C strings are not length based so the whole string has to be scanned over and over.) You simply increment the pointer to the next char:
char letter;
while ( (letter = *chars++) ) {…}
or
do
{
// *chars points to the actual char
} while (*char++);
int lenght = sizeof(chars) / sizeof(char)
might work, but it will (inte the best case) return same thing as
sentence.lenght
in worst case 0 because the whole pointer / sizeof thing i don't remember now
I convert an image to NSData and NSData to base64string using
NSData *imagedata = UIImageJPEGRepresentation(imageView.image, 0.1f);
NSString *c = [NSString base64StringFromData:imagedata];
the fn for stringconversion
+ (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];
}
but the resulted base64string is too long, its length is above 300000.
ie,
int len = c.length;
value of len is above 300000.
the image is of 3 to 4 mb
infact I compress the image to 0.1f
NSData *imagedata = UIImageJPEGRepresentation(iivv.image, 0.1f);
how to minimize the length, is there any other code for base64conversion from NSData?
Base64 will always have larger space requirements than the original data, because it does not use all the bits in one byte. This is done intentionally in order to make sure that higher bits do not cause problems when being handed from one system to another. So in effect it trades space for transmission safety.
It is called Base64 because it only uses 6 bits (2^6=64) for each byte, therefore effectively taking up 5 bytes where the original data only had 4. Or put another way: size will increase by 25%.
The Base64 encoder of course does not care about what the bytes you feed into it represent, so you are free to compress the heck out of your data, as long as it is still in its own format (e. g. create a PNG or JPG out of uncompressed image data) and then encode that as Base64.