/
byte_conversion.dart
100 lines (85 loc) · 3.02 KB
/
byte_conversion.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.convert;
/// The [ByteConversionSink] provides an interface for converters to
/// efficiently transmit byte data.
///
/// Instead of limiting the interface to one non-chunked list of bytes it
/// accepts its input in chunks (themselves being lists of bytes).
abstract mixin class ByteConversionSink
implements ChunkedConversionSink<List<int>> {
const ByteConversionSink();
factory ByteConversionSink.withCallback(
void callback(List<int> accumulated)) = _ByteCallbackSink;
factory ByteConversionSink.from(Sink<List<int>> sink) = _ByteAdapterSink;
/// Adds the next [chunk] to `this`.
///
/// Adds the bytes defined by [start] and [end]-exclusive to `this`.
///
/// If [isLast] is `true` closes `this`.
///
/// Contrary to `add` the given [chunk] must not be held onto.
/// Once the method returns, it is safe to overwrite the data in it.
void addSlice(List<int> chunk, int start, int end, bool isLast) {
add(chunk.sublist(start, end));
if (isLast) close();
}
}
/// This class provides a base-class for converters that need to accept byte
/// inputs.
// TODO(lrn): @Deprecated("Use ByteConversionSink instead")
typedef ByteConversionSinkBase = ByteConversionSink;
/// This class adapts a simple [Sink] to a [ByteConversionSink].
///
/// All additional methods of the [ByteConversionSink] (compared to the
/// ChunkedConversionSink) are redirected to the `add` method.
class _ByteAdapterSink extends ByteConversionSink {
final Sink<List<int>> _sink;
_ByteAdapterSink(this._sink);
void add(List<int> chunk) {
_sink.add(chunk);
}
void close() {
_sink.close();
}
}
/// This class accumulates all chunks into one list of bytes
/// and invokes a callback when the sink is closed.
///
/// This class can be used to terminate a chunked conversion.
class _ByteCallbackSink extends ByteConversionSink {
static const _INITIAL_BUFFER_SIZE = 1024;
final void Function(List<int>) _callback;
List<int> _buffer = Uint8List(_INITIAL_BUFFER_SIZE);
int _bufferIndex = 0;
_ByteCallbackSink(void callback(List<int> accumulated))
: _callback = callback;
void add(Iterable<int> chunk) {
var freeCount = _buffer.length - _bufferIndex;
if (chunk.length > freeCount) {
// Grow the buffer.
var oldLength = _buffer.length;
var newLength = _roundToPowerOf2(chunk.length + oldLength) * 2;
var grown = Uint8List(newLength);
grown.setRange(0, _buffer.length, _buffer);
_buffer = grown;
}
_buffer.setRange(_bufferIndex, _bufferIndex + chunk.length, chunk);
_bufferIndex += chunk.length;
}
static int _roundToPowerOf2(int v) {
assert(v > 0);
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
void close() {
_callback(_buffer.sublist(0, _bufferIndex));
}
}