Convert one NSArray filled with NSStrings to a UTF8String vector - objective-c

So I was wondering, is there some quick way of converting one NSArray filled with NSStrings to the equivalent UTF8string values?
I want to store some parameter configuration in a NSArray and then use them in a function that takes (int argv, const char *argv[]) as arguments.
I implemented this in a convoluted way
int argc = [gameParameters count];
const char **argv = (const char **)malloc(sizeof(const char*)*argc);
for (int i = 0; i < argc; i++) {
argv[i] = (const char *)malloc(sizeof(char)*[[gameParameters objectAtIndex:i] length]+1);
strncpy((void *)argv[i], [[gameParameters objectAtIndex:i] UTF8String], [[gameParameters objectAtIndex:i] length]+1);
}
but I'm not really happy with and cleaning up memory is tedious.
Do you know a better way to achieve this result?

Your current implementation is not correct if the string contains non-ASCII characters. For example, the string #"é" (SMALL LETTER E WITH ACUTE) has length 1, but the UTF-8 sequence "C3 A9" has 2 bytes. Your code would not allocate enough memory for that string.
(In other words: [string length] returns the number of Unicode characters in the string, not the number of bytes of the UTF-8 representation.)
Using strdup(), as suggested by Kevin Ballard, would solve this problem:
argv[i] = strdup([[gameParameters objectAtIndex:i] UTF8String]);
But you should also check if duplicating the strings is necessary at all. If you call the function in the current autorelease context, the following would be sufficient:
int argc = [gameParameters count];
const char **argv = (const char **)malloc(sizeof(const char*)*argc);
for (int i = 0; i < argc; i++) {
argv[i] = [[gameParameters objectAtIndex:i] UTF8String];
}
yourFunction(argc, argv);
free(argv);

Related

Converting NSString to char byte array

In my program, I receive a NSString like this one : AA010158AA7D385002. And I need to pass it to a method which accept a char byte array, as below :
char[9] = {0xAA, 0x01, 0x01, 0x58, 0xAA, 0x7D, 0x38, 0x50, 0x02};
How to convert my NSString to char byte array like this one?
Thanks!
NSString *strCharData = #"AA010158AA7D385002";
const char *characterRes = [strCharData cStringUsingEncoding:NSUTF8StringEncoding];
or
NSString *strCharData = #"AA010158AA7D385002";
const char *characterRes = [strCharData UTF8String];
Use this answer if i am correct,i did little coding but might be there are possibilities of simpler solutions also like #user3182143
NSString * inputStr = #"AA010158AA7D385002";
NSMutableArray *charByteArray = [[NSMutableArray alloc]initWithCapacity:1];
int i = 0;
for (i = 0; i+2 <= inputStr.length; i+=2) {
NSRange range = NSMakeRange(i, 2);
NSString* charStr = [inputStr substringWithRange:range];
[charByteArray addObject:[NSString stringWithFormat:#"0x%#",charStr]];
}
Output :
char[9] = (
0xAA,
0x01,
0x01,
0x58,
0xAA,
0x7D,
0x38,
0x50,
0x02
)
Since your text is hex and you want actual bytes out (which each correspond to two hex characters), you'll have to manually convert each character into the corresponding number, and then add them together into the correct numerical value.
To do this, I'm taking advantage of the fact that, in ASCII characters, a...z are in a row, as are 0...9. I'm also taking advantage of the fact that hexadecimal is valid ASCII, and that Unicode characters from 0...127 are identical to their corresponding ASCII characters.
Below is a program that does this and prints out the original string's characters as well as the calculated bytes (as hex again):
#import <Foundation/Foundation.h>
int main(int argc, char *argv[])
{
#autoreleasepool
{
NSString *hexStr = #"1234567890abcdef12";
unsigned char theBytes[9] = {};
for( NSUInteger x = 0; x < sizeof(theBytes); x++ )
{
unsigned char digitOne = [hexStr characterAtIndex: x * 2];
if( digitOne >= 'a' )
digitOne -= 'a' -10;
else
digitOne -= '0';
unsigned char digitTwo = [hexStr characterAtIndex: (x * 2) +1];
if( digitTwo >= 'a' )
digitTwo -= 'a' -10;
else
digitTwo -= '0';
printf("%01x%01x",digitOne,digitTwo);
theBytes[x] = (digitOne << 4) | digitTwo;
}
printf("\n");
for( int x = 0; x < sizeof(theBytes); x++ )
printf("%02x",theBytes[x]);
printf("\n");
}
}
Note: This code naïvely assumes that you are providing a correct string. I.e. your input has to consist of lowercase characters and numbers only, and exactly 18 characters. Anything else and you get a wrong result or an exception.
I finally managed to find the answer to my own question. I am posting it here in case it helps someone else.
So I use a method to convert an NSString hex to bytes :
#implementation NSString (HexToBytes)
- (NSData *)hexToBytes
{
NSMutableData *data = [NSMutableData data];
int idx;
for (idx = 0; idx + 2 <= self.length; idx += 2) {
NSRange range = NSMakeRange(idx, 2);
NSString *hexStr = [self substringWithRange:range];
NSScanner *scanner = [NSScanner scannerWithString:hexStr];
unsigned int intValue;
[scanner scanHexInt:&intValue];
[data appendBytes:&intValue length:1];
}
return data;
}
#end
And then, I simply use it like that :
NSString *str = #"AA010158AA7D385002";
NSData *databytes = [str hexToBytes];
char *bytePtr = (char *)[databytes bytes];
And I finally get my char array. Hope it helps someone else.

How to parse out each Chinese character?

Given a sentence composing of X number of Chinese characters. I want to parse each character out in Objective-C or C++.
I tried:
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++)
{
char current = [nsText characterAtIndex:i];
printf("%i: %c\n", i, current);
}
But I'm not getting the right characters, I got index 0 = ', index 1 = }, etc. The length is returned correctly, which equals 3. I need UTF8 encoding to display it to the UI.
Any tips will be helpful.
Thank you
Three things wrong. First, characterAtIndex: returns a unichar, which is bigger than the char to which you're assigning. You're losing information there. Second, %c is the format specifier for printing an ASCII value (8 bits). You want %C (uppercase 'C') to print a 16-bit unichar. Finally, printf() doesn't seem to accept %C, so you need to use NSLog() instead. Rewritten, then, we have:
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++)
{
unichar current = [nsText characterAtIndex:i];
NSLog(#"%i: %C\n", i, current);
}
Can this solve your problem?
NSString * nsText = [NSString stringWithFormat:#"你好吗"];
for (int i = 0; i < [nsText length]; i++) {
NSString *str = [nsText substringToIndex:i+1];
NSString *str2 =[str substringFromIndex:i];
NSLog(#"%#",str2);
}

Convert NSString to C string, increment and come back to NSString

I'm trying to develop a simple application where i can encrypt a message. The algorithm is Caesar's algorithm and for example, for 'Hello World' it prints 'KHOOR ZRUOG' if the increment is 3 (standard).
My problem is how to take each single character and increment it...
I've tried this:
NSString *text = #"hello";
int q, increment = 3;
NSString *string;
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String] + increment;
NSLog(#"%#", [NSString stringWithUTF8String:c]);
}
very simple but it doesn't work.. My theory was: take each single character, transform into c string and increment it, then return to NSString and print it, but xcode print nothing, also if i print the char 'c' i can't see the result in console. Where is the problem?
First of all, incrementing byte by byte only works for ASCII strings. If you use UTF-8, you will get garbage for glyphs that have multi-byte representations.
With that in mind, this should work (and work faster than characterAtIndex: and similar methods):
NSString *foo = #"FOOBAR";
int increment = 3;
NSUInteger bufferSize = [foo length] + 1;
char *buffer = (char *)calloc(bufferSize, sizeof(char));
if ([foo getCString:buffer maxLength:bufferSize encoding:NSASCIIStringEncoding]) {
int bufferLen = strlen(buffer);
for (int i = 0; i < bufferLen; i++) {
buffer[i] += increment;
if (buffer[i] > 'Z') {
buffer[i] -= 26;
}
}
NSString *encoded = [NSString stringWithCString:buffer
encoding:NSASCIIStringEncoding];
}
free(buffer);
first of all replace your code with this:
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String];
NSLog(#"Addr: 0x%X", c);
c = c + increment;
NSLog(#"Addr: 0x%X", c);
NSLog(#"%#", [NSString stringWithUTF8String:c]);
}
Now you can figure out your problem. const char *c is a pointer. A pointer saves a memory address.
When I run this code the first log output is this:
Addr: 0x711DD10
that means the char 'h' from the NSString named string with the value #"h" is saved at address 0x711DD10 in memory.
Now we increment this address by 3. Next output is this:
Addr: 0x711DD13
In my case at this address there is a '0x00'. But it doesn't matter what is actually there because a 'k' won't be there (unless you are very lucky).
If you are happy there is a 0x00 too. Because then nothing bad will happen. If you are unlucky there is something else. If there is something other than 0x00 (or the string delimiter or "end of string") NSString will try to convert it. It might crash while trying this, or it might open a huge security hole.
so instead of manipulating pointers you have to manipulate the values where they point to.
You can do this like this:
for (q = 0; q < [text length]; q++) {
string = [text substringWithRange:NSMakeRange(q, 1)];
const char *c = [string UTF8String]; // get the pointer
char character = *c; // get the character from this pointer address
character = character + 3; // add 3 to the letter
char cString[2] = {0, 0}; // create a cstring with length of 1. The second char is \0, the delimiter (the "end marker") of the string
cString[0] = character; // assign our changed character to the first character of the cstring
NSLog(#"%#", [NSString stringWithUTF8String:cString]); // profit...
}

How to make the fowling data conversion: NSArray to char

Well I'm currently calling a method that requires one char input method, but I the data for it is loaded from a file than putted into an array and then I want to convert one of the array's elements to an const char (all the array's elements are URL's). What basically I'm trying to do is to make the program to load a specific file and then put the lines separately into the array's elements (I mean: 1 line = 1 new array element), and then I made a for loop like this:
NSUInteger nElements = [array count];
int i;
for (i = 0; i<nElements; i++) {
const char* urlName = [[array objectAtIndex:i] cStringUsingEncoding:NSUTF8StringEncoding]; // I don't know if this is correct but don't works :)
}
If it's an array of NSURL objects you'd have to convert them to strings like this:
const char* urlName = [[[array objectAtIndex:i] absoluteString] UTF8String];
Assuming it's an array of NSString, you could do this:
const char* urlName = [[array objectAtIndex:i] UTF8String];

How do I convert NSString with Hexvalue to binary char*?

I have a long hex value stored as a NSString, something like:
c12761787e93534f6c443be73be31312cbe343816c062a278f3818cb8363c701
How do I convert it back into a binary value stored as a char*
This is a little sloppy, but should get you on the right track:
NSString *hexString = #"c12761787e93534f6c443be73be31312cbe343816c062a278f3818cb8363c701";
char binChars[128]; // I'm being sloppy and just making some room
const char *hexChars = [hexString UTF8String];
NSUInteger hexLen = strlen(hexChars);
const char *nextHex = hexChars;
char *nextChar = binChars;
for (NSUInteger i = 0; i < hexLen - 1; i++)
{
sscanf(nextHex, "%2x", nextChar);
nextHex += 2;
nextChar++;
}
There was a thread on this (or on a very similar) hexadecimal conversion topic a couple of weeks back over on one of the Cocoa mailing lists.
I can't reasonably reproduce the full discussion here (long thread), but the message that starts off the thread is here:
http://www.cocoabuilder.com/archive/message/cocoa/2009/5/9/236391
I do wish there were a Cocoa method for this task, but (pending finding that or pending its implementation) the code (by Mr Gecko, posted at http://www.cocoabuilder.com/archive/message/cocoa/2009/5/10/236424) looks like it would work here.
static NSString* hexval(NSData *data) {
NSMutableString *hex = [NSMutableString string];
unsigned char *bytes = (unsigned char *)[data bytes];
char temp[3];
int i = 0;
for (i = 0; i < [data length]; i++) {
temp[0] = temp[1] = temp[2] = 0;
(void)sprintf(temp, "%02x", bytes[i]);
[hex appendString:[NSString stringWithUTF8String: temp]];
}
return hex;
}