Initialize libbullet git in 2.0_beta.
[platform/upstream/libbullet.git] / Extras / iff / iff.h
1 #ifndef IFF_H
2 #define IFF_H
3 /*----------------------------------------------------------------------*/
4 /* IFF.H  defs for IFF-85 Interchange Format Files.             10/8/85 */
5 /*                                                                      */
6 /* By Jerry Morrison and Steve Shaw, Electronic Arts.                   */
7 /* This software is in the public domain.                               */
8 /* Original version was for the Commodore-Amiga computer.                               */
9 /* This version is compatible with PC, OSX, PS3, Wii, iPhone. 10/26/2008*/
10 /*----------------------------------------------------------------------*/
11
12
13
14 #define NL 0L   /** A ver of NULL So Manx will like it **/
15 #include <stdio.h> //printf debugging
16 typedef unsigned char UBYTE;
17 typedef FILE* BPTR;
18 typedef unsigned short int UWORD;
19 typedef short int WORD;
20 typedef char BYTE;
21 #define LOCAL
22 #define TRUE 1
23 #define FALSE 0
24 typedef int BOOL;
25 #define OFFSET_END SEEK_END
26 #define OFFSET_CURRENT SEEK_CUR
27 #define OFFSET_BEGINNING SEEK_SET
28
29 #define Seek fseek
30 #define Write fwrite
31 #define Read(file,buffer,nbytes)        fread(buffer,1,nbytes,file)
32 #define GWriteFlush(file)          (0)
33 //#define GWrite(file, buffer, nBytes)       fwrite(buffer,1,nBytes,file)
34 #define GSeek(file, position, mode)       Seek(file, position, mode)
35
36
37
38
39
40
41 typedef int IFFP;      /* Status code result from an IFF procedure */
42 /* int, because must be type compatable with ID for GetChunkHdr.*/
43 /* Note that the error codes below are not legal IDs.*/
44 #define IFF_OKAY  0L     /* Keep going...*/
45 #define END_MARK  -1L    /* As if there was a chunk at end of group.*/
46 #define IFF_DONE  -2L    /* clientProc returns this when it has READ enough.
47 * It means return thru all levels. File is Okay.*/
48 #define DOS_ERROR -3L
49 #define NOT_IFF   -4L   /* not an IFF file.*/
50 #define NO_FILE   -5L   /* Tried to open file, DOS didn't find it.*/
51 #define CLIENT_ERROR -6L /* Client made invalid request, for instance, asking
52 * for more bytes than existed in chunk.*/
53 #define BAD_FORM  -7L    /* A client read proc complains about FORM semantics;
54 * e.g. valid IFF, but missing a required chunk.*/
55 #define SHORT_CHUNK -8L  /* Client asked to IFFReadBytes more bytes than left
56 * in the chunk. Could be client bug or bad form.*/
57 #define BAD_IFF   -9L   /* mal-formed IFF file. [TBD] Expand this into a
58 * range of error codes.*/
59 #define LAST_ERROR (short)BAD_IFF
60
61 /* This MACRO is used to RETURN immediately when a termination condition is
62 * found. This is a pretty weird macro. It requires the caller to declare a
63 * local "IFFP iffp" and assign it. This wouldn't work as a subroutine since
64 * it returns for it's caller. */
65 #define CheckIFFP()   { if (iffp != IFF_OKAY) return(iffp); }
66
67
68 /* ---------- ID -------------------------------------------------------*/
69
70 typedef int ID;        /* An ID is four printable ASCII chars but
71                                                 * stored as a int for efficient copy & compare.*/
72
73 /* Four-character IDentifier builder.*/
74 #define MakeID(a,b,c,d)  (((long)(a)) | ((long)(b))<<8L | (c)<<16L | (d)<<24L)
75 //#define MakeID(a,b,c,d)  (((long)(a))<<24L | ((long)(b))<<16L | (c)<<8 | (d))
76
77 /* Standard group IDs.  A chunk with one of these IDs contains a
78 SubTypeID followed by zero or more chunks.*/
79 #define FORM MakeID('F','O','R','M')
80 #define PROP MakeID('P','R','O','P')
81 #define LIST MakeID('L','I','S','T')
82 #define CAT  MakeID('C','A','T',' ')
83 #define FILLER MakeID(' ',' ',' ',' ')
84 /* The IDs "FOR1".."FOR9", "LIS1".."LIS9", & "CAT1".."CAT9" are reserved
85 * for future standardization.*/
86
87 /* Pseudo-ID used internally by chunk reader and writer.*/
88 #define NULL_CHUNK 0L          /* No current chunk.*/
89
90
91 /* ---------- Chunk ----------------------------------------------------*/
92
93 /* All chunks start with a type ID and a count of the data bytes that
94 follow--the chunk's "logical size" or "data size". If that number is odd,
95 a 0 pad byte is written, too. */
96 typedef struct {
97         ID    ckID;
98         int  ckSize;
99 } ChunkHeader;
100
101 typedef struct {
102         ID    ckID;
103         int  ckSize;
104         UBYTE ckData[ 1 /*REALLY: ckSize*/ ];
105 } Chunk;
106
107 /* Pass ckSize = szNotYetKnown to the writer to mean "compute the size".*/
108 #define szNotYetKnown 0x80000001L
109
110 /* Need to know whether a value is odd so can word-align.*/
111 #define IS_ODD(a)   ((a) & 1)
112
113 /* This macro rounds up to an even number. */
114 #define WordAlign(size)   ((size+1)&~1)
115
116 /* ALL CHUNKS MUST BE PADDED TO EVEN NUMBER OF BYTES.
117 * ChunkPSize computes the total "physical size" of a padded chunk from
118 * its "data size" or "logical size". */
119 #define ChunkPSize(dataSize)  (WordAlign(dataSize) + (long)sizeof(ChunkHeader))
120
121 /* The Grouping chunks (LIST, FORM, PROP, & CAT) contain concatenations of
122 * chunks after a subtype ID that identifies the content chunks.
123 * "FORM type XXXX", "LIST of FORM type XXXX", "PROPerties associated
124 * with FORM type XXXX", or "conCATenation of XXXX".*/
125 typedef struct {
126         ID    ckID;
127         int  ckSize;       /* this ckSize includes "grpSubID".*/
128         ID    grpSubID;
129 } GroupHeader;
130
131 typedef struct {
132         ID    ckID;
133         int  ckSize;
134         ID    grpSubID;
135         UBYTE grpData[ 1 /*REALLY: ckSize-sizeof(grpSubID)*/ ];
136 } GroupChunk;
137
138
139 /* ---------- IFF Reader -----------------------------------------------*/
140
141 /******** Routines to support a stream-oriented IFF file reader *******
142 *
143 * These routines handle lots of details like error checking and skipping
144 * over padding. They're also careful not to read past any containing context.
145 *
146 * These routines ASSUME they're the only ones reading from the file.
147 * Client should check IFFP error codes. Don't press on after an error!
148 * These routines try to have no side effects in the error case, except
149 * partial I/O is sometimes unavoidable.
150 *
151 * All of these routines may return DOS_ERROR. In that case, ask DOS for the
152 * specific error code.
153 *
154 * The overall scheme for the low level chunk reader is to open a "group read
155 * context" with OpenRIFF or OpenRGroup, read the chunks with GetChunkHdr
156 * (and its kin) and IFFReadBytes, and close the context with CloseRGroup.
157 *
158 * The overall scheme for reading an IFF file is to use ReadIFF, ReadIList,
159 * and ReadICat to scan the file. See those procedures, ClientProc (below),
160 * and the skeleton IFF reader. */
161
162 /* Client passes ptrs to procedures of this type to ReadIFF which call them
163 * back to handle LISTs, FORMs, CATs, and PROPs.
164 *
165 * Use the GroupContext ptr when calling reader routines like GetChunkHdr.
166 * Look inside the GroupContext ptr for your ClientFrame ptr. You'll
167 * want to type cast it into a ptr to your containing struct to get your
168 * private contextual data (stacked property settings). See below. */
169 typedef IFFP ClientProc( struct _GroupContext * );
170
171 /* Client's context for reading an IFF file or a group.
172 * Client should actually make this the first component of a larger struct
173 * (it's personal stack "frame") that has a field to store each "interesting"
174 * property encountered.
175 * Either initialize each such field to a global default or keep a boolean
176 * indicating if you've read a property chunk into that field.
177 * Your getList and getForm procs should allocate a new "frame" and copy the
178 * parent frame's contents. The getProp procedure should store into the frame
179 * allocated by getList for the containing LIST. */
180 typedef struct _ClientFrame {
181         ClientProc *getList, *getProp, *getForm, *getCat;
182         /* client's own data follows; place to stack property settings */
183 } ClientFrame;
184
185 /* Our context for reading a group chunk. */
186 typedef struct _GroupContext {
187         struct _GroupContext *parent; /* Containing group; NULL => whole file. */
188         ClientFrame *clientFrame;     /* Reader data & client's context state. */
189         BPTR file;          /* Byte-stream file handle. */
190         int position;      /* The context's logical file position. */
191         int bound;         /* File-absolute context bound
192                                                 * or szNotYetKnown (writer only). */
193         ChunkHeader ckHdr;  /* Current chunk header. ckHdr.ckSize = szNotYetKnown
194                                                 * means we need to go back and set the size (writer onl
195                                                 y).
196                                                 * See also Pseudo-IDs, above. */
197         ID subtype;         /* Group's subtype ID when reading. */
198         int bytesSoFar;    /* # bytes read/written of current chunk's data. */
199 } GroupContext;
200
201 /* Computes the number of bytes not yet read from the current chunk, given
202 * a group read context gc. */
203 #define ChunkMoreBytes(gc)  ((gc)->ckHdr.ckSize - (gc)->bytesSoFar)
204
205
206 /***** Low Level IFF Chunk Reader *****/
207
208 /* Given an open file, open a read context spanning the whole file.
209 * This is normally only called by ReadIFF.
210 * This sets new->clientFrame = clientFrame.
211 * ASSUME context allocated by caller but not initialized.
212 * ASSUME caller doesn't deallocate the context before calling CloseRGroup.
213 * NOT_IFF ERROR if the file is too short for even a chunk header.*/
214 extern IFFP OpenRIFF(BPTR file, GroupContext *, ClientFrame * );
215
216 /* Open the remainder of the current chunk as a group read context.
217 * This will be called just after the group's subtype ID has been read
218 * (automatically by GetChunkHdr for LIST, FORM, PROP, and CAT) so the
219 * remainder is a sequence of chunks.
220 * This sets new->clientFrame = parent->clientFrame. The caller should repoint
221 * it at a new clientFrame if opening a LIST context so it'll have a "stack
222 * frame" to store PROPs for the LIST. (It's usually convenient to also
223 * allocate a new Frame when you encounter FORM of the right type.)
224 *
225 * ASSUME new context allocated by caller but not initialized.
226 * ASSUME caller doesn't deallocate the context or access the parent context
227 * before calling CloseRGroup.
228 * BAD_IFF ERROR if context end is odd or extends past parent. */
229 extern IFFP OpenRGroup(GroupContext *, GroupContext * );
230 /* parent,         new  */
231
232 /* Close a group read context, updating its parent context.
233 * After calling this, the old context may be deallocated and the parent
234 * context can be accessed again. It's okay to call this particular procedure
235 * after an error has occurred reading the group.
236 * This always returns IFF_OKAY. */
237 extern IFFP CloseRGroup( GroupContext * );
238 /* old  */
239
240 /* Skip any remaining bytes of the previous chunk and any padding, then
241 * read the next chunk header into context.ckHdr.
242 * If the ckID is LIST, FORM, CAT, or PROP, this automatically reads the
243 * subtype ID into context->subtype.
244 * Caller should dispatch on ckID (and subtype) to an appropriate handler.
245 *
246 * RETURNS context.ckHdr.ckID (the ID of the new chunk header); END_MARK
247 * if there are no more chunks in this context; or NOT_IFF if the top level
248 * file chunk isn't a FORM, LIST, or CAT; or BAD_IFF if malformed chunk, e.g.
249 * ckSize is negative or too big for containing context, ckID isn't positive,
250 * or we hit end-of-file.
251 *
252 * See also GetFChunkHdr, GetF1ChunkHdr, and GetPChunkHdr, below.*/
253 extern ID       GetChunkHdr(/* GroupContext * */);
254 /*  context.ckHdr.ckID       context  */
255
256 /* Read nBytes number of data bytes of current chunk. (Use OpenGroup, etc.
257 * instead to read the contents of a group chunk.) You can call this several
258 * times to read the data piecemeal.
259 * CLIENT_ERROR if nBytes < 0. SHORT_CHUNK if nBytes > ChunkMoreBytes(context)
260 * which could be due to a client bug or a chunk that's shorter than it
261 * ought to be (bad form). (on either CLIENT_ERROR or SHORT_CHUNK,
262 * IFFReadBytes won't read any bytes.) */
263 extern IFFP IFFReadBytes( GroupContext *, BYTE *, int );
264 /* context,        buffer, nBytes  */
265
266
267 /***** IFF File Reader *****/
268
269 /* This is a noop ClientProc that you can use for a getList, getForm, getProp,
270 * or getCat procedure that just skips the group. A simple reader might just
271 * implement getForm, store &ReadICat in the getCat field of clientFrame, and
272 * use &SkipGroup for the getList and getProp procs.*/
273 extern IFFP SkipGroup( GroupContext* );
274
275 /* IFF file reader.
276 * Given an open file, allocate a group context and use it to read the FORM,
277 * LIST, or CAT and it's contents. The idea is to parse the file's contents,
278 * and for each FORM, LIST, CAT, or PROP encountered, call the getForm,
279 * getList, getCat, or getProp procedure in clientFrame, passing the
280 * GroupContext ptr.
281 * This is achieved with the aid of ReadIList (which your getList should
282 * call) and ReadICat (which your getCat should call, if you don't just use
283 * &ReadICat for your getCat). If you want to handle FORMs, LISTs, and CATs
284 * nested within FORMs, the getForm procedure must dispatch to getForm,
285 * getList, and getCat (it can use GetF1ChunkHdr to make this easy).
286 *
287 * Normal return is IFF_OKAY (if whole file scanned) or IFF_DONE (if a client
288 * proc said "done" first).
289 * See the skeletal getList, getForm, getCat, and getProp procedures. */
290 extern IFFP ReadIFF( BPTR, ClientFrame * );
291 /* file, clientFrame  */
292
293 /* IFF LIST reader.
294 * Your "getList" procedure should allocate a ClientFrame, copy the parent's
295 * ClientFrame, and then call this procedure to do all the work.
296 *
297 * Normal return is IFF_OKAY (if whole LIST scanned) or IFF_DONE (if a client
298 * proc said "done" first).
299 * BAD_IFF ERROR if a PROP appears after a non-PROP. */
300 extern IFFP ReadIList(GroupContext* parent, ClientFrame * clientFrame );
301
302 /* IFF CAT reader.
303 * Most clients can simply use this to read their CATs. If you must do extra
304 * setup work, put a ptr to your getCat procedure in the clientFrame, and
305 * have that procedure call ReadICat to do the detail work.
306 *
307 * Normal return is IFF_OKAY (if whole CAT scanned) or IFF_DONE (if a client
308 * proc said "done" first).
309 * BAD_IFF ERROR if a PROP appears in the CAT. */
310 extern IFFP ReadICat( GroupContext * );
311 /* parent  */
312
313 /* Call GetFChunkHdr instead of GetChunkHdr to read each chunk inside a FORM.
314 * It just calls GetChunkHdr and returns BAD_IFF if it gets a PROP chunk. */
315 extern ID       GetFChunkHdr( GroupContext * );
316 /*  context.ckHdr.ckID        context  */
317
318 /* GetF1ChunkHdr is like GetFChunkHdr, but it automatically dispatches to the
319 * getForm, getList, and getCat procedure (and returns the result) if it
320 * encounters a FORM, LIST, or CAT. */
321 extern ID       GetF1ChunkHdr( GroupContext * );
322 /*  context.ckHdr.ckID         context  */
323
324 /* Call GetPChunkHdr instead of GetChunkHdr to read each chunk inside a PROP.
325 * It just calls GetChunkHdr and returns BAD_IFF if it gets a group chunk. */
326 extern ID       GetPChunkHdr( GroupContext * );
327 /*  context.ckHdr.ckID        context  */
328
329 /** endianSwap32/endianSwap16 convert integers from big endian to little endian on little-endian platforms. 
330 *   They have no effect on big-endian platforms
331 **/
332 extern int endianSwap32(int value);
333 extern short int endianSwap16(short int value);
334
335
336
337 /* ---------- IFF Writer -----------------------------------------------*/
338
339 /******* Routines to support a stream-oriented IFF file writer *******
340 *
341 * These routines will random access back to set a chunk size value when the
342 * caller doesn't know it ahead of time. They'll also do things automatically
343 * like padding and error checking.
344 *
345 * These routines ASSUME they're the only ones writing to the file.
346 * Client should check IFFP error codes. Don't press on after an error!
347 * These routines try to have no side effects in the error case, except that
348 * partial I/O is sometimes unavoidable.
349 *
350 * All of these routines may return DOS_ERROR. In that case, ask DOS for the
351 * specific error code.
352 *
353 * The overall scheme is to open an output GroupContext via OpenWIFF or
354 * OpenWGroup, call either PutCk or {PutCkHdr {IFFWriteBytes}* PutCkEnd} for
355 * each chunk, then use CloseWGroup to close the GroupContext.
356 *
357 * To write a group (LIST, FORM, PROP, or CAT), call StartWGroup, write out
358 * its chunks, then call EndWGroup. StartWGroup automatically writes the
359 * group header and opens a nested context for writing the contents.
360 * EndWGroup closes the nested context and completes the group chunk. */
361
362
363 /* Given a file open for output, open a write context.
364 * The "limit" arg imposes a fence or upper limit on the logical file
365 * position for writing data in this context. Pass in szNotYetKnown to be
366 * bounded only by disk capacity.
367 * ASSUME new context structure allocated by caller but not initialized.
368 * ASSUME caller doesn't deallocate the context before calling CloseWGroup.
369 * The caller is only allowed to write out one FORM, LIST, or CAT in this top
370 * level context (see StartWGroup and PutCkHdr).
371 * CLIENT_ERROR if limit is odd.*/
372 extern IFFP OpenWIFF( BPTR, GroupContext *, int );
373 /* file, new,            limit {file position}  */
374
375 /* Start writing a group (presumably LIST, FORM, PROP, or CAT), opening a
376 * nested context. The groupSize includes all nested chunks + the subtype ID.
377 *
378 * The subtype of a LIST or CAT is a hint at the contents' FORM type(s). Pass
379 * in FILLER if it's a mixture of different kinds.
380 *
381 * This writes the chunk header via PutCkHdr, writes the subtype ID via
382 * IFFWriteBytes, and calls OpenWGroup. The caller may then write the nested
383 * chunks and finish by calling EndWGroup.
384 * The OpenWGroup call sets new->clientFrame = parent->clientFrame.
385 *
386 * ASSUME new context structure allocated by caller but not initialized.
387 * ASSUME caller doesn't deallocate the context or access the parent context
388 * before calling CloseWGroup.
389 * ERROR conditions: See PutCkHdr, IFFWriteBytes, OpenWGroup. */
390 extern IFFP StartWGroup( GroupContext *, int, int, int, GroupContext * );
391 /* End a group started by StartWGroup.
392 * This just calls CloseWGroup and PutCkEnd.
393 * ERROR conditions: See CloseWGroup and PutCkEnd. */
394 extern IFFP EndWGroup( GroupContext * );
395 /* old  */
396
397 /* Open the remainder of the current chunk as a group write context.
398 * This is normally only called by StartWGroup.
399 *
400 * Any fixed limit to this group chunk or a containing context will impose
401 * a limit on the new context.
402 * This will be called just after the group's subtype ID has been written
403 * so the remaining contents will be a sequence of chunks.
404 * This sets new->clientFrame = parent->clientFrame.
405 * ASSUME new context structure allocated by caller but not initialized.
406 * ASSUME caller doesn't deallocate the context or access the parent context
407 * before calling CloseWGroup.
408 * CLIENT_ERROR if context end is odd or PutCkHdr wasn't called first. */
409 extern IFFP OpenWGroup( GroupContext *, GroupContext *);
410
411
412 /* Close a write context and update its parent context.
413 * This is normally only called by EndWGroup.
414 *
415 * If this is a top level context (created by OpenWIFF) we'll set the file's
416 * EOF (end of file) but won't close the file.
417 * After calling this, the old context may be deallocated and the parent
418 * context can be accessed again.
419 *
420 * Amiga DOS Note: There's no call to set the EOF. We just position to the
421 * desired end and return. Caller must Close file at that position.
422 * CLIENT_ERROR if PutCkEnd wasn't called first. */
423 extern IFFP CloseWGroup( GroupContext * );
424 /* old  */
425
426 /* Write a whole chunk to a GroupContext. This writes a chunk header, ckSize
427 * data bytes, and (if needed) a pad byte. It also updates the GroupContext.
428 * CLIENT_ERROR if ckSize == szNotYetKnown. See also PutCkHdr errors. */
429 extern IFFP PutCk( GroupContext *, ID,   int,   BYTE * );
430 /* context,        ckID, ckSize, *data  */
431
432 /* Write just a chunk header. Follow this will any number of calls to
433 * IFFWriteBytes and finish with PutCkEnd.
434 * If you don't yet know how big the chunk is, pass in ckSize = szNotYetKnown,
435 * then PutCkEnd will set the ckSize for you later.
436 * Otherwise, IFFWriteBytes and PutCkEnd will ensure that the specified
437 * number of bytes get written.
438 * CLIENT_ERROR if the chunk would overflow the GroupContext's bound, if
439 * PutCkHdr was previously called without a matching PutCkEnd, if ckSize < 0
440 * (except szNotYetKnown), if you're trying to write something other
441 * than one FORM, LIST, or CAT in a top level (file level) context, or
442 * if ckID <= 0 (these illegal ID values are used for error codes). */
443 extern IFFP PutCkHdr( GroupContext* context, int ckID,   int ckSize);
444
445 /* Write nBytes number of data bytes for the current chunk and update
446 * GroupContext.
447 * CLIENT_ERROR if this would overflow the GroupContext's limit or the
448 * current chunk's ckSize, or if PutCkHdr wasn't called first, or if
449 * nBytes < 0. */
450 extern IFFP IFFWriteBytes(GroupContext *context0, BYTE *data, int nBytes);
451
452 /* Complete the current chunk, write a pad byte if needed, and update
453 * GroupContext.
454 * If current chunk's ckSize = szNotYetKnown, this goes back and sets the
455 * ckSize in the file.
456 * CLIENT_ERROR if PutCkHdr wasn't called first, or if client hasn't
457 * written 'ckSize' number of bytes with IFFWriteBytes. */
458 extern IFFP PutCkEnd( GroupContext* context );
459
460 #endif