(The primary purpose of this file is to impress you with how short it is. :-) Putting PICKLE support in ZIP is basically trivial, and does not have to interfere with any existing support for external resource files. Make the appropriate customizations to pickle.h for your system. This is probably just choosing the endianness. (If you get this wrong, the library will detect it and spew errors at you.) See the PICKLE Reader Library docs for information on how to do this. Add pickle.c to the compiler command. (That's pickle.c, not picklewr.c. An interpreter only needs to read PICKLE files, not create them.) Add the following declarations to the top of fileio.c: ------------------ #include "pickle.h" /* A couple of definitions for constants used to access PICKLE files. Both are Mac-style four-byte constants. You can read each as four characters, MSB first. (Don't worry about whether your system is big- or little-endian; the PICKLE library takes care of that stuff.) */ /* The "use" of executable chunks */ #define PICKLETYPE_exec (0x65786563) /* The "format" of executable chunks containing Z-code */ #define PICKLETYPE_zcod (0x7a636f64) /* All of the following variables are set in open_story(). */ /* is_pickle is a boolean flag; it will be TRUE if the open zcode is contained in a PICKLE file. It is not static because other modules may wish to check its value. */ int is_pickle; /* pickle_map is the opaque handle to the PICKLE file map in memory. It is not static because other modules will need it in order to load PICKLE chunks. */ pikMapPtr pickle_map; /* zcode_length is the length of the zcode. If is_pickle is FALSE, this is the actual file length. */ static unsigned long zcode_length; /* zcode_offset is the starting position of the zcode in its file. If is_pickle is FALSE, this is just 0. */ static unsigned long zcode_offset; ------------------ Now replace open_story() with the following code. ------------------ { /* Most of this function is new. --Z */ int ix; char firstfour[4]; pikErr err; pikChunkID chunkid; pikChunk chunk; /* This is the list of formats that the PICKLE library will check for. You can extend it in the obvious way. */ #define NUMPICKLEFORMATS (4) static pikFormat formatlist[NUMPICKLEFORMATS] = { {PICKLETYPE_zcod, 3}, {PICKLETYPE_zcod, 4}, {PICKLETYPE_zcod, 5}, {PICKLETYPE_zcod, 8} }; /* The following three lines are what used to here. --Z */ gfp = fopen (storyname, "rb"); if (gfp == NULL) fatal ("Game file not found"); /* Now the new code... --Z */ for (ix = 0; ix < 4; ix++) { firstfour[ix] = fgetc (gfp); if (firstfour[ix] == EOF) break; } /* The PICKLE library doesn't require the file to be rewound here, and standard ZIP doesn't either, but it doesn't hurt to be sure. */ rewind(gfp); is_pickle = FALSE; zcode_length = 0; zcode_offset = 0; if (ix == 4) { if (pikIsPickleHeader(firstfour)) { /* Yes! It is indeed a PICKLE file! */ is_pickle = TRUE; /* Open the PICKLE file and load the map into memory. */ err = pikCreateMap(gfp, &pickle_map); if (err) fatal ("Unable to open PICKLE file"); /* Find and load the Z-code chunk. */ err = pikFindChunk(pickle_map, PICKLETYPE_exec, 0, NUMPICKLEFORMATS, formatlist, &chunkid); if (err == pikerr_NotFound) fatal ("There is no Z-code chunk in this PICKLE file"); if (err) fatal ("Unable to search PICKLE file"); err = pikLoadChunk(pickle_map, chunkid, pikmethod_FilePos, &chunk); if (err) fatal ("Unable to read Z-code chunk from PICKLE file"); zcode_offset = chunk.data.startpos; zcode_length = chunk.length; } } } /* open_story () */ ------------------ Replace close_story() with the following code: ------------------ { if (is_pickle) { /* --Z */ pikDestroyMap(pickle_map); } /* --Z */ /* The rest of this function is not changed. --Z */ if (gfp != NULL) fclose (gfp); } /* close_story */ ------------------ Replace get_story_size() with the following code: ------------------ { unsigned long file_length; if (is_pickle) { /* --Z */ /* Read whole file to calculate file size */ rewind (gfp); for (file_length = 0; fgetc (gfp) != EOF; file_length++) ; rewind (gfp); } else { /* Use the length loaded from the PICKLE file */ file_length = zcode_length; } /* --Z */ /* The rest of this function is not changed. --Z */ /* Calculate length of file in game allocation units */ file_length = (file_length + (unsigned long) (story_scaler - 1)) / (unsigned long) story_scaler; return ((unsigned int) file_length); }/* get_story_size */ ------------------ Finally, in read_page, you'll twice find the line: ------------------ fseek (gfp, (long) page * PAGE_SIZE, SEEK_SET); ------------------ Change this to ------------------ fseek (gfp, zcode_offset + (long) page * PAGE_SIZE, SEEK_SET); /* --Z */ ------------------ Be sure you change both occurences! Note also that if is_pickle is FALSE, zcode_offset will be zero, so this change will be safe even though there is no explicit test for is_pickle. That's it for basic PICKLE support. If you want to be able to load sounds, graphics, or whatever from PICKLE files, you'll have to roll your own code. The idea is easy: when you want some data, write code like: if (is_pickle == FALSE) { /* Do whatever you did before to get the data */ /* ... */ } else { /* Load the data from the PICKLE file */ err = pikFindChunk(pickle_map, USE, 0, NUMFORMATS, FORMATLIST, &chunkid); if (err == pikerr_NotFound) { /* No such chunk found */ } else if (err) { /* Some real error */ } /* Call pikLoadChunk() to get a hold of the data... */ } Note this is exactly what is done in open_story in order to read the Z-code chunk, after the PICKLE file is opened. This ain't a coincidence. See the PICKLE Reader Library docs for more information.