I would convert
NSString *myString = #"0x10 0x1c 0x37 0x00"; //Aquired reading text file using NSString methods..
to
unsigned char convertedfrommyString[] = { 0x10, 0x1c, 0x37, 0x00 };
My goal is to aquiring them and then swap it using this code:
unsigned char convertedfrommyString[] = { 0x10, 0x1c, 0x37, 0x00 };
int data = *((int *) convertedfromString);
NSLog(#"log = %08x", data);
the output should be:
log = 00371c10
Any help?
EDIT
From both Jan Baptiste Younès and Sven I found the way to understand my problem and solve with this code:
NSString *myString = [[#"0x10 0x1c 0x37 0x00" stringByReplacingOccurrencesOfString:#"0x" withString:#""] stringByReplacingOccurrencesOfString:#" " withString:#""];
unsigned result = 0;
NSScanner *scanner = [NSScanner scannerWithString:myString];
[scanner scanHexInt:&result];
int reverse = NSSwapInt(result);
NSLog(#"scanner: %8u", result);
NSLog(#"bytes:%08x", result);
NSLog(#"reverse:%08x (that is what i need!)", reverse);
Really OK!
But can I accept two answer?
That's more than a simple conversion, you need to actually parse the values from your string. You can use NSScanner to do this.
NSScanner *scanner = [NSScanner scannerWithString: #"0x10 0x1c 0x37 0x00"];
unsigned char convertedfrommyString[4];
unsigned index = 0;
while (![scanner isAtEnd]) {
unsigned value = 0;
if (![scanner scanHexInt: &value]) {
// invalid value
break;
}
convertedfrommyString[index++] = value;
}
Of course this sample is missing error handling (the single values could not fit into an unsigned char or there could be more than four).
But this solved only half your problem. The other issue is converting this to an int. You did this by casting the unsigned char pointer to an int pointer. This is not portable and also not legal in C. To always get the result you want you should instead use bit shifts to assemble your int. So inside your loop you could do
result = result | (value << i);
i += 8;
instead of putting the values inside an unsigned char array. For this result and i should both be initialized to zero.
You may cut your original string at spaces and use the solution given here Objective-C parse hex string to integer. You can also use scanUpToString:intoString to parse upto space chars.
I'm trying to connect to a Cisco C40 codec via telnet from objective c. When using the terminal on my computer I get:
Password:
However when doing a socket connection there are telnet negotiations that need to be made. Which I am but for some reason I cannot get to the "Password:" prompt above.
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSLog(#"RECEIVE BUFFER %#",data);
//store read bytes to rawData
self.rawData = [[NSMutableData alloc] initWithData:data];
//cast bytes
const uint8_t *bytes = [self.rawData bytes];
//go through rawdata format and save it to networkbuffer
for (int i =0; i < [self.rawData length]; i++)
{
if (![[NSString stringWithFormat:#"%02X", bytes[i]]isEqual:#"0D"])
{
[self.networkBuffer addObject:[NSString stringWithFormat:#"%02X", bytes[i]]];
}
}
//negotiate any telnet protocal stuff (just accept options )
//example:
//FF:FD:18 returns FF:FB:18
while([[self.networkBuffer objectAtIndex:0]isEqualToString:#"FF"] && [[self.networkBuffer objectAtIndex:1]isEqualToString:#"FD"] ) {
// NSLog(#"HERE");
NSData * tempData =[data subdataWithRange:NSMakeRange(0, 3)];
NSMutableData * tempMutData = [NSMutableData dataWithData:tempData];
const unsigned char replacement[] = {
0xFC
};
[tempMutData replaceBytesInRange:NSMakeRange(1, 1) withBytes:replacement];
[self sendCommand:tempMutData];
data = [data subdataWithRange:NSMakeRange(3, [data length]-3)];
self.networkBuffer = [NSMutableArray arrayWithArray:[self.networkBuffer subarrayWithRange:NSMakeRange(3, [self.networkBuffer count]-3)]];
// NSLog(#"network buffer after removal: %#", data);
if ([self.networkBuffer count]<3) {
[self.networkBuffer insertObject:#" " atIndex:0];
}
}
//decode from bytes to text
for ( NSString * component in self.networkBuffer)
{
int value = 0;
sscanf([component cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
[self.dataString appendFormat:#"%c", (char)value];
NSLog(#"data byte: %c",(char)value);
}
[self telnetResponse:self.dataString];
[self.networkBuffer removeAllObjects];
[self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];//CRLFData
}
Here is a breakdown of the telnet negotiation options Im receiving and sending:
server sending me:
FF,FD,18 (0x18 = 24dec) (Do terminal type)
FF,FD,20 (0x20 = 32dec) (Do terminal speed)
FF,FD,23 (0x23 = 35dec) (Do X Display Location)
FF,FD,27 (0x27 = 39dec) (Do New Environment Option)
My attempt at a response that doesnt work (no prompt for further input):
FF,FC,18 (0x18 = 24dec) (Wont terminal type)
FF,FC,20 (0x20 = 32dec) (Wont terminal speed)
FF,FC,23 (0x23 = 35dec) (Wont X Display Location)
FF,FC,27 (0x27 = 39dec) (Wont New Environment Option)
If you look at the code you will see that I am checking for FF and if so responding with similar bytes (replacing FD with FC), in hopes that wont accept the options but that does not seem to be working.
Links that helped me:
https://stackoverflow.com/a/2913991/530933
Telnet IAC commands (NSStream socket)
http://www.iprodeveloper.com/forums/aft/52910
UPDATE
I did a wireshark with a command shell and the cisco codec. After which I duplicated those negotiation setting/packets. Now the only problem is that Im only getting the echo. So i will get nothing, send a command, then get back a prompt plus my text. (Example. get nothing - send username "admin" - get back "login: admin") Hence what I mean by only getting the echo. I should get a prompt "login:" then send "admin" then it should prompt me for the password.
here are the negotiation options Im sending on connect:
//will terminal type
//will negotiate about window size
const unsigned char nineteen[] = {
0xFF, 0xFB, 0x18, 0xFF, 0xFB, 0x1F
};
self.dataToBeSent = [[NSData alloc]initWithBytes:nineteen length:sizeof(nineteen)];
[self sendCommand:self.dataToBeSent];
//wont terminal speed
//wont X display location
//will new environment option
const unsigned char twenty[] = {
0xFF, 0xFC, 0x20, 0xFF, 0xFC, 0x23, 0xFF, 0xFB, 0x27
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twenty length:sizeof(twenty)];
[self sendCommand:self.dataToBeSent];
//Suboption being: negotiate about window size
//end
const unsigned char twentyOne[] = {
//0xFF,0xFC, 0x18
0xFF, 0xFA, 0x1F, 0x00, 0x50, 0x00, 0x19, 0xFF, 0xF0
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentyOne length:sizeof(twentyOne)];
[self sendCommand:self.dataToBeSent];
//new enviroment option
//end
const unsigned char twentyThree[] = {
0xFF,0xFA, 0x27, 0x00, 0xFF, 0xF0
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentyThree length:sizeof(twentyThree)];
[self sendCommand:self.dataToBeSent];
//Terminal Type (ANSI)
//end
const unsigned char twentySeven[] = {
0xFF,0xFA, 0x18, 0x00, 0x41, 0x4E, 0x53, 0x49, 0xFF, 0xF0
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentySeven length:sizeof(twentySeven)];
[self sendCommand:self.dataToBeSent];
//do suppress go ahead
const unsigned char twentyEight[] = {
0xFF, 0xFD, 0x03
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentyEight length:sizeof(twentyEight)];
[self sendCommand:self.dataToBeSent];
//will echo
//dont status
//wont remote flow control
const unsigned char twentyFour[] = {
0xFF, 0xFB, 0x01, 0xFF, 0xFE, 0x05, 0xFF,0xFC, 0x21
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentyFour length:sizeof(twentyFour)];
[self sendCommand:self.dataToBeSent];
//wont echo
const unsigned char twentyFive[] = {
0xFF, 0xFC, 0x01
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentyFive length:sizeof(twentyFive)];
[self sendCommand:self.dataToBeSent];
//Do echo
const unsigned char twentySix[] = {
0xFF,0xFD, 0x01
};
self.dataToBeSent = [[NSData alloc]initWithBytes:twentySix length:sizeof(twentySix)];
[self sendCommand:self.dataToBeSent];
So a big problem came from the fact that the prompts (login: or password:) do no end the line with CR NL (0D:0A). And I was doing
[self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];
so I was never reading the data that held the prompt (a big problem also was that wireshark wasnt working (fixed that myself too)). Once I figured this out I changed the line above to:
[self.socket readDataWithTimeout:-1 tag:0];
Which successfully gave me my prompt. Below are the negotiations Im sending to get to this point and what the original questions entailed (same as above in the update):
will terminal type - 0xFF, 0xFB, 0x18
will negotiate about window size - 0xFF, 0xFB, 0x1F
wont terminal speed - 0xFF, 0xFC, 0x20
wont X display location - 0xFF, 0xFC, 0x23
will new environment option - 0xFF, 0xFB, 0x27
Suboptions
negotiate about window size - 0xFF, 0xFA, 0x1F, 0x00, 0x50, 0x00, 0x19
end - 0xFF, 0xF0
new enviroment option - 0xFF,0xFA, 0x27, 0x00,
end - 0xFF, 0xF0
Terminal Type (ANSI) - 0xFF,0xFA, 0x18, 0x00, 0x41, 0x4E, 0x53, 0x49,
end - 0xFF, 0xF0
do suppress go ahead - 0xFF, 0xFD, 0x03
will echo - 0xFF, 0xFB, 0x01
dont status - 0xFF, 0xFE, 0x05
wont remote flow control - 0xFF,0xFC, 0x21
wont echo - 0xFF, 0xFC, 0x01
Do echo - 0xFF,0xFD, 0x01
This might also help. It removes the negotiation bytes from the stream so when your encoding to make the string it doesnt include negotiation bytes.
while([[self.networkBuffer objectAtIndex:0]isEqualToString:#"FF"])
{
if ([[self.networkBuffer objectAtIndex:1]isEqualToString:#"FD"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:#"FB"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:#"FE"] || [[self.networkBuffer objectAtIndex:1]isEqualToString:#"FA"]) {
//most negotiation options are 3 bytes long
int indexToRemoveFromBuffer = 3;
//if FA then they are longer then 3 bytes
if ([[self.networkBuffer objectAtIndex:1]isEqualToString:#"FA"]) {
//look for indicator of END (F0)
indexToRemoveFromBuffer = [self.networkBuffer indexOfObject:#"F0"]+1;
}
//remove these bytes from networkbuffer
self.networkBuffer = [NSMutableArray arrayWithArray:[self.networkBuffer subarrayWithRange:NSMakeRange(indexToRemoveFromBuffer, [self.networkBuffer count]-indexToRemoveFromBuffer)]];
if ([self.networkBuffer count] == 0) {
if (self.isLoggedIn) {
[self.socket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1 tag:0];//CRLFData
}else{
[self.socket readDataWithTimeout:-1 tag:0];
}
return;
}
}else{
break;
}
}
I am using bluetooth 4 (Low Energy) and need to transfer an 8-bit slider value to my slave device. The receiving end should get something like this : 000000A3 but right now I am stuck with A3000000
I have tried different solutions:
int value = ((int)slider.value >> 24) ;
NSData *dataToWrite = [NSData dataWithBytes:&value length:4]; //data to be sent has to be of type NSData
and
int value[] = {0x00, 0x00, 0x00, slider.value};
and the only working one
char value[4] = {0x00, 0x00, 0x00, slider.value};
but I think this looks a bit ugly. Any other ideas on how to do this?
Core Foundation has functions for handling byte-order conversions: Byte-Order Utilities Reference
Recently, I am using CCCrypt to implement some self defined crypto algorithm. However, when i use CCCryptorUpdate to decrypt cipher text, the output is always 8 bytes less than origin plain text. Following is my codes:
+ (void) EncryptBy3DES:(NSInputStream*)strmSrc Output:(NSOutputStream*)strmDest CryptoRef:(CCCryptorRef)tdesCrypto
{
size_t dataOutMoved;
uint8_t inputBuf[BlockSize];
uint8_t outputBuf[BlockSize];
CCCryptorStatus cryptStatus;
int iBytesRead = 0;
while ( (iBytesRead = [strmSrc read:inputBuf maxLength:BlockSize]) > 0 )
{
NSLog(#"Bytes read from plain buffer: %d", iBytesRead);
[Util FillBuffer:inputBuf Length:BlockSize Current:iBytesRead];
cryptStatus = CCCryptorUpdate(tdesCrypto, &inputBuf, BlockSize, &outputBuf, BlockSize, &dataOutMoved);
assert(dataOutMoved<=BlockSize && cryptStatus==noErr);
NSLog(#"EncDataOutMoved: %ld", dataOutMoved);
[Util FillBuffer:outputBuf Length:BlockSize Current:dataOutMoved];
[strmDest write:outputBuf maxLength:BlockSize];
}
}
+ (void) DecryptBy3DES:(NSInputStream*)strmSrc Output:(NSOutputStream*)strmDest CryptoRef:(CCCryptorRef)tdesCrypto
{
size_t dataOutMoved;
uint8_t inputBuf[BlockSize];
uint8_t outputBuf[BlockSize+kCCBlockSize3DES];
CCCryptorStatus cryptStatus;
int iBytesRead = 0;
while ( (iBytesRead = [strmSrc read:inputBuf maxLength:BlockSize]) > 0 )
{
NSLog(#"Bytes read from cipher buffer: %d", iBytesRead);
cryptStatus = CCCryptorUpdate(tdesCrypto, &inputBuf, BlockSize, &outputBuf, BlockSize+kCCBlockSize3DES, &dataOutMoved);
NSLog(#"Lengh needed: %zu", CCCryptorGetOutputLength(tdesCrypto, BlockSize, YES));
NSLog(#"DecDataOutMoved: %ld", dataOutMoved);
assert(dataOutMoved<=BlockSize && cryptStatus==noErr);
[strmDest write:outputBuf maxLength:dataOutMoved];
}
}
I encrypted 3 buffer of 4096. When decrypting them, the log shows that the size of 1st decrypted data is 4088, BUT! The missing data is actually in the begining of the 2nd decrypted data.
2012-04-14 15:17:41.929 otest[25168:7803] Bytes read from cipher buffer: 4096
2012-04-14 15:17:41.929 otest[25168:7803] Lengh needed: 4104
2012-04-14 15:17:41.930 otest[25168:7803] DecDataOutMoved: 4088
end of 1st block:<..d71eaf27 affc4c8c b1c54afa c5434397 ebc17a49>
2012-04-14 15:17:45.291 otest[25168:7803] Bytes read from cipher buffer: 4096
2012-04-14 15:17:45.292 otest[25168:7803] Lengh needed: 4104
2012-04-14 15:17:45.293 otest[25168:7803] DecDataOutMoved: 4096
begining of 2nd block <**86b61bce b4342728** 88240a64 837327d4 0bb572a2 f5220928
Note that 86b61bce b4342728 was in the end of 1st block before encryption.
I also checked the begining of the 1st block, and I am sure that I did not mess up with the range of data. It seems that the data are decrypted, but they are not retrieved until the next operation.
I want to get a full block at each encrypt/decrypt operation, but I don't want to use function CCCrypt since I have to pass both Key and Iv bits to it. I just want to pass CCCryptorRef to it, which is relatively simple.
Hubert
You need to finish the encryption and decryption by calling CCCryptFinal. This will take care of adding/removing padding.
I use CCCrypt function to DES encrypting something. When length of data to be encrypted is not multiple of 8 Byte, error size took place.
So I handle this as following:
- (NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
{
NSString *ciphertext = nil;
const char *textBytes = [plainText UTF8String];
NSUInteger dataLength = [plainText length];
NSUInteger len1=dataLength % 8;
if(len1!=0)
{
dataLength+=(8-len1);
}
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
Byte iv[] = {0x02, 0x00, 0x01, 0x02, 0x00, 0x06, 0x00, 0x05};
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
NULL,
[key UTF8String], kCCKeySizeDES,
iv,
textBytes, dataLength,
buffer, 1024,
&numBytesEncrypted);
.....
}
Then everything ok!
I do have the following code that read in from a socket:
Int8 buffer[102400];
UInt8 *buffer_p = buffer;;
int bytesRead;
bytesRead = CFReadStreamRead(stream, buffer, 102400);
The message i am expecting begin with short(2 bytes) short(2 bytes) integer(4 bytes).
I am not sure how to convert them to the corresponding types.
I tried the following:
uint16_t zero16 = NTOHS(buffer_p);
buffer_p += sizeof(uint16_t);
uint16_t msg_id16 = NTOHS(buffer_p);
buffer_p += sizeof(uint16_t);
uint32_t length32 = NTOHL(buffer_p);
buffer_p += sizeof(uint32_t);
or
NSMutableData *data = [NSMutableData dataWithBytes:buffer length:bytesRead];
NSRange firstshort = {0,2};
NSRange secondshort = {2,2};
NSRange intrange = {4,4};
short zero;
[data getBytes:&zero range:firstshort];
short msgid;
[data getBytes:&msgid range:secondshort];
int length;
[data getBytes:&length range:intrange];
But non is working. Thanks in advance.
You may want to look at OSByteOrder.h. This defines a bunch of macros that can be used to read various integer types or to do byte-swapping. Specifically, you could do something like
uint16_t zero16 = OSReadBigInt16(buffer_p, 0);
uint16_t msg_id16 = OSReadBigInt16(buffer_p, 2);
uint32_t length32 = OSReadBigInt32(buffer_p, 4);