Translating C to Obj-C file reading code - objective-c

I have this file which I need to read the first bytes to check the information.
I don't need to load the whole file, only the beginning..
The code in C is, more or less, what follows. It is a big code, so I just wrote the basic functionality here.
Now I want to make it 100% Objective-C, but I cannot find a way to do it properly.
FILE *f;
char *buf;
f = fopen ("/Users/foo/Desktop/theFile.fil", "rb");
if(f) {
fseek(f , 0 , SEEK_END);
size = ftell(f);
rewind (f);
buf = (char*) malloc (sizeof(char)*size);
switch( ntohl(*(uint32 *)buf) ) {
case 0x28BA61CE:
case 0x28BA4E50:
NSLog(#"Message");
break;
}
fclose(f);
free (buf);
The most close I got to this is what follows:
NSData *test = [[NSData alloc] initWithContentsOfFile:filePath];
This gets me all the binary, but anyway, I got stuck. Better try to start all over..
Any help appreciated!

Well, valid C code is valid Objective-C code. So this is already in Objective-C.
What's your actual goal? What are you trying to do with the file? Is there a reason you can't use NSData?

C code is already Obj-C. It's perfectly reasonable to just use what you're already doing. But if you're dead-set on using Obj-C objects to perform this, you want to take a look at NSInputStream.

The most close I got to this is what follows:
NSData *test = [[NSData alloc] initWithContentsOfFile:filePath];
This gets me all the binary, but anyway, I got stuck.
It's not clear where you're stuck, because that's the (simplest) correct way to read a file in one big slurp in Cocoa. You've successfully read the file; there's nothing more to do for that.
If you're looking to proceed to the switch statement, the pointer to the bytes that it read is [test bytes]. That's the pointer that you will want to assign to buf. See the NSData documentation.

Well.. I sorted that out.. And did what follows.
Cheers and thanks for the help!
NSString *filePath = [[NSString alloc] initWithFormat:#"/Users/foo/Desktop/theFile.fil"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
Byte *byteData = (Byte*)malloc(len);
memcpy(byteData, [data bytes], len);
NSNumber *size = [[NSNumber alloc] initWithUnsignedLong:len/2^20];
NSLog(#"%#", size);
switch( ntohl(*(uint32 *)byteData) ) {
case 0x28BA61CE:
case 0x28BA4E50:
NSLog(#"Message");
break;
}
[size release];
[filePath release];

Related

Signed byte array to UIImage

I am trying to display a picture from a byte-array produced by a web service. Printing out a description it looks like this:
("-119",80,78,71,13,10,26,10,0,0,0,13,3 ... )
From the header it is clear that it's a png encoded in signed integers. It is an __NSCFArray having __NSCFNumber elements.
My code in Objective-C (based on much googling):
NSData *data = [NSData dataWithBytes:(const void *)myImageArray length [myImageArray count]];
UIImage *arrayImage = [UIImage imageWithData:data];
I receive a null UIImage pointer.
I also tried to converting it to unsigned NSNumbers first and then passing it to NSData, though perhaps I did not do this correctly. What am I doing wrong?
You cannot simply cast an NSArray of NSNumber into binary data. Both NSArray and NSNumber are objects; they have their own headers and internal structure that is not the same as the original string of bytes. You'll need to convert it byte-by-byte with something along these lines:
NSArray *bytes = #[#1, #2, #3];
NSMutableData *data = [NSMutableData dataWithLength:bytes.count];
for (NSUInteger i = 0; i < bytes.count; i++) {
char value = [bytes[i] charValue];
[data replaceBytesInRange:NSMakeRange(i, 1) withBytes:&value];
}
char is a signed int8_t, which appears to be the kind of data you're working with. It is often used to mean "an ASCII character," but in C it is commonly also used to mean "byte."

How to read input in Objective-C?

I am trying to write some simple code that searches two dictionaries for a string and prints to the console if the string appears in both dictionaries. I want the user to be able to input the string via the console, and then pass the string as a variable into a message. I was wondering how I could go about getting a string from the console and using it as the argument in the following method call.
[x rangeOfString:"the string goes here" options:NSCaseInsensitiveSearch];
I am unsure as to how to get the string from the user. Do I use scanf(), or fgets(), into a char and then convert it into a NSSstring, or simply scan into an NSString itself. I am then wondering how to pass that string as an argument. Please help:
Here is the code I have so far. I know it is not succinct, but I just want to get the job done:
#import <Foundation/Foundation.h>
#include <stdio.h>
#include "stdlib.h"
int main(int argc, const char* argv[]){
#autoreleasepool {
char *name[100];
printf("Please enter the name you wish to search for");
scanf("%s", *name);
NSString *name2 = [NSString stringWithFormat:#"%s" , *name];
NSString *nameString = [NSString stringWithContentsOfFile:#"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
NSString *dictionary = [NSString stringWithContentsOfFile:#"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
NSArray *nameString2 = [nameString componentsSeparatedByString:#"\n"];
NSArray *dictionary2 = [dictionary componentsSeparatedByString:#"\n"];
int nsYES = 0;
int dictYES = 0;
for (NSString *n in nameString2) {
NSRange r = [n rangeOfString:name2 options:NSCaseInsensitiveSearch];
if (r.location != NSNotFound){
nsYES = 1;
}
}
for (NSString *x in dictionary2) {
NSRange l = [x rangeOfString:name2 options:NSCaseInsensitiveSearch];
if (l.location != NSNotFound){
dictYES = 1;
}
}
if (dictYES && nsYES){
NSLog(#"glen appears in both dictionaries");
}
}
}
Thanks.
Safely reading from standard input in an interactive manner in C is kind of involved. The standard functions require a fixed-size buffer, which means either some input will be too long (and corrupt your memory!) or you'll have to read in a loop. And unfortunately, Cocoa doesn't offer us a whole lot of help.
For reading standard input entirely (as in, if you're expecting an input file over standard input), there is NSFileHandle, which makes it pretty succinct. But for interactively reading and writing like you want to do here, you pretty much have to go with the linked answer for reading.
Once you have read some input into a C string, you can easily turn it into an NSString with, for example, +[NSString stringWithUTF8String:].

Copy a part of NSData byte array to another NSData type

I have an original NSData type which contains let's say 100 bytes. I want to get 2 other NSData types. The first containing the first 20 bytes of the 100, and the second one containing the other 80.
They should be copied from the original NSData. Sorry if I wasn't so clear, but I'm pretty new with Objective-C.
You can use NSData's -(NSData *)subdataWithRange:(NSRange)range; to do that.
From your example, here is some code :
// original data in myData
NSData *d1 = [myData subdataWithRange:NSMakeRange(0, 20)];
NSData *d2 = [myData subdataWithRange:NSMakeRange(20, 80)];
Of course, the ranges are immediate here, you will probably have to do calculations, to make it work for your actual code.
Swift 3
let subdata1 = data?.subdata(in: 0..<20)
let subdata2 = data?.subdata(in: 20..<80)
Due to this is question is in very top of Google Search I wanna write here an example for swift
NSData *mainData = /*This is you actual Data*/
NSData *fPart = [mainData subdataWithRange:NSMakeRange(0, 20)];
NSData *sPart = [mainData subdataWithRange:NSMakeRange(20, 80)];
Instead 80 you can use some dynamic - like data length

Converting NSData bytes to NSString

I am trying to create a 16 byte and later 32 byte initialization vector in objective-c (Mac OS). I took some code on how to create random bytes and modified it to 16 bytes, but I have some difficulty with this. The NSData dumps the hex, but an NSString dump gives nil, and a cstring NSLog gives the wrong number of characters (not reproduced the same in the dump here).
Here is my terminal output:
2012-01-07 14:29:07.705 Test3Test[4633:80f] iv hex <48ea262d efd8f5f5 f8021126 fd74c9fd>
2012-01-07 14:29:07.710 Test3Test[4633:80f] IV string: (null)
2012-01-07 14:29:07.711 Test3Test[4633:80f] IV char string t^Q¶�^��^A
Here is the main program:
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//NSString *iv_string = [NSString stringWithCString:iv encoding:NSUTF8StringEncoding];
testclass *obj = [testclass alloc];
NSData *iv_data = [obj createRandomNSData];
//[iv_string dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"iv hex %#",iv_data);
//NSString *iv_string = [[NSString alloc] initWithBytes:[iv_data bytes] length:16 encoding:NSUTF8StringE$
NSString *iv_string = [[NSString alloc] initWithData:iv_data encoding:NSUTF8StringEncoding];
NSLog(#"IV string: %#",iv_string);
NSLog(#"IV char string %.*s",[iv_data bytes]);
return 0;
]
(I left in the above some commented code that I tried and did not work also).
Below is my random number generater, taken from a stack overflow example:
#implementation testclass
-(NSData*)createRandomNSData
{
int twentyMb = 16;
NSMutableData* theData = [NSMutableData dataWithCapacity:twentyMb];
for( unsigned int i = 0 ; i < twentyMb/4 ; ++i )
{
u_int32_t randomBits = arc4random();
[theData appendBytes:(void*)&randomBits length:4];
}
NSData *data = [NSData dataWithData:theData];
[theData dealloc];
return data;
}
#end
I am really quite clueless as to what could be the problem here. If I have data as bytes, it should convert to a string or not necessarily? I have looked over the relevant examples here on stackoverflow, but none of them have worked in this situation.
Thanks,
Elijah
An arbitrary byte sequence may not be legal UTF8 encoding. As #Joachim Isaksson notes, there is seldom reason to convert to strings this way. If you need to store random data as a string, you should use an encoding scheme like Base64, serialize the NSData to a plist, or similar approach. You cannot simply use a cstring either, since NULL is legal inside of a random byte sequence, but is not legal inside of a cstring.
You do not need to build your own random byte creator on Mac or iOS. There's one built-in called SecRandomCopyBytes(). For example (from Properly encrypting with AES with CommonCrypto):
+ (NSData *)randomDataOfLength:(size_t)length {
NSMutableData *data = [NSMutableData dataWithLength:length];
int result = SecRandomCopyBytes(kSecRandomDefault,
length,
data.mutableBytes);
NSAssert(result == 0, #"Unable to generate random bytes: %d",
errno);
return data;
}
When converting NSData to NSString using an UTF8 encoding, you won't necessarily end up with the same number of bytes since not all binary values are valid encodings of characters. I'd say using a string for binary data is a recipe for problems.
What is the use of the string? NSData is exactly the datatype you want for storing binary data to begin with.

AVAudioPlayer refuses to play modified wav file

The first time i call this method file1 will be nil and file2 will be returned. When this hapens the file will play normally (so the calling of this method should be fine). But when i call it for the second time it will return an NSURL which the AVAudioPlayer does not play. My guess is I have missed something in the header. In the debugging mode i have seen that the totalLength is exactly as long as the data's length.
+(NSURL *)mergeFile1:(NSURL *)file1 withFile2:(NSURL *)file2 {
if(file1 == nil) {
return [file2 copy];
}
NSData * wav1Data = [NSData dataWithContentsOfURL:file1];
NSData * wav2Data = [NSData dataWithContentsOfURL:file2];
int wav1DataSize = [wav1Data length] - 46;
int wav2DataSize = [wav2Data length] - 46;
if (wav1DataSize <= 0 || wav2DataSize <= 0) {
return nil;
}
NSMutableData * soundFileData = [NSMutableData dataWithData:[wav1Data subdataWithRange:NSMakeRange(0, 46)]];
[soundFileData appendData:[wav1Data subdataWithRange:NSMakeRange(46, wav1DataSize)]];
[soundFileData appendData:[wav2Data subdataWithRange:NSMakeRange(46, wav2DataSize)]];
unsigned int totalLength = [soundFileData length];
NSLog(#"Calculated: %d - Real: %d", totalLength, [soundFileData length]);
[soundFileData replaceBytesInRange:NSMakeRange(4, 4)
withBytes:&(UInt32){NSSwapHostIntToLittle(totalLength-8)}];
[soundFileData replaceBytesInRange:NSMakeRange(42, 4)
withBytes:&(UInt32){NSSwapHostIntToLittle(totalLength)}];
[soundFileData writeToURL:file1 atomically:YES];
return [file1 copy];
}
If anyone sees something that can be of help it would be much appreciated!
Any questions will be answered asap.
EDIT
I know there are 2 sorts of wav headers: 44 bytes or 46 bytes. I have tried both.
EDIT
I have looked at the Audio File Services Reference which contains a lot of nice stuff i might want to use, but i can't figure out how to use all this. I'm not really known with c. Hope anyone could help me out with this.
EDIT
An example of a merged wav file is found here: 7--443522512
Looks like your WAV file includes a broken FLLR chunk before the data chunk, or at least VLC thinks the FLLR chunk is over 2GB large so it tries to skip to the next chunk which is beyond the file end.
Maybe you should try to create WAV files without FLLR chunk before merging, the kAudioFileFlags_DontPageAlignAudioData seams to make Audio File Services skip it.
Another option is to extract the data chunks and write a new wav file, a did a proof of concept implementation here: https://gist.github.com/1555889