Go Back   MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Sep 1, 2012, 12:53 PM   #1
Angry Bugs
macrumors newbie
 
Join Date: Sep 2012
Binary file read issue

Hi!,

I use the following code to open a binary file:

Code:
const char* fileName = "myFile.bin";	

FILE* file = NULL;


const char* buffer;

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *path = [NSString stringWithUTF8String:fileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:path];
	
if (path != nil)
    buffer = [path UTF8String];


[pool release];

file = fopen(buffer, "rb");
	
if (!file)
    return -1;

//Do fread stuff here

fclose(file);

return 0;

But sometimes, not very often, the functions returns -1.
Is there any problem in this code, or a reason why only sometimes this function doesn't find the file?, although the file is present.

Any help would be appreciated.

Thanks.

Last edited by Angry Bugs; Sep 1, 2012 at 02:12 PM.
Angry Bugs is offline   0 Reply With Quote
Old Sep 1, 2012, 01:15 PM   #2
chown33
macrumors 603
 
Join Date: Aug 2009
1. Go to the NSString class reference doc. Find the description of the UTF8String method. Read what it says about "the autorelease context in which the C string is created."


2. When referring to file paths, you should always use the file-system representation. There are two NSString methods related to this. I recommend the one that copies the data into your provided buffer.
chown33 is offline   0 Reply With Quote
Old Sep 1, 2012, 01:40 PM   #3
Angry Bugs
Thread Starter
macrumors newbie
 
Join Date: Sep 2012
Thanks a lot.

I think replacing this :

buffer = [path UTF8String];

with this:

sprintf(buffer, "%s", [path UTF8String]);

will do the job.

Last edited by Angry Bugs; Sep 1, 2012 at 02:11 PM.
Angry Bugs is offline   0 Reply With Quote
Old Sep 1, 2012, 03:41 PM   #4
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by Angry Bugs View Post
I think replacing this :

buffer = [path UTF8String];

with this:

sprintf(buffer, "%s", [path UTF8String]);

will do the job.
If that's the only change you make, then you haven't fixed anything. You've just traded one bug for another.

The posted sprintf() is just a strange way of performing an strcpy(). I advise you to look up strcpy() to see what it does. I also advise looking at strncpy() to see how it differs, and compare to snprintf(). Consider what might happen if you copy a string that's longer than the buffer memory reserved for it.

At the point you propose placing that code, what is buffer pointing to? Is it a valid allocated block of memory? Of what length? I suggest using the debugger to step through and see what buffer holds at that point. If buffer isn't pointing at a valid block of memory, what do you suppose will happen if you copy a string into that memory?


And you're still making the mistake of using UTF8String instead of one of the file-system representation methods. See this post on Apple's cocoa-dev list:
http://lists.apple.com/archives/coco.../msg00821.html
chown33 is offline   0 Reply With Quote
Old Sep 1, 2012, 05:03 PM   #5
PhoneyDeveloper
macrumors 68030
 
PhoneyDeveloper's Avatar
 
Join Date: Sep 2008
Use [path fileSystemRepresentation]

Is it possible that your file names have non-ascii characters in them?

Get that [pool release] out of there. You are making your path go away!
PhoneyDeveloper is offline   0 Reply With Quote
Old Sep 1, 2012, 05:10 PM   #6
Angry Bugs
Thread Starter
macrumors newbie
 
Join Date: Sep 2012
Thanks for taking the time to reply.

I read the link you post, and the changed the code.
I'm not sure that the length of the buffer is enough.

Code:
const char* fileName = "myFile.bin";	

FILE* file = NULL;


char buffer[256];

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *path = [NSString stringWithUTF8String:fileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:path];

BOOL success;
	
if (path != nil)
    success = [path getFileSystemRepresentation:buffer maxLength:256]

if (!success)
    return -1;

[pool release];

file = fopen(buffer, "rb");
	
if (!file)
    return -1;

//Do fread stuff here

fclose(file);

return 0;
Angry Bugs is offline   0 Reply With Quote
Old Sep 1, 2012, 05:24 PM   #7
Angry Bugs
Thread Starter
macrumors newbie
 
Join Date: Sep 2012
Quote:
Use [path fileSystemRepresentation]

Is it possible that your file names have non-ascii characters in them?

Get that [pool release] out of there. You are making your path go away!
All the characters are ascii, i think the other way could be to use fileSystemRepresentation and move [pool release] to the end of the function, right?
Angry Bugs is offline   0 Reply With Quote
Old Sep 1, 2012, 06:03 PM   #8
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by Angry Bugs View Post
All the characters are ascii, i think the other way could be to use fileSystemRepresentation and move [pool release] to the end of the function, right?
Why are you so concerned about memory usage that you feel the need to bracket a few strings with their own auto-release pool?


If you're looking for waste, consider the red-hilited code:
Code:
const char* fileName = "myFile.bin";	

FILE* file = NULL;

char buffer[256];

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *path = [NSString stringWithUTF8String:fileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:path];
You're starting with a constant C string, converting that to an immutable NSString, then appending that to another NSString. Why all the conversions? Do you realize that Objective-C supports NSString literals? For example, all the red can be replaced by one green line:
Code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"myFile.bin"];
Notice that I also removed the extra auto-release pool, so now you can just use fileSystemRepresentation without having to copy it or worry that your local buffer isn't long enough. All the objects that were made will be auto-released when the existing pool is drained. No micro-managing of memory is necessary.


As another possible bug, consider what happens if path is nil in your code. If you haven't done a static analysis, I think you'll find a reference to an uninitialized buffer being used by fopen(). You may even find that the compiler is giving you a warning about this.
chown33 is offline   0 Reply With Quote
Old Sep 1, 2012, 06:52 PM   #9
KnightWRX
macrumors Pentium
 
KnightWRX's Avatar
 
Join Date: Jan 2009
Location: Quebec, Canada
Quote:
Originally Posted by chown33 View Post
Why are you so concerned about memory usage that you feel the need to bracket a few strings with their own auto-release pool?


If you're looking for waste, consider the red-hilited code:
Code:
const char* fileName = "myFile.bin";	

FILE* file = NULL;

char buffer[256];

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSString *path = [NSString stringWithUTF8String:fileName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:path];
If we're talking waste, how bout plain ol' :

Code:
FILE * file;
NSString * path = [[NSBundle mainBundle] pathForResource: @"myFile" ofType: @"bin"];
if(path)
{
      file = fopen([path fileSystemRepresentation], "rb");

      if(file)
      {
            /* Do Stuff */
            fclose(file);
      }
}
No need for 50 URLs/paths/strings here, strictly speaking if we're discussing iOS programming. I don't think you have access outside your app bundle anyhow.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others."
-- Pericles
KnightWRX is offline   0 Reply With Quote
Old Sep 1, 2012, 06:53 PM   #10
Angry Bugs
Thread Starter
macrumors newbie
 
Join Date: Sep 2012
Quote:
As another possible bug, consider what happens if path is nil in your code. If you haven't done a static analysis, I think you'll find a reference to an uninitialized buffer being used by fopen(). You may even find that the compiler is giving you a warning about this.
You're right.

Again, thanks a lot for your reply, it really helps me a lot.
Angry Bugs is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Similar Threads
thread Thread Starter Forum Replies Last Post
Can not read to file Iphone Buhussain iPhone/iPad Programming 5 Mar 10, 2014 01:10 AM
How to read a cvs file into NSArray? vukid Mac Programming 30 Oct 11, 2013 08:55 PM
won't read file extensions seawench2002 Mac Pro 2 Jan 1, 2013 10:04 PM
How to read IPSW File georgelmoore iPhone Tips, Help and Troubleshooting 0 Sep 6, 2012 07:11 AM
Cannot execute binary file Please help grandeurfly MacBook Pro 5 Aug 14, 2012 02:11 AM

Forum Jump

All times are GMT -5. The time now is 12:34 PM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC