Appearance
UriData final
final class UriDataA way to access the structure of a data: URI.
Data URIs are non-hierarchical URIs that can contain any binary data. They are defined by RFC 2397.
This class allows parsing the URI text, extracting individual parts of the URI, as well as building the URI text from structured parts.
Constructors
UriData.fromBytes() factory
factory UriData.fromBytes(
List<int> bytes, {
String mimeType = "application/octet-stream",
Map<String, String>? parameters,
bool percentEncoded = false,
})Creates a data: URI containing an encoding of bytes.
Equivalent to Uri.dataFromBytes(...).data, but may be more efficient if the uri itself isn't used.
Implementation
dart
factory UriData.fromBytes(
List<int> bytes, {
String mimeType = "application/octet-stream",
Map<String, String>? parameters,
bool percentEncoded = false,
}) {
StringBuffer buffer = StringBuffer();
List<int> indices = [_noScheme];
_writeUri(mimeType, null, parameters, buffer, indices);
indices.add(buffer.length);
if (percentEncoded) {
buffer.write(',');
_uriEncodeBytes(_uricMask, bytes, buffer);
} else {
buffer.write(';base64,');
indices.add(buffer.length - 1);
_base64.encoder
.startChunkedConversion(StringConversionSink.fromStringSink(buffer))
.addSlice(bytes, 0, bytes.length, true);
}
return UriData._(buffer.toString(), indices, null);
}UriData.fromString() factory
factory UriData.fromString(
String content, {
String? mimeType,
Encoding? encoding,
Map<String, String>? parameters,
bool base64 = false,
})Creates a data: URI containing the content string.
Equivalent to Uri.dataFromString(...).data, but may be more efficient if the uri itself isn't used.
Implementation
dart
factory UriData.fromString(
String content, {
String? mimeType,
Encoding? encoding,
Map<String, String>? parameters,
bool base64 = false,
}) {
StringBuffer buffer = StringBuffer();
List<int> indices = [_noScheme];
String? charsetName = parameters?["charset"];
String? encodingName;
if (encoding == null) {
if (charsetName != null) {
encoding = Encoding.getByName(charsetName);
}
} else if (charsetName == null) {
// Non-null only if parameters does not contain "charset".
encodingName = encoding.name;
}
encoding ??= ascii;
_writeUri(mimeType, encodingName, parameters, buffer, indices);
indices.add(buffer.length);
if (base64) {
buffer.write(';base64,');
indices.add(buffer.length - 1);
buffer.write(encoding.fuse(_base64).encode(content));
} else {
buffer.write(',');
_uriEncodeBytes(_uricMask, encoding.encode(content), buffer);
}
return UriData._(buffer.toString(), indices, null);
}UriData.fromUri() factory
factory UriData.fromUri(Uri uri)Creates a DataUri from a Uri which must have data as Uri.scheme.
The uri must have scheme data and no authority or fragment, and the path (concatenated with the query, if there is one) must be valid as data URI content with the same rules as parse.
Implementation
dart
factory UriData.fromUri(Uri uri) {
if (!uri.isScheme("data")) {
throw ArgumentError.value(uri, "uri", "Scheme must be 'data'");
}
if (uri.hasAuthority) {
throw ArgumentError.value(uri, "uri", "Data uri must not have authority");
}
if (uri.hasFragment) {
throw ArgumentError.value(
uri,
"uri",
"Data uri must not have a fragment part",
);
}
if (!uri.hasQuery) {
return _parse(uri.path, 0, uri);
}
// Includes path and query (and leading "data:").
return _parse(uri.toString(), 5, uri);
}Properties
charset no setter
String get charsetThe charset parameter of the media type.
If the parameters of the media type contains a charset parameter then this returns its value, otherwise it returns US-ASCII, which is the default charset for data URIs. If the values contain non-ASCII percent escapes, they are decoded as UTF-8.
If the MIME type representation in the URI text contains URI escapes, they are unescaped in the returned string.
Implementation
dart
String get charset {
var charsetIndex = _findCharsetIndex();
if (charsetIndex >= 0) {
var valueStart = _separatorIndices[charsetIndex + 1] + 1;
var valueEnd = _separatorIndices[charsetIndex + 2];
return _Uri._uriDecode(_text, valueStart, valueEnd, utf8, false);
}
return "US-ASCII";
}contentText no setter
String get contentTextThe content part of the data URI, as its actual representation.
This string may contain percent escapes.
Implementation
dart
String get contentText => _text.substring(_separatorIndices.last + 1);hashCode no setter inherited
int get hashCodeThe hash code for this object.
A hash code is a single integer which represents the state of the object that affects operator == comparisons.
All objects have hash codes. The default hash code implemented by Object represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).
If operator == is overridden to use the object state instead, the hash code must also be changed to represent that state, otherwise the object cannot be used in hash based data structures like the default Set and Map implementations.
Hash codes must be the same for objects that are equal to each other according to operator ==. The hash code of an object should only change if the object changes in a way that affects equality. There are no further requirements for the hash codes. They need not be consistent between executions of the same program and there are no distribution guarantees.
Objects that are not equal are allowed to have the same hash code. It is even technically allowed that all instances have the same hash code, but if clashes happen too often, it may reduce the efficiency of hash-based data structures like HashSet or HashMap.
If a subclass overrides hashCode, it should override the operator == operator as well to maintain consistency.
Inherited from Object.
Implementation
dart
external int get hashCode;isBase64 no setter
bool get isBase64Whether the data is Base64 encoded or not.
Implementation
dart
bool get isBase64 => _separatorIndices.length.isOdd;mimeType no setter
String get mimeTypeThe MIME type of the data URI.
A data URI consists of a "media type" followed by data. The media type starts with a MIME type and can be followed by extra parameters. If the MIME type representation in the URI text contains URI escapes, they are unescaped in the returned string. If the value contain non-ASCII percent escapes, they are decoded as UTF-8.
Example:
dart
data:text/plain;charset=utf-8,Hello%20World!This data URI has the media type text/plain;charset=utf-8, which is the MIME type text/plain with the parameter charset with value utf-8. See RFC 2045 for more detail.
If the first part of the data URI is empty, it defaults to text/plain.
Implementation
dart
String get mimeType {
int start = _separatorIndices[0] + 1;
int end = _separatorIndices[1];
if (start == end) return "text/plain";
return _Uri._uriDecode(_text, start, end, utf8, false);
}parameters no setter
A map representing the parameters of the media type.
A data URI may contain parameters between the MIME type and the data. This converts these parameters to a map from parameter name to parameter value. The map only contains parameters that actually occur in the URI. The charset parameter has a default value even if it doesn't occur in the URI, which is reflected by the charset getter. This means that charset may return a value even if parameters["charset"] is null.
If the values contain non-ASCII values or percent escapes, they are decoded as UTF-8.
Implementation
dart
Map<String, String> get parameters {
var result = <String, String>{};
for (int i = 3; i < _separatorIndices.length; i += 2) {
var start = _separatorIndices[i - 2] + 1;
var equals = _separatorIndices[i - 1];
var end = _separatorIndices[i];
String key = _Uri._uriDecode(_text, start, equals, utf8, false);
String value = _Uri._uriDecode(_text, equals + 1, end, utf8, false);
result[key] = value;
}
return result;
}runtimeType no setter inherited
Type get runtimeTypeA representation of the runtime type of the object.
Inherited from Object.
Implementation
dart
external Type get runtimeType;uri no setter
Uri get uriThe Uri that this UriData is giving access to.
Returns a Uri with scheme data and the remainder of the data URI as path.
Implementation
dart
Uri get uri {
return _uriCache ??= _computeUri();
}Methods
contentAsBytes()
Uint8List contentAsBytes()The content part of the data URI as bytes.
If the data is Base64 encoded, it will be decoded to bytes.
If the data is not Base64 encoded, it will be decoded by unescaping percent-escaped characters and returning byte values of each unescaped character. The bytes will not be, e.g., UTF-8 decoded.
Implementation
dart
Uint8List contentAsBytes() {
String text = _text;
int start = _separatorIndices.last + 1;
if (isBase64) {
return base64.decoder.convert(text, start);
}
// Not base64, do percent-decoding and return the remaining bytes.
// Compute result size.
const int percent = 0x25;
int length = text.length - start;
for (int i = start; i < text.length; i++) {
var codeUnit = text.codeUnitAt(i);
if (codeUnit == percent) {
i += 2;
length -= 2;
}
}
// Fill result array.
Uint8List result = Uint8List(length);
if (length == text.length) {
result.setRange(0, length, text.codeUnits, start);
return result;
}
int index = 0;
for (int i = start; i < text.length; i++) {
var codeUnit = text.codeUnitAt(i);
if (codeUnit != percent) {
result[index++] = codeUnit;
} else {
if (i + 2 < text.length) {
int byte = parseHexByte(text, i + 1);
if (byte >= 0) {
result[index++] = byte;
i += 2;
continue;
}
}
throw FormatException("Invalid percent escape", text, i);
}
}
assert(index == result.length);
return result;
}contentAsString()
Creates a string from the content of the data URI.
If the content is Base64 encoded, it will be decoded to bytes and then decoded to a string using encoding. If encoding is omitted, the value of a charset parameter is used if it is recognized by Encoding.getByName; otherwise it defaults to the ascii encoding, which is the default encoding for data URIs that do not specify an encoding.
If the content is not Base64 encoded, it will first have percent-escapes converted to bytes and then the character codes and byte values are decoded using encoding.
Implementation
dart
String contentAsString({Encoding? encoding}) {
if (encoding == null) {
var charset = this.charset; // Returns "US-ASCII" if not present.
encoding = Encoding.getByName(charset);
if (encoding == null) {
throw UnsupportedError("Unknown charset: $charset");
}
}
String text = _text;
int start = _separatorIndices.last + 1;
if (isBase64) {
var converter = base64.decoder.fuse(encoding.decoder);
return converter.convert(text.substring(start));
}
return _Uri._uriDecode(text, start, text.length, encoding, false);
}isCharset()
Checks whether the charset parameter of the mime type is charset.
If this URI has no "charset" parameter, it is assumed to have a default of charset=US-ASCII. If charset is empty, it's treated like "US-ASCII".
Returns true if charset and the "charset" parameter value are equal strings, ignoring the case of ASCII letters, or both correspond to the same Encoding, as given by Encoding.getByName.
Implementation
dart
@Since("2.17")
bool isCharset(String charset) {
var charsetIndex = _findCharsetIndex();
if (charsetIndex < 0) {
return charset.isEmpty ||
_caseInsensitiveEquals(charset, "US-ASCII") ||
identical(Encoding.getByName(charset), ascii);
}
if (charset.isEmpty) charset = "US-ASCII";
var valueStart = _separatorIndices[charsetIndex + 1] + 1;
var valueEnd = _separatorIndices[charsetIndex + 2];
var length = valueEnd - valueStart;
if (charset.length == length &&
_caseInsensitiveStartsWith(charset, _text, valueStart)) {
return true;
}
var checkedEncoding = Encoding.getByName(charset);
return checkedEncoding != null &&
identical(
checkedEncoding,
Encoding.getByName(
_Uri._uriDecode(_text, valueStart, valueEnd, utf8, false),
),
);
}isEncoding()
Whether the charset parameter represents encoding.
If the "charset" parameter is not present in the URI, it defaults to "US-ASCII", which is the ascii encoding. If present, it's converted to an Encoding using Encoding.getByName, and compared to encoding.
Implementation
dart
@Since("2.17")
bool isEncoding(Encoding encoding) {
var charsetIndex = _findCharsetIndex();
if (charsetIndex < 0) {
return identical(encoding, ascii);
}
var valueStart = _separatorIndices[charsetIndex + 1] + 1;
var valueEnd = _separatorIndices[charsetIndex + 2];
return identical(
encoding,
Encoding.getByName(
_Uri._uriDecode(_text, valueStart, valueEnd, utf8, false),
),
);
}isMimeType()
Whether the UriData.mimeType is equal to mimeType.
Compares the data: URI's MIME type to mimeType with a case- insensitive comparison which ignores the case of ASCII letters.
An empty mimeType is considered equivalent to text/plain, both in the mimeType argument and in the data: URI itself.
Implementation
dart
@Since("2.17")
bool isMimeType(String mimeType) {
int start = _separatorIndices[0] + 1;
int end = _separatorIndices[1];
if (start == end) {
return mimeType.isEmpty ||
identical(mimeType, "text/plain") ||
_caseInsensitiveEquals(mimeType, "text/plain");
}
if (mimeType.isEmpty) mimeType = "text/plain";
return (mimeType.length == end - start) &&
_caseInsensitiveStartsWith(mimeType, _text, start);
}noSuchMethod() inherited
dynamic noSuchMethod(Invocation invocation)Invoked when a nonexistent method or property is accessed.
A dynamic member invocation can attempt to call a member which doesn't exist on the receiving object. Example:
dart
dynamic object = 1;
object.add(42); // Statically allowed, run-time errorThis invalid code will invoke the noSuchMethod method of the integer 1 with an Invocation representing the .add(42) call and arguments (which then throws).
Classes can override noSuchMethod to provide custom behavior for such invalid dynamic invocations.
A class with a non-default noSuchMethod invocation can also omit implementations for members of its interface. Example:
dart
class MockList<T> implements List<T> {
noSuchMethod(Invocation invocation) {
log(invocation);
super.noSuchMethod(invocation); // Will throw.
}
}
void main() {
MockList().add(42);
}This code has no compile-time warnings or errors even though the MockList class has no concrete implementation of any of the List interface methods. Calls to List methods are forwarded to noSuchMethod, so this code will log an invocation similar to Invocation.method(#add, [42]) and then throw.
If a value is returned from noSuchMethod, it becomes the result of the original invocation. If the value is not of a type that can be returned by the original invocation, a type error occurs at the invocation.
The default behavior is to throw a NoSuchMethodError.
Inherited from Object.
Implementation
dart
@pragma("vm:entry-point")
@pragma("wasm:entry-point")
external dynamic noSuchMethod(Invocation invocation);toString() override
String toString()A string representation of this object.
Some classes have a default textual representation, often paired with a static parse function (like int.parse). These classes will provide the textual representation as their string representation.
Other classes have no meaningful textual representation that a program will care about. Such classes will typically override toString to provide useful information when inspecting the object, mainly for debugging or logging.
Implementation
dart
String toString() =>
(_separatorIndices[0] == _noScheme) ? "data:$_text" : _text;Operators
operator ==() inherited
The equality operator.
The default behavior for all Objects is to return true if and only if this object and other are the same object.
Override this method to specify a different equality relation on a class. The overriding method must still be an equivalence relation. That is, it must be:
Total: It must return a boolean for all arguments. It should never throw.
Reflexive: For all objects
o,o == omust be true.Symmetric: For all objects
o1ando2,o1 == o2ando2 == o1must either both be true, or both be false.Transitive: For all objects
o1,o2, ando3, ifo1 == o2ando2 == o3are true, theno1 == o3must be true.
The method should also be consistent over time, so whether two objects are equal should only change if at least one of the objects was modified.
If a subclass overrides the equality operator, it should override the hashCode method as well to maintain consistency.
Inherited from Object.
Implementation
dart
external bool operator ==(Object other);Static Methods
parse()
Parses a string as a data URI.
The string must have the format:
plaintext
'data:' (type '/' subtype)? (';' attribute '=' value)* (';base64')? ',' datawhere type, subtype, attribute and value are specified in RFC-2045, and data is a sequence of URI-characters (RFC-2396 uric).
This means that all the characters must be ASCII, but the URI may contain percent-escapes for non-ASCII byte values that need an interpretation to be converted to the corresponding string.
Parsing checks that Base64 encoded data is valid, and it normalizes it to use the default Base64 alphabet and to use padding. Non-Base64 data is escaped using percent-escapes as necessary to make it valid, and existing escapes are case normalized.
Accessing the individual parts may fail later if they turn out to have content that cannot be decoded successfully as a string, for example if existing percent escapes represent bytes that cannot be decoded by the chosen Encoding (see contentAsString).
A FormatException is thrown if uri is not a valid data URI.
Implementation
dart
static UriData parse(String uri) {
if (uri.length >= 5) {
int dataDelta = _startsWithData(uri, 0);
if (dataDelta == 0) {
// Exact match on "data:".
return _parse(uri, 5, null);
}
if (dataDelta == 0x20) {
// Starts with a non-normalized "data" scheme containing upper-case
// letters. Parse anyway, but throw away the scheme.
return _parse(uri.substring(5), 0, null);
}
}
throw FormatException("Does not start with 'data:'", uri, 0);
}