home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / workbench / libs / iffparse / parseiff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-03  |  5.9 KB  |  279 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: parseiff.c,v 1.1 1997/02/03 16:44:27 digulla Exp $
  4.  
  5.     Desc:
  6.     Lang: english
  7. */
  8. #include "iffparse_intern.h"
  9.  
  10. /*****************************************************************************
  11.  
  12.     NAME */
  13. #include <proto/iffparse.h>
  14.  
  15.     AROS_LH2(LONG, ParseIFF,
  16.  
  17. /*  SYNOPSIS */
  18.     AROS_LHA(struct IFFHandle *, iff, A0),
  19.     AROS_LHA(LONG              , mode, D0),
  20.  
  21. /*  LOCATION */
  22.     struct Library *, IFFParseBase, 7, IFFParse)
  23.  
  24. /*  FUNCTION
  25.     This function is the parser itself. It has three control modes.
  26.         IFFPARSE_SCAN - the parser will go through the file invoking
  27.         entry and exit handlers on its way.
  28.         When it returns it might be for 3 different reasons:
  29.  
  30.         - It invoked a Stop entry/exit handler ( Installed by StopChunk[s] or
  31.           StopOnExit )
  32.  
  33.         - An error occured.
  34.           (return value will be negative.)
  35.  
  36.         - The parser reached EOF and returns IFFERR_EOF.
  37.  
  38.         IFFPARSE_STEP  -  The parser steps through the file, returning to the
  39.         user each time it enters (returns NULL) and each time it exits
  40.         (return (IFFERR_EOC) a chunk.
  41.         It will also invoke entry/exit - handlers.
  42.  
  43.         IFFPARSE_RAWSTEP - same as IFFPARSE_STEP except that in this mode
  44.         the parse won't invoke any handlers.
  45.  
  46.  
  47.     INPUTS
  48.     iff - pointer to IFFHandle struct.
  49.     mode - IFFPARSE_SCAN, IFFPARSE_STEP or IFFPARSE_RAWSTEP.
  50.  
  51.     RESULT
  52.     0 if successfull or IFFERR_#?
  53.  
  54.     NOTES
  55.  
  56.  
  57.     EXAMPLE
  58.  
  59.     BUGS
  60.  
  61.     SEE ALSO
  62.     PushChunk(), PopChunk(), EntryHandler(), ExitHandler(), PropChunk[s](),
  63.     CollectionChunk[s](), StopChunk[s](), StopOnExit()
  64.  
  65.  
  66.     INTERNALS
  67.  
  68.     HISTORY
  69.   27-11-96    digulla automatically created from
  70.       iffparse_lib.fd and clib/iffparse_protos.h
  71.  
  72. *****************************************************************************/
  73. {
  74.     AROS_LIBFUNC_INIT
  75.     AROS_LIBBASE_EXT_DECL(struct Library *,IFFParseBase)
  76.  
  77.     LONG size;
  78.  
  79.     struct ContextNode *cn;
  80.  
  81.     LONG err;
  82.  
  83.     /* To hold number of bytes left to seek in a chunk */
  84.     LONG toseek;
  85.  
  86.     BOOL done = FALSE;
  87.  
  88.     /* Cannot parse iff when it is not opened yet */
  89.     if (!(iff->iff_Flags & IFFF_OPEN))
  90.     return (IFFERR_SYNTAX);
  91.  
  92.     /* Cannot parse iff file, when it is opened in write-mode */
  93.     if (iff->iff_Flags & IFFF_WRITE)
  94.     return (IFFERR_SYNTAX);
  95.  
  96.     /* Main loop for reading the iff file
  97.  
  98.     This works as a Finite State Automaton  where we between the states might return to the
  99.     user, and get called by the user again. InternalIFFHandle->CurrentState holds
  100.     the current state */
  101.  
  102.     while (!done)
  103.     {
  104.  
  105.     switch ( GetIntIH(iff)->iff_CurrentState )
  106.     {
  107.  
  108.         case IFFSTATE_COMPOSITE:
  109.  
  110.         /* We are inside a FORM, LIST, CAT or PROP
  111.           and expect a new chunk header to be found,
  112.           but first we must invoke the handlers on the current one */
  113.  
  114.         /* Where to go next */
  115.         GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
  116.  
  117.         /* Invoke the handlers */
  118.         err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
  119.  
  120.         if (err)
  121.         {
  122.             if (err == IFF_RETURN2CLIENT)
  123.             err = NULL;
  124.             done = TRUE;
  125.         }
  126.  
  127.  
  128.  
  129.         break;
  130.  
  131.         case IFFSTATE_PUSHCHUNK:
  132.  
  133.         /*  What we want to do now is to get the next chunk, make a context-node of it,
  134.           and put it in top of the stack */
  135.  
  136.         err = GetChunkHeader(iff, IPB(IFFParseBase));
  137.         if (err)
  138.         {
  139.             done = TRUE;
  140.             break;
  141.         }
  142.  
  143.  
  144.         /* Determine if top chunk is composite or atomic */
  145.         cn = TopChunk(iff);
  146.  
  147.         if ( GetIntCN(cn)->cn_Composite)
  148.             GetIntIH(iff)->iff_CurrentState = IFFSTATE_COMPOSITE;
  149.         else
  150.             GetIntIH(iff)->iff_CurrentState = IFFSTATE_ATOMIC;
  151.  
  152.  
  153.         break;
  154.  
  155.  
  156.         case IFFSTATE_ATOMIC:
  157.  
  158.         /* We have entried an atomic chunk. Its contextnode has
  159.         allready been laid onto the stack */
  160.  
  161.         GetIntIH(iff)->iff_CurrentState = IFFSTATE_SCANEXIT;
  162.  
  163.         err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
  164.         if (err)
  165.         {
  166.             if (err == IFF_RETURN2CLIENT)
  167.             err = 0L;
  168.  
  169.             done = TRUE;
  170.         }
  171.         break;
  172.  
  173.         case IFFSTATE_SCANEXIT:
  174.  
  175.         /* We have done the needed entry stuff inside the ATOMIC chunk scan towards
  176.         the end of it */
  177.  
  178.         GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
  179.  
  180.         cn = TopChunk(iff);
  181.  
  182.         toseek = cn->cn_Size - cn->cn_Scan;
  183.         /* If cn_Size is not wordaligned we must seek one more byte */
  184.         if (cn->cn_Size % 2)
  185.             toseek += 1;
  186.  
  187.         err = SeekStream(iff,toseek, IPB(IFFParseBase));
  188.         if (err)
  189.             done = TRUE;
  190.  
  191.         break;
  192.  
  193.         case IFFSTATE_EXIT:
  194.  
  195.         /* We are at the end of the chunk, should scan for exithandlers */
  196.         GetIntIH(iff)->iff_CurrentState = IFFSTATE_POPCHUNK;
  197.  
  198.         err = InvokeHandlers(iff, mode, IFFLCI_EXITHANDLER, IPB(IFFParseBase));
  199.         if (err)
  200.         {
  201.             if (err == IFF_RETURN2CLIENT)
  202.             err = NULL;
  203.  
  204.  
  205.             done = TRUE;
  206.  
  207.         }
  208.         break;
  209.  
  210.         case IFFSTATE_POPCHUNK:
  211.  
  212.  
  213.  
  214.         /* Before we pop the top node, get its size */
  215.         cn     = TopChunk(iff);
  216.         size  = cn->cn_Size;
  217.  
  218.         /* Align the size */
  219.         if (size % 2)
  220.             size +=1;
  221.  
  222.         /* Add size of chunk header */
  223.         if ( GetIntCN(cn)->cn_Composite )
  224.             size += 12;
  225.         else
  226.             size += 8;
  227.  
  228.         /* Pop the top node */
  229.         PopContextNode(iff, IPB(IFFParseBase));
  230.  
  231.         /* The underlying node must get updated its scancount */
  232.         cn  = TopChunk(iff);
  233.         cn->cn_Scan += size;
  234.  
  235.  
  236.         /* The outer node is ALWAYS a composite one
  237.         Now we might have 3 different situations :
  238.  
  239.         1. There are more chunks inside this composite chunk, and we should
  240.            enter the PUSHCHUNK state to get them.
  241.  
  242.         2. There are no more chunks in this composite, but we are not in the outer-most
  243.            composite, so we just want to enter the EXIT state.
  244.  
  245.         3. We are at the end of and about to leave the outermost composite chunk,
  246.            and should therefore return IFFERR_EOF.
  247.  
  248.            */
  249.  
  250.         /* Nr. 1 */
  251.         if (cn->cn_Scan < cn->cn_Size)
  252.             GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
  253.  
  254.         else
  255.         {
  256.             /* Nr. 3 */
  257.             if (!iff->iff_Depth )
  258.             {
  259.             err = IFFERR_EOF;
  260.             done = TRUE;
  261.             }
  262.             else
  263.             /* Nr. 2 */
  264.             GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
  265.  
  266.         }
  267.         break;
  268.  
  269.  
  270.     }  /* End of switch */
  271.  
  272.  
  273.     }  /* End of while */
  274.  
  275.     return (err);
  276.  
  277.     AROS_LIBFUNC_EXIT
  278. } /* ParseIFF */
  279.