1/* buffio.c -- Treat buffer as an I/O stream.
2
3  (c) 1998-2006 (W3C) MIT, ERCIM, Keio University
4  See tidy.h for the copyright notice.
5
6  CVS Info :
7
8    $Author: iccir $
9    $Date: 2007/01/30 23:46:51 $
10    $Revision: 1.3 $
11
12  Requires buffer to automatically grow as bytes are added.
13  Must keep track of current read and write points.
14
15*/
16
17#include "tidy.h"
18#include "buffio.h"
19
20
21/**************
22   TIDY
23**************/
24
25static int TIDY_CALL insrc_getByte( void* appData )
26{
27  TidyBuffer* buf = (TidyBuffer*) appData;
28  return tidyBufGetByte( buf );
29}
30static Bool TIDY_CALL insrc_eof( void* appData )
31{
32  TidyBuffer* buf = (TidyBuffer*) appData;
33  return tidyBufEndOfInput( buf );
34}
35static void TIDY_CALL insrc_ungetByte( void* appData, byte bv )
36{
37  TidyBuffer* buf = (TidyBuffer*) appData;
38  tidyBufUngetByte( buf, bv );
39}
40
41void TIDY_CALL tidyInitInputBuffer( TidyInputSource* inp, TidyBuffer* buf )
42{
43  inp->getByte    = insrc_getByte;
44  inp->eof        = insrc_eof;
45  inp->ungetByte  = insrc_ungetByte;
46  inp->sourceData = buf;
47}
48
49static void TIDY_CALL outsink_putByte( void* appData, byte bv )
50{
51  TidyBuffer* buf = (TidyBuffer*) appData;
52  tidyBufPutByte( buf, bv );
53}
54
55void TIDY_CALL tidyInitOutputBuffer( TidyOutputSink* outp, TidyBuffer* buf )
56{
57  outp->putByte  = outsink_putByte;
58  outp->sinkData = buf;
59}
60
61
62void TIDY_CALL tidyBufInit( TidyBuffer* buf )
63{
64    assert( buf != NULL );
65    ClearMemory( buf, sizeof(TidyBuffer) );
66}
67
68void TIDY_CALL tidyBufAlloc( TidyBuffer* buf, uint allocSize )
69{
70    tidyBufInit( buf );
71    tidyBufCheckAlloc( buf, allocSize, 0 );
72    buf->next = 0;
73}
74void TIDY_CALL tidyBufFree( TidyBuffer* buf )
75{
76    assert( buf != NULL );
77    MemFree( buf->bp );
78    tidyBufInit( buf );
79}
80
81void TIDY_CALL tidyBufClear( TidyBuffer* buf )
82{
83    assert( buf != NULL );
84    if ( buf->bp )
85    {
86        ClearMemory( buf->bp, buf->allocated );
87        buf->size = 0;
88    }
89    buf->next = 0;
90}
91
92/* Avoid thrashing memory by doubling buffer size
93** until larger than requested size.
94   buf->allocated is bigger than allocSize+1 so that a trailing null byte is
95   always available.
96*/
97void TIDY_CALL tidyBufCheckAlloc( TidyBuffer* buf, uint allocSize, uint chunkSize )
98{
99    assert( buf != NULL );
100    if ( 0 == chunkSize )
101        chunkSize = 256;
102    if ( allocSize+1 > buf->allocated )
103    {
104        byte* bp;
105        uint allocAmt = chunkSize;
106        if ( buf->allocated > 0 )
107            allocAmt = buf->allocated;
108        while ( allocAmt < allocSize+1 )
109            allocAmt *= 2;
110
111        bp = (byte*)MemRealloc( buf->bp, allocAmt );
112        if ( bp != NULL )
113        {
114            ClearMemory( bp + buf->allocated, allocAmt - buf->allocated );
115            buf->bp = bp;
116            buf->allocated = allocAmt;
117        }
118    }
119}
120
121/* Attach buffer to a chunk O' memory w/out allocation */
122void  TIDY_CALL tidyBufAttach( TidyBuffer* buf, byte* bp, uint size )
123{
124    assert( buf != NULL );
125    buf->bp = bp;
126    buf->size = buf->allocated = size;
127    buf->next = 0;
128}
129
130/* Clear pointer to memory w/out deallocation */
131void TIDY_CALL tidyBufDetach( TidyBuffer* buf )
132{
133    tidyBufInit( buf );
134}
135
136
137/**************
138   OUTPUT
139**************/
140
141void TIDY_CALL tidyBufAppend( TidyBuffer* buf, void* vp, uint size )
142{
143    assert( buf != NULL );
144    if ( vp != NULL && size > 0 )
145    {
146        tidyBufCheckAlloc( buf, buf->size + size, 0 );
147        memcpy( buf->bp + buf->size, vp, size );
148        buf->size += size;
149    }
150}
151
152void TIDY_CALL tidyBufPutByte( TidyBuffer* buf, byte bv )
153{
154    assert( buf != NULL );
155    tidyBufCheckAlloc( buf, buf->size + 1, 0 );
156    buf->bp[ buf->size++ ] = bv;
157}
158
159
160int TIDY_CALL tidyBufPopByte( TidyBuffer* buf )
161{
162    int bv = EOF;
163    assert( buf != NULL );
164    if ( buf->size > 0 )
165      bv = buf->bp[ --buf->size ];
166    return bv;
167}
168
169/**************
170   INPUT
171**************/
172
173int TIDY_CALL tidyBufGetByte( TidyBuffer* buf )
174{
175    int bv = EOF;
176    if ( ! tidyBufEndOfInput(buf) )
177      bv = buf->bp[ buf->next++ ];
178    return bv;
179}
180
181Bool TIDY_CALL tidyBufEndOfInput( TidyBuffer* buf )
182{
183    return ( buf->next >= buf->size );
184}
185
186void TIDY_CALL tidyBufUngetByte( TidyBuffer* buf, byte bv )
187{
188    if ( buf->next > 0 )
189    {
190        --buf->next;
191        assert( bv == buf->bp[ buf->next ] );
192    }
193}
194
195/*
196 * local variables:
197 * mode: c
198 * indent-tabs-mode: nil
199 * c-basic-offset: 4
200 * eval: (c-set-offset 'substatement-open 0)
201 * end:
202 */
203