
PICKLE Reader Library API, version 1

This library is a very simple one, intended for use in interpreters
that want to support reading PICKLE files. This library does not
have functions to write or analyze PICKLE files, just to read them
in the rather limited way that interpreters should want to.

* Building

To compile the library, you'll first have to adapt the pickle.h file
to your machine. Uncomment the definition of either BIG_ENDIAN or
LITTLE_ENDIAN, depending on whether integers are stored with the
most significant byte or the least significant byte first.
(Respectively.) Also, if the "long int" type is not 32 bits long,
you'll have to change the typedef of pikLong to whatever signed
integer type is 32 bits.

The library checks these settings at run-time, so you'll get error
codes if you set them wrong. See the list of result codes for 
pikCreateMap.

Then compile pickle.c, either as a library or directly in your
interpreter makefile. (If it complains that pikNative is not
defined, you forgot to uncomment one of the _ENDIAN definitions.)

Note that picklex.h and picklex.c are not part of the reader library.
They are the editor library, which is used to write and analyze PICKLE
files. 

* Use

This is the idea:

- You open the PICKLE file yourself, using fopen(), or whatever is
appropriate.
- Read the first four bytes of the file. Use pikIsPickleHeader to
verify that it really is a PICKLE file.
- Pass the file pointer to pikCreateMap. This reads the index map
into memory, and returns a pikMapPtr, which is what you will use to
refer to the PICKLE file in future library calls.
- For each chunk you want to read, call pikFindChunk, which returns
a pikChunkID. You can then pass the pikChunkID to pikLoadChunk in
order to actually get at the chunk. pikLoadChunk will actually
allocate memory and read in the chunk, if you want. If you don't
want, it will just tell you where the chunk lies in the file, so
that you can read it yourself. (This is handy if you already have
interpreter routines which read the data, or if you want to read it
in small pieces.)
- Optionally, call pikUnloadChunk, to dispose of the memory used by
a chunk which you allocated with pikLoadChunk.
- When you're finished with the PICKLE file, call pikDestroyMap to
destroy the index map and associated structures. The pikMapPtr
becomes invalid.
- You may then close the file, using fclose() or whatever.

* Types

pikLong: A signed 32-bit numeric value.
pikType: A 32-bit value, which can be read as four characters. The
	first character is the MSB; the fourth is the LSB. (Note that
	pikTypes are endian-dependent, just as pikLongs are. You need
	not worry about this. The reader library handles all endianness
	problems when reading PICKLE files.) The pikMakeType macro can
	be used to create pikType constants.
pikMapPtr: A 32-bit identifier, which refers to an open PICKLE file.
	You get this from pikCreateMap, and pass it to every other 
	function that refers to that file.
pikFormat: A 64-bit value which represents a PICKLE chunk format.
	This consists of a major format (name) and a minor format 
	(version).
pikChunkID: A 32-bit identifier, which refers to a particular chunk
	in a PICKLE file. You get this from pikFindChunk, and pass it
	to pikLoadChunk or pikUnloadChunk.
pikChunk: A structure, which is used by pikLoadChunk to return data
	about a chunk.

* Function Reference

Most functions return a result code of type pikErr. The various
result codes are defined in pickle.h.

short pikIsPickleHeader(char *header)

This function determines if a given file is a PICKLE file. header
should point to a buffer containing at least the first four bytes of
a file. The function examines those four bytes. If they are 'pikl'
(hex values 70 69 6b 6c), the file appears to be a PICKLE file, and
pikIsPickleHeader returns TRUE (1). Otherwise it returns FALSE (0).
Result codes: TRUE or FALSE.

pikType pikMakeType(char c1, char c2, char c3, char c4)

This macro turns four characters into a pikType value. This is just
for convenience. Since it is a macro, you can use it in compile-time
constants.

pikErr pikCreateMap(FILE *file, pikMapPtr *newmap)

This function looks at an open PICKLE file, and creates an index map
in memory. file must be a file which is already open for reading.
(It may also be open for writing, if your operating system allows
this, but you should not write to the file after calling
pikCreateMap.) If pikCreateMap succeeds, the location pointed at by
newmap will be filled in with a pikMapPtr value, which you will use
in future calls to refer to the index map. If an error occurs,
*newmap is left unchanged.
Result codes:
	pikerr_None: The index map was successfully created.
	pikerr_NotAMap: The file is not a PICKLE file, or is of a  
		version not recognized by the library.
	pikerr_CantRead: An error was encounted while trying to read  
		from the file. 
	pikerr_Memory: The library was unable to allocate enough 
		memory to store the index map.
	pikerr_WrongSizeInts: When the library was compiled, pikLong was
		not defined to be a 32-bit value. You must edit pickle.h and
		recompile.
	pikerr_WrongEndian: When the library was compiled, BIG_ENDIAN
		was defined instead of LITTLE_ENDIAN, or vice versa. You 
		must edit pickle.h and recompile.	

pikErr pikDestroyMap(pikMapPtr map)

This function destroys an index map created with pikCreateMap. It
also unloads any chunks loaded into memory with pikLoadChunk, so you
should not rely on such pointers after you call pikDestroyMap. You
must call pikDestroyMap before closing the open file that you
created the map with.
Result codes:
	pikerr_None: The index map was successfully destroyed.
	pikerr_NotAMap: map is not a valid index map.
	
pikErr pikFindChunk(pikMapPtr map, pikType use, pikLong number,
	short numformats, pikFormat *formatlist, pikChunkID *idfound)

This function finds a chunk which matches a given use and number. If
numformats is 0 and formatlist is NULL, pikFindChunk will return any
chunk which matches the use and number; if there is more than one,
an arbitrary one is returned. You may also specify a list of formats
in formatlist, setting numformats to the length of the list. In this
case, pikFindChunk will return a chunk matching a format in the
list; if there is more than one, pikFindChunk will return the one
whose format is earliest in the list.
The returned value is a pikChunkID, which is written into the
location pointed at by idfound. The pikChunkID can then be passed to
pikLoadChunk and pikUnloadChunk. If you do not care about the
pikChunkID, but only want the result code, you may set idfound to
NULL.
Result codes:
	pikerr_None: A chunk was found, and *idfound has been set to its
		id.
	pikerr_NotFound: No chunk was found matching your requirements. 
		In this case, *idfound is set to the special constant 
		pik_NoChunk.
	pikerr_BadOption: One of the function arguments is invalid.
	pikerr_NotAMap: map is not a valid index map.

pikErr pikLoadChunk(pikMapPtr map, pikChunkID id, short method,
	pikChunk *found)

This function allows you to access a chunk which you have found with
pikFindChunk. Information about the chunk is written into the
pikChunk structure pointed to by found. The length of the chunk, in
bytes, will be stored in found->length; the format of the chunk will
be stored in found->format.
The method argument describes how you want to access the chunk, and
must be one of the following constants:
	pikmethod_FilePos: The position of the start of the chunk, 
		measured in bytes from the start of the file, will be stored 
		in found->data.startpos. You can use this information 
		together with found->length to read the chunk data.
	pikmethod_Memory: The entire chunk will be loaded into memory, 
		and a pointer to the start of the chunk will be stored in
		found->data.ptr. You should not write to this memory, or try
		to free() it. Further calls to pikLoadChunk with the 
		same pikChunkID will not load multiple copies of the chunk;
		they will all return the same pointer. Use pikUnloadChunk to
		free this allocated memory.
	pikmethod_DontRead: None of the above. You can use this method
		when you only care about the length or format of the chunk.
Result codes:
	pikerr_None: The function succeeded, and *found contains the
		information you requested.
	pikerr_CantRead: An error was encounted while trying to read  
		from the file. (This can only occur with the 
		pikmethod_Memory method.)
	pikerr_Memory: The library was unable to allocate enough 
		memory to store the chunk. (This can only occur with the 
		pikmethod_Memory method.)
	pikerr_BadOption: One of the function arguments is invalid.
	pikerr_NotAMap: map is not a valid index map.	
	 	
pikErr pikUnloadChunk(pikMapPtr map, pikChunkID id)

This function deallocates any memory for the given chunk which was
allocated by a call to pikLoadChunk with the pikmethod_Memory method.
The pointer which was placed infound->data.ptr becomes invalid. It is
safe to call this for a chunk which was never loaded (although
pikerr_NotFound will be returned.)
Result codes:
	pikerr_None: The memory was deallocated.
	pikerr_NotFound: pikLoadChunk has never allocated memory for 
		this chunk.
	pikerr_BadOption: One of the function arguments is invalid.
	pikerr_NotAMap: map is not a valid index map.	

