Jump to content

Recommended Posts

Posted

I'm trying to work on the Mac Blades a little, but I've run into a few problems.

 

First, it can't seem to find the scenarios, and I can't understand why since there seems to be nothing wrong with my code.

 

Second, after informing me that there are no scenarios installed, it crashes. I can't locate where exactly the crash is occurring, but it's SIGSEGV, which I think means access violation.

 

And last but certainly not least, I can't debug it. The debugger gives me a "Bad CPU type in executable" error. I suspect that this is because it's compiled as a PPC application, which is odd, because the Architecture setting clearly says "i386". I can't seem to get either an Intel or a Universal application for some reason.

 

If I can resolve the third problem, I may be able to figure out the first two. Does anyone have any ideas?

Posted

It cannot be compiled as Intel, I think, because of the many old libraries, such as Quickdraw, on which it depends. This means that generally you get to fall back on debug-by-printf.

 

With regard to the crash: Yep, if you get a SIGSEGV or SIGTERM you almost certainly dereferenced a bad pointer. I fear I can't reproduce your crash, as the (likely different) version of the code I have lying around finds the scenarios and does okay until it claims it has an 'error 9880'.

Posted

I was actually trying to locate where the problem was by inserting SysBeep(1) in various locations (one at a time though).

 

Maybe it'll help if I post the code?

Code:
FSRef ref;FSIterator iter;err = FSPathMakeRef((UInt8*)"Blades of Exile Scenarios/",&ref,NULL);err = FSOpenIterator(&ref, kFSIterateFlat, &iter);if (err != noErr)SysBeep(2);ItemCount numScens = 0;FSRef fileRefs[50];FSSpec files[50];//myCPB.dirInfo.ioCompletion = NULL;//myCPB.dirInfo.ioNamePtr = scen_name;//myCPB.dirInfo.ioVRefNum = start_volume;do {    //myCPB.hFileInfo.ioFDirIndex = index;    //myCPB.hFileInfo.ioDirID = scen_dir;    //err = PBGetCatalogInfoSync(&myCPB);    if(cur_entry == numScens){        err = FSGetCatalogInfoBulk(iter, 50, &numScens, NULL,	kFSCatInfoNone, NULL, fileRefs, files, NULL);        cur_entry = 0;    }

As you can see, I tried to rewrite it to use non-deprecated functions. I can't see anything wrong with the code itself: the FSRef call completes successfully, as does the following call, but the GetCatalog call returns a "no more items" error.

 

This isn't what's causing the crash, though. I'm not sure whether the crash is related to this, but it occurs after the code runs through to the end of this function and even right back out into the switch statement in handle_startup_press(). I haven't tested further than that, so it could be almost anywhere beyond there or even in the next iteration of the event loop.

 

The odd thing about the crash is that sometimes, instead of SIGSEGV, it simply stops responding...

Posted

I would recommend printf instead of SysBeep. That way you can get out the same information that you would have gotten if you had been able to use the debugger, if with the annoyance that you have to recompile when you think of another bit of information that you want to check.

 

One point that occurs to me: It looks like you're using a relative path as the argument to FSPathMakeRef. Are you sure that the current directory, to which your path is relative, is what you think it is? You might try using CFBundleCopyBundleURL to get a URL to the location of the application, and from there constructing an absolute path.

Posted

I may be wrong, but i though FSPathMakeRef used POSIX paths :

 

Blades of Exile Scenarios/ vs Blades of Exile Scenarios:

 

confused

 

Also, in the windows code, the custom scenario problem was caused by the program looking in the wrong directory (because an OpenFileName function changed the working directory.

 

Hope it helps,

Chokboyz

Posted
Originally Posted By: Niemand
I would recommend printf instead of SysBeep. That way you can get out the same information that you would have gotten if you had been able to use the debugger, if with the annoyance that you have to recompile when you think of another bit of information that you want to check.
But how do I see the output?

Originally Posted By: Niemand
One point that occurs to me: It looks like you're using a relative path as the argument to FSPathMakeRef. Are you sure that the current directory, to which your path is relative, is what you think it is? You might try using CFBundleCopyBundleURL to get a URL to the location of the application, and from there constructing an absolute path.
In the project window, under Executables, I right-clicked on the app, chose Get Info, and set the working directory to "Project directory". Before doing that, it failed to find the resource files (for which I also used relative paths); now it finds them perfectly well. So unless the working directory has somehow changed since opening the resource files, that can't be the problem.

Originally Posted By: Chokboyz
I may be wrong, but i though FSPathMakeRef used POSIX paths :

Blades of Exile Scenarios/ vs Blades of Exile Scenarios:
The former is a POSIX path; the latter is the Mac Classic path format.

Originally Posted By: Chokboyz
Also, in the windows code, the custom scenario problem was caused by the program looking in the wrong directory (because an OpenFileName function changed the working directory.
Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory?
Posted

Printf prints to the console, while is the system log, viewable in Cosole.app if you're running the program stand-alone, or in XCode's console when run from within Xcode. Xcode should open the console automatically when you run the program, but if it doesn't, use Command+Shift+R.

 

The issue with setting the working directory in the IDE is that this will make it work within the IDE, but not necessarily when it's launched by itself, such as from the Finder. You might want to test and see whether your version works this was as well or not.

 

EDIT: I thought it might help to provide some somewhat similar and working code. Below is a chunk I added to the character editor to make it able to load the item definitions from the scenario the party is in. I wouldn't call it great code (particularly as it only reports error messages to the console where the user won't see them), but it does at least run, so maybe there's something useful in it.

Click to reveal..
Code:
bool load_scen_item_defs(char scen_name[256]){	OSErr err;	char cPath[768];	CFBundleRef mainBundle=CFBundleGetMainBundle();	CFURLRef progURL = CFBundleCopyBundleURL(mainBundle);	CFStringRef progPath = CFURLCopyFileSystemPath(	  progURL, kCFURLPOSIXPathStyle);	CFRange findRes;	if(!CFStringFindWithOptions(progPath, CFSTR("/"), 	  CFRangeMake(0, CFStringGetLength(progPath)), 	  kCFCompareBackwards, &findRes)){		printf(		  "Error: Unable to find scenario directory\n");		return(false);	}	CFStringRef scenPath = CFStringCreateWithFormat(	  NULL,NULL,CFSTR("%@/Blades of Exile Scenarios/%s"),	  CFStringCreateWithSubstring(NULL, progPath, 	  CFRangeMake(0,findRes.location)),scen_name);	CFStringGetCString(scenPath, cPath, 768, 	  kCFStringEncodingUTF8);	FSRef scenRef;	FSPathMakeRef((UInt8*)cPath, &scenRef, false);	FSIORefNum forkRef;	HFSUniStr255 forkName;	FSGetDataForkName(&forkName);	err=FSOpenFork(&scenRef, forkName.length, 	  forkName.unicode, fsRdPerm, &forkRef);	if(err!=noErr){		printf("Unable to open scenario data\n");		return(false);	}	err=FSReadFork(forkRef, fsFromStart, 41942, 	  26400, &(item_list[0]), NULL);	if(err!=noErr){		printf("Unable to read scenario data\n");		return(false);	}	err=FSCloseFork(forkRef);	if(err!=noErr){		printf("Unable to close scenario data\n");	}	return(true);}
Posted
Originally Posted By: Niemand
The issue with setting the working directory in the IDE is that this will make it work within the IDE, but not necessarily when it's launched by itself, such as from the Finder. You might want to test and see whether your version works this was as well or not.
Hmm... if launched from the Finder, would the working directory be set to the folder containing the package?

That could explain why it doesn't work when I double-click it...

...but moving it into the project directory doesn't change that, so maybe not.
Posted
Quote:
Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory?

Yup, but aren't you squishing the err value resulting from FSPathMakeRef when assigning it to the output of FSOpenIterator ?
Let's imagine that FSPathMakeRef fails and ref is empty. Then FSOpenIterator has nothing to do thus doesn't return an error.
Then FSGetCatalogInfoBulk is called with iter which can be absolutely everything since it hasn't been initialized ...
FSOpenIterator should report an error if iter was not properly open ...

Is the function working when using fullpath ?

Besides, we're assuming that cur_entry is valid since we don't know where it is declared smile

An hypothesis though, wink
Chokboyz
Posted
Originally Posted By: Chokboyz
Quote:
Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory?

Yup, but aren't you squishing the err value resulting from FSPathMakeRef when assigning it to the output of FSOpenIterator ?
In that version of the code, yes, but a slightly different version revealed that FSPathMakeRef returned noErr (ie 0).

Originally Posted By: Chokboyz
Besides, we're assuming that cur_entry is valid since we don't know where it is declared smile
It's declared as a short a few lines up, and initialized to 0.
Posted

Whoa, I imagine this is probably the cause of the crash:

Quote:

Blades of Exile(43576,0xa08f6830) malloc: *** error for object 0x2000: pointer being freed was not allocated

*** set a breakpoint in malloc_error_break to debug

 

I just need to determine where that happens. Tomorrow, maybe.

Posted

In theory yes, but likely not in practice for two reasons: Jeff almost never used C++ techniques, so I would be surprised if the program explicitly used new anywhere at all, and by default with g++ (as far as I can tell) operator new is implemented using malloc, so you might actually get away with mixing the mechanisms.

 

My guess would be that your pointer isn't being allocated at all, it's just holding a junk value which causes trouble when you try to work with it. The fact that the pointer apparently has the rather improbable value of 0x2000 seems to me to support this idea.

Posted

Well, I changed one or two mallocs to new, but I never changed any frees to delete, so that's why I thought it might be that.

 

I'll go look up all instances of malloc, new, and free, though. It's obviously one of them that caused that. (I only got that message once, though...)

 

EDIT: It's not the source of the crash – there was only a single occurence, in a function which I suspect was not part of the original source. (a function for loading a bmp from a file)

Posted

GDB doesn't work – it gives me a "Bad CPU type in executable" error.

 

I haven't determined what caused that message to appear, but it hasn't appeared since, so maybe it solved itself somehow.

 

I finally figured out the cause of the SIGSEGV, though. Since I changed the type of scen_headers from scen_header_type[25] to vector<scen_header_type>, the version check immediately after calling pick_a_scen() was no longer safe because the vector may have 0 elements (if no scenarios are found). I simply shifted the code to check for scen < 0 before that instead of after.

 

The game still fails to find the scenarios, though. I'm no closer to a solution than before, really. I took Niemand's advice and altered it to use an absolute path, but that didn't change anything. There are clearly 3 scenarios in the folder it is checking in, but they aren't being found.

Posted

I'm not sure how to do that from C. It shouldn't help here, since I'm using an absolute path.

 

The path of the scenario folder is being printed, though, and it's correct, so that does not appear to be the problem. FSOpenIterator also completes without error. It's just the catalog info call that fails, and I can't figure out why.

 

...Maybe I'll try putting the absolute path in as a single string literal, just to see if it'll work. Obviously that's an incredibly bad strategy, but I don't have any other ideas...

 

EDIT: Unsurprisingly, that didn't help.

Posted

Try outputting a simple file to the scenario directory (or what the program thinks is the scenario directory), then checking the Scenario Folder for the file. Or searching for it on your HD if it's not in the scenario folder.

 

That way you can tell whether it's a directory problem or a scenario reading problem.

Posted
Quote:
just the catalog info call that fails, and I can't figure out why.

The function seems correct to me ... (from what i can tell from only looking at the prototype smile )
Is there a way to look inside iter to see if it's empty ?

Apart from that, have you tested if your check if(cur_entry == numScens) was succeding ?

Good luck,
Chokboyz
Posted
Originally Posted By: Drakefyre
Try outputting a simple file to the scenario directory (or what the program thinks is the scenario directory), then checking the Scenario Folder for the file. Or searching for it on your HD if it's not in the scenario folder.

That way you can tell whether it's a directory problem or a scenario reading problem.
Hmm... I could probably try that...

EDIT: Tried it, and the file was exactly where I would expect it to be. I called FSCreateFileUnicode(&ref, 15, name, NULL, NULL, NULL, NULL), where ref is the FSRef that I just created from FSPathMakeRef to point to the scenario directory. No error was returned, and when I checked the scenario directory, the file was there.

Originally Posted By: Chokboyz
Quote:
just the catalog info call that fails, and I can't figure out why.

The function seems correct to me ... (from what i can tell from only looking at the prototype smile )
Is there a way to look inside iter to see if it's empty ?

Apart from that, have you tested if your check if(cur_entry == numScens) was succeding ?

Good luck,
Chokboyz
The format of the FSIterator type is hidden, so I have no way to tell if it's valid apart from the fact that FSOpenIterator did not return an error.

There are two ways I can be sure that the if(cur_entry == numScens) check is succeeding. The first is that they are both initialized to zero; the second is that the diagnostic message I placed in that if statement is being displayed.
Posted

Posting here partly because it's somewhat related, partly because this problem is still not resolved (unless it resolved itself silently), and partly because if I put it in the Compiled Suggestion List it's liable to get lost quickly.

 

 

I have successfully compiled the scenario editor as a Universal binary which runs successfully. (The two things preventing this from working were accessing picFrame rather than using QDGetPictureBounds or whatever it's called, and possibly also constructing the GWorlds in big-endian rather than native-endian.) It still works in ppc mode too.

 

The only problem is that loading a scenario fails in Intel mode – it tries to locate the first town beyond the end of the file. I'm guessing this is also an endian issue; I'll look into it at some point.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...