mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:39:49 +00:00
Migrate dart:convert to NNBD.
Initial port of dart:convert to be statically NNBD clean with the current analyzer implementation, using some assumptions about how the rest of the platform libraries will be migrated. Change-Id: Iad96c684dc7a2c1315ee6a3090ccd7b6d0f71c58 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122173 Reviewed-by: Bob Nystrom <rnystrom@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
This commit is contained in:
parent
fe3aa126a2
commit
225df822b6
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// An instance of the default implementation of the [AsciiCodec].
|
||||
|
@ -50,9 +48,8 @@ class AsciiCodec extends Encoding {
|
|||
///
|
||||
/// If [allowInvalid] is not provided, it defaults to the value used to create
|
||||
/// this [AsciiCodec].
|
||||
String decode(List<int> bytes, {bool allowInvalid}) {
|
||||
allowInvalid ??= _allowInvalid;
|
||||
if (allowInvalid) {
|
||||
String decode(List<int> bytes, {bool? allowInvalid}) {
|
||||
if (allowInvalid ?? _allowInvalid) {
|
||||
return const AsciiDecoder(allowInvalid: true).convert(bytes);
|
||||
} else {
|
||||
return const AsciiDecoder(allowInvalid: false).convert(bytes);
|
||||
|
@ -77,9 +74,13 @@ class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
|
|||
///
|
||||
/// If [start] and [end] are provided, only the substring
|
||||
/// `string.substring(start, end)` is used as input to the conversion.
|
||||
Uint8List convert(String string, [int start = 0, int end]) {
|
||||
Uint8List convert(String string, [int start = 0, int? end]) {
|
||||
var stringLength = string.length;
|
||||
end = RangeError.checkValidRange(start, end, stringLength);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
var length = end - start;
|
||||
var result = Uint8List(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
|
@ -164,11 +165,12 @@ abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
|
|||
///
|
||||
/// If [start] and [end] are provided, only the sub-list of bytes from
|
||||
/// `start` to `end` (`end` not inclusive) is used as input to the conversion.
|
||||
String convert(List<int> bytes, [int start = 0, int end]) {
|
||||
var byteCount = bytes.length;
|
||||
RangeError.checkValidRange(start, end, byteCount);
|
||||
end ??= byteCount;
|
||||
|
||||
String convert(List<int> bytes, [int start = 0, int? end]) {
|
||||
end = RangeError.checkValidRange(start, end, bytes.length);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
for (var i = start; i < end; i++) {
|
||||
var byte = bytes[i];
|
||||
if ((byte & ~_subsetMask) != 0) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
|
||||
|
@ -37,18 +35,18 @@ const Base64Codec base64Url = Base64Codec.urlSafe();
|
|||
|
||||
/// Encodes [bytes] using [base64](https://tools.ietf.org/html/rfc4648) encoding.
|
||||
///
|
||||
/// Shorthand for [base64.encode]. Useful if a local variable shadows the global
|
||||
/// Shorthand for `base64.encode(bytes)`. Useful if a local variable shadows the global
|
||||
/// [base64] constant.
|
||||
String base64Encode(List<int> bytes) => base64.encode(bytes);
|
||||
|
||||
/// Encodes [bytes] using [base64url](https://tools.ietf.org/html/rfc4648) encoding.
|
||||
///
|
||||
/// Shorthand for [base64url.encode].
|
||||
/// Shorthand for `base64url.encode(bytes)`.
|
||||
String base64UrlEncode(List<int> bytes) => base64Url.encode(bytes);
|
||||
|
||||
/// Decodes [base64](https://tools.ietf.org/html/rfc4648) or [base64url](https://tools.ietf.org/html/rfc4648) encoded bytes.
|
||||
///
|
||||
/// Shorthand for [base64.decode]. Useful if a local variable shadows the
|
||||
/// Shorthand for `base64.decode(bytes)`. Useful if a local variable shadows the
|
||||
/// global [base64] constant.
|
||||
Uint8List base64Decode(String source) => base64.decode(source);
|
||||
|
||||
|
@ -95,11 +93,15 @@ class Base64Codec extends Codec<List<int>, String> {
|
|||
/// * Validate that existing padding (trailing `=` characters) is correct.
|
||||
/// * If no padding exists, add correct padding if necessary and possible.
|
||||
/// * Validate that the length is correct (a multiple of four).
|
||||
String normalize(String source, [int start = 0, int end]) {
|
||||
String normalize(String source, [int start = 0, int? end]) {
|
||||
end = RangeError.checkValidRange(start, end, source.length);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
const percent = 0x25;
|
||||
const equals = 0x3d;
|
||||
StringBuffer buffer;
|
||||
StringBuffer? buffer;
|
||||
var sliceStart = start;
|
||||
var alphabet = _Base64Encoder._base64Alphabet;
|
||||
var inverseAlphabet = _Base64Decoder._inverseAlphabet;
|
||||
|
@ -142,9 +144,9 @@ class Base64Codec extends Codec<List<int>, String> {
|
|||
if (originalChar == equals) continue;
|
||||
}
|
||||
if (value != _Base64Decoder._invalid) {
|
||||
buffer ??= StringBuffer();
|
||||
buffer.write(source.substring(sliceStart, sliceEnd));
|
||||
buffer.writeCharCode(char);
|
||||
(buffer ??= StringBuffer())
|
||||
..write(source.substring(sliceStart, sliceEnd))
|
||||
..writeCharCode(char);
|
||||
sliceStart = i;
|
||||
continue;
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ class Base64Encoder extends Converter<List<int>, String> {
|
|||
String convert(List<int> input) {
|
||||
if (input.isEmpty) return "";
|
||||
var encoder = _Base64Encoder(_urlSafe);
|
||||
var buffer = encoder.encode(input, 0, input.length, true);
|
||||
var buffer = encoder.encode(input, 0, input.length, true)!;
|
||||
return String.fromCharCodes(buffer);
|
||||
}
|
||||
|
||||
|
@ -302,10 +304,10 @@ class _Base64Encoder {
|
|||
/// with the necessary padding.
|
||||
///
|
||||
/// Returns `null` if there is no output.
|
||||
Uint8List encode(List<int> bytes, int start, int end, bool isLast) {
|
||||
Uint8List? encode(List<int> bytes, int start, int end, bool isLast) {
|
||||
assert(0 <= start);
|
||||
assert(start <= end);
|
||||
assert(bytes == null || end <= bytes.length);
|
||||
assert(end <= bytes.length);
|
||||
var length = end - start;
|
||||
|
||||
var count = _stateCount(_state);
|
||||
|
@ -395,16 +397,21 @@ class _BufferCachingBase64Encoder extends _Base64Encoder {
|
|||
///
|
||||
/// When the buffer isn't released to the sink, only used to create another
|
||||
/// value (a string), the buffer can be reused between chunks.
|
||||
Uint8List bufferCache;
|
||||
Uint8List? bufferCache;
|
||||
|
||||
_BufferCachingBase64Encoder(bool urlSafe) : super(urlSafe);
|
||||
|
||||
Uint8List createBuffer(int bufferLength) {
|
||||
if (bufferCache == null || bufferCache.length < bufferLength) {
|
||||
bufferCache = Uint8List(bufferLength);
|
||||
Uint8List? buffer = bufferCache;
|
||||
if (buffer == null || buffer.length < bufferLength) {
|
||||
bufferCache = buffer = Uint8List(bufferLength);
|
||||
}
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (buffer == null) {
|
||||
throw "unreachable";
|
||||
}
|
||||
// Return a view of the buffer, so it has the requested length.
|
||||
return Uint8List.view(bufferCache.buffer, 0, bufferLength);
|
||||
return Uint8List.view(buffer.buffer, 0, bufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,7 +421,7 @@ abstract class _Base64EncoderSink extends ByteConversionSinkBase {
|
|||
}
|
||||
|
||||
void close() {
|
||||
_add(null, 0, 0, true);
|
||||
_add(const [], 0, 0, true);
|
||||
}
|
||||
|
||||
void addSlice(List<int> source, int start, int end, bool isLast) {
|
||||
|
@ -480,11 +487,15 @@ class Base64Decoder extends Converter<String, List<int>> {
|
|||
/// The returned [Uint8List] contains exactly the decoded bytes,
|
||||
/// so the [Uint8List.length] is precisely the number of decoded bytes.
|
||||
/// The [Uint8List.buffer] may be larger than the decoded bytes.
|
||||
Uint8List convert(String input, [int start = 0, int end]) {
|
||||
Uint8List convert(String input, [int start = 0, int? end]) {
|
||||
end = RangeError.checkValidRange(start, end, input.length);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
if (start == end) return Uint8List(0);
|
||||
var decoder = _Base64Decoder();
|
||||
var buffer = decoder.decode(input, start, end);
|
||||
var buffer = decoder.decode(input, start, end)!;
|
||||
decoder.close(input, end);
|
||||
return buffer;
|
||||
}
|
||||
|
@ -594,7 +605,7 @@ class _Base64Decoder {
|
|||
/// Returns a [Uint8List] with the decoded bytes.
|
||||
/// If a previous call had an incomplete four-character block, the bits from
|
||||
/// those are included in decoding
|
||||
Uint8List decode(String input, int start, int end) {
|
||||
Uint8List? decode(String input, int start, int end) {
|
||||
assert(0 <= start);
|
||||
assert(start <= end);
|
||||
assert(end <= input.length);
|
||||
|
@ -604,12 +615,14 @@ class _Base64Decoder {
|
|||
}
|
||||
if (start == end) return Uint8List(0);
|
||||
var buffer = _allocateBuffer(input, start, end, _state);
|
||||
_state = decodeChunk(input, start, end, buffer, 0, _state);
|
||||
if (buffer.length > 0) {
|
||||
_state = decodeChunk(input, start, end, buffer, 0, _state);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// Checks that [_state] represents a valid decoding.
|
||||
void close(String input, int end) {
|
||||
void close(String? input, int? end) {
|
||||
if (_state < _encodePaddingState(0)) {
|
||||
throw FormatException("Missing padding character", input, end);
|
||||
}
|
||||
|
@ -693,6 +706,8 @@ class _Base64Decoder {
|
|||
throw FormatException("Invalid character", input, i);
|
||||
}
|
||||
|
||||
static Uint8List _emptyBuffer = Uint8List(0);
|
||||
|
||||
/// Allocates a buffer with room for the decoding of a substring of [input].
|
||||
///
|
||||
/// Includes room for the characters in [state], and handles padding correctly.
|
||||
|
@ -712,7 +727,7 @@ class _Base64Decoder {
|
|||
if (bufferLength > 0) return Uint8List(bufferLength);
|
||||
// If the input plus state is less than four characters, and it's not
|
||||
// at the end of input, no buffer is needed.
|
||||
return null;
|
||||
return _emptyBuffer;
|
||||
}
|
||||
|
||||
/// Returns the position of the start of padding at the end of the input.
|
||||
|
@ -844,7 +859,7 @@ class _Base64DecoderSink extends StringConversionSinkBase {
|
|||
}
|
||||
|
||||
void addSlice(String string, int start, int end, bool isLast) {
|
||||
end = RangeError.checkValidRange(start, end, string.length);
|
||||
RangeError.checkValidRange(start, end, string.length);
|
||||
if (start == end) return;
|
||||
var buffer = _decoder.decode(string, start, end);
|
||||
if (buffer != null) _sink.add(buffer);
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// The [ByteConversionSink] provides an interface for converters to
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// A [ChunkedConversionSink] is used to transmit data more efficiently between
|
||||
|
@ -74,7 +72,7 @@ class _ConverterStreamEventSink<S, T> implements EventSink<S> {
|
|||
_chunkedSink.add(o);
|
||||
}
|
||||
|
||||
void addError(Object error, [StackTrace stackTrace]) {
|
||||
void addError(Object error, [StackTrace? stackTrace]) {
|
||||
_eventSink.addError(error, stackTrace);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// A [Codec] encodes and (if supported) decodes data.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
///
|
||||
/// Encoders and decoders for converting between different data representations,
|
||||
/// including JSON and UTF-8.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// A [Converter] converts data from one representation into another.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// Open-ended Encoding enum.
|
||||
|
@ -74,10 +72,9 @@ abstract class Encoding extends Codec<String, List<int>> {
|
|||
///
|
||||
/// The [name] passed is case insensitive.
|
||||
///
|
||||
/// If character set is not supported [:null:] is returned.
|
||||
static Encoding getByName(String name) {
|
||||
/// If character set is not supported `null` is returned.
|
||||
static Encoding? getByName(String? name) {
|
||||
if (name == null) return null;
|
||||
name = name.toLowerCase();
|
||||
return _nameToEncoding[name];
|
||||
return _nameToEncoding[name.toLowerCase()];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// A `String` converter that converts characters to HTML entities.
|
||||
|
@ -160,11 +158,11 @@ class HtmlEscape extends Converter<String, String> {
|
|||
///
|
||||
/// Returns `null` if no changes were necessary, otherwise returns
|
||||
/// the converted string.
|
||||
String _convert(String text, int start, int end) {
|
||||
StringBuffer result;
|
||||
String? _convert(String text, int start, int end) {
|
||||
StringBuffer? result;
|
||||
for (var i = start; i < end; i++) {
|
||||
var ch = text[i];
|
||||
String replacement;
|
||||
String? replacement;
|
||||
switch (ch) {
|
||||
case '&':
|
||||
replacement = '&';
|
||||
|
@ -187,6 +185,11 @@ class HtmlEscape extends Converter<String, String> {
|
|||
}
|
||||
if (replacement != null) {
|
||||
result ??= StringBuffer();
|
||||
// TODO(38725): Remove workaround when assignment promotion is
|
||||
// implemented
|
||||
if (result == null) {
|
||||
throw "unreachable";
|
||||
}
|
||||
if (i > start) result.write(text.substring(start, i));
|
||||
result.write(replacement);
|
||||
start = i + 1;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// Error thrown by JSON serialization if an object cannot be serialized.
|
||||
|
@ -16,15 +14,15 @@ part of dart.convert;
|
|||
/// serializable, the [cause] is null.
|
||||
class JsonUnsupportedObjectError extends Error {
|
||||
/// The object that could not be serialized.
|
||||
final Object unsupportedObject;
|
||||
final Object? unsupportedObject;
|
||||
|
||||
/// The exception thrown when trying to convert the object.
|
||||
final Object cause;
|
||||
final Object? cause;
|
||||
|
||||
/// The partial result of the conversion, up until the error happened.
|
||||
///
|
||||
/// May be null.
|
||||
final String partialResult;
|
||||
final String? partialResult;
|
||||
|
||||
JsonUnsupportedObjectError(this.unsupportedObject,
|
||||
{this.cause, this.partialResult});
|
||||
|
@ -48,7 +46,7 @@ class JsonUnsupportedObjectError extends Error {
|
|||
/// When the cycle is detected, a [JsonCyclicError] is thrown.
|
||||
class JsonCyclicError extends JsonUnsupportedObjectError {
|
||||
/// The first object that was detected as part of a cycle.
|
||||
JsonCyclicError(Object object) : super(object);
|
||||
JsonCyclicError(Object? object) : super(object);
|
||||
String toString() => "Cyclic error in JSON stringify";
|
||||
}
|
||||
|
||||
|
@ -76,9 +74,10 @@ const JsonCodec json = JsonCodec();
|
|||
/// If [toEncodable] is omitted, it defaults to a function that returns the
|
||||
/// result of calling `.toJson()` on the unencodable object.
|
||||
///
|
||||
/// Shorthand for [json.encode]. Useful if a local variable shadows the global
|
||||
/// Shorthand for `json.encode`. Useful if a local variable shadows the global
|
||||
/// [json] constant.
|
||||
String jsonEncode(Object object, {Object toEncodable(Object nonEncodable)}) =>
|
||||
String jsonEncode(Object? object,
|
||||
{Object? toEncodable(Object? nonEncodable)?}) =>
|
||||
json.encode(object, toEncodable: toEncodable);
|
||||
|
||||
/// Parses the string and returns the resulting Json object.
|
||||
|
@ -90,9 +89,10 @@ String jsonEncode(Object object, {Object toEncodable(Object nonEncodable)}) =>
|
|||
///
|
||||
/// The default [reviver] (when not provided) is the identity function.
|
||||
///
|
||||
/// Shorthand for [json.decode]. Useful if a local variable shadows the global
|
||||
/// Shorthand for `json.decode`. Useful if a local variable shadows the global
|
||||
/// [json] constant.
|
||||
dynamic jsonDecode(String source, {Object reviver(Object key, Object value)}) =>
|
||||
dynamic jsonDecode(String source,
|
||||
{Object? reviver(Object? key, Object? value)?}) =>
|
||||
json.decode(source, reviver: reviver);
|
||||
|
||||
/// A [JsonCodec] encodes JSON objects to strings and decodes strings to
|
||||
|
@ -102,9 +102,9 @@ dynamic jsonDecode(String source, {Object reviver(Object key, Object value)}) =>
|
|||
///
|
||||
/// var encoded = json.encode([1, 2, { "a": null }]);
|
||||
/// var decoded = json.decode('["foo", { "bar": 499 }]');
|
||||
class JsonCodec extends Codec<Object, String> {
|
||||
final Function(Object key, Object value) _reviver;
|
||||
final Function(dynamic) _toEncodable;
|
||||
class JsonCodec extends Codec<Object?, String> {
|
||||
final Object? Function(Object? key, Object? value)? _reviver;
|
||||
final Object? Function(dynamic)? _toEncodable;
|
||||
|
||||
/// Creates a `JsonCodec` with the given reviver and encoding function.
|
||||
///
|
||||
|
@ -127,7 +127,9 @@ class JsonCodec extends Codec<Object, String> {
|
|||
///
|
||||
/// If [toEncodable] is omitted, it defaults to a function that returns the
|
||||
/// result of calling `.toJson()` on the unencodable object.
|
||||
const JsonCodec({reviver(Object key, Object value), toEncodable(var object)})
|
||||
const JsonCodec(
|
||||
{Object? reviver(Object? key, Object? value)?,
|
||||
Object? toEncodable(dynamic object)?})
|
||||
: _reviver = reviver,
|
||||
_toEncodable = toEncodable;
|
||||
|
||||
|
@ -137,7 +139,7 @@ class JsonCodec extends Codec<Object, String> {
|
|||
/// that has been parsed during decoding. The `key` argument is either the
|
||||
/// integer list index for a list property, the string map key for object
|
||||
/// properties, or `null` for the final result.
|
||||
JsonCodec.withReviver(reviver(Object key, Object value))
|
||||
JsonCodec.withReviver(dynamic reviver(Object? key, Object? value))
|
||||
: this(reviver: reviver);
|
||||
|
||||
/// Parses the string and returns the resulting Json object.
|
||||
|
@ -148,7 +150,8 @@ class JsonCodec extends Codec<Object, String> {
|
|||
/// properties, or `null` for the final result.
|
||||
///
|
||||
/// The default [reviver] (when not provided) is the identity function.
|
||||
dynamic decode(String source, {reviver(Object key, Object value)}) {
|
||||
dynamic decode(String source,
|
||||
{Object? reviver(Object? key, Object? value)?}) {
|
||||
reviver ??= _reviver;
|
||||
if (reviver == null) return decoder.convert(source);
|
||||
return JsonDecoder(reviver).convert(source);
|
||||
|
@ -163,7 +166,7 @@ class JsonCodec extends Codec<Object, String> {
|
|||
///
|
||||
/// If [toEncodable] is omitted, it defaults to a function that returns the
|
||||
/// result of calling `.toJson()` on the unencodable object.
|
||||
String encode(Object value, {toEncodable(object)}) {
|
||||
String encode(Object? value, {Object? toEncodable(dynamic object)?}) {
|
||||
toEncodable ??= _toEncodable;
|
||||
if (toEncodable == null) return encoder.convert(value);
|
||||
return JsonEncoder(toEncodable).convert(value);
|
||||
|
@ -181,18 +184,18 @@ class JsonCodec extends Codec<Object, String> {
|
|||
}
|
||||
|
||||
/// This class converts JSON objects to strings.
|
||||
class JsonEncoder extends Converter<Object, String> {
|
||||
class JsonEncoder extends Converter<Object?, String> {
|
||||
/// The string used for indention.
|
||||
///
|
||||
/// When generating multi-line output, this string is inserted once at the
|
||||
/// beginning of each indented line for each level of indentation.
|
||||
///
|
||||
/// If `null`, the output is encoded as a single line.
|
||||
final String indent;
|
||||
final String? indent;
|
||||
|
||||
/// Function called on non-encodable objects to return a replacement
|
||||
/// encodable object that will be encoded in the orignal's place.
|
||||
final Function(dynamic) _toEncodable;
|
||||
final Object? Function(dynamic)? _toEncodable;
|
||||
|
||||
/// Creates a JSON encoder.
|
||||
///
|
||||
|
@ -204,7 +207,7 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
///
|
||||
/// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
|
||||
/// the object.
|
||||
const JsonEncoder([toEncodable(object)])
|
||||
const JsonEncoder([Object? toEncodable(dynamic object)?])
|
||||
: indent = null,
|
||||
_toEncodable = toEncodable;
|
||||
|
||||
|
@ -224,7 +227,8 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
///
|
||||
/// If [toEncodable] is omitted, it defaults to calling `.toJson()` on
|
||||
/// the object.
|
||||
const JsonEncoder.withIndent(this.indent, [toEncodable(object)])
|
||||
const JsonEncoder.withIndent(this.indent,
|
||||
[Object? toEncodable(dynamic object)?])
|
||||
: _toEncodable = toEncodable;
|
||||
|
||||
/// Converts [object] to a JSON [String].
|
||||
|
@ -253,7 +257,7 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
/// If an object is serialized more than once, [convert] may cache the text
|
||||
/// for it. In other words, if the content of an object changes after it is
|
||||
/// first serialized, the new values may not be reflected in the result.
|
||||
String convert(Object object) =>
|
||||
String convert(Object? object) =>
|
||||
_JsonStringStringifier.stringify(object, _toEncodable, indent);
|
||||
|
||||
/// Starts a chunked conversion.
|
||||
|
@ -263,7 +267,7 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
///
|
||||
/// Returns a chunked-conversion sink that accepts at most one object. It is
|
||||
/// an error to invoke `add` more than once on the returned sink.
|
||||
ChunkedConversionSink<Object> startChunkedConversion(Sink<String> sink) {
|
||||
ChunkedConversionSink<Object?> startChunkedConversion(Sink<String> sink) {
|
||||
if (sink is _Utf8EncoderSink) {
|
||||
return _JsonUtf8EncoderSink(
|
||||
sink._sink,
|
||||
|
@ -278,15 +282,15 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
}
|
||||
|
||||
// Override the base class's bind, to provide a better type.
|
||||
Stream<String> bind(Stream<Object> stream) => super.bind(stream);
|
||||
Stream<String> bind(Stream<Object?> stream) => super.bind(stream);
|
||||
|
||||
Converter<Object, T> fuse<T>(Converter<String, T> other) {
|
||||
if (other is Utf8Encoder && T is List<int>) {
|
||||
Converter<Object?, T> fuse<T>(Converter<String, T> other) {
|
||||
if (other is Utf8Encoder) {
|
||||
// The instance check guarantees that `T` is (a subtype of) List<int>,
|
||||
// but the static type system doesn't know that, and so we cast.
|
||||
// Cast through dynamic to keep the cast implicit for builds using
|
||||
// unchecked implicit casts.
|
||||
return JsonUtf8Encoder(indent, _toEncodable) as dynamic;
|
||||
return JsonUtf8Encoder(indent, _toEncodable) as Converter<Object?, T>;
|
||||
}
|
||||
return super.fuse<T>(other);
|
||||
}
|
||||
|
@ -297,17 +301,17 @@ class JsonEncoder extends Converter<Object, String> {
|
|||
/// This encoder works equivalently to first converting the object to
|
||||
/// a JSON string, and then UTF-8 encoding the string, but without
|
||||
/// creating an intermediate string.
|
||||
class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
||||
class JsonUtf8Encoder extends Converter<Object?, List<int>> {
|
||||
/// Default buffer size used by the JSON-to-UTF-8 encoder.
|
||||
static const int _defaultBufferSize = 256;
|
||||
@deprecated
|
||||
static const int DEFAULT_BUFFER_SIZE = _defaultBufferSize;
|
||||
|
||||
/// Indentation used in pretty-print mode, `null` if not pretty.
|
||||
final List<int> _indent;
|
||||
final List<int>? _indent;
|
||||
|
||||
/// Function called with each un-encodable object encountered.
|
||||
final Function(dynamic) _toEncodable;
|
||||
final Object? Function(dynamic)? _toEncodable;
|
||||
|
||||
/// UTF-8 buffer size.
|
||||
final int _bufferSize;
|
||||
|
@ -336,12 +340,12 @@ class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
|||
/// If [toEncodable] is omitted, it defaults to calling `.toJson()` on the
|
||||
/// object.
|
||||
JsonUtf8Encoder(
|
||||
[String indent, toEncodable(object), int bufferSize = _defaultBufferSize])
|
||||
[String? indent, dynamic toEncodable(dynamic object)?, int? bufferSize])
|
||||
: _indent = _utf8Encode(indent),
|
||||
_toEncodable = toEncodable,
|
||||
_bufferSize = bufferSize;
|
||||
_bufferSize = bufferSize ?? _defaultBufferSize;
|
||||
|
||||
static List<int> _utf8Encode(String string) {
|
||||
static List<int>? _utf8Encode(String? string) {
|
||||
if (string == null) return null;
|
||||
if (string.isEmpty) return Uint8List(0);
|
||||
checkAscii:
|
||||
|
@ -355,7 +359,7 @@ class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
|||
}
|
||||
|
||||
/// Convert [object] into UTF-8 encoded JSON.
|
||||
List<int> convert(Object object) {
|
||||
List<int> convert(Object? object) {
|
||||
var bytes = <List<int>>[];
|
||||
// The `stringify` function always converts into chunks.
|
||||
// Collect the chunks into the `bytes` list, then combine them afterwards.
|
||||
|
@ -391,7 +395,7 @@ class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
|||
///
|
||||
/// The argument [sink] will receive byte lists in sizes depending on the
|
||||
/// `bufferSize` passed to the constructor when creating this encoder.
|
||||
ChunkedConversionSink<Object> startChunkedConversion(Sink<List<int>> sink) {
|
||||
ChunkedConversionSink<Object?> startChunkedConversion(Sink<List<int>> sink) {
|
||||
ByteConversionSink byteSink;
|
||||
if (sink is ByteConversionSink) {
|
||||
byteSink = sink;
|
||||
|
@ -402,7 +406,7 @@ class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
|||
}
|
||||
|
||||
// Override the base class's bind, to provide a better type.
|
||||
Stream<List<int>> bind(Stream<Object> stream) {
|
||||
Stream<List<int>> bind(Stream<Object?> stream) {
|
||||
return super.bind(stream);
|
||||
}
|
||||
}
|
||||
|
@ -410,9 +414,9 @@ class JsonUtf8Encoder extends Converter<Object, List<int>> {
|
|||
/// Implements the chunked conversion from object to its JSON representation.
|
||||
///
|
||||
/// The sink only accepts one value, but will produce output in a chunked way.
|
||||
class _JsonEncoderSink extends ChunkedConversionSink<Object> {
|
||||
final String _indent;
|
||||
final Function(dynamic) _toEncodable;
|
||||
class _JsonEncoderSink extends ChunkedConversionSink<Object?> {
|
||||
final String? _indent;
|
||||
final Object? Function(dynamic)? _toEncodable;
|
||||
final StringConversionSink _sink;
|
||||
bool _isDone = false;
|
||||
|
||||
|
@ -423,7 +427,7 @@ class _JsonEncoderSink extends ChunkedConversionSink<Object> {
|
|||
/// It is an error to invoke this method more than once on any instance. While
|
||||
/// this makes the input effectively non-chunked the output will be generated
|
||||
/// in a chunked way.
|
||||
void add(Object o) {
|
||||
void add(Object? o) {
|
||||
if (_isDone) {
|
||||
throw StateError("Only one call to add allowed");
|
||||
}
|
||||
|
@ -437,11 +441,11 @@ class _JsonEncoderSink extends ChunkedConversionSink<Object> {
|
|||
}
|
||||
|
||||
/// Sink returned when starting a chunked conversion from object to bytes.
|
||||
class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
|
||||
class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object?> {
|
||||
/// The byte sink receiveing the encoded chunks.
|
||||
final ByteConversionSink _sink;
|
||||
final List<int> _indent;
|
||||
final Function(dynamic) _toEncodable;
|
||||
final List<int>? _indent;
|
||||
final Object? Function(dynamic)? _toEncodable;
|
||||
final int _bufferSize;
|
||||
bool _isDone = false;
|
||||
_JsonUtf8EncoderSink(
|
||||
|
@ -452,7 +456,7 @@ class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
|
|||
_sink.addSlice(chunk, start, end, false);
|
||||
}
|
||||
|
||||
void add(Object object) {
|
||||
void add(Object? object) {
|
||||
if (_isDone) {
|
||||
throw StateError("Only one call to add allowed");
|
||||
}
|
||||
|
@ -471,13 +475,14 @@ class _JsonUtf8EncoderSink extends ChunkedConversionSink<Object> {
|
|||
}
|
||||
|
||||
/// This class parses JSON strings and builds the corresponding objects.
|
||||
class JsonDecoder extends Converter<String, Object> {
|
||||
final Function(Object key, Object value) _reviver;
|
||||
class JsonDecoder extends Converter<String, Object?> {
|
||||
final Object? Function(Object? key, Object? value)? _reviver;
|
||||
|
||||
/// Constructs a new JsonDecoder.
|
||||
///
|
||||
/// The [reviver] may be `null`.
|
||||
const JsonDecoder([reviver(Object key, Object value)]) : _reviver = reviver;
|
||||
const JsonDecoder([Object? reviver(Object? key, Object? value)?])
|
||||
: _reviver = reviver;
|
||||
|
||||
/// Converts the given JSON-string [input] to its corresponding object.
|
||||
///
|
||||
|
@ -497,14 +502,14 @@ class JsonDecoder extends Converter<String, Object> {
|
|||
/// Starts a conversion from a chunked JSON string to its corresponding object.
|
||||
///
|
||||
/// The output [sink] receives exactly one decoded element through `add`.
|
||||
external StringConversionSink startChunkedConversion(Sink<Object> sink);
|
||||
external StringConversionSink startChunkedConversion(Sink<Object?> sink);
|
||||
|
||||
// Override the base class's bind, to provide a better type.
|
||||
Stream<Object> bind(Stream<String> stream) => super.bind(stream);
|
||||
Stream<Object?> bind(Stream<String> stream) => super.bind(stream);
|
||||
}
|
||||
|
||||
// Internal optimized JSON parsing implementation.
|
||||
external _parseJson(String source, reviver(key, value));
|
||||
external _parseJson(String source, reviver(key, value)?);
|
||||
|
||||
// Implementation of encoder/stringifier.
|
||||
|
||||
|
@ -537,10 +542,10 @@ abstract class _JsonStringifier {
|
|||
/// Function called for each un-encodable object encountered.
|
||||
final Function(dynamic) _toEncodable;
|
||||
|
||||
_JsonStringifier(toEncodable(o))
|
||||
_JsonStringifier(dynamic toEncodable(dynamic o)?)
|
||||
: _toEncodable = toEncodable ?? _defaultToEncodable;
|
||||
|
||||
String get _partialResult;
|
||||
String? get _partialResult;
|
||||
|
||||
/// Append a string to the JSON output.
|
||||
void writeString(String characters);
|
||||
|
@ -610,7 +615,7 @@ abstract class _JsonStringifier {
|
|||
///
|
||||
/// Records the object if it isn't already seen. Should have a matching call to
|
||||
/// [_removeSeen] when the object is no longer being traversed.
|
||||
void _checkCycle(object) {
|
||||
void _checkCycle(Object? object) {
|
||||
for (var i = 0; i < _seen.length; i++) {
|
||||
if (identical(object, _seen[i])) {
|
||||
throw JsonCyclicError(object);
|
||||
|
@ -623,7 +628,7 @@ abstract class _JsonStringifier {
|
|||
///
|
||||
/// Should be called in the opposite order of the matching [_checkCycle]
|
||||
/// calls.
|
||||
void _removeSeen(object) {
|
||||
void _removeSeen(Object? object) {
|
||||
assert(_seen.isNotEmpty);
|
||||
assert(identical(_seen.last, object));
|
||||
_seen.removeLast();
|
||||
|
@ -633,7 +638,7 @@ abstract class _JsonStringifier {
|
|||
///
|
||||
/// If [object] isn't directly encodable, the [_toEncodable] function gets one
|
||||
/// chance to return a replacement which is encodable.
|
||||
void writeObject(object) {
|
||||
void writeObject(Object? object) {
|
||||
// Tries stringifying object directly. If it's not a simple value, List or
|
||||
// Map, call toJson() to get a custom representation and try serializing
|
||||
// that.
|
||||
|
@ -655,7 +660,7 @@ abstract class _JsonStringifier {
|
|||
///
|
||||
/// Returns true if the value is one of these types, and false if not.
|
||||
/// If a value is both a [List] and a [Map], it's serialized as a [List].
|
||||
bool writeJsonValue(object) {
|
||||
bool writeJsonValue(Object? object) {
|
||||
if (object is num) {
|
||||
if (!object.isFinite) return false;
|
||||
writeNumber(object);
|
||||
|
@ -691,7 +696,7 @@ abstract class _JsonStringifier {
|
|||
}
|
||||
|
||||
/// Serialize a [List].
|
||||
void writeList(List list) {
|
||||
void writeList(List<Object?> list) {
|
||||
writeString('[');
|
||||
if (list.isNotEmpty) {
|
||||
writeObject(list[0]);
|
||||
|
@ -704,12 +709,12 @@ abstract class _JsonStringifier {
|
|||
}
|
||||
|
||||
/// Serialize a [Map].
|
||||
bool writeMap(Map map) {
|
||||
bool writeMap(Map<Object?, Object?> map) {
|
||||
if (map.isEmpty) {
|
||||
writeString("{}");
|
||||
return true;
|
||||
}
|
||||
var keyValueList = List(map.length * 2);
|
||||
var keyValueList = List<Object?>(map.length * 2);
|
||||
var i = 0;
|
||||
var allStringKeys = true;
|
||||
map.forEach((key, value) {
|
||||
|
@ -725,7 +730,7 @@ abstract class _JsonStringifier {
|
|||
for (var i = 0; i < keyValueList.length; i += 2) {
|
||||
writeString(separator);
|
||||
separator = ',"';
|
||||
writeStringContent(keyValueList[i]);
|
||||
writeStringContent(keyValueList[i] as String);
|
||||
writeString('":');
|
||||
writeObject(keyValueList[i + 1]);
|
||||
}
|
||||
|
@ -744,7 +749,7 @@ abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
|
|||
/// Add [indentLevel] indentations to the JSON output.
|
||||
void writeIndentation(int indentLevel);
|
||||
|
||||
void writeList(List list) {
|
||||
void writeList(List<Object?> list) {
|
||||
if (list.isEmpty) {
|
||||
writeString('[]');
|
||||
} else {
|
||||
|
@ -764,12 +769,12 @@ abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
|
|||
}
|
||||
}
|
||||
|
||||
bool writeMap(Map map) {
|
||||
bool writeMap(Map<Object?, Object?> map) {
|
||||
if (map.isEmpty) {
|
||||
writeString("{}");
|
||||
return true;
|
||||
}
|
||||
var keyValueList = List(map.length * 2);
|
||||
var keyValueList = List<Object?>(map.length * 2);
|
||||
var i = 0;
|
||||
var allStringKeys = true;
|
||||
map.forEach((key, value) {
|
||||
|
@ -788,7 +793,7 @@ abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
|
|||
separator = ",\n";
|
||||
writeIndentation(_indentLevel);
|
||||
writeString('"');
|
||||
writeStringContent(keyValueList[i]);
|
||||
writeStringContent(keyValueList[i] as String);
|
||||
writeString('": ');
|
||||
writeObject(keyValueList[i + 1]);
|
||||
}
|
||||
|
@ -804,7 +809,8 @@ abstract class _JsonPrettyPrintMixin implements _JsonStringifier {
|
|||
class _JsonStringStringifier extends _JsonStringifier {
|
||||
final StringSink _sink;
|
||||
|
||||
_JsonStringStringifier(this._sink, dynamic Function(dynamic) _toEncodable)
|
||||
_JsonStringStringifier(
|
||||
this._sink, dynamic Function(dynamic object)? _toEncodable)
|
||||
: super(_toEncodable);
|
||||
|
||||
/// Convert object to a string.
|
||||
|
@ -816,7 +822,8 @@ class _JsonStringStringifier extends _JsonStringifier {
|
|||
/// with newlines and indentation. The `indent` string is added as indentation
|
||||
/// for each indentation level. It should only contain valid JSON whitespace
|
||||
/// characters (space, tab, carriage return or line feed).
|
||||
static String stringify(object, toEncodable(o), String indent) {
|
||||
static String stringify(
|
||||
Object? object, dynamic toEncodable(dynamic object)?, String? indent) {
|
||||
var output = StringBuffer();
|
||||
printOn(object, output, toEncodable, indent);
|
||||
return output.toString();
|
||||
|
@ -825,8 +832,8 @@ class _JsonStringStringifier extends _JsonStringifier {
|
|||
/// Convert object to a string, and write the result to the [output] sink.
|
||||
///
|
||||
/// The result is written piecemally to the sink.
|
||||
static void printOn(
|
||||
object, StringSink output, toEncodable(o), String indent) {
|
||||
static void printOn(Object? object, StringSink output,
|
||||
dynamic toEncodable(dynamic o)?, String? indent) {
|
||||
_JsonStringifier stringifier;
|
||||
if (indent == null) {
|
||||
stringifier = _JsonStringStringifier(output, toEncodable);
|
||||
|
@ -836,7 +843,7 @@ class _JsonStringStringifier extends _JsonStringifier {
|
|||
stringifier.writeObject(object);
|
||||
}
|
||||
|
||||
String get _partialResult => _sink is StringBuffer ? _sink.toString() : null;
|
||||
String? get _partialResult => _sink is StringBuffer ? _sink.toString() : null;
|
||||
|
||||
void writeNumber(num number) {
|
||||
_sink.write(number.toString());
|
||||
|
@ -859,7 +866,8 @@ class _JsonStringStringifierPretty extends _JsonStringStringifier
|
|||
with _JsonPrettyPrintMixin {
|
||||
final String _indent;
|
||||
|
||||
_JsonStringStringifierPretty(StringSink sink, toEncodable(o), this._indent)
|
||||
_JsonStringStringifierPretty(
|
||||
StringSink sink, dynamic toEncodable(dynamic o)?, this._indent)
|
||||
: super(sink, toEncodable);
|
||||
|
||||
void writeIndentation(int count) {
|
||||
|
@ -877,7 +885,8 @@ class _JsonUtf8Stringifier extends _JsonStringifier {
|
|||
Uint8List buffer;
|
||||
int index = 0;
|
||||
|
||||
_JsonUtf8Stringifier(toEncodable(o), this.bufferSize, this.addChunk)
|
||||
_JsonUtf8Stringifier(
|
||||
dynamic toEncodable(dynamic o)?, this.bufferSize, this.addChunk)
|
||||
: buffer = Uint8List(bufferSize),
|
||||
super(toEncodable);
|
||||
|
||||
|
@ -890,8 +899,12 @@ class _JsonUtf8Stringifier extends _JsonStringifier {
|
|||
///
|
||||
/// If [indent] is non-`null`, the result will be "pretty-printed" with extra
|
||||
/// newlines and indentation, using [indent] as the indentation.
|
||||
static void stringify(Object object, List<int> indent, toEncodable(o),
|
||||
int bufferSize, void addChunk(Uint8List chunk, int start, int end)) {
|
||||
static void stringify(
|
||||
Object? object,
|
||||
List<int>? indent,
|
||||
dynamic toEncodable(dynamic o)?,
|
||||
int bufferSize,
|
||||
void addChunk(Uint8List chunk, int start, int end)) {
|
||||
_JsonUtf8Stringifier stringifier;
|
||||
if (indent != null) {
|
||||
stringifier =
|
||||
|
@ -909,11 +922,11 @@ class _JsonUtf8Stringifier extends _JsonStringifier {
|
|||
if (index > 0) {
|
||||
addChunk(buffer, 0, index);
|
||||
}
|
||||
buffer = null;
|
||||
buffer = Uint8List(0);
|
||||
index = 0;
|
||||
}
|
||||
|
||||
String get _partialResult => null;
|
||||
String? get _partialResult => null;
|
||||
|
||||
void writeNumber(num number) {
|
||||
writeAsciiString(number.toString());
|
||||
|
@ -937,7 +950,7 @@ class _JsonUtf8Stringifier extends _JsonStringifier {
|
|||
void writeStringSlice(String string, int start, int end) {
|
||||
// TODO(lrn): Optimize by copying directly into buffer instead of going
|
||||
// through writeCharCode/writeByte. Assumption is the most characters
|
||||
// in starings are plain ASCII.
|
||||
// in strings are plain ASCII.
|
||||
for (var i = start; i < end; i++) {
|
||||
var char = string.codeUnitAt(i);
|
||||
if (char <= 0x7f) {
|
||||
|
@ -1005,8 +1018,8 @@ class _JsonUtf8Stringifier extends _JsonStringifier {
|
|||
class _JsonUtf8StringifierPretty extends _JsonUtf8Stringifier
|
||||
with _JsonPrettyPrintMixin {
|
||||
final List<int> indent;
|
||||
_JsonUtf8StringifierPretty(toEncodable(o), this.indent, int bufferSize,
|
||||
void addChunk(Uint8List buffer, int start, int end))
|
||||
_JsonUtf8StringifierPretty(dynamic toEncodable(dynamic o)?, this.indent,
|
||||
int bufferSize, void addChunk(Uint8List buffer, int start, int end))
|
||||
: super(toEncodable, bufferSize, addChunk);
|
||||
|
||||
void writeIndentation(int count) {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// An instance of the default implementation of the [Latin1Codec].
|
||||
|
@ -49,9 +47,8 @@ class Latin1Codec extends Encoding {
|
|||
///
|
||||
/// If [allowInvalid] is not provided, it defaults to the value used to create
|
||||
/// this [Latin1Codec].
|
||||
String decode(List<int> bytes, {bool allowInvalid}) {
|
||||
allowInvalid ??= _allowInvalid;
|
||||
if (allowInvalid) {
|
||||
String decode(List<int> bytes, {bool? allowInvalid}) {
|
||||
if (allowInvalid ?? _allowInvalid) {
|
||||
return const Latin1Decoder(allowInvalid: true).convert(bytes);
|
||||
} else {
|
||||
return const Latin1Decoder(allowInvalid: false).convert(bytes);
|
||||
|
@ -102,11 +99,11 @@ class Latin1Decoder extends _UnicodeSubsetDecoder {
|
|||
}
|
||||
|
||||
class _Latin1DecoderSink extends ByteConversionSinkBase {
|
||||
StringConversionSink _sink;
|
||||
StringConversionSink? _sink;
|
||||
_Latin1DecoderSink(this._sink);
|
||||
|
||||
void close() {
|
||||
_sink.close();
|
||||
_sink!.close();
|
||||
_sink = null;
|
||||
}
|
||||
|
||||
|
@ -119,12 +116,12 @@ class _Latin1DecoderSink extends ByteConversionSinkBase {
|
|||
// _sink.addSlice(source, start, end, isLast).
|
||||
// The code below is an moderately stupid workaround until a real
|
||||
// solution can be made.
|
||||
_sink.add(String.fromCharCodes(source, start, end));
|
||||
_sink!.add(String.fromCharCodes(source, start, end));
|
||||
if (isLast) close();
|
||||
}
|
||||
|
||||
void addSlice(List<int> source, int start, int end, bool isLast) {
|
||||
end = RangeError.checkValidRange(start, end, source.length);
|
||||
RangeError.checkValidRange(start, end, source.length);
|
||||
if (start == end) return;
|
||||
if (source is! Uint8List) {
|
||||
// List may contain value outside of the 0..255 range. If so, throw.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
// Character constants.
|
||||
|
@ -27,8 +25,12 @@ class LineSplitter extends StreamTransformerBase<String, String> {
|
|||
/// `lines.substring(start, end)`. The [start] and [end] values must
|
||||
/// specify a valid sub-range of [lines]
|
||||
/// (`0 <= start <= end <= lines.length`).
|
||||
static Iterable<String> split(String lines, [int start = 0, int end]) sync* {
|
||||
static Iterable<String> split(String lines, [int start = 0, int? end]) sync* {
|
||||
end = RangeError.checkValidRange(start, end, lines.length);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
var sliceStart = start;
|
||||
var char = 0;
|
||||
for (var i = start; i < end; i++) {
|
||||
|
@ -92,7 +94,7 @@ class _LineSplitterSink extends StringConversionSinkBase {
|
|||
///
|
||||
/// If the previous slice ended in a line without a line terminator,
|
||||
/// then the next slice may continue the line.
|
||||
String _carry;
|
||||
String? _carry;
|
||||
|
||||
/// Whether to skip a leading LF character from the next slice.
|
||||
///
|
||||
|
@ -112,9 +114,10 @@ class _LineSplitterSink extends StringConversionSinkBase {
|
|||
if (isLast) close();
|
||||
return;
|
||||
}
|
||||
if (_carry != null) {
|
||||
String? carry = _carry;
|
||||
if (carry != null) {
|
||||
assert(!_skipLeadingLF);
|
||||
chunk = _carry + chunk.substring(start, end);
|
||||
chunk = carry + chunk.substring(start, end);
|
||||
start = 0;
|
||||
end = chunk.length;
|
||||
_carry = null;
|
||||
|
@ -130,7 +133,7 @@ class _LineSplitterSink extends StringConversionSinkBase {
|
|||
|
||||
void close() {
|
||||
if (_carry != null) {
|
||||
_sink.add(_carry);
|
||||
_sink.add(_carry!);
|
||||
_carry = null;
|
||||
}
|
||||
_sink.close();
|
||||
|
@ -168,7 +171,7 @@ class _LineSplitterEventSink extends _LineSplitterSink
|
|||
: _eventSink = eventSink,
|
||||
super(StringConversionSink.from(eventSink));
|
||||
|
||||
void addError(Object o, [StackTrace stackTrace]) {
|
||||
void addError(Object o, [StackTrace? stackTrace]) {
|
||||
_eventSink.addError(o, stackTrace);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// This class provides an interface for converters to
|
||||
|
@ -101,8 +99,8 @@ class _ClosableStringSink implements ClosableStringSink {
|
|||
class _StringConversionSinkAsStringSinkAdapter implements ClosableStringSink {
|
||||
static const _MIN_STRING_SIZE = 16;
|
||||
|
||||
StringBuffer _buffer;
|
||||
StringConversionSink _chunkedSink;
|
||||
final StringBuffer _buffer;
|
||||
final StringConversionSink _chunkedSink;
|
||||
|
||||
_StringConversionSinkAsStringSinkAdapter(this._chunkedSink)
|
||||
: _buffer = StringBuffer();
|
||||
|
@ -117,12 +115,12 @@ class _StringConversionSinkAsStringSinkAdapter implements ClosableStringSink {
|
|||
if (_buffer.length > _MIN_STRING_SIZE) _flush();
|
||||
}
|
||||
|
||||
void write(Object o) {
|
||||
void write(Object? o) {
|
||||
if (_buffer.isNotEmpty) _flush();
|
||||
_chunkedSink.add(o.toString());
|
||||
}
|
||||
|
||||
void writeln([Object o = ""]) {
|
||||
void writeln([Object? o = ""]) {
|
||||
_buffer.writeln(o);
|
||||
if (_buffer.length > _MIN_STRING_SIZE) _flush();
|
||||
}
|
||||
|
@ -177,10 +175,11 @@ abstract class StringConversionSinkMixin implements StringConversionSink {
|
|||
/// This class is a [StringConversionSink] that wraps a [StringSink].
|
||||
class _StringSinkConversionSink<TStringSink extends StringSink>
|
||||
extends StringConversionSinkBase {
|
||||
TStringSink _stringSink;
|
||||
final TStringSink _stringSink;
|
||||
_StringSinkConversionSink(this._stringSink);
|
||||
|
||||
void close() {}
|
||||
|
||||
void addSlice(String str, int start, int end, bool isLast) {
|
||||
if (start != 0 || end != str.length) {
|
||||
for (var i = start; i < end; i++) {
|
||||
|
@ -211,6 +210,7 @@ class _StringSinkConversionSink<TStringSink extends StringSink>
|
|||
/// This class can be used to terminate a chunked conversion.
|
||||
class _StringCallbackSink extends _StringSinkConversionSink<StringBuffer> {
|
||||
final void Function(String) _callback;
|
||||
|
||||
_StringCallbackSink(this._callback) : super(StringBuffer());
|
||||
|
||||
void close() {
|
||||
|
@ -253,16 +253,18 @@ class _StringAdapterSink extends StringConversionSinkBase {
|
|||
}
|
||||
|
||||
/// Decodes UTF-8 code units and stores them in a [StringSink].
|
||||
///
|
||||
/// The `Sink` provided is closed when this sink is closed.
|
||||
class _Utf8StringSinkAdapter extends ByteConversionSink {
|
||||
final _Utf8Decoder _decoder;
|
||||
final Sink _sink;
|
||||
final Sink<Object?> _sink;
|
||||
|
||||
_Utf8StringSinkAdapter(this._sink, StringSink stringSink, bool allowMalformed)
|
||||
: _decoder = _Utf8Decoder(stringSink, allowMalformed);
|
||||
|
||||
void close() {
|
||||
_decoder.close();
|
||||
if (_sink != null) _sink.close();
|
||||
_sink.close();
|
||||
}
|
||||
|
||||
void add(List<int> chunk) {
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
// 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.
|
||||
|
||||
// @dart = 2.5
|
||||
|
||||
part of dart.convert;
|
||||
|
||||
/// The Unicode Replacement character `U+FFFD` (<EFBFBD>).
|
||||
const int unicodeReplacementCharacterRune = 0xFFFD;
|
||||
|
||||
/// The Unicode Byte Order Marker (BOM) character `U+FEFF`.
|
||||
/// The Unicode Byte Order Marker (f) character `U+FEFF`.
|
||||
const int unicodeBomCharacterRune = 0xFEFF;
|
||||
|
||||
/// An instance of the default implementation of the [Utf8Codec].
|
||||
|
@ -56,9 +54,9 @@ class Utf8Codec extends Encoding {
|
|||
///
|
||||
/// If [allowMalformed] is not given, it defaults to the `allowMalformed` that
|
||||
/// was used to instantiate `this`.
|
||||
String decode(List<int> codeUnits, {bool allowMalformed}) {
|
||||
allowMalformed ??= _allowMalformed;
|
||||
return Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits);
|
||||
String decode(List<int> codeUnits, {bool? allowMalformed}) {
|
||||
return Utf8Decoder(allowMalformed: allowMalformed ?? _allowMalformed)
|
||||
.convert(codeUnits);
|
||||
}
|
||||
|
||||
Utf8Encoder get encoder => const Utf8Encoder();
|
||||
|
@ -77,9 +75,13 @@ class Utf8Encoder extends Converter<String, List<int>> {
|
|||
///
|
||||
/// If [start] and [end] are provided, only the substring
|
||||
/// `string.substring(start, end)` is converted.
|
||||
Uint8List convert(String string, [int start = 0, int end]) {
|
||||
Uint8List convert(String string, [int start = 0, int? end]) {
|
||||
var stringLength = string.length;
|
||||
end = RangeError.checkValidRange(start, end, stringLength);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
var length = end - start;
|
||||
if (length == 0) return Uint8List(0);
|
||||
// Create a new encoder with a length that is guaranteed to be big enough.
|
||||
|
@ -298,7 +300,7 @@ class Utf8Decoder extends Converter<List<int>, String> {
|
|||
///
|
||||
/// If the [codeUnits] start with the encoding of a
|
||||
/// [unicodeBomCharacterRune], that character is discarded.
|
||||
String convert(List<int> codeUnits, [int start = 0, int end]) {
|
||||
String convert(List<int> codeUnits, [int start = 0, int? end]) {
|
||||
// Allow the implementation to intercept and specialize based on the type
|
||||
// of codeUnits.
|
||||
var result = _convertIntercepted(_allowMalformed, codeUnits, start, end);
|
||||
|
@ -308,6 +310,10 @@ class Utf8Decoder extends Converter<List<int>, String> {
|
|||
|
||||
var length = codeUnits.length;
|
||||
end = RangeError.checkValidRange(start, end, length);
|
||||
// TODO(38725): Remove workaround when assignment promotion is implemented
|
||||
if (end == null) {
|
||||
throw RangeError("Invalid range");
|
||||
}
|
||||
|
||||
// Fast case for ASCII strings avoids StringBuffer/_Utf8Decoder.
|
||||
int oneBytes = _scanOneByteCharacters(codeUnits, start, end);
|
||||
|
@ -321,9 +327,9 @@ class Utf8Decoder extends Converter<List<int>, String> {
|
|||
}
|
||||
buffer = StringBuffer(firstPart);
|
||||
isFirstCharacter = false;
|
||||
} else {
|
||||
buffer = StringBuffer();
|
||||
}
|
||||
|
||||
buffer ??= StringBuffer();
|
||||
var decoder = _Utf8Decoder(buffer, _allowMalformed);
|
||||
decoder._isFirstCharacter = isFirstCharacter;
|
||||
decoder.convert(codeUnits, start, end);
|
||||
|
@ -350,8 +356,8 @@ class Utf8Decoder extends Converter<List<int>, String> {
|
|||
|
||||
external Converter<List<int>, T> fuse<T>(Converter<String, T> next);
|
||||
|
||||
external static String _convertIntercepted(
|
||||
bool allowMalformed, List<int> codeUnits, int start, int end);
|
||||
external static String? _convertIntercepted(
|
||||
bool allowMalformed, List<int> codeUnits, int start, int? end);
|
||||
}
|
||||
|
||||
// UTF-8 constants.
|
||||
|
@ -409,7 +415,7 @@ class _Utf8Decoder {
|
|||
///
|
||||
/// The [source] and [offset] of the current position may be provided,
|
||||
/// and are included in the exception if one is thrown.
|
||||
void flush([List<int> source, int offset]) {
|
||||
void flush([List<int>? source, int? offset]) {
|
||||
if (hasPartialInput) {
|
||||
if (!_allowMalformed) {
|
||||
throw FormatException(
|
||||
|
|
Loading…
Reference in a new issue