NSString * to Char[] (GameCenter Send Struct) - iphone

I want to send a struct to another player in GameCenter.
I have read the other questions about this, however, I cannot get any of them to work.
I need to get #"1234" into a char[4] (ex char[0] = '1', char[1] = '2', etc)
I have tried [NSString UTF8String], but it doesn't seem to do what I want.
It assigns fine, but when I pull it back into NSString * with [NSString stringWithUTF8String:], It returns blank.
If someone could show me the conversion to and from, it would be greatly appreciated.
Thanks.
EDIT:
I can't get it to work :/ Here is my code (the abridged version):
Matchmaker.h
enum { NChars = 4 };
typedef struct {
MessageType messageType;
} Message;
typedef struct {
Message message;
char code[NChars];
} MessageGameCode;
#interface Matchmaker : CCLayer <GameCenterMasterDelegate>{
NSString *_code;
}
#property (nonatomic,retain) NSString *_code;
Matchmaker.m
#synthesize _code;
-(void)viewDidLoad{
self._code = #"1234";
}
- (void)sendCode {
NSLog(#"Sending Code....");
MessageGameCode message;
message.message.messageType = kMessageTypeGameCode;
NSString * const source = self._code;
const char* const sourceAsUTF8 = source.UTF8String;
for (size_t idx = 0; idx < NChars; ++idx) {
message.code[idx] = sourceAsUTF8[idx];
}
NSData *data = [NSData dataWithBytes:&message length:NChars];
[self sendData:data];
}
- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
Message *message = (Message *) [data bytes];
if (message->messageType == kMessageTypeGameCode) {
MessageGameCode *codeMessage = (MessageGameCode *)[data bytes];
self._code = [[NSString alloc] initWithBytes:codeMessage->code length:NChars encoding:NSUTF8StringEncoding];
[self setGameState:kGameStateWaitingForStart];
NSLog(#"Game Code Recieved");
NSLog(#"Recieved Code: %#",self._code); //This always shows self._code as blank
}
}

Your attempt will fail because the cstring which you pass to + [NSString stringWithUTF8String:] is not terminated.
Try this:
NSString * result = [[NSString alloc] initWithBytes:bytes
length:4
encoding:NSUTF8StringEncoding];
Edit
A more complete demonstration:
enum { NChars = 4 };
/* requires error checking */
void transmit() {
NSString * const source = #"1234";
char tmp[NChars] = { 0 };
const char* const sourceAsUTF8 = source.UTF8String;
for (size_t idx = 0; idx < NChars; ++idx) {
tmp[idx] = sourceAsUTF8[idx];
}
/* .. */
}
/* requires error checking */
void receive(const char bytes[NChars]) {
NSString * result = [[NSString alloc] initWithBytes:bytes length:NChars encoding:NSUTF8StringEncoding];
/* ... */
}

One way is
char bytes[4];
NSData* data = [#"1234" dataUsingEncoding: NSUTF8StringEncoding];
if ([data length] <= 4)
{
memcpy(bytes, [data bytes], [data length]);
}
And to go the other way:
NSString* recodedString = [[NSString alloc] initWithBytes: bytes
length: savedLengthFromBefore
encoding: NSUTF8StringEncoding];

There are a couple of possible pitfalls here.
One is that with [NSString UTF8String] "The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.". So, depending on how long you're expecting the value to stick around you may need to copy it (for example, using strcpy)
The other issue is that [NSString UTF8String] and [NSString stringWithUTF8String:] both expect NULL-terminated C strings, so you need a char[5], not a char[4] to hold #"1234".

Related

blowfish algorithm objective c

I have to use Blowfish algorithm in my code for encryption and decryption. After calling the decryption method, blowfishDecrypt, I am getting the value in NSData but it give me always null when I convert it to NSString.
I am using the following code :
-(void)methodCalled
{
syncTime=#"c7c937169084b20c3ff882dcda193a59";
NSData* data = [syncTime dataUsingEncoding:NSUTF8StringEncoding];
NSData* data2 = [#"R=U!LH$O2B#" dataUsingEncoding:NSUTF8StringEncoding];
NSData* dycryptData=[self blowfishDecrypt:data usingKey:data2];
// prints <0eec37b6 2b76c2df cdf72356 0f033ed8 d6bd37dd 5223bf66 5c318ebe 07f3cf71>
NSLog(#"%#",dycryptData);
NSString *dSync=[[NSString alloc] initWithBytes:[dycryptData bytes]
length:[dycryptData length]
encoding:NSUTF8StringEncoding];
// prints (null)
NSLog(#"Sync timeis %#",dSync);
}
-(NSData *)blowfishDecrypt:(NSData *)messageData
usingKey:(NSData *)secretKeyData {
NSMutableData *decryptedData = [messageData mutableCopy];
BLOWFISH_CTX ctx;
Blowfish_Init (&ctx, (unsigned char*)[secretKeyData bytes], [secretKeyData length]);
NSRange aLeftRange, aRightRange;
NSData *aLeftBox, *aRightBox;
unsigned long dl = 0, dr = 0;
for (int i = 0; i< [decryptedData length]; i += 8) { // Divide data into octets...
// …and then into quartets
aLeftRange = NSMakeRange(i, 4);
aRightRange = NSMakeRange(i + 4, 4);
aLeftBox = [decryptedData subdataWithRange:aLeftRange];
aRightBox = [decryptedData subdataWithRange:aRightRange];
// Convert bytes into unsigned long
[aLeftBox getBytes:&dl length:sizeof(unsigned long)];
[aRightBox getBytes:&dr length:sizeof(unsigned long)];
// Decipher
Blowfish_Decrypt(&ctx, &dl, &dr);
// Put bytes back
[decryptedData replaceBytesInRange:aLeftRange withBytes:&dl];
[decryptedData replaceBytesInRange:aRightRange withBytes:&dr];
}
return decryptedData;
}
Blowfish library code can be found eg. here
HINT#1 //general answer
NSString provides an initializer for this purpose. You can see more info using the docs here.
NSString * dSync = [[NSString alloc] initWithData: dycryptData
encoding:NSUTF8StringEncoding];
Assuming you use ARC.
HINT#2 // the answer for this particular question
I tried your code and confirm the above NSString conversion returns null. So why it is not working? dycryptData is stream of bytes represented as hex, so I tried the following and received the desired result:
int dycryptData_len = [dycryptData length];
NSMutableString *dSync_hex = [NSMutableString stringWithCapacity:dycryptData_len*2];
const unsigned char *dycryptData_bytes = [dycryptData bytes];
for (int i = 0; i < dycryptData_len; ++i) {
[dSync_hex appendFormat:#"%02x", dycryptData_bytes[i]];
}
NSLog(#"dSync_hex=%#",dSync_hex);
I can see this result in log output:
dSync_hex=0eec37b62b76c2dfcdf723560f033ed8d6bd37dd5223bf665c318ebe07f3cf71

Correct Length of NSString

I am working on my first iPhone application, in that application I have to calculate the length of NSString, I have tried the available methods and solutions here on SO but for the length is always wrong. For example for a string "test4" NSString.length returns 12 while it should return 5.
I have tried NSString's length property and lengthOfBytesUsingEncoding but both return the same result.
Any help would be appreciated.
EDIT
NSString *string = #"test4";
[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; // returns 12
string.length; // returns 12
Complete Code
+(NSString *)AES256Encrypt:(NSString *)data withKey:(NSString *)rawkey{
rawkey = [NSString stringWithFormat:#"%#%#", #"123456789023456", rawkey];
rawkey = [rawkey substringWithRange:NSMakeRange(0, 32)];
NSData *key = [rawkey dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [key subdataWithRange:NSMakeRange(0, 16)];
const char *bytes = [data cStringUsingEncoding:NSUTF8StringEncoding];
NSLog(#"%d", data.length); // prints 12
data = [self encode:bytes length:data.length];
NSData *rawData = [data dataUsingEncoding:NSUTF8StringEncoding];
CCCryptorStatus status = kCCSuccess;
NSData *encrypted = [rawData dataEncryptedUsingAlgorithm:kCCAlgorithmAES128 key:key initializationVector:iv options:kCCOptionPKCS7Padding error:&status];
NSString *text = [encrypted base64EncodedString];
return text;
}
Thanks
NSString *myString = #"test4";
int i =myString.length;
NSLog(#"Count =%d",i);
which print Count = 5

iOS zip with gzipDeflate

I'm using the NSData+compression.h and the Base64Transcoder.h elements to be able to zip and unzip content.
Basically to unzip the server responses.
The unzip method works perfectly
+ (NSString *) unzip: (NSString*) stringValue{
Byte inputData[[stringValue lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[[stringValue dataUsingEncoding:NSUTF8StringEncoding] getBytes:inputData];
size_t inputDataSize = (size_t)[stringValue length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);
Byte outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64DecodeData(inputData, inputDataSize, outputData, &outputDataSize);
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];
//And now we gunzip:
NSData* result = [theData gzipInflate];//make bigger==gunzip
NSString *temp = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
return temp;
}
But when I try to zip a content, using the simetric way, the gzipDeflate fails, and return an empty or nil value.
This is my zip code
+ (NSData *) zip:(NSData *) theSourceData {
// And now we zip:
NSData *result = [theSourceData gzipDeflate];
Byte inputData[[result length]];
[result getBytes:inputData];
size_t inputDataSize = (size_t)[result length];
size_t outputDataSize = EstimateBas64DecodedDataSize(inputDataSize);
char outputData[outputDataSize];//prepare a Byte[] for the decoded data
Base64EncodeData(inputData, inputDataSize, outputData, &outputDataSize, NO);
NSData *theData = [[NSData alloc] initWithBytes:outputData length:outputDataSize];
return theData;
}
Any suggestions?
Thanks
The problem was on the Base64 encoder.
+ (NSString *) zip:(NSData *) theSourceData {
// And now we zip:
NSData *result = [theSourceData gzipDeflate];
NSString *source = [NSString base64StringFromData:result length:[result length]];
return source;
}
We've integrated the base64StringFromData:length: method to solve it.
Thanks,
Ivan

How to convert an NSString to hex values

I'd like to convert a regular NSString into an NSString with the (what I assume are) ASCII hex values and back.
I need to produce the same output that the Java methods below do, but I can't seem to find a way to do it in Objective-C. I've found some examples in C and C++ but I've had a hard time working them into my code.
Here are the Java methods I'm trying to reproduce:
/**
* Encodes the given string by using the hexadecimal representation of its UTF-8 bytes.
*
* #param s The string to encode.
* #return The encoded string.
*/
public static String utf8HexEncode(String s) {
if (s == null) {
return null;
}
byte[] utf8;
try {
utf8 = s.getBytes(ENCODING_UTF8);
} catch (UnsupportedEncodingException x) {
throw new RuntimeException(x);
}
return String.valueOf(Hex.encodeHex(utf8));
}
/**
* Decodes the given string by using the hexadecimal representation of its UTF-8 bytes.
*
* #param s The string to decode.
* #return The decoded string.
* #throws Exception If an error occurs.
*/
public static String utf8HexDecode(String s) throws Exception {
if (s == null) {
return null;
}
return new String(Hex.decodeHex(s.toCharArray()), ENCODING_UTF8);
}
Update: Thanks to drawnonward's answer here's the method I wrote to create the hex NSStrings. It gives me an "Initialization discards qualifiers from pointer target type" warning on the char declaration line, but it works.
- (NSString *)stringToHex:(NSString *)string
{
char *utf8 = [string UTF8String];
NSMutableString *hex = [NSMutableString string];
while ( *utf8 ) [hex appendFormat:#"%02X" , *utf8++ & 0x00FF];
return [NSString stringWithFormat:#"%#", hex];
}
Haven't had time to write the decoding method yet. When I do, I'll edit this to post it for anyone else interested.
Update2: So the method I posted above actually doesn't output what I'm looking for. Instead of outputting hex values in 0-f format, it was instead outputting all numbers. I finally got back to working on this problem and was able to write a category for NSString that exactly duplicates the Java methods I posted. Here it is:
//
// NSString+hex.h
// Created by Ben Baron on 10/20/10.
//
#interface NSString (hex)
+ (NSString *) stringFromHex:(NSString *)str;
+ (NSString *) stringToHex:(NSString *)str;
#end
//
// NSString+hex.m
// Created by Ben Baron on 10/20/10.
//
#import "NSString+hex.h"
#implementation NSString (hex)
+ (NSString *) stringFromHex:(NSString *)str
{
NSMutableData *stringData = [[[NSMutableData alloc] init] autorelease];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (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);
[stringData appendBytes:&whole_byte length:1];
}
return [[[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding] autorelease];
}
+ (NSString *) stringToHex:(NSString *)str
{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
[hexString appendString:[NSString stringWithFormat:#"%x", chars[i]]];
}
free(chars);
return [hexString autorelease];
}
#end
The perfect and short way to convert nsstring to hexadecimal values
NSMutableString *tempHex=[[NSMutableString alloc] init];
[tempHex appendString:#"0xD2D2D2"];
unsigned colorInt = 0;
[[NSScanner scannerWithString:tempHex] scanHexInt:&colorInt];
lblAttString.backgroundColor=UIColorFromRGB(colorInt);
The macro used for this code is----
#define UIColorFromRGB(rgbValue)
[UIColor \colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
For these lines of Java
utf8 = s.getBytes(ENCODING_UTF8);
new String(decodedHexString, ENCODING_UTF8);
Objective-C equivalents would be
utf8 = [s UTF8String];
[NSString initWithUTF8String:decodedHexString];
To make an NSString with the hexadecimal representation of a character string:
NSMutableString *hex = [NSMutableString string];
while ( *utf8 ) [hex appendFormat:#"%02X" , *utf8++ & 0x00FF];
You will have to make your own decodeHex function. Just pull two characters out of the string and, if they are valid, add a byte to the result.
There is a problem with your stringToHex method - it drops leading 0s, and ignores 00s. Just as a quick fix, I made the below:
+ (NSString *) stringToHex:(NSString *)str
{
NSUInteger len = [str length];
unichar *chars = malloc(len * sizeof(unichar));
[str getCharacters:chars];
NSMutableString *hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
{
// [hexString [NSString stringWithFormat:#"%02x", chars[i]]]; /*previous input*/
[hexString appendFormat:#"%02x", chars[i]]; /*EDITED PER COMMENT BELOW*/
}
free(chars);
return [hexString autorelease];
}
Thanks to all who contributed on this thread. It was a great help to me. Since things have moved on a little since the original post, here's my updated implementation for iOS 6. I went with the categories approach, but chose to split the load between NSData and NSString. Comments welcomed.
First, the NSString half, which handles decoding a hex encoded string into an NSData object.
#implementation NSString (StringToHexData)
//
// Decodes an NSString containing hex encoded bytes into an NSData object
//
- (NSData *) stringToHexData
{
int len = [self length] / 2; // Target length
unsigned char *buf = malloc(len)
unsigned char *whole_byte = buf;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [self length] / 2; i++) {
byte_chars[0] = [self characterAtIndex:i*2];
byte_chars[1] = [self characterAtIndex:i*2+1];
*whole_byte = strtol(byte_chars, NULL, 16);
whole_byte++;
}
NSData *data = [NSData dataWithBytes:buf length:len];
free( buf );
return data;
}
#end
The changes were mostly for efficiency's sake: some simple old-fashioned pointer arithmetic means I could allocate the whole buffer in one go, and populate it byte by byte. Then the whole thing is passed to NSData in one go.
The encoding part, in NSData, looks like this:
#implementation NSData (DataToHexString)
- (NSString *) dataToHexString
{
NSUInteger len = [self length];
char * chars = (char *)[self bytes];
NSMutableString * hexString = [[NSMutableString alloc] init];
for(NSUInteger i = 0; i < len; i++ )
[hexString appendString:[NSString stringWithFormat:#"%0.2hhx", chars[i]]];
return hexString;
}
#end
Again, some minor changes, though I suspect no efficiency gains here. The use of "%0.2hhx" solved all the problems of missing leading zero's and ensures that only a single-byte is output at a time.
Hope this helps the next person taking this on!
One possible solution:
+(NSString*)hexFromStr:(NSString*)str
{
NSData* nsData = [str dataUsingEncoding:NSUTF8StringEncoding];
const char* data = [nsData bytes];
NSUInteger len = nsData.length;
NSMutableString* hex = [NSMutableString string];
for(int i = 0; i < len; ++i)[hex appendFormat:#"%02X", data[i]];
return hex;
}
So, first off, I would like to thank drawnonward for his answer. This gave me the first function, mean and clean. In the same spirit, I wrote the other one. Hope you like it.
#synthesize unsigned char* value= _value;
- (NSString*) hexString
{
_value[CONSTANT]= '\0';
unsigned char* ptr= _value;
NSMutableString* hex = [[NSMutableString alloc] init];
while ( *ptr ) [hex appendFormat:#"%02x", *ptr++ & 0x00FF];
return [hex autorelease];
}
- (void) setHexString:(NSString*)hexString
{
_value[CONSTANT]= '\0';
unsigned char* ptr= _value;
for (const char* src= [hexString cStringUsingEncoding:NSASCIIStringEncoding];
*src;
src+=2)
{
unsigned int hexByte;
/*int res=*/ sscanf(src,"%02x",&hexByte);
*ptr++= (unsigned char)(hexByte & 0x00FF);
}
*ptr= '\0';
}
My input was an digit base10 string, and the output should be the hex representation in string format. Examples:
#"10" -> #"A"
#"1128" -> #"468"
#"1833828235" -> #"6D4DFF8B"
Implementation:
+ (NSString *) stringToHex:(NSString *)str{
NSInteger result = [str integerValue];
NSString *hexStr = (result)?#"":#"0";
while (result!=0) {
NSInteger reminder = result % 16;
if(reminder>=0 && reminder<=9){
hexStr = [[NSString stringWithFormat:#"%ld",(long)reminder] stringByAppendingString:hexStr];
}else if(reminder==10){
hexStr = [#"A" stringByAppendingString:hexStr];
}else if(reminder==11){
hexStr = [#"B" stringByAppendingString:hexStr];
}else if(reminder==12){
hexStr = [#"C" stringByAppendingString:hexStr];
}else if(reminder==13){
hexStr = [#"D" stringByAppendingString:hexStr];
}else if(reminder==14){
hexStr = [#"E" stringByAppendingString:hexStr];
}else{
hexStr = [#"F" stringByAppendingString:hexStr];
}
result /=16;
}
return hexStr;
}
Perhaps you should use NSString dataUsingEncoding: to encode and initWithData:length:encoding: to decode. Depends on where you are getting the data from.

Have been cursing over data packets for 36 hours now, please help!

Ok Here is the problem. I am trying to send through a structure or anything through the apple bluetooth send network packet code. The code to send is below
-(void)sendMessagePacket:(GKSession *)session packetID:(int)packetID withData:(void *)data ofLength:(int)length reliable:(BOOL)howtosend {
static unsigned char networkPacket[maxPacketSize];
const unsigned int packetHeaderSize = 2 * sizeof(int); // we have two "ints" for our header
if(length < (maxPacketSize - packetHeaderSize)) { // our networkPacket buffer size minus the size of the header info
int *pIntData = (int *)&networkPacket[0];
// header info
pIntData[0] = 10;
pIntData[1] = packetID;
// copy data in after the header
memcpy( &networkPacket[packetHeaderSize], data, length );
NSData *packet = [NSData dataWithBytes: networkPacket length: (length+8)];
if(howtosend == YES) {
[session sendDataToAllPeers:packet withDataMode:GKSendDataReliable error:nil];
} else {
[session sendDataToAllPeers:packet withDataMode:GKSendDataUnreliable error:nil];
}
}
}
If anyone could go through this with a comb and explain what is going on that would be greatly appreciated. Next, the receive code.
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context {
// Caller whenever data is received from the session
unsigned char *incomingPacket = (unsigned char *)[data bytes];
//EXPECTS THAT WHAT IS IN INCOMING PACKET [0] TO BE OF DATA TYPE INTEGER
int *pIntData = (int *)&incomingPacket[0];
int packetTime = pIntData[0];
int packetID = pIntData[1];
static int lastPacketTime = -1;
switch (packetID) {
case NETWORK_COINTOSS:
//DO SOMETHING
break;
case NETWORK_TEXT_EVENT:
NSString *fewMore = (NSString *)&incomingPacket[8];
fewThings *bitMore = &fewMore[peer];
//NSLog(#"Trace Bit More: %#",fewMore);
break;
default:
break;
}
NSInteger lengthBytes = [data length];
NSLog(#"Length of data : %i", lengthBytes);
}
What i am struggling to understnad being a newcome to objective c is how all this works, how do i access the string that i have send as all efforts to log it cause the program to crash.
Below is the code used to start the send:
NSString *bigWord = #"BigWordBigWord";
NSInteger len = [bigWord length];
[self sendMessagePacket:gameSession packetID:NETWORK_TEXT_EVENT withData:bigWord ofLength:(len) reliable:YES];
Any help would be so appreciated. Thank You.
You really need to change the NSString object into either a UTF8 representation to send, or to archive it as an NSData object you send with the full length - you can't just cast an NSString as a C string (either for sending or receiving!!!).
You can get a C string version of NSString using:
const char *sendString = [bigWord cStringUsingEncoding:NSUTF8StringEncoding]
And then get it out of your incoming NSData object with
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
This guy is sending and receiving the string over network just fine. But, I'm also still getting error on the receiving end.
http://discussions.apple.com/thread.jspa?messageID=10215848
At last got it. GKTank is transferring the data using struct, so I placed my string inside the struct and rest is the history.
typedef struct {
NSString *strInfo;
} myInfo;