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

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: bufferingfuncs.c,v 1.3 1997/02/07 14:32:39 digulla Exp $
  4.  
  5.     Desc: Funtions needed for buffering writes
  6.     Lang: English.
  7. */
  8. #include "iffparse_intern.h"
  9.  
  10.  
  11.  
  12. /****************/
  13. /* AllocBuffer    */
  14. /****************/
  15.  
  16. struct BufferList *AllocBuffer(ULONG bufnodesize,
  17.     struct IFFParseBase_intern * IFFParseBase)
  18. {
  19.     struct BufferList *buflist;
  20.     struct BufferNode *bufnode;
  21.  
  22.  
  23.     /* First allocate memory for the BufferList structure */
  24.  
  25.     buflist = AllocMem(sizeof (struct BufferList), MEMF_ANY);
  26.  
  27.     if (buflist)
  28.     {
  29.     /* Initialize teh bufferlist */
  30.     NewList( (struct List*)&(buflist->bl_ListHeader) );
  31.     buflist->bl_BufferNodeSize = bufnodesize;
  32.  
  33.  
  34.     /* The bufferlist should always contain at least one buffer */
  35.  
  36.     bufnode = AllocBufferNode(buflist, IFFParseBase);
  37.  
  38.     if (bufnode)
  39.     {
  40.         buflist->bl_CurrentNode     = bufnode;
  41.         buflist->bl_CurrentOffset     =  0;
  42.         buflist->bl_BufferSize    =  0;
  43.         buflist->bl_CurrentNodeNum    = 1;
  44.  
  45.         return (buflist);
  46.     }
  47.  
  48.     FreeMem(buflist, sizeof (struct BufferList) );
  49.     }
  50.  
  51.     return (FALSE);
  52. }
  53.  
  54.  
  55. /**************/
  56. /* FreeBuffer  */
  57. /**************/
  58.  
  59. /* Frees all the buffers and buffernodes inside a bufferlist */
  60.  
  61. VOID FreeBuffer(struct BufferList *buflist,
  62.     struct IFFParseBase_intern * IFFParseBase)
  63. {
  64.     /* Frees all the buffernodes in a bufferlist */
  65.     struct BufferNode *node, *nextnode;
  66.  
  67.     /* first free all the nodes */
  68.  
  69.     node = (struct BufferNode*)buflist->bl_ListHeader.mlh_Head;
  70.  
  71.     while ((nextnode=(struct BufferNode*)node->bn_Node.mln_Succ))
  72.     {
  73.  
  74.     FreeMem(node->bn_BufferPtr, buflist->bl_BufferNodeSize);
  75.  
  76.     FreeMem(node,sizeof(struct BufferNode));
  77.     node = nextnode;
  78.     }
  79.  
  80.     /* Free the bufferlist itself */
  81.  
  82.     FreeMem(buflist, sizeof (struct BufferList));
  83.     return;
  84. }
  85.  
  86.  
  87. /********************/
  88. /* AllocBufferNode  */
  89. /********************/
  90.  
  91. /* Allocate a new buffernode,
  92.   a new buffer, and add the buffernode to the TAIL of the bufferlist
  93. */
  94. struct BufferNode *AllocBufferNode(struct BufferList *buflist,
  95.     struct IFFParseBase_intern * IFFParseBase)
  96. {
  97.     /* New buffernodes are added at the HEAD of the list */
  98.  
  99.     struct BufferNode *n;
  100.  
  101.     /* first allocate node */
  102.     if ((n=(struct BufferNode*)AllocMem(sizeof(struct BufferNode),MEMF_ANY)))
  103.     {
  104.     /* Then allocate buffer */
  105.     if ((n->bn_BufferPtr=(UBYTE*)AllocMem(buflist->bl_BufferNodeSize, MEMF_ANY)))
  106.     {
  107.         AddTail((struct List*)buflist,(struct Node*)n);
  108.  
  109.         return (n);
  110.     }
  111.  
  112.     FreeMem(n,sizeof(struct BufferNode));
  113.     }
  114.     return (FALSE);
  115. }
  116.  
  117. /********************/
  118. /* WriteToBuffer    */
  119. /********************/
  120.  
  121. /* Copies a number of bytes into the buffer at the current position */
  122.  
  123. LONG WriteToBuffer( struct BufferList *buflist, UBYTE *mem, LONG size,
  124.     struct IFFParseBase_intern * IFFParseBase)
  125. {
  126.     /* The buffernode that the routine currently will buffer to */
  127.     struct BufferNode *bufnode;
  128.  
  129.  
  130.     /* Total number of bytes to be written */
  131.     ULONG   bytes2write;
  132.  
  133.     /* Bytes left in bufnode that may be written into */
  134.     ULONG  bytesleft;
  135.       /* The offset int bufnode that the routine will start buffering at */
  136.     ULONG  bufoffset;
  137.  
  138.     ULONG  bufnodenum;
  139.     /*
  140.       This is the offset in bytes into the whole buffer, not obly into the
  141.       current node
  142.     */
  143.     ULONG offset_into_bigbuf;
  144.  
  145.  
  146.  
  147.     bytes2write = size;
  148.  
  149.     /* Get pointer to current buffer in list */
  150.     bufnode   = buflist->bl_CurrentNode;
  151.     bufoffset  = buflist->bl_CurrentOffset;
  152.  
  153.     bufnodenum = buflist->bl_CurrentNodeNum;
  154.  
  155.     /* Calculate the offset into the buffer as a whole */
  156.     offset_into_bigbuf    =  (bufnodenum  - 1) * buflist->bl_BufferNodeSize + bufoffset;
  157.  
  158.     while (bytes2write)
  159.     {
  160.  
  161.     /* Find out how many bytes we can write into the current node */
  162.  
  163.     bytesleft = buflist->bl_BufferNodeSize - bufoffset;
  164.  
  165.  
  166.     if (bytes2write > bytesleft)
  167.     {
  168.         /* Copy into the old buffer all that there is place for */
  169.         CopyMem(mem,bufnode->bn_BufferPtr + bufoffset, bytesleft);
  170.  
  171.         /* We have written bytesleft bytes */
  172.         bytes2write -= bytesleft;
  173.         mem += bytesleft;
  174.  
  175.         /* No more space in this buffernode */
  176.         bytesleft = 0;
  177.  
  178.         /* Go to the next buffer in the list */
  179.         bufnode = (struct BufferNode*)bufnode->bn_Node.mln_Succ;
  180.  
  181.         bufnodenum ++;
  182.         /* We go to the start of the current buffernode */
  183.         bufoffset = 0;
  184.  
  185.         if (!bufnode->bn_Node.mln_Succ)
  186.         {
  187.         /* No more nodes in the list.    We have to allocate and add a new one */
  188.  
  189.  
  190.         bufnode = AllocBufferNode(buflist, IFFParseBase);
  191.  
  192.         /* Did the allocation succeed ? */
  193.         if (!bufnode)
  194.             /* Return number of bytes written so far */
  195.             return (size - bytes2write);
  196.  
  197.  
  198.         }
  199.  
  200.     }
  201.     else
  202.     {
  203.         /* There is place enough to write the remaining bytes into the current buffer */
  204.         CopyMem
  205.         (
  206.         mem,
  207.         bufnode->bn_BufferPtr + bufoffset,
  208.         bytes2write
  209.         );
  210.  
  211.         bufoffset          += bytes2write;
  212.  
  213.         bytes2write     =   0;
  214.     }
  215.  
  216.     }  /* End of while */
  217.  
  218.     /* If we have reached here, we can be sure that bytes written == size
  219.        (everything has been succesfull) */
  220.  
  221.     /* Update some stuff */
  222.     buflist->bl_CurrentNode     = bufnode;
  223.     buflist->bl_CurrentOffset     = bufoffset;
  224.     buflist->bl_CurrentNodeNum     = bufnodenum;
  225.  
  226.     /* Update the offset into buffer as a whole */
  227.     offset_into_bigbuf    += size;
  228.  
  229.     /* Have we expanded the buffer ? */
  230.     if (offset_into_bigbuf > buflist->bl_BufferSize)
  231.      /* Update the size of the buffer */
  232.      buflist->bl_BufferSize = offset_into_bigbuf;
  233.  
  234.  
  235.     return (size);
  236. }
  237.  
  238. /****************/
  239. /* SeekBuffer     */
  240. /****************/
  241.  
  242.  
  243. BOOL SeekBuffer
  244. (
  245.     struct BufferList *buflist,
  246.     LONG offset
  247.  
  248. )
  249. {
  250.     struct BufferNode *bufnode;
  251.  
  252.     /*    The number of bytes we potentially can seek in this buffernode's buffer
  253.     */
  254.     ULONG  left2seekinbuf,
  255.       /* The size of each buffer. (same for all buffers) */
  256.       bufnodesize,
  257.       bufoffset,
  258.       bufnodenum;
  259.  
  260.     LONG offset_into_bigbuf,
  261.       new_offset_into_bigbuf;
  262.  
  263.     /* Get the size of the buffers */
  264.     bufnodesize  = buflist->bl_BufferNodeSize;
  265.     bufnode     = buflist->bl_CurrentNode;
  266.     bufoffset    = buflist->bl_CurrentOffset;
  267.     bufnodenum    = buflist->bl_CurrentNodeNum;
  268.  
  269.     offset_into_bigbuf    =  (bufnodenum - 1) * bufnodesize + bufoffset;
  270.  
  271.     /* Calculate the new offset into whole buffer. Remember: If the offset is negative,
  272.        this will be substarction.*/
  273.     new_offset_into_bigbuf = offset_into_bigbuf + offset;
  274.  
  275.     /* Are we seeking forwards, backwords or not at all ? */
  276.     if (offset > 0)
  277.     {
  278.     /* Forwards seek */
  279.  
  280.     /* Are we trying to seek outside the bounds of the buffer */
  281.     if (new_offset_into_bigbuf > buflist->bl_BufferSize)
  282.         return (FALSE);
  283.  
  284.     /* How much is there left to seek towards the end of the first buf ? */
  285.     left2seekinbuf    = bufnodesize - bufoffset;
  286.  
  287.     while (offset) /* While there are more bytes to seek */
  288.     {
  289.         if (offset > left2seekinbuf)
  290.         {
  291.         /* We have to jump to the next buffer in the list */
  292.         bufnode = (struct BufferNode*)bufnode->bn_Node.mln_Succ;
  293.  
  294. #if 0
  295.         if (!bufnode->bn_Node.mln_Succ)
  296.             /* Oops !! No more buffers to seek in */
  297.             return (FALSE);
  298. #endif
  299.  
  300.         offset -= left2seekinbuf;
  301.         bufnodenum ++;
  302.  
  303.         /* Current offset is at start of the buffer */
  304.         bufoffset  =  0;
  305.  
  306.         /* The number of bytes written to this buffer
  307.         is the number we can potentially seek.
  308.          */
  309.         left2seekinbuf = bufnodesize;
  310.  
  311.         }
  312.         else
  313.         {
  314.         /* We are at the last buffernode we have to seek. */
  315.         bufoffset += offset;
  316.  
  317.         /* not more to seek */
  318.         offset     = 0;
  319.         }
  320.     }  /* End of while */
  321.     }
  322.  
  323.     else if (offset < 0)
  324.     {
  325.  
  326.     /* Backwards seek */
  327.  
  328.     /* Are we trying to seek outside the bounds of the buffer */
  329.     if (new_offset_into_bigbuf < 0)
  330.         return (FALSE);
  331.  
  332.     /* For simplicity we take the absolute value of offset */
  333.     offset = abs(offset);
  334.  
  335.     /* How much is there left to seek towards the start of the first buf ? */
  336.     left2seekinbuf    = bufoffset;
  337.  
  338.     while (offset) /* While there are more bytes to seek */
  339.     {
  340.         if (offset > left2seekinbuf)
  341.         {
  342.  
  343.         /* We have to jump to the next buffer in the list */
  344.         bufnode = (struct BufferNode*)bufnode->bn_Node.mln_Pred;
  345.  
  346. #if 0
  347.         if (bufnode->bn_Node.mln_Pred == NULL )
  348.             /* Oops !! No more buffers to seek in */
  349.             return (FALSE);
  350. #endif
  351.  
  352.         offset -= left2seekinbuf;
  353.         bufnodenum --;
  354.  
  355.         /* Current offset is at end of the buffer */
  356.         bufoffset  =  bufnodesize;
  357.  
  358.         /* The number of bytes written to this buffer
  359.         is the number we can potentially seek.
  360.          */
  361.         left2seekinbuf = bufoffset;
  362.  
  363.         }
  364.         else
  365.         {
  366.         /* We are at the last buffernode we have to seek. */
  367.         bufoffset -= offset;
  368.         offset      = 0;
  369.  
  370.         /* not more to seek */
  371.  
  372.         }
  373.     }  /* End of while */
  374.     }
  375.  
  376.     /* if offset is 0, we are finished seeking */
  377.  
  378.     buflist->bl_CurrentNode    = bufnode;
  379.     buflist->bl_CurrentOffset     = bufoffset;
  380.     buflist->bl_CurrentNodeNum    = bufnodenum;
  381.  
  382.     return (TRUE);
  383.  
  384. }
  385.  
  386. /******************/
  387. /* BufferToStream  */
  388. /******************/
  389.  
  390. /* Writes a whole buffer to a stream.
  391. It is VERY important that intiff->BufferStartDepth is 0, when this
  392. function is called. Else, WriteStream will buffer the writes, and we will
  393. get a nice loop allocating ALL the memory of the machine. (imagine that with VM ;-)
  394.  
  395. Well, I guess I'll set that to 0 at the start of this function, just for safety.
  396.  
  397. */
  398.  
  399. BOOL BufferToStream
  400. (
  401.     struct BufferList *buflist,
  402.     struct IFFHandle   *iff,
  403.     struct IFFParseBase_intern * IFFParseBase
  404. )
  405. {
  406.     struct BufferNode *node,
  407.               *nextnode;
  408.  
  409.  
  410.     /* Number of bytes axtually writen to the stream,
  411.       or if negative: an IFFERR_.. error */
  412.  
  413.     LONG   byteswritten,
  414.       bytes2write,
  415.       numbytes;
  416.  
  417.     numbytes = buflist->bl_BufferSize;
  418.     /* For safety. Read at the function header. */
  419.     GetIntIH(iff)->iff_BufferStartDepth = 0;
  420.  
  421.     nextnode = (struct BufferNode*)buflist->bl_ListHeader.mlh_Head;
  422.  
  423.     while (numbytes)
  424.     {
  425.     node = nextnode;
  426.  
  427.     /* Should we write more than the first buffer ? */
  428.  
  429.     if (numbytes > buflist->bl_BufferNodeSize)
  430.     {
  431.  
  432.         nextnode = (struct BufferNode*)node->bn_Node.mln_Succ;
  433.         /* Check if there are enough buffers to write numbytesf */
  434.         if (!nextnode) return (FALSE);;
  435.  
  436.  
  437.         bytes2write = buflist->bl_BufferNodeSize;
  438.  
  439.     }
  440.     else
  441.     {
  442.         /* We are at the last buffer to write */
  443.  
  444.         bytes2write = numbytes;
  445.     }
  446.  
  447.     /* Write a buffernode to the stream */
  448.     byteswritten = WriteStream
  449.     (
  450.         iff,
  451.         node->bn_BufferPtr,
  452.         bytes2write,
  453.         IFFParseBase
  454.     );
  455.  
  456.     /* Do we have a IFFERR_.. ? */
  457.     if (byteswritten < 0) return (FALSE);
  458.  
  459.  
  460.     /* There is bytes2write less to write */
  461.  
  462.     numbytes -= bytes2write;
  463.     }
  464.  
  465.  
  466.     return (byteswritten);
  467. }
  468.  
  469. /*****************************************/
  470. /* BufferStream initialization & cleanup */
  471. /*****************************************/
  472.  
  473. /* Put in own functions just to make code tidier */
  474.  
  475. LONG  InitBufferedStream(struct IFFHandle *iff,
  476.     struct IFFParseBase_intern * IFFParseBase)
  477. {
  478.     if
  479.     (
  480.     !(GetIntIH(iff)->iff_BufferStartDepth)
  481.     )
  482.     {
  483.     /* Preserve the stream */
  484.     GetIntIH(iff)->iff_PreservedStream = iff->iff_Stream;
  485.  
  486.     /* Allocate buffers that WriteStream can buffer its output to */
  487.     if
  488.     (
  489.         !( iff->iff_Stream = (IPTR)AllocBuffer
  490.         (
  491.             BUFFERNODESIZE,
  492.             IFFParseBase
  493.         )
  494.         )
  495.     )
  496.           return (IFFERR_NOMEM);
  497.  
  498.     /* To inform WriteStream that it should buffer all input */
  499.     /* + 1 because we have not PushContextNode()ed yet */
  500.  
  501.     GetIntIH(iff)->iff_BufferStartDepth = iff->iff_Depth + 1;
  502.  
  503.     /* Preserve the old hook and the old flags */
  504.  
  505.     GetIntIH(iff)->iff_PreservedHandler = GetIntIH(iff)->iff_StreamHandler;
  506.  
  507.  
  508.     GetIntIH(iff)->iff_PreservedFlags = iff->iff_Flags;
  509.  
  510.  
  511.     /* Insert the BufStreamHandler into the hook instead */
  512.     InitIFF(iff, IFFF_RSEEK, &IFFParseBase->bufhook);
  513.  
  514.     }
  515.  
  516.     return (NULL);
  517. }
  518.  
  519. LONG ExitBufferedStream(struct IFFHandle *iff,
  520.     struct IFFParseBase_intern * IFFParseBase)
  521. {
  522.     /*
  523.       If we have come to the chunk that started internal buffering, then we should do the following.
  524.  
  525.         - Turn it off, so that WriteStream again writes to the REAL stream.
  526.         - Write the whole buffer to this stream.
  527.         - Free the buffer/
  528.     */
  529.     LONG err;
  530.  
  531.     struct BufferList *buflist;
  532.  
  533.     /* Turn off buffering */
  534.     GetIntIH(iff)->iff_BufferStartDepth = 0;
  535.  
  536.       /* Read out the bufferlist stream pointer */
  537.     buflist = (struct BufferList*)iff->iff_Stream;
  538.  
  539.  
  540.     /* Now we can reinstall the old StreamHandler */
  541.     GetIntIH(iff)->iff_StreamHandler =   GetIntIH(iff)->iff_PreservedHandler;
  542.  
  543.     /* Reinstall the old flags */
  544.     iff->iff_Flags = GetIntIH(iff)->iff_PreservedFlags;
  545.  
  546.  
  547.     /* Reinstall the old stream */
  548.     iff->iff_Stream = GetIntIH(iff)->iff_PreservedStream;
  549.  
  550.  
  551.     /* Write all the buffers into the old stream */
  552.     if
  553.     (
  554.     !BufferToStream
  555.     (
  556.         buflist,
  557.         iff,
  558.         IFFParseBase
  559.     )
  560.     )
  561.     err = IFFERR_WRITE;
  562.  
  563.  
  564.  
  565.     FreeBuffer(buflist, IFFParseBase);
  566.  
  567.     return (err);
  568. }
  569.  
  570. /**********************/
  571. /* BufStreamHandler    */
  572. /**********************/
  573.  
  574. #define IFFParseBase        (IPB(hook->h_Data))
  575.  
  576. ULONG BufStreamHandler
  577. (
  578.     struct Hook     *hook,
  579.     struct IFFHandle    *iff,
  580.     struct IFFStreamCmd  *cmd
  581. )
  582. {
  583.  
  584.     LONG error;
  585.  
  586.     switch (cmd->sc_Command)
  587.     {
  588.  
  589.     case IFFCMD_READ:
  590.  
  591.         /* It should NEVER be needed to read a buffered stream.
  592.           To output the buffered stream to the real stream,
  593.           we have the routne BufferToStream which is MUCH more effective
  594.         */
  595.  
  596.         error = TRUE;
  597.         break;
  598.  
  599.     case IFFCMD_WRITE:
  600.         error =
  601.         (
  602.         WriteToBuffer
  603.         (
  604.             (struct BufferList*)iff->iff_Stream,
  605.             cmd->sc_Buf,
  606.             cmd->sc_NBytes,
  607.             IFFParseBase
  608.         )
  609.         !=
  610.         cmd->sc_NBytes
  611.         );
  612.  
  613.         break;
  614.  
  615.     case IFFCMD_SEEK:
  616.  
  617.         error =
  618.         (!
  619.         SeekBuffer
  620.         (
  621.             (struct BufferList*)iff->iff_Stream,
  622.             cmd->sc_NBytes
  623.         )
  624.         );
  625.  
  626.         break;
  627.  
  628.     case IFFCMD_INIT:
  629.     case IFFCMD_CLEANUP:
  630.  
  631.         error = NULL;
  632.         break;
  633.  
  634.     }
  635.  
  636.     return (error);
  637. }
  638.  
  639.