4

I have a folder in the same directory as my mac .app and in it is a file called test.ssm. This is trying to be opened by this function:

FILE *input_file = fopen("./data/maps/test.ssm", "r");

The problem is that the application keeps getting the code: EXC_BAD_ACCESS, because it cannot open this file. My project has been set up in xcode using a normal coccoa project. This is an opengl/glut application.

qw3rty_rocks
  • 41
  • 1
  • 3
  • You should always, but always, test the return value from `fopen()` before using the file pointer that was supposed to be created. That way, you avoid crashes because of accessing a null pointer. Also, in C++, you should probably be using `` rather than either `` or ``. – Jonathan Leffler Sep 17 '11 at 05:45

3 Answers3

2

The problem is that a .app is a package, and therefore it is actually a directory structure as well, not a "normal" file. Your actual executable is inside the directory YourApp.app/Contents/MacOSX/. Thus when you use a relative path starting with ./ to open a file in C-code, the executable is actually looking for your file inside the YourApp.app/Contents/MacOSX/ directory, and not the parent directory that the .app package is installed in.

You can actually browse the directory structure of your .app by right-clicking on it and choosing View Package Contents.

If you are going to place files in the file-system that you would like accessible from your executable, either package them inside the .app, or place them outside the .app, and place enough ../ in your file access to get you out of the .app directory structure and into the parent directory where the .app is installed.

If you want your /data directory to be inside the .app package, then you would only have to add enough ../ to your path to get you to out of your /MacOSX directory and into the root of the .app where the /data directory would be found.

Finally, if you need to know the absolute path where your executable is located, you can always use the C-function _NSGetExecutablePath found inside of mach-o/dyld.h (i.e., you don't need objective-C). From there you can modify the path to get at any other directory in the file-system relative to where your executable is by trimming it to the proper parent directory and then appending the path name to the file you want to open.

Jason
  • 31,834
  • 7
  • 59
  • 78
  • Yes I understand that bit but I have no idea where to put the folder. Wherever I put it, it doesn't seem to want to work. Do you know where in the .app directory i put it? – qw3rty_rocks Sep 17 '11 at 02:46
  • You would have to place the file in the same directory that the executable is in, or at least relative to it. As noted in my answer, you can browse the package contents to see where your executable is by right-clicking on the `.app` and choosing `View Package Contents`. – Jason Sep 17 '11 at 02:48
  • I have put the folder in the same directory and it is still not working??? I have no idea what is going on. – qw3rty_rocks Sep 17 '11 at 02:52
  • The file `test.ssm` does exist, and you have the correct permissions on the file, right? – Jason Sep 17 '11 at 02:53
  • The file exsists and it has the right permissions. If i have the folder at the root of my hard drive and remove the dot in my fopen call, the application works, but I don't want to do it like this. – qw3rty_rocks Sep 17 '11 at 03:12
  • I found out that if I go to terminal and cd to the directory inside the .app where the executable is located and then run it from inside terminal it works, but double clicking the .app doesn't work, any idea how to fix this? – qw3rty_rocks Sep 17 '11 at 03:48
  • Ok so ive tried your idea and it gives me this string: /Users/jeremy/Documents/Virus/build/Release/Virus.app/Contents/MacOS/./virus/../data/maps/test.ssm - How would i make it work, as it has the executable name in the string – qw3rty_rocks Sep 17 '11 at 05:27
  • You are going to have to trim the string that `_NSGetExecutablePath` returns. For instance, with that string, you will have to take out any directories and executables up to the parent directory where `/data` is located. For instance, if you get `/Users/jeremy/Documents/Virus/build/Release/Virus.app/Contents/MacOS/virus` returned from the function, and `/data` is stored inside of `/MacOSX`, you will have to convert the string into `/Users/jeremy/Documents/Virus/build/Release/Virus.app/Contents/MacOS/data/maps/test.ssm`. That means truncating off `virus`. – Jason Sep 17 '11 at 05:35
  • If `/data` was stored inside of the root of `Virus.app`, then you would have to truncate `Contents/MacOS/virus`, and then append the path to your file so that it looks like `/Users/jeremy/Documents/Virus/build/Release/Virus.app/data/maps/‌​test.ssm`. You can use functions like `strtok()` and other string-manipulation functions in order to split up the string passed to your from `_NSGetExecutablePath` and create a new path that will get you to your file's directory. – Jason Sep 17 '11 at 05:38
  • Creating files in the `.app` directory is a bad idea, in general. For example, I certainly don't run apps with root privileges except under duress, so I'd better not be able to create files in the `.app` directory. That smacks of Windows-think! Shouldn't you be using something under `$HOME/Library/Application Support/YourAppName` or something like that? – Jonathan Leffler Sep 17 '11 at 05:48
  • the point of not putting the files in the users document folders, etc is to make sure that the files stay with the application wherever it moves and to make it easier to distribute. – qw3rty_rocks Sep 17 '11 at 05:54
  • I may have found the solution: http://stackoverflow.com/questions/516200/relative-paths-not-working-in-xcode-c – qw3rty_rocks Sep 17 '11 at 06:42
  • Yep, that link is a genius, I got it working, basically you get a url(directory) and you use the command chdir() to change to that directory and then you can use relative directory paths again :) – qw3rty_rocks Sep 17 '11 at 20:49
1

You have to provide absolute file path in Mac OS X, because Mac OS X is built to work with file dialogs or something like that.

fnc12
  • 2,241
  • 1
  • 21
  • 27
0

As said above, the .app is a package, or a special folder that the Mac OS X GUI treats like a file. The .app isn't what's being run, what's being run is your.app/Contents/MacOS/your, and the current directory refers to your.app/Contents/MacOS/. If you don't mind using Objective-C in your app (if you're not linking Foundation.framework already I'd advise you find another way), you can do this to get the path of the app bundle:

const std::string GetApplicationDirectory()
{
    id info = [[NSBundle mainBundle] infoDictionary];
    NSString *bundleID = [info objectForKey: @"CFBundleIdentifier"];

    NSWorkspace *wp = [[NSWorkspace alloc] init];
    NSString *app   = [wp absolutePathForAppBundleWithIdentifier: bundleID];

    const char *str = [[app substringToIndex: [app length] - [[app lastPathComponent] length]]] cStringUsingEncoding: NSASCIIStringEncoding];
    return std::string( str );
}
RC Howe
  • 509
  • 3
  • 16