mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:18:13 +00:00
b101a7d002
Change-Id: Ib33169c3e0ffc870915c189404074a1dea472546 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196548 Reviewed-by: Bob Nystrom <rnystrom@google.com> Commit-Queue: Leaf Petersen <leafp@google.com>
272 lines
4.7 KiB
Dart
272 lines
4.7 KiB
Dart
// Copyright (c) 2012, 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.
|
|
|
|
// @dart = 2.9
|
|
|
|
import "package:expect/expect.dart";
|
|
import 'dart:convert';
|
|
|
|
String decode(List<int> bytes) {
|
|
StringBuffer buffer = new StringBuffer();
|
|
var stringSink = new StringConversionSink.fromStringSink(buffer);
|
|
var byteSink = new Utf8Decoder().startChunkedConversion(stringSink);
|
|
bytes.forEach((byte) {
|
|
byteSink.add([byte]);
|
|
});
|
|
byteSink.close();
|
|
return buffer.toString();
|
|
}
|
|
|
|
String decodeAllowMalformed(List<int> bytes) {
|
|
StringBuffer buffer = new StringBuffer();
|
|
var stringSink = new StringConversionSink.fromStringSink(buffer);
|
|
var decoder = new Utf8Decoder(allowMalformed: true);
|
|
var byteSink = decoder.startChunkedConversion(stringSink);
|
|
bytes.forEach((byte) {
|
|
byteSink.add([byte]);
|
|
});
|
|
byteSink.close();
|
|
return buffer.toString();
|
|
}
|
|
|
|
final TESTS0 = [
|
|
// Unfinished UTF-8 sequences.
|
|
[0xc3],
|
|
[0xE2, 0x82],
|
|
[0xF0, 0xA4, 0xAD]
|
|
];
|
|
|
|
final TESTS1 = [
|
|
// Overlong encoding of euro-sign.
|
|
[0xF0, 0x82, 0x82, 0xAC],
|
|
// Other overlong/unfinished sequences.
|
|
[0xC0],
|
|
[0xC1],
|
|
[0xF5],
|
|
[0xF6],
|
|
[0xF7],
|
|
[0xF8],
|
|
[0xF9],
|
|
[0xFA],
|
|
[0xFB],
|
|
[0xFC],
|
|
[0xFD],
|
|
[0xFE],
|
|
[0xFF],
|
|
[0xC0, 0x80],
|
|
[0xC1, 0x80],
|
|
// Outside valid range.
|
|
[0xF4, 0xBF, 0xBF, 0xBF]
|
|
];
|
|
|
|
final TESTS2 = [
|
|
// Test that 0xC0|1, 0x80 does not eat the next character.
|
|
[
|
|
[0xC0, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xC1, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
// 0xF5 .. 0xFF never appear in valid UTF-8 sequences.
|
|
[
|
|
[0xF5, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xF6, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xF7, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xF8, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xF9, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFA, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFB, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFC, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFD, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFE, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xFF, 0x80],
|
|
"XX"
|
|
],
|
|
[
|
|
[0xF5, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xF6, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xF7, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xF8, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xF9, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFA, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFB, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFC, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFD, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFE, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
[
|
|
[0xFF, 0x80, 0x61],
|
|
"XXa"
|
|
],
|
|
// Characters outside the valid range.
|
|
[
|
|
[0xF5, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xF6, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xF7, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xF8, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xF9, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFA, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFB, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFC, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFD, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFE, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
],
|
|
[
|
|
[0xFF, 0x80, 0x80, 0x61],
|
|
"XXXa"
|
|
]
|
|
];
|
|
|
|
main() {
|
|
var allTests = [...TESTS0, ...TESTS1].expand((test) {
|
|
// Pairs of test and expected string output when malformed strings are
|
|
// allowed. Replacement character: U+FFFD, one per unfinished sequence or
|
|
// undecodable byte.
|
|
String replacement =
|
|
TESTS0.contains(test) ? "\u{FFFD}" : "\u{FFFD}" * test.length;
|
|
return [
|
|
[test, "${replacement}"],
|
|
[
|
|
[0x61, ...test],
|
|
"a${replacement}"
|
|
],
|
|
[
|
|
[0x61, ...test, 0x61],
|
|
"a${replacement}a"
|
|
],
|
|
[
|
|
[...test, 0x61],
|
|
"${replacement}a"
|
|
],
|
|
[
|
|
[...test, ...test],
|
|
"${replacement}${replacement}"
|
|
],
|
|
[
|
|
[...test, 0x61, ...test],
|
|
"${replacement}a${replacement}"
|
|
],
|
|
[
|
|
[0xc3, 0xa5, ...test],
|
|
"å${replacement}"
|
|
],
|
|
[
|
|
[0xc3, 0xa5, ...test, 0xc3, 0xa5],
|
|
"å${replacement}å"
|
|
],
|
|
[
|
|
[...test, 0xc3, 0xa5],
|
|
"${replacement}å"
|
|
],
|
|
[
|
|
[...test, 0xc3, 0xa5, ...test],
|
|
"${replacement}å${replacement}"
|
|
]
|
|
];
|
|
});
|
|
|
|
var allTests2 = TESTS2.map((test) {
|
|
// Pairs of test and expected string output when malformed strings are
|
|
// allowed. Replacement character: U+FFFD
|
|
String expected = (test[1] as String).replaceAll("X", "\u{FFFD}");
|
|
return [test[0], expected];
|
|
});
|
|
|
|
for (var test in []..addAll(allTests)..addAll(allTests2)) {
|
|
List<int> bytes = test[0];
|
|
Expect.throwsFormatException(() => decode(bytes));
|
|
|
|
String expected = test[1];
|
|
Expect.equals(expected, decodeAllowMalformed(bytes));
|
|
}
|
|
}
|