OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 class _BaseDataInputStream { | |
6 abstract int available(); | |
7 | |
8 List<int> read([int len]) { | |
9 if (_closeCallbackCalled || _scheduledCloseCallback != null) return null; | |
10 int bytesToRead = available(); | |
11 if (bytesToRead == 0) { | |
12 _checkScheduleCallbacks(); | |
13 return null; | |
14 } | |
15 if (len !== null) { | |
16 if (len <= 0) { | |
17 throw new StreamException("Illegal length $len"); | |
18 } else if (bytesToRead > len) { | |
19 bytesToRead = len; | |
20 } | |
21 } | |
22 return _read(bytesToRead); | |
23 } | |
24 | |
25 int readInto(List<int> buffer, [int offset = 0, int len]) { | |
26 if (_closeCallbackCalled || _scheduledCloseCallback != null) return 0; | |
27 if (len === null) len = buffer.length; | |
28 if (offset < 0) throw new StreamException("Illegal offset $offset"); | |
29 if (len < 0) throw new StreamException("Illegal length $len"); | |
30 int bytesToRead = min(len, available()); | |
31 return _readInto(buffer, offset, bytesToRead); | |
32 } | |
33 | |
34 void pipe(OutputStream output, {bool close: true}) { | |
35 _pipe(this, output, close: close); | |
36 } | |
37 | |
38 void close() { | |
39 _cancelScheduledDataCallback(); | |
40 _close(); | |
41 _checkScheduleCallbacks(); | |
42 } | |
43 | |
44 bool get closed => _closeCallbackCalled; | |
45 | |
46 void set onData(void callback()) { | |
47 _clientDataHandler = callback; | |
48 _checkScheduleCallbacks(); | |
49 } | |
50 | |
51 void set onClosed(void callback()) { | |
52 _clientCloseHandler = callback; | |
53 _checkScheduleCallbacks(); | |
54 } | |
55 | |
56 void set onError(void callback(e)) { | |
57 _clientErrorHandler = callback; | |
58 } | |
59 | |
60 void _reportError(e) { | |
61 if (_clientErrorHandler != null) { | |
62 _clientErrorHandler(e); | |
63 } else { | |
64 throw e; | |
65 } | |
66 } | |
67 | |
68 abstract List<int> _read(int bytesToRead); | |
69 | |
70 void _dataReceived() { | |
71 // More data has been received asynchronously. Perform the data | |
72 // handler callback now. | |
73 _cancelScheduledDataCallback(); | |
74 if (_clientDataHandler !== null) { | |
75 _clientDataHandler(); | |
76 } | |
77 _checkScheduleCallbacks(); | |
78 } | |
79 | |
80 void _closeReceived() { | |
81 // Close indication has been received asynchronously. Perform the | |
82 // close callback now if all data has been delivered. | |
83 _streamMarkedClosed = true; | |
84 if (available() == 0) { | |
85 _closeCallbackCalled = true; | |
86 if (_clientCloseHandler !== null) _clientCloseHandler(); | |
87 } else { | |
88 _checkScheduleCallbacks(); | |
89 } | |
90 } | |
91 | |
92 void _cancelScheduledDataCallback() { | |
93 if (_scheduledDataCallback != null) { | |
94 _scheduledDataCallback.cancel(); | |
95 _scheduledDataCallback = null; | |
96 } | |
97 } | |
98 | |
99 void _checkScheduleCallbacks() { | |
100 void issueDataCallback(Timer timer) { | |
101 _scheduledDataCallback = null; | |
102 if (_clientDataHandler !== null) { | |
103 _clientDataHandler(); | |
104 _checkScheduleCallbacks(); | |
105 } | |
106 } | |
107 | |
108 void issueCloseCallback(Timer timer) { | |
109 _scheduledCloseCallback = null; | |
110 _closeCallbackCalled = true; | |
111 if (_clientCloseHandler !== null) _clientCloseHandler(); | |
112 } | |
113 | |
114 // Schedule data callback if there is more data to read. Schedule | |
115 // close callback once when all data has been read. Only schedule | |
116 // a new callback if the previous one has actually been called. | |
117 if (!_closeCallbackCalled) { | |
118 if (available() > 0) { | |
119 if (_scheduledDataCallback == null) { | |
120 _scheduledDataCallback = new Timer(0, issueDataCallback); | |
121 } | |
122 } else if (_streamMarkedClosed && _scheduledCloseCallback == null) { | |
123 _cancelScheduledDataCallback(); | |
124 _close(); | |
125 _scheduledCloseCallback = new Timer(0, issueCloseCallback); | |
126 } | |
127 } | |
128 } | |
129 | |
130 // When this is set to true the stream is marked closed. When a | |
131 // stream is marked closed no more data can arrive and the value | |
132 // from available is now all remaining data. If this is true and the | |
133 // value of available is zero the close handler is called. | |
134 bool _streamMarkedClosed = false; | |
135 | |
136 // When this is set to true the close callback has been called and | |
137 // the stream is fully closed. | |
138 bool _closeCallbackCalled = false; | |
139 | |
140 Timer _scheduledDataCallback; | |
141 Timer _scheduledCloseCallback; | |
142 Function _clientDataHandler; | |
143 Function _clientCloseHandler; | |
144 Function _clientErrorHandler; | |
145 } | |
146 | |
147 | |
148 void _pipe(InputStream input, OutputStream output, {bool close}) { | |
149 Function pipeDataHandler; | |
150 Function pipeCloseHandler; | |
151 Function pipeNoPendingWriteHandler; | |
152 | |
153 Function _inputCloseHandler; | |
154 | |
155 pipeDataHandler = () { | |
156 List<int> data; | |
157 while ((data = input.read()) !== null) { | |
158 if (!output.write(data)) { | |
159 input.onData = null; | |
160 output.onNoPendingWrites = pipeNoPendingWriteHandler; | |
161 break; | |
162 } | |
163 } | |
164 }; | |
165 | |
166 pipeCloseHandler = () { | |
167 if (close) output.close(); | |
168 if (_inputCloseHandler !== null) { | |
169 _inputCloseHandler(); | |
170 } | |
171 }; | |
172 | |
173 pipeNoPendingWriteHandler = () { | |
174 input.onData = pipeDataHandler; | |
175 output.onNoPendingWrites = null; | |
176 }; | |
177 | |
178 _inputCloseHandler = input._clientCloseHandler; | |
179 input.onData = pipeDataHandler; | |
180 input.onClosed = pipeCloseHandler; | |
181 output.onNoPendingWrites = null; | |
182 } | |
183 | |
184 | |
185 class _BaseOutputStream { | |
186 bool writeString(String string, [Encoding encoding = Encoding.UTF_8]) { | |
187 if (string.length > 0) { | |
188 // Encode and write data. | |
189 _StringEncoder encoder = _StringEncoders.encoder(encoding); | |
190 List<int> data = encoder.encodeString(string); | |
191 return write(data, false); | |
192 } | |
193 return true; | |
194 } | |
195 | |
196 void set onError(void callback(e)) { | |
197 _onError = callback; | |
198 } | |
199 | |
200 void _reportError(e) { | |
201 if (_onError != null) { | |
202 _onError(e); | |
203 } else { | |
204 throw e; | |
205 } | |
206 } | |
207 | |
208 Function _onError; | |
209 } | |
OLD | NEW |