wip prep commit in lieu of gfx subsystem update changes.
[AROS.git] / workbench / libs / iffparse / basicfuncs.c
bloba9a95870d9da85370678565a0845c974dca3bcc0
1 /*
2 Copyright © 1995-2004, The AROS Development Team. All rights reserved.
3 $Id$
5 Basic help functions needed by iffparse.
6 */
8 #define DEBUG 0
9 #include <aros/debug.h>
10 #include "iffparse_intern.h"
12 LONG PushContextNode
14 struct IFFHandle *iff,
15 LONG type,
16 LONG id,
17 LONG size,
18 LONG scan,
19 struct IFFParseBase_intern *IFFParseBase
22 /* Allocates and puts a new context-node into the top of the context-stack
23 Also does GoodType and GoodID checking */
24 struct ContextNode *cn;
25 BOOL composite;
27 D(bug("PushContextNode(iff=%p, type=%c%c%c%c, id=%c%c%c%c, size=%d, scan=%d)\n",
28 iff,
29 dmkid(type),
30 dmkid(id),
31 size,
32 scan
33 ));
35 /* Set the composite flag if we have a composite contextnnode */
36 if (id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP)
38 composite = TRUE;
39 /* We have a new type, check it */
41 else
43 composite = FALSE;
44 /* No composite type found. Get old type from top contextnode */
45 cn = TopChunk(iff);
46 type = cn->cn_Type;
49 /* Check if type and ids are valid */
50 if (!(GoodType(type) && GoodID(id)) )
51 ReturnInt ("PushContextNode",LONG,IFFERR_MANGLED);
53 /* Allocate a new context node */
54 if ( !(cn = AllocMem ( sizeof (struct IntContextNode), MEMF_ANY ) ) )
55 ReturnInt ("PushContextNode",LONG,IFFERR_NOMEM);
57 /* Put the context node at top of the stack */
58 AddHead ( (struct List*)&( GetIntIH(iff)->iff_CNStack ), (struct Node*)cn );
60 /* Set the contextnode attrs */
61 cn->cn_Type = type;
62 cn->cn_ID = id;
63 cn->cn_Size = size;
64 cn->cn_Scan = scan;
66 GetIntCN(cn)->cn_Composite = composite;
67 /* Initialize the LCI-list */
68 NewList ((struct List*)&( GetIntCN(cn)->cn_LCIList ));
70 /* Deeper stack */
71 iff->iff_Depth ++;
73 ReturnInt ("PushContextNode",LONG,0L);
76 VOID PopContextNode(struct IFFHandle* iff,
77 struct IFFParseBase_intern *IFFParseBase)
79 struct LocalContextItem *node,
80 *nextnode;
82 struct IntContextNode *cn;
84 D(bug("PopContextNode(iff=%p)\n", iff));
86 cn = GetIntCN( TopChunk( iff ) );
88 if (cn)
90 D(bug("(%c%c%c%c, %c%c%c%c)\n",
91 dmkid(cn->CN.cn_Type),
92 dmkid(cn->CN.cn_ID)
93 ));
95 else
97 D(bug("\n"));
100 /* Free all localcontextitems */
101 node = (struct LocalContextItem*)cn->cn_LCIList.mlh_Head;
103 while ((nextnode = (struct LocalContextItem*)node->lci_Node.mln_Succ))
105 PurgeLCI((struct LocalContextItem*)node, IFFParseBase);
107 node = nextnode;
110 /* Free the contextnode itself */
111 Remove((struct Node*)cn);
112 FreeMem(cn,sizeof (struct IntContextNode));
114 /*One less node on stack */
115 iff->iff_Depth --;
118 LONG ReadStreamLong (struct IFFHandle *iff,
119 APTR valptr,
120 struct IFFParseBase_intern *IFFParseBase)
122 LONG val;
123 #if AROS_BIG_ENDIAN
124 # define bytes valptr
125 #else
126 UBYTE bytes[4];
127 #endif
129 D(bug("ReadStreamLong(iff=%p valptr=%p)\n", iff, valptr));
131 val = ReadStream (iff, bytes, sizeof(LONG), IFFParseBase);
133 D(bug("ReadStreamLong: val %ld\n", val));
135 if (val < 0)
136 return val;
137 else if (val != sizeof(LONG))
138 return IFFERR_EOF;
140 #if !AROS_BIG_ENDIAN
141 *(LONG *)valptr = bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
142 #endif
144 D(bug("ReadStreamLong: *valptr 0x%08lx '%c%c%c%c'\n", *(LONG *) valptr, dmkid(*(LONG *) valptr)));
146 return sizeof(LONG);
147 } /* ReadStreamLong */
150 LONG WriteStreamLong (struct IFFHandle *iff,
151 APTR valptr,
152 struct IFFParseBase_intern *IFFParseBase)
154 LONG val;
155 #if AROS_BIG_ENDIAN
156 # define bytes valptr
157 #else
158 UBYTE bytes[4];
159 val = *(LONG *)valptr;
161 bytes[0] = val >> 24;
162 bytes[1] = val >> 16;
163 bytes[2] = val >> 8;
164 bytes[3] = val;
165 #endif
167 D(bug("WriteStreamLong(iff=%p valptr=%p)\n", iff, valptr));
169 val = WriteStream (iff, bytes, sizeof(LONG), IFFParseBase);
171 D(bug("WriteStreamLong: val %ld\n", val));
173 if (val < 0)
174 return val;
175 else if (val != sizeof(LONG))
176 return IFFERR_EOF;
178 return sizeof(LONG);
179 } /* WriteStreamLong */
181 /********************/
182 /* GetChunkHeader */
183 /********************/
185 LONG GetChunkHeader(struct IFFHandle *iff,
186 struct IFFParseBase_intern *IFFParseBase)
188 LONG type,
190 size;
191 LONG scan = 0;
192 LONG bytesread;
194 D(bug("GetChunkHeader (iff=%p)\n", iff));
196 /* Reads in the appropriate stuff from a chunk and makes a contextnode of it */
198 /* Read chunk ID */
199 bytesread = ReadStreamLong ( iff, &id, IFFParseBase );
201 /* We may have an IFF Error */
202 if (bytesread < 0)
203 ReturnInt ("GetChunkHeader",LONG,bytesread);
205 /* Read chunk size */
206 bytesread = ReadStreamLong ( iff, &size, IFFParseBase );
208 if (bytesread < 0)
209 ReturnInt ("GetChunkHeader",LONG,bytesread);
211 /* We must see if we have a IFF header ("FORM", "CAT" or "LIST" */
212 if ( id == ID_FORM || id == ID_CAT || id == ID_LIST || id == ID_PROP )
214 /* Read chunk size */
215 bytesread = ReadStreamLong ( iff, &type, IFFParseBase );
217 if (bytesread < 0)
218 ReturnInt ("GetChunkHeader",LONG,bytesread);
220 DB2(bug(" Found Chunk %c%c%c%c size=%d type %c%c%c%c\n",
221 dmkid(id),
222 size,
223 dmkid(type)
226 /* Type is inside chunk so we had to add its size to the scancount. */
227 scan = sizeof (LONG);
229 else
231 type = 0L;
232 DB2(bug(" Found Chunk %c%c%c%c size=%d\n",
233 dmkid(id),
234 size
238 ReturnInt
240 "GetChunkHeader",
241 LONG,
242 PushContextNode
244 iff,
245 type,
247 size,
248 scan,
249 IFFParseBase
254 /********************/
255 /* InvokeHandlers */
256 /********************/
258 LONG InvokeHandlers(struct IFFHandle *iff, LONG mode, LONG ident,
259 struct IFFParseBase_intern *IFFParseBase)
261 struct ContextNode *cn;
262 struct HandlerInfo *hi;
263 struct LocalContextItem *lci;
265 LONG err;
266 /* Either RETURN_2CLIENT or IFFERR_EOC */
267 LONG stepping_retval;
268 IPTR param;
270 D(bug("InvokeHandlers (Iff=%p, mode=%d, ident=0x%08lx\n",
271 iff, mode, ident
274 if (ident == IFFLCI_ENTRYHANDLER)
275 stepping_retval = IFF_RETURN2CLIENT;
276 else
277 stepping_retval = IFFERR_EOC;
279 /* Check for IFFPARSE_RAWSTEP *before* calling evt entryhandlers */
280 if (mode == IFFPARSE_RAWSTEP)
281 ReturnInt ("InvokeHandlers(1)",LONG,stepping_retval);
283 /* Get top of contextstack */
284 cn = TopChunk(iff);
286 /* Scan downwards to find a contextnode with a matching LCI */
287 lci = FindLocalItem ( iff, cn->cn_Type, cn->cn_ID, ident );
289 if (lci)
291 /* Get the HandlerInfo userdata */
292 hi = LocalItemData(lci);
295 /* First check if a hook really is present */
296 if (! hi->hi_Hook)
297 ReturnInt ("InvokeHandlers",LONG,IFFERR_NOHOOK);
299 /* What kind off command shall the hook receive */
301 if (ident == IFFLCI_ENTRYHANDLER)
302 param = IFFCMD_ENTRY;
303 else
304 param = IFFCMD_EXIT;
307 /* Call the handler */
308 if ( (err = CallHookPkt ( hi->hi_Hook, hi->hi_Object, (APTR)param)) )
309 ReturnInt ("InvokeHandlers(2)",LONG,err);
312 /* Check for IFFPARSE_STEP. (stepping through file WITH handlers enabled */
313 if (mode == IFFPARSE_STEP)
314 ReturnInt ("InvokeHandlers(3)",LONG,stepping_retval);
316 ReturnInt ("InvokeHandlers",LONG,0L);
319 /******************/
320 /* PurgeLCI */
321 /******************/
323 VOID PurgeLCI(struct LocalContextItem *lci,
324 struct IFFParseBase_intern *IFFParseBase)
326 /* Look in the RKM SetLocalItemPurge autodoc for explanation on that one below */
328 D(bug("PurgeLCI(lci=%p)\n", lci));
330 Remove((struct Node*)lci);
331 /* Has the user specified a Purge hook ? */
333 if ( GetIntLCI(lci)->lci_PurgeHook)
334 CallHookPkt
336 GetIntLCI(lci)->lci_PurgeHook,
337 lci,
338 (APTR)IFFCMD_PURGELCI
341 else
342 FreeLocalItem(lci);
347 /******************/
348 /* Readstream */
349 /******************/
351 /* Reads from the current StreamHandler */
353 /* returns one of the standard IFF errors */
354 LONG ReadStream(struct IFFHandle *iff, APTR buf, LONG bytestoread,
355 struct IFFParseBase_intern *IFFParseBase)
357 LONG retval,
358 err;
360 /* For use with custom streams */
361 struct IFFStreamCmd cmd;
363 D(bug("ReadStream(iff=%p buf=%p bytestoread=%d)\n", iff, buf, bytestoread));
365 retval = bytestoread;
366 if (bytestoread)
368 /* Now we can do the actual reading of the stream */
369 cmd.sc_Command = IFFCMD_READ;
370 cmd.sc_Buf = buf;
371 cmd.sc_NBytes = bytestoread;
373 err = CallHookPkt
375 GetIntIH(iff)->iff_StreamHandler,
376 iff,
377 &cmd
380 if (err)
381 retval = IFFERR_READ;
384 D(bug("ReadStream: return %d\n", retval));
385 return (retval);
389 /****************/
390 /* WriteStream */
391 /****************/
393 LONG WriteStream(struct IFFHandle *iff, APTR buf, LONG bytestowrite,
394 struct IFFParseBase_intern *IFFParseBase)
396 LONG retval,
397 err;
399 struct IFFStreamCmd cmd;
401 /* Call the custom hook with a write command */
403 D(bug("WriteStream(iff=%p buf=%p bytestowrite=%d)\n", iff, buf, bytestowrite));
405 retval = bytestowrite;
407 if (bytestowrite)
409 cmd.sc_Command = IFFCMD_WRITE;
410 cmd.sc_Buf = buf;
411 cmd.sc_NBytes = bytestowrite;
413 err = CallHookPkt
415 GetIntIH(iff)->iff_StreamHandler,
416 iff,
417 &cmd
420 if (err)
421 retval = IFFERR_WRITE;
424 D(bug("WriteStream: return %d\n", retval));
425 return (retval);
427 /***************/
428 /* SeekStream */
429 /***************/
431 LONG SeekStream(struct IFFHandle *iff,LONG offset,
432 struct IFFParseBase_intern *IFFParseBase)
435 /* Some different problem - situations:
437 1. Backwards seek in non back seekable stream. In this case the stream is buffered,
438 and we may seek in the buffer. This is done automagically, since PushChunk
439 then has inserted a Buffering streamhandle.
442 2. Forwards seek in a non - seekable stream. Simulate the seek with a bunch
443 of ReadStream's
447 struct IFFStreamCmd cmd;
448 ULONG flags;
449 LONG retval = 0;
450 LONG err;
451 UBYTE *seekbuf;
453 D(bug("SeekStream(iff=%p offset=%d)\n", iff, offset));
455 flags = iff->iff_Flags;
458 /* Problem 2. */
461 (offset > 0)
465 (flags & IFFF_RSEEK)
467 (flags & IFFF_FSEEK)
472 /* We should use consecutive ReadStream()s to simulate a Seek */
474 /* Allocate a buffer to use with the read */
475 seekbuf = AllocMem(SEEKBUFSIZE, MEMF_ANY);
477 if (!seekbuf)
478 retval = IFFERR_NOMEM;
479 else
482 for (; offset > SEEKBUFSIZE; offset -= SEEKBUFSIZE)
484 retval = ReadStream(iff, seekbuf, SEEKBUFSIZE, IFFParseBase);
486 if (retval != SEEKBUFSIZE)
487 retval = IFFERR_SEEK;
490 /* Seek what is left of offset */
491 retval = ReadStream(iff, seekbuf, SEEKBUFSIZE, IFFParseBase);
492 if ( retval != SEEKBUFSIZE)
493 retval = IFFERR_SEEK;
495 FreeMem(seekbuf, SEEKBUFSIZE);
499 else if (offset == 0)
501 ; /* Do nothing */
503 else
506 /* Everything is just fine... Seek in a normal manner */
508 cmd.sc_Command = IFFCMD_SEEK;
509 cmd.sc_NBytes = offset;
511 err = CallHookPkt
513 GetIntIH(iff)->iff_StreamHandler,
514 iff,
515 &cmd
518 if (err)
519 retval = IFFERR_SEEK;
522 D(bug("SeekStream: return %d\n", retval));
523 return (retval);
527 /********************/
528 /* Buffering stuff */
529 /********************/