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

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: basicfuncs.c,v 1.3 1997/02/04 14:10:03 digulla Exp $
  4.  
  5.     Desc: Basic help functions needed by iffparse.
  6.     Lang: English.
  7. */
  8. #include "iffparse_intern.h"
  9.  
  10. LONG PushContextNode
  11. (
  12.     struct IFFHandle   *iff,
  13.     LONG           type,
  14.     LONG           id,
  15.     LONG           size,
  16.     LONG           scan,
  17.     struct IFFParseBase_intern *IFFParseBase
  18. )
  19. {
  20.     /* Allocates and puts a new context-node into the top of the context-stack
  21.      Also does GoodType and GoodID checking  */
  22.  
  23.     struct ContextNode     *cn;
  24.  
  25.     BOOL composite;
  26.  
  27.  
  28.     /* Set the composite flag if we have a composite contextnnode */
  29.     if (id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP)
  30.     {
  31.     composite = TRUE;
  32.     /* We have a new type, check it */
  33.     }
  34.     else
  35.     {
  36.     composite = FALSE;
  37.     /* No composite type found.  Get old type from top contextnode */
  38.     cn = TopChunk(iff);
  39.     type = cn->cn_Type;
  40.     }
  41.  
  42.       /* Check if type and ids are valid */
  43.     if (!(GoodType(type) && GoodID(id)) )
  44.     return (IFFERR_MANGLED);
  45.  
  46.     /* Allocate a new context node */
  47.     if
  48.     (
  49.     !(cn = AllocMem
  50.         (
  51.         sizeof (struct IntContextNode),
  52.         MEMF_ANY
  53.         )
  54.     )
  55.     )
  56.     return (IFFERR_NOMEM);
  57.  
  58.     /* Put the context node at top of the stack */
  59.     AddHead
  60.     (
  61.     (struct List*)&( GetIntIH(iff)->iff_CNStack ),
  62.     (struct Node*)cn
  63.     );
  64.  
  65.  
  66.     /* Set the contextnode attrs */
  67.     cn->cn_Type  =  type;
  68.     cn->cn_ID    = id;
  69.     cn->cn_Size  = size;
  70.     cn->cn_Scan  =  scan;
  71.  
  72.     GetIntCN(cn)->cn_Composite = composite;
  73.     /* Initialize the LCI-list */
  74.     NewList ((struct List*)&( GetIntCN(cn)->cn_LCIList ));
  75.  
  76.     /* Deeper stack */
  77.     iff->iff_Depth ++;
  78.  
  79.     return (NULL);
  80. }
  81.  
  82. VOID PopContextNode(struct IFFHandle* iff,
  83.     struct IFFParseBase_intern *IFFParseBase)
  84. {
  85.     struct LocalContextItem *node,
  86.                 *nextnode;
  87.  
  88.     struct IntContextNode *cn;
  89.  
  90.     cn = GetIntCN( TopChunk( iff ) );
  91.  
  92.     /* Free all localcontextitems */
  93.     node = (struct LocalContextItem*)cn->cn_LCIList.mlh_Head;
  94.  
  95.     while ((nextnode = (struct LocalContextItem*)node->lci_Node.mln_Succ))
  96.     {
  97.     PurgeLCI((struct LocalContextItem*)node, IFFParseBase);
  98.  
  99.     node = nextnode;
  100.     }
  101.  
  102.     /* Free the contextnode itself */
  103.     Remove((struct Node*)cn);
  104.     FreeMem(cn,sizeof (struct IntContextNode));
  105.  
  106.     /*One less node on stack */
  107.     iff->iff_Depth --;
  108.     return;
  109. }
  110.  
  111. LONG ReadStreamLong (struct IFFHandle *iff,
  112.     APTR valptr,
  113.     struct IFFParseBase_intern *IFFParseBase)
  114. {
  115.     LONG val;
  116.     UBYTE bytes[4];
  117.  
  118.     val = ReadStream (iff, bytes, sizeof(LONG), IFFParseBase);
  119.  
  120.     if (val < 0)
  121.     return val;
  122.     else if (val != sizeof(LONG))
  123.     return IFFERR_EOF;
  124.  
  125.     *(LONG *)valptr = bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
  126.  
  127.     return sizeof(LONG);
  128. } /* ReadStreamLong */
  129.  
  130. LONG WriteStreamLong (struct IFFHandle *iff,
  131.     APTR valptr,
  132.     struct IFFParseBase_intern *IFFParseBase)
  133. {
  134.     LONG val = *(LONG *)valptr;
  135.     UBYTE bytes[4];
  136.  
  137.     bytes[0] = val >> 24;
  138.     bytes[1] = val >> 16;
  139.     bytes[2] = val >> 8;
  140.     bytes[3] = val;
  141.  
  142.     val = WriteStream (iff, bytes, sizeof(LONG), IFFParseBase);
  143.  
  144.     if (val < 0)
  145.     return val;
  146.     else if (val != sizeof(LONG))
  147.     return IFFERR_EOF;
  148.  
  149.     return sizeof(LONG);
  150. } /* WriteStreamLong */
  151.  
  152. /********************/
  153. /* GetChunkHeader   */
  154. /********************/
  155.  
  156. LONG GetChunkHeader(struct IFFHandle *iff,
  157.     struct IFFParseBase_intern *IFFParseBase)
  158. {
  159.     LONG type,
  160.      id,
  161.      size;
  162.  
  163.     LONG scan = 0;
  164.  
  165.     LONG bytesread;
  166.  
  167.     /* Reads in the appropriate stuff from a chunk and makes a contextnode of it */
  168.  
  169.     /* Read chunk ID */
  170.     bytesread = ReadStreamLong
  171.     (
  172.     iff,
  173.     &id,
  174.     IFFParseBase
  175.     );
  176.  
  177.     /* We may have an IFF Error */
  178.     if ( bytesread < 0) return (bytesread);
  179.  
  180.     /* Read chunk size */
  181.     bytesread = ReadStreamLong
  182.     (
  183.     iff,
  184.     &size,
  185.     IFFParseBase
  186.     );
  187.  
  188.     if ( bytesread < 0) return (bytesread);
  189.  
  190.     /* We must see if we have a IFF header ("FORM", "CAT" or "LIST" */
  191.     if
  192.     (
  193.     id == ID_FORM
  194.     ||
  195.     id == ID_CAT
  196.     ||
  197.     id == ID_LIST
  198.     ||
  199.     id == ID_PROP
  200.     )
  201.     {
  202.     /* Read chunk size */
  203.     bytesread = ReadStreamLong
  204.     (
  205.         iff,
  206.         &type,
  207.         IFFParseBase
  208.     );
  209.  
  210.     if ( bytesread < 0) return (bytesread);
  211.  
  212.     /* Type is inside chunk so we had to add its size to the scancount. */
  213.     scan = sizeof (LONG);
  214.  
  215.     }
  216.  
  217.  
  218.     return
  219.     (
  220.     PushContextNode
  221.     (
  222.         iff,
  223.         type,
  224.         id,
  225.         size,
  226.         scan,
  227.         IFFParseBase
  228.     )
  229.     );
  230. }
  231.  
  232. /********************/
  233. /* InvokeHandlers    */
  234. /********************/
  235.  
  236. LONG InvokeHandlers(struct IFFHandle *iff, LONG mode, LONG ident,
  237.     struct IFFParseBase_intern *IFFParseBase)
  238. {
  239.     struct ContextNode         *cn;
  240.     struct HandlerInfo        *hi;
  241.     struct LocalContextItem *lci;
  242.  
  243.     LONG err;
  244.  
  245.     /* Either RETURN_2CLIENT or IFFERR_EOC */
  246.     LONG stepping_retval;
  247.  
  248.     ULONG param;
  249.  
  250.     if (ident == IFFLCI_ENTRYHANDLER)
  251.     stepping_retval = IFF_RETURN2CLIENT;
  252.     else
  253.     stepping_retval = IFFERR_EOC;
  254.  
  255.     /* Check for IFFPARSE_RAWSTEP *before* calling evt entryhandlers */
  256.     if (mode == IFFPARSE_RAWSTEP)
  257.     return (stepping_retval);
  258.  
  259.  
  260.     /* Get top of contextstack */
  261.     cn = TopChunk(iff);
  262.  
  263.     /* Scan downwards to find a contextnode with a matching LCI */
  264.  
  265.     lci = FindLocalItem
  266.     (
  267.     iff,
  268.     cn->cn_Type,
  269.     cn->cn_ID,
  270.     ident
  271.     );
  272.  
  273.     if (lci)
  274.     {
  275.     /* Get the HandlerInfo userdata */
  276.     hi = LocalItemData(lci);
  277.  
  278.  
  279.     /* First check if a hook really is present */
  280.     if (! hi->hi_Hook)
  281.         return (IFFERR_NOHOOK);
  282.  
  283.     /* What kind off command shall the hook receive */
  284.  
  285.     if (ident == IFFLCI_ENTRYHANDLER)
  286.         param = IFFCMD_ENTRY;
  287.     else
  288.         param = IFFCMD_EXIT;
  289.  
  290.  
  291.     /* Call the handler */
  292.     if ( (err = CallHookPkt (  hi->hi_Hook, hi->hi_Object, (APTR)param)) )
  293.         return (err);
  294.     }
  295.  
  296.     /* Check for IFFPARSE_STEP. (stepping through file WITH handlers enabled */
  297.     if (mode == IFFPARSE_STEP)
  298.     return (stepping_retval);
  299.  
  300.     return (NULL);
  301. }
  302.  
  303. /******************/
  304. /* PurgeLCI       */
  305. /******************/
  306.  
  307. VOID PurgeLCI(struct LocalContextItem *lci,
  308.     struct IFFParseBase_intern *IFFParseBase)
  309. {
  310.     /* Look in the RKM SetLocalItemPurge autodoc for explanation on that one below */
  311.  
  312.     Remove((struct Node*)lci);
  313.     /* Has the user specified a Purge hook ? */
  314.  
  315.     if ( GetIntLCI(lci)->lci_PurgeHook)
  316.     CallHookPkt
  317.     (
  318.         GetIntLCI(lci)->lci_PurgeHook,
  319.         lci,
  320.         (APTR)IFFCMD_PURGELCI
  321.     );
  322.  
  323.     else
  324.     FreeLocalItem(lci);
  325.  
  326.     return;
  327. }
  328.  
  329.  
  330.  
  331. /******************/
  332. /* Readstream       */
  333. /******************/
  334.  
  335. /* Reads from the current StreamHandler */
  336.  
  337. /* returns one of the standar IFF errors */
  338. LONG ReadStream(struct IFFHandle *iff, APTR buf, LONG bytestoread,
  339.     struct IFFParseBase_intern *IFFParseBase)
  340. {
  341.     LONG   retval,
  342.       err;
  343.  
  344.     /* For use with custom streams */
  345.     struct IFFStreamCmd cmd;
  346.  
  347.     /* Now we can do the actual reading of the stream */
  348.     cmd.sc_Command  = IFFCMD_READ;
  349.     cmd.sc_Buf        = buf;
  350.     cmd.sc_NBytes    = bytestoread;
  351.  
  352.     err = CallHookPkt
  353.     (
  354.     GetIntIH(iff)->iff_StreamHandler,
  355.     iff,
  356.     &cmd
  357.     );
  358.     if (err)
  359.         retval = IFFERR_READ;
  360.     else
  361.         retval = bytestoread;
  362.  
  363.     return (retval);
  364. }
  365.  
  366.  
  367. /****************/
  368. /* WriteStream    */
  369. /****************/
  370.  
  371. LONG WriteStream(struct IFFHandle *iff, APTR buf, LONG bytestowrite,
  372.     struct IFFParseBase_intern *IFFParseBase)
  373. {
  374.     LONG   retval,
  375.       err;
  376.  
  377.     struct IFFStreamCmd cmd;
  378.  
  379.     /* Call the custom hook with a write command */
  380.  
  381.     cmd.sc_Command   = IFFCMD_WRITE;
  382.     cmd.sc_Buf        = buf;
  383.     cmd.sc_NBytes    = bytestowrite;
  384.  
  385.     err = CallHookPkt
  386.     (
  387.     GetIntIH(iff)->iff_StreamHandler,
  388.     iff,
  389.     &cmd
  390.     );
  391.  
  392.     if (err)
  393.     retval = IFFERR_WRITE;
  394.     else
  395.     retval = bytestowrite;
  396.  
  397.     return (retval);
  398. }
  399. /***************/
  400. /* SeekStream */
  401. /***************/
  402.  
  403. LONG SeekStream(struct IFFHandle *iff,LONG offset,
  404.     struct IFFParseBase_intern *IFFParseBase)
  405. {
  406.  
  407.     /* Some different problem - situations:
  408.  
  409.     1. Backwards seek in non back seekable stream. In this case the stream is buffered,
  410.       and we may seek in the buffer. This is done automagically, since PushChunk
  411.       then has inserted a Buffering streamhandle.
  412.  
  413.  
  414.     2. Forwards seek in a non - seekable stream. Simulate the seek with a bunch
  415.       of ReadStream's
  416.  
  417.     */
  418.  
  419.     struct IFFStreamCmd cmd;
  420.  
  421.  
  422.     ULONG flags;
  423.  
  424.     LONG retval = NULL;
  425.  
  426.     LONG err;
  427.  
  428.     UBYTE *seekbuf;
  429.  
  430.     flags = iff->iff_Flags;
  431.  
  432.  
  433.     /* Problem 2. */
  434.     if
  435.     (
  436.     (offset > 0)
  437.     &&
  438.     (
  439.         !(
  440.         (flags & IFFF_RSEEK)
  441.         ||
  442.         (flags & IFFF_FSEEK)
  443.         )
  444.     )
  445.     )
  446.     {
  447.     /* We should use consecutive ReadStream()s to simulate a Seek */
  448.  
  449.     /* Allocote a buffer to use with the read */
  450.     seekbuf = AllocMem(SEEKBUFSIZE, MEMF_ANY);
  451.  
  452.     if (!seekbuf)
  453.         retval = IFFERR_NOMEM;
  454.     else
  455.     {
  456.  
  457.         for (; offset > SEEKBUFSIZE; offset -= SEEKBUFSIZE)
  458.         {
  459.         retval = ReadStream(iff, seekbuf, SEEKBUFSIZE, IFFParseBase);
  460.  
  461.         if (retval != SEEKBUFSIZE)
  462.             retval = IFFERR_SEEK;
  463.         }
  464.  
  465.         /* Seek what is left of offset  */
  466.         retval = ReadStream(iff, seekbuf, SEEKBUFSIZE, IFFParseBase);
  467.         if ( retval != SEEKBUFSIZE)
  468.         retval = IFFERR_SEEK;
  469.  
  470.         FreeMem(seekbuf, SEEKBUFSIZE);
  471.     }
  472.  
  473.     }
  474.     else if (offset == 0)
  475.     {
  476.     ; /* Do nothing */
  477.     }
  478.     else
  479.     {
  480.  
  481.     /* Everything is just fine... Seek in a normal manner */
  482.  
  483.     cmd.sc_Command = IFFCMD_SEEK;
  484.     cmd.sc_NBytes       = offset;
  485.  
  486.     err =  CallHookPkt
  487.     (
  488.         GetIntIH(iff)->iff_StreamHandler,
  489.         iff,
  490.         &cmd
  491.     );
  492.  
  493.     if (err)
  494.           retval = IFFERR_SEEK;
  495.     }
  496.  
  497.     return (retval);
  498. }
  499.  
  500.  
  501. /********************/
  502. /* Buffering stuff  */
  503. /********************/
  504.  
  505.  
  506.  
  507.  
  508. /************************/
  509. /* Endian conversions     */
  510. /************************/
  511.  
  512. /* If the CPU is little endian, the id will be switched to the opposite
  513. endianess of what it is now.
  514.  
  515. Have tried to put this into a macro, but only got heaps of errors.
  516.  
  517. */
  518.  
  519. LONG SwitchIfLittleEndian(LONG id)
  520. {
  521.  
  522. #if (AROS_BIG_ENDIAN == 0)
  523.     id = ((id & 0xFF000000) >> 24)
  524.       | ((id & 0x00FF0000) >> 8)
  525.       | ((id & 0x0000FF00) << 8)
  526.       | ((id & 0x000000FF) << 24);
  527. #endif
  528.  
  529.   return (id);
  530. }
  531.