2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
5 Funtions needed for buffering writes.
7 #include "iffparse_intern.h"
15 struct BufferList
*AllocBuffer(ULONG bufnodesize
,
16 struct IFFParseBase_intern
* IFFParseBase
)
18 struct BufferList
*buflist
;
19 struct BufferNode
*bufnode
;
21 DEBUG_ALLOCBUFFER(dprintf("AllocBuffer: bufnodesize 0x%lx\n", bufnodesize
));
23 /* First allocate memory for the BufferList structure */
25 buflist
= AllocMem(sizeof (struct BufferList
), MEMF_ANY
);
29 /* Initialize teh bufferlist */
30 NewList( (struct List
*)&(buflist
->bl_ListHeader
) );
31 buflist
->bl_BufferNodeSize
= bufnodesize
;
34 /* The bufferlist should always contain at least one buffer */
36 bufnode
= AllocBufferNode(buflist
, IFFParseBase
);
40 buflist
->bl_CurrentNode
= bufnode
;
41 buflist
->bl_CurrentOffset
= 0;
42 buflist
->bl_BufferSize
= 0;
43 buflist
->bl_CurrentNodeNum
= 1;
45 DEBUG_ALLOCBUFFER(dprintf("AllocBuffer: return %p\n", buflist
));
49 FreeMem(buflist
, sizeof (struct BufferList
) );
52 DEBUG_ALLOCBUFFER(dprintf("AllocBuffer: return NULL\n"));
61 /* Frees all the buffers and buffernodes inside a bufferlist */
63 VOID
FreeBuffer(struct BufferList
*buflist
,
64 struct IFFParseBase_intern
* IFFParseBase
)
66 /* Frees all the buffernodes in a bufferlist */
67 struct BufferNode
*node
, *nextnode
;
69 /* first free all the nodes */
71 node
= (struct BufferNode
*)buflist
->bl_ListHeader
.mlh_Head
;
73 while ((nextnode
=(struct BufferNode
*)node
->bn_Node
.mln_Succ
))
76 FreeMem(node
->bn_BufferPtr
, buflist
->bl_BufferNodeSize
);
78 FreeMem(node
,sizeof(struct BufferNode
));
82 /* Free the bufferlist itself */
84 FreeMem(buflist
, sizeof (struct BufferList
));
89 /********************/
91 /********************/
93 /* Allocate a new buffernode,
94 a new buffer, and add the buffernode to the TAIL of the bufferlist
96 struct BufferNode
*AllocBufferNode(struct BufferList
*buflist
,
97 struct IFFParseBase_intern
* IFFParseBase
)
99 /* New buffernodes are added at the HEAD of the list */
101 struct BufferNode
*n
;
103 DEBUG_ALLOCBUFFER(dprintf("AllocBufferNode: buflist %p\n", buflist
));
105 /* first allocate node */
106 if ((n
=(struct BufferNode
*)AllocMem(sizeof(struct BufferNode
),MEMF_ANY
)))
108 /* Then allocate buffer */
109 if ((n
->bn_BufferPtr
=(UBYTE
*)AllocMem(buflist
->bl_BufferNodeSize
, MEMF_ANY
)))
111 AddTail((struct List
*)buflist
,(struct Node
*)n
);
113 DEBUG_ALLOCBUFFER(dprintf("AllocBufferNode: return %p\n", n
));
117 FreeMem(n
,sizeof(struct BufferNode
));
120 DEBUG_ALLOCBUFFER(dprintf("AllocBufferNode: return NULL\n"));
124 /********************/
126 /********************/
128 /* Copies a number of bytes into the buffer at the current position */
130 LONG
WriteToBuffer( struct BufferList
*buflist
, UBYTE
*mem
, LONG size
,
131 struct IFFParseBase_intern
* IFFParseBase
)
133 /* The buffernode that the routine currently will buffer to */
134 struct BufferNode
*bufnode
;
137 /* Total number of bytes to be written */
140 /* Bytes left in bufnode that may be written into */
142 /* The offset int bufnode that the routine will start buffering at */
147 This is the offset in bytes into the whole buffer, not obly into the
150 ULONG offset_into_bigbuf
;
153 DEBUG_WRITETOBUFFER(dprintf("WriteToBuffer: buflist %p mem %p size %ld\n", buflist
, mem
, size
));
157 /* Get pointer to current buffer in list */
158 bufnode
= buflist
->bl_CurrentNode
;
159 bufoffset
= buflist
->bl_CurrentOffset
;
161 bufnodenum
= buflist
->bl_CurrentNodeNum
;
163 /* Calculate the offset into the buffer as a whole */
164 offset_into_bigbuf
= (bufnodenum
- 1) * buflist
->bl_BufferNodeSize
+ bufoffset
;
169 /* Find out how many bytes we can write into the current node */
171 bytesleft
= buflist
->bl_BufferNodeSize
- bufoffset
;
174 if (bytes2write
> bytesleft
)
176 /* Copy into the old buffer all that there is place for */
177 CopyMem(mem
,bufnode
->bn_BufferPtr
+ bufoffset
, bytesleft
);
179 /* We have written bytesleft bytes */
180 bytes2write
-= bytesleft
;
183 /* No more space in this buffernode */
186 /* Go to the next buffer in the list */
187 bufnode
= (struct BufferNode
*)bufnode
->bn_Node
.mln_Succ
;
190 /* We go to the start of the current buffernode */
193 if (!bufnode
->bn_Node
.mln_Succ
)
195 /* No more nodes in the list. We have to allocate and add a new one */
198 bufnode
= AllocBufferNode(buflist
, IFFParseBase
);
200 /* Did the allocation succeed ? */
203 /* Return number of bytes written so far */
204 DEBUG_WRITETOBUFFER(dprintf("WriteToBuffer: return %ld\n", (size
- bytes2write
)));
205 return (size
- bytes2write
);
212 /* There is place enough to write the remaining bytes into the current buffer */
216 bufnode
->bn_BufferPtr
+ bufoffset
,
220 bufoffset
+= bytes2write
;
227 /* If we have reached here, we can be sure that bytes written == size
228 (everything has been successful) */
230 /* Update some stuff */
231 buflist
->bl_CurrentNode
= bufnode
;
232 buflist
->bl_CurrentOffset
= bufoffset
;
233 buflist
->bl_CurrentNodeNum
= bufnodenum
;
235 /* Update the offset into buffer as a whole */
236 offset_into_bigbuf
+= size
;
238 /* Have we expanded the buffer ? */
239 if (offset_into_bigbuf
> buflist
->bl_BufferSize
)
240 /* Update the size of the buffer */
241 buflist
->bl_BufferSize
= offset_into_bigbuf
;
243 DEBUG_WRITETOBUFFER(dprintf("WriteToBuffer: return %ld\n", size
));
254 struct BufferList
*buflist
,
259 struct BufferNode
*bufnode
;
261 /* The number of bytes we potentially can seek in this buffernode's buffer
263 ULONG left2seekinbuf
,
264 /* The size of each buffer. (same for all buffers) */
269 LONG offset_into_bigbuf
,
270 new_offset_into_bigbuf
;
272 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: buflist %p offset %ld\n", buflist
, offset
));
274 /* Get the size of the buffers */
275 bufnodesize
= buflist
->bl_BufferNodeSize
;
276 bufnode
= buflist
->bl_CurrentNode
;
277 bufoffset
= buflist
->bl_CurrentOffset
;
278 bufnodenum
= buflist
->bl_CurrentNodeNum
;
280 offset_into_bigbuf
= (bufnodenum
- 1) * bufnodesize
+ bufoffset
;
282 /* Calculate the new offset into whole buffer. Remember: If the offset is negative,
283 this will be substarction.*/
284 new_offset_into_bigbuf
= offset_into_bigbuf
+ offset
;
286 /* Are we seeking forwards, backwords or not at all ? */
291 /* Are we trying to seek outside the bounds of the buffer */
292 if (new_offset_into_bigbuf
> buflist
->bl_BufferSize
)
294 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: return FALSE #1\n"));
298 /* How much is there left to seek towards the end of the first buf ? */
299 left2seekinbuf
= bufnodesize
- bufoffset
;
301 while (offset
) /* While there are more bytes to seek */
303 if (offset
> left2seekinbuf
)
305 /* We have to jump to the next buffer in the list */
306 bufnode
= (struct BufferNode
*)bufnode
->bn_Node
.mln_Succ
;
309 if (!bufnode
->bn_Node
.mln_Succ
)
311 /* Oops !! No more buffers to seek in */
312 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: return FALSE #2\n"));
317 offset
-= left2seekinbuf
;
320 /* Current offset is at start of the buffer */
323 /* The number of bytes written to this buffer
324 is the number we can potentially seek.
326 left2seekinbuf
= bufnodesize
;
331 /* We are at the last buffernode we have to seek. */
334 /* not more to seek */
345 /* Are we trying to seek outside the bounds of the buffer */
346 if (new_offset_into_bigbuf
< 0)
348 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: return FALSE #3\n"));
352 /* For simplicity we take the absolute value of offset */
353 offset
= abs(offset
);
355 /* How much is there left to seek towards the start of the first buf ? */
356 left2seekinbuf
= bufoffset
;
358 while (offset
) /* While there are more bytes to seek */
360 if (offset
> left2seekinbuf
)
363 /* We have to jump to the next buffer in the list */
364 bufnode
= (struct BufferNode
*)bufnode
->bn_Node
.mln_Pred
;
367 if (bufnode
->bn_Node
.mln_Pred
== NULL
)
369 /* Oops !! No more buffers to seek in */
370 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: return FALSE #4\n"));
375 offset
-= left2seekinbuf
;
378 /* Current offset is at end of the buffer */
379 bufoffset
= bufnodesize
;
381 /* The number of bytes written to this buffer
382 is the number we can potentially seek.
384 left2seekinbuf
= bufoffset
;
389 /* We are at the last buffernode we have to seek. */
393 /* not more to seek */
399 /* if offset is 0, we are finished seeking */
401 buflist
->bl_CurrentNode
= bufnode
;
402 buflist
->bl_CurrentOffset
= bufoffset
;
403 buflist
->bl_CurrentNodeNum
= bufnodenum
;
405 DEBUG_SEEKBUFFER(dprintf("WriteToBuffer: return TRUE\n"));
413 /* Writes a whole buffer to a stream.
414 It is VERY important that intiff->BufferStartDepth is 0, when this
415 function is called. Else, WriteStream will buffer the writes, and we will
416 get a nice loop allocating ALL the memory of the machine. (imagine that with VM ;-)
418 Well, I guess I'll set that to 0 at the start of this function, just for safety.
424 struct BufferList
*buflist
,
425 struct IFFHandle
*iff
,
426 struct IFFParseBase_intern
* IFFParseBase
429 struct BufferNode
*node
,
433 /* Number of bytes axtually writen to the stream,
434 or if negative: an IFFERR_.. error */
436 LONG byteswritten
= 0,
441 DEBUG_BUFFERTOSTREAM(dprintf("BufferToStream: buflist %p iff %p\n", buflist
, iff
));
443 numbytes
= buflist
->bl_BufferSize
;
444 /* For safety. Read at the function header. */
445 GetIntIH(iff
)->iff_BufferStartDepth
= 0;
447 nextnode
= (struct BufferNode
*)buflist
->bl_ListHeader
.mlh_Head
;
453 /* Should we write more than the first buffer ? */
455 if (numbytes
> buflist
->bl_BufferNodeSize
)
458 nextnode
= (struct BufferNode
*)node
->bn_Node
.mln_Succ
;
459 /* Check if there are enough buffers to write numbytesf */
462 DEBUG_BUFFERTOSTREAM(dprintf("BufferToStream: return FALSE #1\n"));
467 bytes2write
= buflist
->bl_BufferNodeSize
;
472 /* We are at the last buffer to write */
474 bytes2write
= numbytes
;
477 /* Write a buffernode to the stream */
478 byteswritten
= WriteStream
486 /* Do we have a IFFERR_.. ? */
487 if (byteswritten
< 0)
489 DEBUG_BUFFERTOSTREAM(dprintf("BufferToStream: return FALSE #2\n"));
494 /* There is bytes2write less to write */
496 numbytes
-= bytes2write
;
500 DEBUG_BUFFERTOSTREAM(dprintf("BufferToStream: return %ld\n", byteswritten
));
501 return (byteswritten
);
504 /*****************************************/
505 /* BufferStream initialization & cleanup */
506 /*****************************************/
508 /* Put in own functions just to make code tidier */
510 LONG
InitBufferedStream(struct IFFHandle
*iff
,
511 struct IFFParseBase_intern
* IFFParseBase
)
513 DEBUG_INITBUFFEREDSTREAM(dprintf("InitBufferedStream: iff %p\n", iff
));
517 !(GetIntIH(iff
)->iff_BufferStartDepth
)
520 /* Preserve the stream */
521 GetIntIH(iff
)->iff_PreservedStream
= iff
->iff_Stream
;
523 /* Allocate buffers that WriteStream can buffer its output to */
524 if (!( iff
->iff_Stream
= (IPTR
)AllocBuffer(BUFFERNODESIZE
, IFFParseBase
)))
526 DEBUG_INITBUFFEREDSTREAM(dprintf("InitBufferedStream: return IFFERR_NOMEM\n"));
527 return (IFFERR_NOMEM
);
530 /* To inform WriteStream that it should buffer all input */
531 /* + 1 because we have not PushContextNode()ed yet */
533 GetIntIH(iff
)->iff_BufferStartDepth
= iff
->iff_Depth
+ 1;
535 /* Preserve the old hook and the old flags */
537 GetIntIH(iff
)->iff_PreservedHandler
= GetIntIH(iff
)->iff_StreamHandler
;
540 GetIntIH(iff
)->iff_PreservedFlags
= iff
->iff_Flags
;
543 /* Insert the BufStreamHandler into the hook instead */
544 InitIFF(iff
, IFFF_RSEEK
, &IFFParseBase
->bufhook
);
548 DEBUG_INITBUFFEREDSTREAM(dprintf("InitBufferedStream: return 0\n"));
552 LONG
ExitBufferedStream(struct IFFHandle
*iff
,
553 struct IFFParseBase_intern
* IFFParseBase
)
556 If we have come to the chunk that started internal buffering, then we should do the following.
558 - Turn it off, so that WriteStream again writes to the REAL stream.
559 - Write the whole buffer to this stream.
564 struct BufferList
*buflist
;
566 DEBUG_EXITBUFFEREDSTREAM(dprintf("ExitBufferedStream: iff %p\n", iff
));
568 /* Turn off buffering */
569 GetIntIH(iff
)->iff_BufferStartDepth
= 0;
571 /* Read out the bufferlist stream pointer */
572 buflist
= (struct BufferList
*)iff
->iff_Stream
;
575 /* Now we can reinstall the old StreamHandler */
576 GetIntIH(iff
)->iff_StreamHandler
= GetIntIH(iff
)->iff_PreservedHandler
;
578 /* Reinstall the old flags */
579 iff
->iff_Flags
= GetIntIH(iff
)->iff_PreservedFlags
;
582 /* Reinstall the old stream */
583 iff
->iff_Stream
= GetIntIH(iff
)->iff_PreservedStream
;
586 /* Write all the buffers into the old stream */
587 if (!BufferToStream(buflist
,
594 FreeBuffer(buflist
, IFFParseBase
);
596 DEBUG_EXITBUFFEREDSTREAM(dprintf("ExitBufferedStream: return %ld\n", err
));
600 /**********************/
601 /* BufStreamHandler */
602 /**********************/
604 #define IFFParseBase (IPB(hook->h_Data))
606 ULONG BufStreamHandler
609 struct IFFHandle
*iff
,
610 struct IFFStreamCmd
*cmd
616 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: hook %p iff %p cmd %p\n", hook
, iff
, cmd
));
618 switch (cmd
->sc_Command
)
623 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: IFFCMD_READ...\n"));
625 /* It should NEVER be needed to read a buffered stream.
626 To output the buffered stream to the real stream,
627 we have the routne BufferToStream which is MUCH more effective
635 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: IFFCMD_WRITE...\n"));
641 (struct BufferList
*)iff
->iff_Stream
,
654 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: IFFCMD_SEEK...\n"));
660 (struct BufferList
*)iff
->iff_Stream
,
670 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: IFFCMD_INIT/IFFCMD_CLEANUP...\n"));
677 DEBUG_BUFSTREAMHANDLER(dprintf("BufStreamHandler: return %ld\n", error
));