Mercurial > hg > ucis.core
annotate Util/PrebufferingStream.cs @ 49:7e4dae99f919
USBLib: fix unhandled exception in WinUSB shutdown after failure to open device
author | Ivo Smits <Ivo@UCIS.nl> |
---|---|
date | Mon, 19 Aug 2013 16:56:50 +0200 |
parents | 2e3f57f326b3 |
children |
rev | line source |
---|---|
5 | 1 ???using System; |
2 using System.Collections.Generic; | |
3 using System.Text; | |
4 using System.IO; | |
5 using System.Threading; | |
6 | |
7 namespace UCIS.Util { | |
8 public class PrebufferingStream : Stream { | |
9 class AsyncResult : AsyncResultBase { | |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
10 public Byte[] Buffer { get; set; } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
11 public int Offset { get; set; } |
5 | 12 public int Left { get; set; } |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
13 public int Count { get; set; } |
5 | 14 public AsyncResult(AsyncCallback callback, Object state) : base(callback, state) { } |
15 public void SetCompleted(Boolean synchronously, int count, Exception error) { | |
16 this.Count = count; | |
17 base.SetCompleted(synchronously, error); | |
18 } | |
37 | 19 public new void SetCompleted(Boolean synchronously, Exception error) { |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
20 base.SetCompleted(synchronously, error); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
21 } |
5 | 22 public int WaitForCompletion() { |
23 WaitHandle wh = null; | |
24 lock (this) if (!IsCompleted) wh = AsyncWaitHandle; | |
25 if (wh != null) wh.WaitOne(); | |
26 ThrowError(); | |
27 return Count; | |
28 } | |
29 } | |
30 | |
31 Stream baseStream; | |
32 Byte[] prebuffer = null; | |
33 int prebufferoffset = 0; | |
34 int prebuffercount = 0; | |
35 int defaultbuffersize; | |
36 | |
37 public Stream BaseStream { get { return baseStream; } } | |
38 | |
39 public PrebufferingStream(Stream stream) : this(stream, 1024) { } | |
40 public PrebufferingStream(Stream stream, int bufferSize) { | |
41 if (stream == null) throw new ArgumentNullException("stream"); | |
42 baseStream = stream; | |
43 defaultbuffersize = bufferSize; | |
44 } | |
45 | |
46 public IAsyncResult BeginPrebuffering(AsyncCallback callback, Object state) { | |
47 return BeginPrebuffering(1, callback, state); | |
48 } | |
49 public IAsyncResult BeginPrebuffering(int count, AsyncCallback callback, Object state) { | |
50 AsyncResult ar = new AsyncResult(callback, state); | |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
51 if (prebuffercount >= count) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
52 ar.SetCompleted(true, prebuffercount, null); |
5 | 53 } else { |
54 PrepareBuffer(count); | |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
55 ar.Left = count - prebuffercount; |
5 | 56 int off = prebufferoffset + prebuffercount; |
57 baseStream.BeginRead(prebuffer, off, prebuffer.Length - off, asyncPrebufferReadCallback, ar); | |
58 } | |
59 return ar; | |
60 } | |
61 private void asyncPrebufferReadCallback(IAsyncResult ar) { | |
62 AsyncResult myar = (AsyncResult)ar.AsyncState; | |
63 try { | |
64 int len = baseStream.EndRead(ar); | |
65 if (len <= 0) { | |
66 myar.SetCompleted(false, prebuffercount, null); | |
67 } else { | |
68 myar.Left -= len; | |
69 prebuffercount += len; | |
70 if (myar.Left > 0) { | |
71 int off = prebufferoffset + prebuffercount; | |
72 baseStream.BeginRead(prebuffer, off, prebuffer.Length - off, asyncPrebufferReadCallback, myar); | |
73 } else { | |
74 myar.SetCompleted(false, prebuffercount, null); | |
75 } | |
76 } | |
77 } catch (Exception ex) { | |
78 myar.SetCompleted(false, prebuffercount, ex); | |
79 } | |
80 } | |
81 public int EndPrebuffering(IAsyncResult ar) { | |
82 AsyncResult myar = (AsyncResult)ar; | |
83 return myar.WaitForCompletion(); | |
84 } | |
85 public int Prebuffer() { | |
86 return Prebuffer(1); | |
87 } | |
88 public int Prebuffer(int count) { | |
89 count -= prebuffercount; | |
90 if (count <= 0) return prebuffercount; | |
91 PrepareBuffer(prebuffercount + count); | |
92 while (count > 0) { | |
93 int off = prebufferoffset + prebuffercount; | |
94 int len = baseStream.Read(prebuffer, off, prebuffer.Length - off); | |
95 if (len <= 0) return prebuffercount; | |
96 count -= len; | |
97 prebuffercount += len; | |
98 } | |
99 return prebuffercount; | |
100 } | |
101 private void PrepareBuffer(int count) { | |
102 if (prebuffercount == 0) prebufferoffset = 0; | |
103 if (prebuffer == null || (prebuffercount == 0 && prebuffer.Length > defaultbuffersize)) { | |
104 if (count < defaultbuffersize) count = defaultbuffersize; | |
105 prebuffer = new Byte[count]; | |
106 prebufferoffset = 0; | |
107 } else if (prebufferoffset + count > prebuffer.Length) { | |
108 if (count > prebuffer.Length) { | |
109 Byte[] newbuffer = new Byte[prebuffercount + count]; | |
110 Buffer.BlockCopy(prebuffer, prebufferoffset, newbuffer, 0, prebuffercount); | |
111 prebuffer = newbuffer; | |
112 } else { | |
113 Buffer.BlockCopy(prebuffer, prebufferoffset, prebuffer, 0, prebuffercount); | |
114 } | |
115 prebufferoffset = 0; | |
116 } | |
117 } | |
118 public Byte Peek() { | |
119 return Peek(0); | |
120 } | |
121 public Byte Peek(int offset) { | |
122 if (Prebuffer(offset + 1) < offset + 1) throw new EndOfStreamException(); | |
123 return prebuffer[prebufferoffset + offset]; | |
124 } | |
125 public void Peek(Byte[] buffer, int offset, int count) { | |
126 Peek(buffer, offset, 0, count); | |
127 } | |
128 public void Peek(Byte[] buffer, int bufferoffset, int peekoffset, int count) { | |
129 if (Prebuffer(peekoffset + count) < peekoffset + count) throw new EndOfStreamException(); | |
130 Buffer.BlockCopy(prebuffer, prebufferoffset + peekoffset, buffer, bufferoffset, count); | |
131 } | |
132 public int TryPeek() { | |
133 return TryPeek(0); | |
134 } | |
135 public int TryPeek(int offset) { | |
136 if (prebuffercount <= offset) return -1; | |
137 return prebuffer[prebufferoffset + offset]; | |
138 } | |
139 public int TryPeek(Byte[] buffer, int offset, int count) { | |
140 return TryPeek(buffer, offset, 0, count); | |
141 } | |
142 public int TryPeek(Byte[] buffer, int bufferoffset, int peekoffset, int count) { | |
143 if (prebuffercount < peekoffset + count) count = prebuffercount - peekoffset; | |
144 if (count < 0) count = 0; | |
145 if (count > 0) Buffer.BlockCopy(prebuffer, prebufferoffset + peekoffset, buffer, bufferoffset, count); | |
146 return count; | |
147 } | |
148 | |
149 public override int Read(byte[] buffer, int offset, int count) { | |
150 if (prebuffercount > 0 || count < 16) { | |
151 if (prebuffercount == 0) if (Prebuffer() < 1) return 0; | |
152 if (count > prebuffercount) count = prebuffercount; | |
153 Buffer.BlockCopy(prebuffer, prebufferoffset, buffer, offset, count); | |
154 prebufferoffset += count; | |
155 prebuffercount -= count; | |
156 return count; | |
157 } else { | |
158 return baseStream.Read(buffer, offset, count); | |
159 } | |
160 } | |
161 | |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
162 public void ReadAll(Byte[] buffer, int offset, int count) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
163 while (count > 0) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
164 int read = Read(buffer, offset, count); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
165 if (read <= 0) throw new EndOfStreamException(); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
166 offset += read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
167 count -= read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
168 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
169 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
170 |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
171 public Byte[] ReadAll(int count) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
172 Byte[] buffer = new Byte[count]; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
173 ReadAll(buffer, 0, count); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
174 return buffer; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
175 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
176 |
5 | 177 public override int ReadByte() { |
178 if (Prebuffer(1) < 1) return -1; | |
179 int v = prebuffer[prebufferoffset]; | |
180 prebufferoffset++; | |
181 prebuffercount--; | |
182 return v; | |
183 } | |
184 | |
185 public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { | |
186 if (prebuffercount > 0) { | |
187 if (count > prebuffercount) count = prebuffercount; | |
188 Buffer.BlockCopy(prebuffer, prebufferoffset, buffer, offset, count); | |
189 prebufferoffset += count; | |
190 prebuffercount -= count; | |
191 AsyncResult ar = new AsyncResult(callback, state); | |
192 ar.SetCompleted(true, count, null); | |
193 return ar; | |
194 } else { | |
195 return baseStream.BeginRead(buffer, offset, count, callback, state); | |
196 } | |
197 } | |
198 | |
199 public override int EndRead(IAsyncResult asyncResult) { | |
200 AsyncResult myar = asyncResult as AsyncResult; | |
201 if (myar != null) { | |
202 return myar.WaitForCompletion(); | |
203 } else { | |
204 return baseStream.EndRead(asyncResult); | |
205 } | |
206 } | |
207 | |
8
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
208 public IAsyncResult BeginReadAll(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
209 AsyncResult ar = new AsyncResult(callback, state); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
210 ar.Buffer = buffer; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
211 ar.Offset = 0; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
212 ar.Left = count; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
213 ar.Count = 0; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
214 if (prebuffercount > 0) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
215 int read = Math.Min(ar.Left, prebuffercount); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
216 Buffer.BlockCopy(prebuffer, prebufferoffset, ar.Buffer, ar.Offset, read); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
217 prebufferoffset += read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
218 prebuffercount -= read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
219 ar.Offset += read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
220 ar.Left -= read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
221 ar.Count += read; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
222 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
223 if (ar.Left > 0) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
224 baseStream.BeginRead(ar.Buffer, ar.Offset, ar.Left, asyncReadAllReadCallback, ar); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
225 } else { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
226 ar.SetCompleted(true, count, null); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
227 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
228 return ar; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
229 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
230 |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
231 private void asyncReadAllReadCallback(IAsyncResult ar) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
232 AsyncResult myar = (AsyncResult)ar.AsyncState; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
233 try { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
234 int len = baseStream.EndRead(ar); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
235 if (len <= 0) throw new EndOfStreamException(); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
236 myar.Offset += len; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
237 myar.Left -= len; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
238 myar.Count += len; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
239 if (myar.Left > 0) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
240 int off = prebufferoffset + prebuffercount; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
241 baseStream.BeginRead(myar.Buffer, myar.Offset, myar.Left, asyncReadAllReadCallback, ar); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
242 } else { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
243 myar.SetCompleted(false, myar.Count, null); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
244 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
245 } catch (Exception ex) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
246 myar.SetCompleted(false, ex); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
247 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
248 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
249 |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
250 public int EndReadAll(IAsyncResult asyncResult) { |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
251 AsyncResult myar = asyncResult as AsyncResult; |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
252 return myar.WaitForCompletion(); |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
253 } |
9525fb2d14ec
Small fix and new functions in PrebufferingStream
Ivo Smits <Ivo@UCIS.nl>
parents:
5
diff
changeset
|
254 |
5 | 255 public override void Close() { |
256 base.Close(); | |
257 baseStream.Close(); | |
258 } | |
259 | |
260 public override void Write(byte[] buffer, int offset, int count) { | |
261 baseStream.Write(buffer, offset, count); | |
262 } | |
263 | |
264 public override void WriteByte(byte value) { | |
265 baseStream.WriteByte(value); | |
266 } | |
267 | |
268 public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { | |
269 return baseStream.BeginWrite(buffer, offset, count, callback, state); | |
270 } | |
271 | |
272 public override void EndWrite(IAsyncResult asyncResult) { | |
273 baseStream.EndWrite(asyncResult); | |
274 } | |
275 | |
276 public override int ReadTimeout { | |
277 get { return baseStream.ReadTimeout; } | |
278 set { baseStream.ReadTimeout = value; } | |
279 } | |
280 | |
281 public override int WriteTimeout { | |
282 get { return baseStream.WriteTimeout; } | |
283 set { baseStream.WriteTimeout = value; } | |
284 } | |
285 | |
286 public override long Length { get { return prebuffercount + baseStream.Length; } } | |
287 public override long Position { | |
288 get { return baseStream.Position - prebuffercount; } | |
289 set { throw new NotImplementedException(); } | |
290 } | |
291 | |
292 public override void SetLength(long value) { throw new NotImplementedException(); } | |
293 public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } | |
294 | |
295 public override bool CanRead { get { return prebuffercount > 0 || baseStream.CanRead; } } | |
296 public override bool CanSeek { get { return false; } } | |
297 public override bool CanTimeout { get { return baseStream.CanTimeout; } } | |
298 public override bool CanWrite { get { return baseStream.CanWrite; } } | |
299 | |
300 public int Buffered { get { return prebuffercount; } } | |
301 | |
302 public override void Flush() { | |
303 baseStream.Flush(); | |
304 } | |
305 } | |
306 } |