home *** CD-ROM | disk | FTP | other *** search
- /*
- (C) 1995-96 AROS - The Amiga Replacement OS
- $Id: parseiff.c,v 1.1 1997/02/03 16:44:27 digulla Exp $
-
- Desc:
- Lang: english
- */
- #include "iffparse_intern.h"
-
- /*****************************************************************************
-
- NAME */
- #include <proto/iffparse.h>
-
- AROS_LH2(LONG, ParseIFF,
-
- /* SYNOPSIS */
- AROS_LHA(struct IFFHandle *, iff, A0),
- AROS_LHA(LONG , mode, D0),
-
- /* LOCATION */
- struct Library *, IFFParseBase, 7, IFFParse)
-
- /* FUNCTION
- This function is the parser itself. It has three control modes.
- IFFPARSE_SCAN - the parser will go through the file invoking
- entry and exit handlers on its way.
- When it returns it might be for 3 different reasons:
-
- - It invoked a Stop entry/exit handler ( Installed by StopChunk[s] or
- StopOnExit )
-
- - An error occured.
- (return value will be negative.)
-
- - The parser reached EOF and returns IFFERR_EOF.
-
- IFFPARSE_STEP - The parser steps through the file, returning to the
- user each time it enters (returns NULL) and each time it exits
- (return (IFFERR_EOC) a chunk.
- It will also invoke entry/exit - handlers.
-
- IFFPARSE_RAWSTEP - same as IFFPARSE_STEP except that in this mode
- the parse won't invoke any handlers.
-
-
- INPUTS
- iff - pointer to IFFHandle struct.
- mode - IFFPARSE_SCAN, IFFPARSE_STEP or IFFPARSE_RAWSTEP.
-
- RESULT
- 0 if successfull or IFFERR_#?
-
- NOTES
-
-
- EXAMPLE
-
- BUGS
-
- SEE ALSO
- PushChunk(), PopChunk(), EntryHandler(), ExitHandler(), PropChunk[s](),
- CollectionChunk[s](), StopChunk[s](), StopOnExit()
-
-
- INTERNALS
-
- HISTORY
- 27-11-96 digulla automatically created from
- iffparse_lib.fd and clib/iffparse_protos.h
-
- *****************************************************************************/
- {
- AROS_LIBFUNC_INIT
- AROS_LIBBASE_EXT_DECL(struct Library *,IFFParseBase)
-
- LONG size;
-
- struct ContextNode *cn;
-
- LONG err;
-
- /* To hold number of bytes left to seek in a chunk */
- LONG toseek;
-
- BOOL done = FALSE;
-
- /* Cannot parse iff when it is not opened yet */
- if (!(iff->iff_Flags & IFFF_OPEN))
- return (IFFERR_SYNTAX);
-
- /* Cannot parse iff file, when it is opened in write-mode */
- if (iff->iff_Flags & IFFF_WRITE)
- return (IFFERR_SYNTAX);
-
- /* Main loop for reading the iff file
-
- This works as a Finite State Automaton where we between the states might return to the
- user, and get called by the user again. InternalIFFHandle->CurrentState holds
- the current state */
-
- while (!done)
- {
-
- switch ( GetIntIH(iff)->iff_CurrentState )
- {
-
- case IFFSTATE_COMPOSITE:
-
- /* We are inside a FORM, LIST, CAT or PROP
- and expect a new chunk header to be found,
- but first we must invoke the handlers on the current one */
-
- /* Where to go next */
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
-
- /* Invoke the handlers */
- err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
-
- if (err)
- {
- if (err == IFF_RETURN2CLIENT)
- err = NULL;
- done = TRUE;
- }
-
-
-
- break;
-
- case IFFSTATE_PUSHCHUNK:
-
- /* What we want to do now is to get the next chunk, make a context-node of it,
- and put it in top of the stack */
-
- err = GetChunkHeader(iff, IPB(IFFParseBase));
- if (err)
- {
- done = TRUE;
- break;
- }
-
-
- /* Determine if top chunk is composite or atomic */
- cn = TopChunk(iff);
-
- if ( GetIntCN(cn)->cn_Composite)
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_COMPOSITE;
- else
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_ATOMIC;
-
-
- break;
-
-
- case IFFSTATE_ATOMIC:
-
- /* We have entried an atomic chunk. Its contextnode has
- allready been laid onto the stack */
-
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_SCANEXIT;
-
- err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
- if (err)
- {
- if (err == IFF_RETURN2CLIENT)
- err = 0L;
-
- done = TRUE;
- }
- break;
-
- case IFFSTATE_SCANEXIT:
-
- /* We have done the needed entry stuff inside the ATOMIC chunk scan towards
- the end of it */
-
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
-
- cn = TopChunk(iff);
-
- toseek = cn->cn_Size - cn->cn_Scan;
- /* If cn_Size is not wordaligned we must seek one more byte */
- if (cn->cn_Size % 2)
- toseek += 1;
-
- err = SeekStream(iff,toseek, IPB(IFFParseBase));
- if (err)
- done = TRUE;
-
- break;
-
- case IFFSTATE_EXIT:
-
- /* We are at the end of the chunk, should scan for exithandlers */
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_POPCHUNK;
-
- err = InvokeHandlers(iff, mode, IFFLCI_EXITHANDLER, IPB(IFFParseBase));
- if (err)
- {
- if (err == IFF_RETURN2CLIENT)
- err = NULL;
-
-
- done = TRUE;
-
- }
- break;
-
- case IFFSTATE_POPCHUNK:
-
-
-
- /* Before we pop the top node, get its size */
- cn = TopChunk(iff);
- size = cn->cn_Size;
-
- /* Align the size */
- if (size % 2)
- size +=1;
-
- /* Add size of chunk header */
- if ( GetIntCN(cn)->cn_Composite )
- size += 12;
- else
- size += 8;
-
- /* Pop the top node */
- PopContextNode(iff, IPB(IFFParseBase));
-
- /* The underlying node must get updated its scancount */
- cn = TopChunk(iff);
- cn->cn_Scan += size;
-
-
- /* The outer node is ALWAYS a composite one
- Now we might have 3 different situations :
-
- 1. There are more chunks inside this composite chunk, and we should
- enter the PUSHCHUNK state to get them.
-
- 2. There are no more chunks in this composite, but we are not in the outer-most
- composite, so we just want to enter the EXIT state.
-
- 3. We are at the end of and about to leave the outermost composite chunk,
- and should therefore return IFFERR_EOF.
-
- */
-
- /* Nr. 1 */
- if (cn->cn_Scan < cn->cn_Size)
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
-
- else
- {
- /* Nr. 3 */
- if (!iff->iff_Depth )
- {
- err = IFFERR_EOF;
- done = TRUE;
- }
- else
- /* Nr. 2 */
- GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
-
- }
- break;
-
-
- } /* End of switch */
-
-
- } /* End of while */
-
- return (err);
-
- AROS_LIBFUNC_EXIT
- } /* ParseIFF */
-