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