How to concatenate 3 NSData variables - iphone

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.

Related

Make UIImage from ByteArray getting from .Net WebService

My problem is same as Converting byte array coming from Web service to UIImage iPhone
.Now I am storing these bytes in NSMutableArray.But the method:
NSData *data = [NSData dataWithBytes:YOUR_BYTE_ARRAY length:ARRAY_LENGTH];
takes arrayOfBytes as parameter.So can anyone tell me that how to convert this array in byte array. I searched a lot but unable to find relevant contents.
Not sure how you're getting the mutable array to begin with. If you're using NSURLConnection, the delegate will get NSData, so you needn't use a mutable array. Consider getting the data using the connection asynch block method like this ...
NSURLRequest *myRequest = // the request you've already got working to get image data
[NSURLConnection sendAsynchronousRequest:myRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// image from data with no intermediate mutable array or byte array
UIImage *image = [UIImage imageWithData:data];
}
}];
Thanks for your co-operation. But it does not help me. After a long research i found my solution. I am sharing my information so that others can get right answer.
NSArray *byteArray = [[NSArray alloc]init]; //strore all data here coming from server in byte formate
unsigned c = [byteArray count];
uint8_t *bytes = malloc(sizeof(*bytes) * c);
unsigned i;
for (i = 0; i < c; i++)
{
NSString *str = [byteArray objectAtIndex:i];
int byte = [str intValue];
bytes[i] = (uint8_t)byte;
}
NSData *data = [[NSData alloc]initWithBytes:bytes length:c];
UIImage *image = [UIImage imageWithData:data];
NSLog(#"image %#",image);

Uploading Large NSData to the Web

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

Appending NSData

Can anyone help me with appending the nsdata
i have NSData as encrypted data
<a5ecaf36 15519fcb cd164cf6 a83eaf55 367f1109 b6898951 2c227b86 ed98d0a6 db2d7a8a 25086baf 58436328 2583ed78 ef3410e5 4507d8a4 40fe22f9 0538a67c 065fbb8e ad445041 56f3ea87 e7b73189 aa0b8c66 a9da381e 6f718583 dce57b9a f2f5d9c9 b336c92f b2df2d43 9083bd1d e33e907b 7fd0fdc7 e5f64db9 b7f0975a>
i want to add F8 to this and send it to server as NSData
NSMutableData *mData = [NSMutableData dataWithData:mData];
unsigned char f8[1] = 0xF8;
[mData appendBytes:f8 length:1];
// You can use the mutable data as is or turn it back into a non-mutable object:
data = [NSData dataWithData:mData];

Verifying resetBytesInRange in NSMutableData

I have a huge NSMutableData object(approximately 1 MB in size) in memory and now I want to replace all the bytes in the object to 0 (not deallocate the memory). The resetBytesInRange method lets me do this. However how do I verify/check if the bytes are actually set to 0. I want to look at the memory addresses and confirm this. Is this possible?
I have the following code
NSMutableData *imgData = [NSMutableData dataWithCapacity:50000000];
imgData = (NSMutableData*)UIImageJPEGRepresentation(img, 1.0);
[imgData resetBytesInRange:NSMakeRange(0, [imgData length]) ];
Now when I look into the address pointed to by imgData (and the following few locations), before and after the resetBytes, I do not see any change in the values in the memory locations starting from the address pointd to by imgData (I expected to see zeros assigned). I assumed that the memory allocations are contiguous starting from the the address pointed to by imgData (upto [imgData length]). Is this assumption corerct (which seems like it is not)? If not where are the bytes in the NSMutableData object stored? Can I access them individually?
Thanks
Vivek
The problem is not that -resetBytesInRange: doesn't work. The problem is that you're sending that message to the wrong object.
imgData = (NSMutableData*)UIImageJPEGRepresentation(img, 1.0); doesn't assign the JPEG bytes to the mutable data you created in the first line. It replaces your reference to that object with a reference to a new object, and uses a cast to suppress the compiler warning about an invalid store. There are a few ways to do this properly:
NSMutableData *imgData = [NSMutableData data]; /* note, we do not specify a capacity--it's pointless for this use case */
[imgData setData: UIImageJPEGRepresentation(img, 1.0)];
[imgData resetBytesInRange: NSMakeRange(0, [imgData length])];
Or:
NSMutableData *imgData = [[UIImageJPEGRepresentation(img, 1.0) mutableCopy] autorelease];
[imgData resetBytesInRange: NSMakeRange(0, [imgData length])];
But both ignore the obvious: if you're immediately clearing the data to zero, why are you even bothering to create the JPEG data? What are you actually trying to do here?
imgData is a pointer (as indicated by the * symbol). So it points to a memory location and assignment will just change the location it points to. It's not really the intention of most programming languages to let you do byte-by-byte manipulation of actual memory locations.
Read this: http://www.cplusplus.com/forum/general/3644/

problem with converting NSData to NSArray

Hi
I have a problem with converting NSData to NSArray
my code is:
NSData *data = [[NSData alloc] initWithBytes:(const void *)buf length:len];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
can any one help me to do it.
I have no idea what is inside your byte buffer. This code works for a simple buffer of character bytes.
Try:
char buf[]="123456";
NSData *bufObj=[NSData dataWithBytes:(const void *)buf length:sizeof buf];
if(bufObj==nil)
NSLog(#"failed to create obj");
else {
NSMutableArray *marr=[NSMutableArray array];
[marr addObject:bufObj];
NSArray *arr=[NSArray arrayWithObject:bufObj];
NSLog(#"test:\n\tbufObj: %#\n\tmarr: %#\n\tarr: %#",bufObj,marr,arr);
}
Use +[NSPropertyListSerialization dataWithPropertyList:format:options:error:] to convert the data, then check if the result -isKindOfClass:[NSArray class].
It will work :)