How can i pass NSData object over Wifi network? can any one provide me the code to send and receive the NSData over Wifi.or any sample code/app reference .
Assuming that you know how to send data in general, here is the code:
uint8_t *bytes = (uint8_t)[myData bytes];
size_t length = [myData length];
sendBytesWithLength(bytes, length);
On the receiver side you regenerate your NSData object like this:
uint8_t *bytes = ; // Get the bytes from somewhere...
size_t length = ; // And the length
NSData *data = [[NSData alloc] initWithBytes:(const void *)bytes length:length];
Have you tried looking at the Bonjour references in the first place to set up the connection? That should lead you on to the other options for network communication.
Related
I am building a simple iphone (SDK6.1) application that encrypts some user's notes, stores the into a database and when user enters a password (does not need to be encrypted) it will decrypt his notes and show them to him.
For the database i am using Core Data (.xcdatamodel). The encrypted text at the moment is declared as String in the data model and in the Notes.h fil,e it is declared as NSString.
For the Encryption i am using apple's sample code from CryptoExercise which works perfectly.
The problem is that when i try to save the encrypted text in the database and then decrypt it i am not getting the desired results.. basically i am getting an empty string back.
Obviously i am using the following code to convert from uint8_t to NSString so i can store it into the data model and i understand that this is my main problem.
uint8_t *cipherBuffer = NULL;
SecKey *encrypt = [[SecKey alloc]init];
NSString *et = [[NSString alloc]init];
[encrypt generateKeyPairRSA];
// Encrypt the plain text
cipherBuffer = [encrypt Encryption:plainTextField.text];
// Convert uint8_t to NSString
NSMutableData *data = [[NSMutableData alloc]init];
[data appendBytes:cipherBuffer length:strlen((char*)cipherBuffer)+1];
NSString *string = [[NSString alloc]initWithData:data encoding: NSASCIIStringEncoding];
// Save to Data Model
[self.currentNote setEncryptedText:string];
[self.delegate addNewNoteViewControllerDidSave];
// Retrieve encrypted text from database
et = [self.currentNote encryptedText];
// Convert back to uint_8
NSData *someData = [et dataUsingEncoding:NSUTF8StringEncoding];
const void *bytes = [someData bytes];
uint8_t *crypto_data = (uint8_t*)bytes;
// Decrypt Data
[encrypt Decryption:crypto_data];
As i said before i understand that converting uint8_t is the main problem here and i would like to know which is the correct way to do this?
Is it possible with Data Model at all, or should i go to SQLite??
You cannot convert arbitrary bytes sequences to NSString and back like that. For example,
if data contains the single byte 128 (hex 0x80), then
NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
creates a string with one Unicode character U+0080. When you convert this back to NSData with
NSData *d1 = [string dataUsingEncoding:NSUTF8StringEncoding];
then d1 will contain the bytes 0xC2 0x80 (which is the UTF-8 for U+0080). But
NSData *d2 = [string dataUsingEncoding:NSASCIIStringEncoding];
does also not work (d2 = nil), because the string cannot be converted to 7-bit
ASCII.
So you should either
store the encrypted data as "Binary Data" in Core Data, or
store the encrypted data as String, but choose a different conversion strategy,
for example Base64.
So just to answer the question so i can use code and everything..
I changed the EncryptedText in the Data Model to Binary Data and then the code would look like this:
uint8_t *cipherBuffer = NULL;
SecKey *encrypt = [[SecKey alloc]init];
[encrypt generateKeyPairRSA];
cipherBuffer = [encrypt Encryption:plainTextField.text];
NSMutableData *data = [[NSMutableData alloc]init];
[data appendBytes:cipherBuffer length:strlen((char*)cipherBuffer)+1];
// Save cipher into the Data Model
[self.currentNote setEncryptedText:data];
[self.delegate addNewNoteViewControllerDidSave];
// Retrieve cipher back from Data Model
NSData *etData = [[NSData alloc]init];
etData = [self.currentNote encryptedText];
// Convert back to uint8_t
const void *bytes = [etData bytes];
uint8_t *crypto_data = (uint8_t*)bytes;
// De cypher
[encrypt Decryption:crypto_data];
How to concatenate 3 NSData variables ?
NSData *iv;
NSData *salt;
NSData *encryptedData;
I need to join these to a single variable. Can any one show me a way.
use an NSMutableData object and the method -(void)appendData:(NSData *)otherData
Edited to add example :
NSMutableData *concatenatedData = [NSMutableData data];
[concatenatedData appendData:iv];
[concatenatedData appendData:salt];
[concatenatedData appendData:encryptedData];
// and now you have all of the data in the single variable "concatenatedData"
For those who coding for iOS5 and later.
I'd like to show some real good concatenation. Why are those answers aren't good enough? Because they are involves extra memory usage for copied data. Let's see the answer:
NSMutableData *concatenatedData = [NSMutableData data];
[concatenatedData appendData:iv];
[concatenatedData appendData:salt];
[concatenatedData appendData:encryptedData];
here we have memory allocated for iv, salt and encryptedData
also each time we append one of them to our mutable concatenation we are obviously copy it to mutable data again. Do we want this extra expenses while dealing with large data? Me not.
There is a way to avoid this unnecessary expense of memory - dispatch_data
I'm not going to explain how it works, you can google it if you want.
I just give you a code that works:
NSData *iv = [#"some data" dataUsingEncoding:NSUTF8StringEncoding];
NSData *salt = [#"even more data" dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [#"and one more" dataUsingEncoding:NSUTF8StringEncoding];
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_data_t dispatch_data_iv = dispatch_data_create([iv bytes], [iv length], queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
dispatch_data_t dispatch_data_salt = dispatch_data_create([salt bytes], [salt length], queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
dispatch_data_t dispatch_data_encrypted = dispatch_data_create([encryptedData bytes], [encryptedData length], queue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
iv = nil; salt = nil; encryptedData = nil; // free all parts, we dont need it anymore
dispatch_data_t dispatch_data_concat = dispatch_data_create_concat( dispatch_data_create_concat(dispatch_data_iv, dispatch_data_salt), dispatch_data_encrypted);
NSData *concatenatedNSData = DataFromDispatchData(dispatch_data_concat);
// lets check now if the concatenation works properly
NSString *stringFromConcatenatedNSData = [[NSString alloc]initWithData:concatenatedNSData encoding:NSUTF8StringEncoding];
NSLog(#"%#",stringFromConcatenatedNSData);
don't forget about the helper-converter
NSData *DataFromDispatchData(dispatch_data_t data)
{
NSMutableData *result = [NSMutableData dataWithCapacity: dispatch_data_get_size(data)];
dispatch_data_apply(data, ^(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
[result appendBytes:buffer length:size];
return (_Bool)true;
});
return result;
}
You could use NSMutableData's -appendData method:
NSMutableData *result = [NSMutableData data];
[result appendData:iv];
[result appendData:salt];
[result appendData:encryptedData];
// result now has what you need.
This comes at the overhead of using mutable data, which can be slower & use more memory, so use with care. Generally speaking you don't want large NSData's floating around.
First create two NSObjects and use this method
-(void)appendData:(NSData *)otherData
and put in one NSData later with 3rd NSData also concatenate with the same method.
I'm currently working on an application that has to upload large files (mainly movies/videos) to the web. After reading what I can, I went the the approach of converting the movie to NSData and then including that as the NSURLConnection's HTTPBody. However, upon converting the movie (which was originally an ALAsset) into NSData, I receive a memory warning and then a subsequent crash.
I have no idea how I would go about uploading these types of large files, if that data just causes an instant crash. One solution that I was thinking of is writing to the filesystem and then uploading a file directly from there, but I have not been able to find any information on how one would accomplish this.
Here is the relevant code that I use. If there is something that I'm doing wrong right here, I'd love to know.
ALAssetRepresentation *representation = [asset defaultRepresentation];
Byte *buffer = (Byte *)malloc([representation size]);
NSUInteger buffered = [representation getBytes:buffer fromOffset:0.0 length:[representation size] error:nil];
uploadData = [NSData dataWithBytes:buffer length:buffered];
free(buffer);
Assuming that it makes sense to upload the movie in its native format, you can really make this easier using the BSD (ie Unix) section 3 interface:
given a filePath, open the file and get an int file descriptor (fd)
with fd, get the length of the file
keep track of how much you've loaded so you know where to get more data
use mmap(3) to map in JUST the data you want to upload at any time, and use the void * pointer returned by mmap as the location of the data
when the data has been sent, munmap the old data chunk and mmap a new chunk
after all data is sent, munmap the last chunk, the close(fd).
No temporary memory - no mallocs. I use mmap whenever I have to deal with huge files.
Edit: you can also use NSData dataWithContentsOfFile:options with options set to use mmap. You would then use the byte pointer to read small chunks as you need them.
In case anyone got here and couldn't solve your problems, I figured out a way to do this.
You have to firstly write your ALAssetRepresentation to disk (as described here):
NSUInteger chunkSize = 100 * 1024;
NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:#"temp.tmp"];
uint8_t *chunkBuffer = malloc(chunkSize * sizeof(uint8_t));
NSUInteger length = [rep size];
NSFileHandle *fileHandle = [[NSFileHandle fileHandleForWritingAtPath: tempFile] retain];
if(fileHandle == nil) {
[[NSFileManager defaultManager] createFileAtPath:tempFile contents:nil attributes:nil];
fileHandle = [[NSFileHandle fileHandleForWritingAtPath:tempFile] retain];
}
NSUInteger offset = 0;
do {
NSUInteger bytesCopied = [rep getBytes:chunkBuffer fromOffset:offset length:chunkSize error:nil];
offset += bytesCopied;
NSData *data = [[NSData alloc] initWithBytes:chunkBuffer length:bytesCopied];
[fileHandle writeData:data];
[data release];
} while (offset < length);
[fileHandle closeFile];
[fileHandle release];
free(chunkBuffer);
chunkBuffer = NULL;
Then you have to create an NSData object that can map the disk without using memory resources (kind of like David's answer, but inspired by this answer):
NSError *error;
NSData *fileData = [NSData dataWithContentsOfFile:tempFile options:NSDataReadingMappedIfSafe error:&error];
if (!fileData) {
NSLog(#"Error %# %#", error, [error description]);
NSLog(#"%#", tempFile);
//do what you need with the error
}
EDIT Although, if you are uploading the file somewhere, you should open a connection and send small buffers of the file, kind of like what I did above. I had to write a C++ class to handle the socket and the connection
You probably shouldn't be trying to read the whole asset in one shot:
Byte *buffer = (Byte *)malloc([representation size]);
NSUInteger buffered = [representation getBytes:buffer fromOffset:0.0 length:[representation size] error:nil];
Instead, set up a loop and read from the asset in chunks. I've outlined the basic approach. You'll need to fill in a few gaps, but it should solve the memory issue.
You might also want to consider running this in a thread so you don't lock up the UI.
NSError error;
int bufferSize = 1000;
float offset=0.0;
//TODO: Open Connection
while (1)
{
Byte *buffer = (Byte *)malloc(bufferSize);
NSUInteger buffered = [representation getBytes:buffer fromOffset:offset length:bufferSize error:&error];
//TODO: Write data
//TODO: Increment offset, check errors
free(buffer);
//if (done){
//break;
//}
}
//TODO close eonnection
My problem is CipherBuffer which is uint8_t i am not able to convert that to NSData and get back the same value.the thing is i need to send the encrypted data to server.
Even i get NSData from serverside and i need to convert that to (unit8_t *). Is their a way to do that i am using below method to decrypt
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)decryptedBuffer
To convert uint8_t to NSData
NSData *data = [NSData dataWithBytes:(const void *)encrypted length:bufferSize];
And to convert NSData to uint8_t you can try below method of NSData
- (const void *)bytes;
I need convert NSData to Binary data for send to php server
You don't need to convert NSData. Just set the post body of the NSMutableURLRequest.
const void *p = [nsDataObject bytes];
NSUInteger length = [nsDataObject length];