
 NAME
 ====
 
 RIFFIO API - RIFFIO data types and concepts
 
 SYNOPSIS
 ========

 The RIFFIO API provides data types and functions for reading, writing, and 
 navigating RIFF files.  The RIFF file format is documented in

|     Microsoft Press, "Microsoft Windows Multimedia Programmer's
|     Reference", Redmond WA, 1991. 
|
|     Telephone: 1-800-MSPRESS, ISBN#1-55615389-9

 Although the RIFFIO API uses similar names and terminology as Microsoft's
 mmio API, the RIFFIO types and functions are _not_ the same as those
 described by Microsoft.

 RIFFIO types, macros, and functions all begin with the string "RIFFIO".


 RIFFIOSuccess
 =============
 How do you know if a RIFFIO function succeeded?
 
 Many RIFFIO functions return a zero status integer if they fail.
 This is equivalent to a false boolean value in C. In other words,
 a test for false is a test for failure.

 To help readability the success values
 are encoded as an enumerated type, RIFFIOSuccess.


| 
| typedef enum
| {
|   RIFFIO_FAIL = 0,      /* false, operation failed     */
|   RIFFIO_OK = 1         /* true, operation successful */
| } RIFFIOSuccess;
| 
              
 WARNING
 -------
 Never test for equality to these values. Use them only 
 as output from a function.


 RIFFIO Errors
 =============
 How does RIFFIO deal with errors?

 No RIFFIO function will cause a correct program to exit.  There are
 however, many assertions in the debug version of the RIFFIO library
 that will terminate a program if they encounter a bug in the
 library or programmer's code.
 
 Upon encountering an error beyond a programmer's control some
 RIFFIO functions will call an error handling function.  The default
 error handling function will print an error message to stderr
 (although it is possible for the library to be compiled with no
 default error handler).
 
 A user may provide their own error handling function with
 RIFFIOInstallErrorHandler().
 
 Error handling functions take the form

 RIFFIOErrorHandler
 ------------------ 

| typedef void (*RIFFIOErrorHandler)(const char *strModule, 
|                                    const char *strFormat, 
|                                    va_list args);
| 

 A RIFFIOErrorHandler is a function that handles an error, given the
 name of a module <strModule> where an error has occurred and a
 message about the error.  The message consists of a printf()
 compatible format string, <strFormat>, followed by its corresponding
 variable argument list <args>.  

| 

 Byte Ordering
 =============
 Byte ordering determines how integers are stored in a RIFF file.

 There are two conventions: 
 
 RIFF form (little-endian, Intel) :
   Least significant byte first, most significant byte last.
 
 RIFX form (big-endian, Motorola) :
   Most significant byte first, least signifcant byte last.
 
 Byte ordering affects integers only; FOURCC's and strings are
 stored the same way in RIFF and RIFX forms.  

 TWB - I don't know if byte order affects IEEE floating point numbers.


 RIFFIOFormType
 --------------
 How is the byte order of a RIFF file represented by RIFFIO?

 Byte order information is conveyed by RIFFIO using an enumerated
 type, RIFFIOFormType. 

 The form type (byte order) of a RIFF file.  

| 
| typedef enum
| {
|         RIFFIO_FORM_UNKNOWN,   /* Unknown byte order */
|         RIFFIO_FORM_RIFF,      /* Intel byte order, little-endian */
|         RIFFIO_FORM_RIFX       /* Motorola byte order, big-endian */
| } RIFFIOFormType;
| 

 It allows for the possiblity that the byte order has not yet
 been determined for a RIFF file.
 
 NOTE
 ----
 This enumerated type is not the same as a four-character code
 and must not be used as a RIFFIOFOURCC. 


 RIFFIOFile
 ==========
 How are RIFF files represented?

 RIFF files are represented by a pointer to a RIFFIOFile structure.
 For example 

| RIFFIOFile *rfNiff; 
 
 There are no public members of a RIFFIOFile.
 
 RIFFIOOffset
 ------------
 An offset into a RIFFIOFile (in bytes).

| typedef unsigned long RIFFIOOffset; 
| 

 RIFFIOFile Callbacks
 ====================
 Upon creation, a RIFFIOFile is useless.  Before you can use a 
 RIFFIOFile you must tell it what file it will operate on and
 also _how_ it will perform its I/O. 
 
 RIFFIOFileInit() accepts a void pointer to a user-defined object
 that represents a "file".  The user must also provide read, write,
 seek, and tell callbacks that are compatible with that "file".

 Subsequent RIFFIOFile operations will supply the callbacks with the
 user-defined file pointer.
 
 RIFFIOReader
 ------------ */
| typedef 
| long (*RIFFIOReader)(void *vpUserFile, void *vpBuffer, long nBytes);

 A RIFFIOReader is a function that reads <nBytes> from a user-defined file 
 <*vpUserFile> and places them at <vpBuffer>. <vpBuffer> must be large
 enough to hold the requested number of bytes.

 RETURNS
 
     *  the number of bytes actually read,
     *  0 on end of file,
     * -1 on error.

 RIFFIOWriter
 ------------

| typedef 
| long (*RIFFIOWriter)(void *vpUserFile, void *vpBuffer, long nBytes);

 A RIFFIOWriter is a function that writes <nBytes> from <vpBuffer> 
 to a user-defined file <vpUserFile>.

 RETURNS
 
     *  the number of bytes actually written, or 
     *  -1 on error.

 RIFFIOSeeker
 ------------

| 
| typedef enum
| {
|   RIFFIO_SEEK_SET, /* Seek relative to file beginning    */
|   RIFFIO_SEEK_CUR, /* Seek relative to current file position */
|   RIFFIO_SEEK_END  /* Seek relative to file end          */ 
| } RIFFIOSeekOrigin;
| 
| typedef 
| RIFFIOSuccess (*RIFFIOSeeker)(void *vpUserFile, 
|                              RIFFIOOffset offset, 
|                              RIFFIOSeekOrigin origin);
| 

 A RIFFIOSeeker sets the position of a user-defined file <vpUserFile>
 relative to <origin> by <offset> bytes.
 It returns 0 on failure.

 RIFFIOTeller
 ------------

| typedef long  (*RIFFIOTeller)(void *vpUserFile);

 A RIFFIOTeller is a function that returns the current position of
 a user-defined file <vpUserFile>.  The file position is reported 
 in bytes offset from the start of file.


 How are RIFF four-character codes supported?
 ============================================
 
 RIFFIOFOURCC
 ------------
 RIFFIO stores a four-character code in a RIFFIOFOURCC type.

| typedef unsigned long RIFFIOFOURCC;
| 

 RIFFIO also provides a macro to construct a RIFFIOFOURCC out
 of four individual characters.
 
 RIFFIOMAKEFOURCC
 ----------------

| #define RIFFIOMAKEFOURCC(first, second, third, fourth)  \
|  ( ((RIFFIOFOURCC) (unsigned char) (first)      )       \
|  | ((RIFFIOFOURCC) (unsigned char) (second) << 8)       \
|  | ((RIFFIOFOURCC) (unsigned char) (third)  << 16)      \
|  | ((RIFFIOFOURCC) (unsigned char) (fourth) << 24))
| 

 Notice that the first character is stored in the least significant
 part of the RIFFIOFOURCC, regardless of machine byte order.

 Use RIFFIOFOURCCToString() to decompose a RIFFIOFOURCC into 
 its constituent characters.

 The memory used by RIFFIOFOURCCToString() must already be allocated
 hold at least RIFFIO_FOURCC_LIM characters.  
 
 TWB - This value is bigger than 5 because I would ultimately like
 to allow strings formatted with escape codes. Microsoft implies that
 FOURCC's can be formatted with escape codes in

|      Win 3.1 SDK: Multimedia Prog. Reference

 We may allow 4 * 4 character escape codes + 1 NUL

| #define RIFFIO_FOURCC_LIM 17
| 
 
 RIFFIO provides some commonly used four-character codes.

| #define RIFFIO_FOURCC_RIFF RIFFIOMAKEFOURCC('R','I','F','F')
| #define RIFFIO_FOURCC_RIFX RIFFIOMAKEFOURCC('R','I','F','X')
| #define RIFFIO_FOURCC_LIST RIFFIOMAKEFOURCC('L','I','S','T')
| 
 
 INFO List Chunks 

| #define RIFFIO_FOURCC_INFO RIFFIOMAKEFOURCC('I','N','F','O')
| 
| #define RIFFIO_FOURCC_IARL RIFFIOMAKEFOURCC('I','A','R','L')
| #define RIFFIO_FOURCC_IART RIFFIOMAKEFOURCC('I','A','R','T')
| #define RIFFIO_FOURCC_ICMS RIFFIOMAKEFOURCC('I','C','M','S')
| #define RIFFIO_FOURCC_ICMT RIFFIOMAKEFOURCC('I','C','M','T')
| #define RIFFIO_FOURCC_ICOP RIFFIOMAKEFOURCC('I','C','O','P')
| #define RIFFIO_FOURCC_ICRD RIFFIOMAKEFOURCC('I','C','R','D')
| #define RIFFIO_FOURCC_ICRP RIFFIOMAKEFOURCC('I','C','R','P')
| #define RIFFIO_FOURCC_IDIM RIFFIOMAKEFOURCC('I','D','I','M')
| #define RIFFIO_FOURCC_IDPI RIFFIOMAKEFOURCC('I','D','P','I')
| #define RIFFIO_FOURCC_IENG RIFFIOMAKEFOURCC('I','E','N','G')
| #define RIFFIO_FOURCC_IGNR RIFFIOMAKEFOURCC('I','G','N','R')
| #define RIFFIO_FOURCC_IKEY RIFFIOMAKEFOURCC('I','K','E','Y')
| #define RIFFIO_FOURCC_ILGT RIFFIOMAKEFOURCC('I','L','G','T')
| #define RIFFIO_FOURCC_IMED RIFFIOMAKEFOURCC('I','M','E','D')
| #define RIFFIO_FOURCC_INAM RIFFIOMAKEFOURCC('I','N','A','M')
| #define RIFFIO_FOURCC_IPLT RIFFIOMAKEFOURCC('I','P','L','T')
| #define RIFFIO_FOURCC_IPRD RIFFIOMAKEFOURCC('I','P','R','D')
| #define RIFFIO_FOURCC_ISBJ RIFFIOMAKEFOURCC('I','S','B','J')
| #define RIFFIO_FOURCC_ISFT RIFFIOMAKEFOURCC('I','S','F','T')
| #define RIFFIO_FOURCC_ISHP RIFFIOMAKEFOURCC('I','S','H','P')
| #define RIFFIO_FOURCC_ISRC RIFFIOMAKEFOURCC('I','S','R','C')
| #define RIFFIO_FOURCC_ISRF RIFFIOMAKEFOURCC('I','S','R','F')
| #define RIFFIO_FOURCC_ITCH RIFFIOMAKEFOURCC('I','T','C','H')
| 

 How are RIFF chunks represented?
 ================================

 RIFFIOChunk
 -----------
 A RIFFIOChunk structure contains type and location information 
 about a chunk in a RIFFIOFile.

| typedef unsigned long RIFFIOSize;    /* Size of a RIFF chunk */
| 
| typedef struct
| {
|   /* Public 
|    * ------
|    * users need to set and read these members 
|    */
| 
|   RIFFIOFOURCC     fccId;      /* chunk identifier eg. LIST for Lists  */
| 
|   RIFFIOFOURCC     fccType;    /* Form or List type eg. NIFF           
|                                 * Ignored for chunks that aren't lists 
|                                 */      
| 
|   RIFFIOSize       sizeData;   /* size of data portion of chunk 
|                                 * INCLUDES 4 bytes for type field of 
|                                 * List and Form chunks
|                                 */
| 
|   /* Other private members 
|    * ---------------------
|    * not for RIFFIO users 
|    */
| 
| } RIFFIOChunk;
| 

 How are RIFFIOChunks Used?
 --------------------------
  - RIFFIOChunks convey chunk information between the chunk
    creation and navigation routines.

  - Some RIFFIOChunk routines may use only a few of the RIFFIOChunk
    data members and ignore others.
 
  - Some RIFFIO routines, such as RIFFIOChunkFinalize(), will expect that a
    RIFFIOChunk has not been modified since a previous call to an
    associated function (eg. RIFFIOChunkCreate).  

