gnusto 
| resources: | Home Installation Mailing list Source code Bugs Screenshots Nightlies |
|---|---|
| reference: | Roadmap Error messages Code overview Debugger (prototype only) Playthroughs |
The null bytes problem
This problem has been solved in current versions of Mozilla, and Gnusto versions later than 0.5.0 can read binary files reliably.
For historical interest
In all current many older versions of Mozilla, JavaScript cannot reliably read a file which contains nulls. This includes all zcode story files. People are working on fixing this, and as soon as it's ready, This is now fixed, and Gnusto will be is able to load story files directly. Of course, Gnusto can't reach v1.0 until this happens. [Update: It looks like this is fixed in the current tree, but it's not in any Mozilla releases yet. Looks good for the next release, though.]
Meanwhile, if you're testing Gnusto, you still need to be able to load story files. I experimented with a few options (uuencoding the files, for example) but they all ran into the same problem: they required a lot of JavaScript processing in order to get the data out. This made loading games very slow (on the order of ten seconds to load a 60K file).
In the end I devised a new encoding, mangled-z5 or "mz5", which doesn't suffer from this problem.
Under Unix, download the encoder here (you'll need Perl, but you probably already have it). If you have a story file called, say, curses.z5, then you can convert it to mz5 by typing
./mz5 curses.z5at the $ or % prompt.
Under Windows, you may either:
- Download the Perl encoder, just as under Windows; type
mz5 curses.z5
at the Command Prompt to use it. Thanks to Cedric Knight for making the necessary changes to let this program run under Windows. - You can also download an mz5 conversion utility for Windows which doesn't need Perl (I haven't tested this, but you might well find it useful). Thanks to Eric Liga for providing this.
You may also download Dylan O'Donnell's game A Troll's Eye View already encoded in mz5.
The details of the mz5 encoding
The encoding had to
- guarantee that the file contained no nulls
- be achievable using xpconnect calls as much as possible, rather than JS processing.
The source file is considered as an array of bytes: source[]. The encoded file is the concatenation of two arrays values[] and fixups[], both the same length as source[]. Thus a file of size n will have size 2n after encoding.
For any byte offset x where 0 <= x < n:
- if source[x]==0
- values[x] may have any nonzero value.
Canonically this should be 48 decimal (digit "0" in ASCII). - fixups[x]==89 decimal (capital "Y" in ASCII)
- values[x] may have any nonzero value.
- if source[x]!=0
- values[x]==source[x]
- fixups[x] may have any nonzero value other than 89 decimal.
Canonically this should be 156 decimal (little "n" in ASCII).
This lets us load the entire file in one go using xpconnect, in return for a performance loss of having to look at two positions in the file every time we want to retrieve one character. (In fact, since the current read method in xpcom returns a string rather than a byte array, and we need to update it as if it were an array, we are already copying values out of the string into the array, so we need between one and three checks: three if the value has not yet been copied out, and one subsequently when it has.) The new null-safe interface is going to return results as a byte array, so we'll be able to do without all this.