Utf16BytesToCodeUnitsDecoder abstract class
Convert UTF-16 encoded bytes to UTF-16 code units by grouping 1-2 bytes to produce the code unit (0-(2^16)-1). Relies on BOM to determine endian-ness, and defaults to BE.
abstract class Utf16BytesToCodeUnitsDecoder implements _ListRangeIterator {
final _ListRangeIterator utf16EncodedBytesIterator;
final int replacementCodepoint;
int _current = null;
Utf16BytesToCodeUnitsDecoder._fromListRangeIterator(
this.utf16EncodedBytesIterator, this.replacementCodepoint);
factory Utf16BytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
if (length == null) {
length = utf16EncodedBytes.length - offset;
}
if (hasUtf16beBom(utf16EncodedBytes, offset, length)) {
return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
length - 2, false, replacementCodepoint);
} else if (hasUtf16leBom(utf16EncodedBytes, offset, length)) {
return new Utf16leBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
length - 2, false, replacementCodepoint);
} else {
return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset,
length, false, replacementCodepoint);
}
}
/**
* Provides a fast way to decode the rest of the source bytes in a single
* call. This method trades memory for improved speed in that it potentially
* over-allocates the List containing results.
*/
List<int> decodeRest() {
List<int> codeunits = new List<int>(remaining);
int i = 0;
while (moveNext()) {
codeunits[i++] = current;
}
if (i == codeunits.length) {
return codeunits;
} else {
List<int> truncCodeunits = new List<int>(i);
truncCodeunits.setRange(0, i, codeunits);
return truncCodeunits;
}
}
int get current => _current;
bool moveNext() {
_current = null;
if (utf16EncodedBytesIterator.remaining < 2) {
utf16EncodedBytesIterator.moveNext();
if (replacementCodepoint != null) {
_current = replacementCodepoint;
return true;
} else {
throw new ArgumentError(
"Invalid UTF16 at ${utf16EncodedBytesIterator.position}");
}
} else {
_current = decode();
return true;
}
}
int get position => utf16EncodedBytesIterator.position ~/ 2;
void backup([int by = 1]) {
utf16EncodedBytesIterator.backup(2 * by);
}
int get remaining => (utf16EncodedBytesIterator.remaining + 1) ~/ 2;
void skip([int count = 1]) {
utf16EncodedBytesIterator.skip(2 * count);
}
int decode();
}
Subclasses
Utf16beBytesToCodeUnitsDecoder, Utf16leBytesToCodeUnitsDecoder
Constructors
factory Utf16BytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [int offset = 0, int length, int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) #
factory Utf16BytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
int offset = 0, int length,
int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
if (length == null) {
length = utf16EncodedBytes.length - offset;
}
if (hasUtf16beBom(utf16EncodedBytes, offset, length)) {
return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
length - 2, false, replacementCodepoint);
} else if (hasUtf16leBom(utf16EncodedBytes, offset, length)) {
return new Utf16leBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
length - 2, false, replacementCodepoint);
} else {
return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset,
length, false, replacementCodepoint);
}
}
Properties
final _ListRangeIterator utf16EncodedBytesIterator #
final _ListRangeIterator utf16EncodedBytesIterator
Methods
List<int> decodeRest() #
Provides a fast way to decode the rest of the source bytes in a single call. This method trades memory for improved speed in that it potentially over-allocates the List containing results.
List<int> decodeRest() {
List<int> codeunits = new List<int>(remaining);
int i = 0;
while (moveNext()) {
codeunits[i++] = current;
}
if (i == codeunits.length) {
return codeunits;
} else {
List<int> truncCodeunits = new List<int>(i);
truncCodeunits.setRange(0, i, codeunits);
return truncCodeunits;
}
}
bool moveNext() #
Moves to the next element. Returns true if current contains the next element. Returns false, if no element was left.
It is safe to invoke moveNext even when the iterator is already positioned after the last element. In this case moveNext has no effect.
bool moveNext() {
_current = null;
if (utf16EncodedBytesIterator.remaining < 2) {
utf16EncodedBytesIterator.moveNext();
if (replacementCodepoint != null) {
_current = replacementCodepoint;
return true;
} else {
throw new ArgumentError(
"Invalid UTF16 at ${utf16EncodedBytesIterator.position}");
}
} else {
_current = decode();
return true;
}
}