您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

655 行
22 KiB

using System;
using System.Collections;
using System.Globalization;
using System.Text;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.services;
namespace Unity.UIWidgets.services {
public class BinaryCodec : MessageCodec<byte[]> {
public BinaryCodec() {
}
public static readonly BinaryCodec instance = new BinaryCodec();
public byte[] decodeMessage(byte[] message) => message;
public byte[] encodeMessage(byte[] message) => message;
}
public class StringCodec : MessageCodec<string> {
public StringCodec() {
}
public static readonly StringCodec instance = new StringCodec();
public string decodeMessage(byte[] message) {
if (message == null)
return null;
return Encoding.UTF8.GetString(message);
}
public byte[] encodeMessage(string message) {
if (message == null)
return null;
return Encoding.UTF8.GetBytes(message);
}
}
public class JSONMessageCodec : MessageCodec<object> {
public JSONMessageCodec() {
}
public static readonly JSONMessageCodec instance = new JSONMessageCodec();
public byte[] encodeMessage(object message) {
var json = toJson(message);
return StringCodec.instance.encodeMessage(json);
}
public string toJson(object message) {
if (message == null)
return null;
var sb = new StringBuilder();
_writeToStringBuilder(message, sb);
return sb.ToString();
}
public object decodeMessage(byte[] message) {
if (message == null)
return null;
return _parseJson(StringCodec.instance.decodeMessage(message));
}
[ThreadStatic] static StringBuilder _escapeBuilder;
static StringBuilder _getEscapeBuilder() {
return _escapeBuilder ?? (_escapeBuilder = new StringBuilder());
}
static string _escape(string aText) {
var sb = _getEscapeBuilder();
sb.Length = 0;
if (sb.Capacity < aText.Length + aText.Length / 10)
sb.Capacity = aText.Length + aText.Length / 10;
foreach (char c in aText) {
switch (c) {
case '\\':
sb.Append("\\\\");
break;
case '\"':
sb.Append("\\\"");
break;
case '\n':
sb.Append("\\n");
break;
case '\r':
sb.Append("\\r");
break;
case '\t':
sb.Append("\\t");
break;
case '\b':
sb.Append("\\b");
break;
case '\f':
sb.Append("\\f");
break;
default:
if (c < ' ') {
ushort val = c;
sb.Append("\\u").Append(val.ToString("X4"));
}
else
sb.Append(c);
break;
}
}
string result = sb.ToString();
sb.Length = 0;
return result;
}
static void _writeToStringBuilder(object obj, StringBuilder sb) {
if (obj is IDictionary dict) {
sb.Append('{');
bool first = true;
foreach (DictionaryEntry k in dict) {
if (!first)
sb.Append(',');
first = false;
sb.Append('\"').Append(_escape(k.Key.ToString())).Append('\"');
sb.Append(':');
_writeToStringBuilder(k.Value, sb);
}
sb.Append('}');
}
else if (obj is IList list) {
sb.Append('[');
int count = list.Count;
for (int i = 0; i < count; i++) {
if (i > 0)
sb.Append(',');
_writeToStringBuilder(list[i], sb);
}
sb.Append(']');
}
else if (obj is string str) {
sb.Append('\"').Append(_escape(str)).Append('\"');
}
else if (obj is double d) {
sb.Append(d.ToString(CultureInfo.InvariantCulture));
}
else if (obj is float f) {
sb.Append(f.ToString(CultureInfo.InvariantCulture));
}
else if (obj is int i) {
sb.Append(i.ToString(CultureInfo.InvariantCulture));
}
else if (obj is long l) {
sb.Append(l.ToString(CultureInfo.InvariantCulture));
}
else if (obj is bool b) {
sb.Append(b ? "true" : "false");
}
else if (obj == null) {
sb.Append("null");
}
else {
throw new Exception("Unsupported object: " + obj);
}
}
static object _parseElement(string token, bool quoted) {
if (quoted)
return token;
string tmp = token.ToLower();
if (tmp == "false" || tmp == "true")
return tmp == "true";
if (tmp == "null")
return null;
if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var val))
return val;
else
return token;
}
static void _addElement(object ctx, string tokenName, object element) {
if (ctx is IDictionary dict) {
dict.Add(tokenName, element);
}
else if (ctx is IList list) {
D.assert(tokenName.isEmpty);
list.Add(element);
}
else {
D.assert(ctx == null);
}
}
static object _parseJson(string jsonStr) {
Stack stack = new Stack();
object ctx = null;
int i = 0;
StringBuilder token = new StringBuilder();
string tokenName = "";
bool quoteMode = false;
bool tokenIsQuoted = false;
while (i < jsonStr.Length) {
switch (jsonStr[i]) {
case '{':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
stack.Push(new Hashtable());
_addElement(ctx, tokenName, stack.Peek());
tokenName = "";
token.Length = 0;
ctx = stack.Peek();
break;
case '[':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
stack.Push(new ArrayList());
_addElement(ctx, tokenName, stack.Peek());
tokenName = "";
token.Length = 0;
ctx = stack.Peek();
break;
case '}':
case ']':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
if (stack.Count == 0)
throw new Exception("JSON Parse: Too many closing brackets");
stack.Pop();
if (token.Length > 0 || tokenIsQuoted)
_addElement(ctx, tokenName, _parseElement(token.ToString(), tokenIsQuoted));
tokenIsQuoted = false;
tokenName = "";
token.Length = 0;
if (stack.Count > 0)
ctx = stack.Peek();
break;
case ':':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
tokenIsQuoted = false;
tokenName = token.ToString();
token.Length = 0;
break;
case '"':
quoteMode ^= true;
tokenIsQuoted |= quoteMode;
break;
case ',':
if (quoteMode) {
token.Append(jsonStr[i]);
break;
}
if (token.Length > 0 || tokenIsQuoted)
_addElement(ctx, tokenName, _parseElement(token.ToString(), tokenIsQuoted));
tokenIsQuoted = false;
tokenName = "";
token.Length = 0;
break;
case '\r':
case '\n':
break;
case ' ':
case '\t':
if (quoteMode)
token.Append(jsonStr[i]);
break;
case '\\':
++i;
if (quoteMode) {
char c = jsonStr[i];
switch (c) {
case 't':
token.Append('\t');
break;
case 'r':
token.Append('\r');
break;
case 'n':
token.Append('\n');
break;
case 'b':
token.Append('\b');
break;
case 'f':
token.Append('\f');
break;
case 'u': {
string s = jsonStr.Substring(i + 1, 4);
token.Append((char) int.Parse(
s,
NumberStyles.AllowHexSpecifier));
i += 4;
break;
}
default:
token.Append(c);
break;
}
}
break;
default:
token.Append(jsonStr[i]);
break;
}
++i;
}
if (quoteMode) {
throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
}
if (ctx == null)
return _parseElement(token.ToString(), tokenIsQuoted);
return ctx;
}
}
}
public class JSONMethodCodec : MethodCodec {
public JSONMethodCodec() {
}
public static readonly JSONMethodCodec instance = new JSONMethodCodec();
public byte[] encodeMethodCall(MethodCall call) {
var obj = new Hashtable {{"method", call.method}, {"args", call.arguments}};
return JSONMessageCodec.instance.encodeMessage(obj);
}
public MethodCall decodeMethodCall(byte[] methodCall) {
object decoded = JSONMessageCodec.instance.decodeMessage(methodCall);
if (!(decoded is IDictionary dict))
throw new Exception($"Expected method call JSONObject, got {decoded}");
object methodRaw = dict["method"];
object arguments = dict["args"];
if (methodRaw is string method)
return new MethodCall(method, arguments);
throw new Exception($"Invalid method call: {decoded}");
}
public object decodeEnvelope(byte[] envelope) {
object decoded = JSONMessageCodec.instance.decodeMessage(envelope);
if (!(decoded is IList list))
throw new Exception($"Expected envelope JSONArray, got {decoded}");
if (list.Count == 1)
return list[0];
if (list.Count == 3
&& list[0] is string code
&& (list[1] == null || list[1] is string))
throw new PlatformException(
code: code,
message: list[1] as string,
details: list[2]
);
throw new Exception($"Invalid envelope: {decoded}");
}
public byte[] encodeSuccessEnvelope(object result) {
var array = new ArrayList {result};
return JSONMessageCodec.instance.encodeMessage(array);
}
public byte[] encodeErrorEnvelope(string code, string message = null, object details = null) {
D.assert(code != null);
var array = new ArrayList {code, message, details};
return JSONMessageCodec.instance.encodeMessage(array);
}
}
public class StandardMessageCodec : MessageCodec<object> {
public StandardMessageCodec() {
}
public static readonly StandardMessageCodec instance = new StandardMessageCodec();
const byte _valueNull = 0;
const byte _valueTrue = 1;
const byte _valueFalse = 2;
const byte _valueInt32 = 3;
const byte _valueInt64 = 4;
const byte _valueFloat32 = 6;
const byte _valueString = 7;
const byte _valueUint8List = 8;
const byte _valueInt32List = 9;
const byte _valueInt64List = 10;
const byte _valueFloat32List = 11;
const byte _valueList = 12;
const byte _valueMap = 13;
public byte[] encodeMessage(object message) {
if (message == null)
return null;
WriteBuffer buffer = new WriteBuffer();
writeValue(buffer, message);
return buffer.done();
}
public object decodeMessage(byte[] message) {
if (message == null)
return null;
ReadBuffer buffer = new ReadBuffer(message);
object result = readValue(buffer);
if (buffer.hasRemaining)
throw new Exception("Message corrupted");
return result;
}
public void writeValue(WriteBuffer buffer, object value) {
if (value == null) {
buffer.putUint8(_valueNull);
}
else if (value is bool b) {
buffer.putUint8(b ? _valueTrue : _valueFalse);
}
else if (value is float f) {
buffer.putUint8(_valueFloat32);
buffer.putFloat32(f);
}
else if (value is int i) {
buffer.putUint8(_valueInt32);
buffer.putInt32(i);
}
else if (value is long l) {
buffer.putUint8(_valueInt64);
buffer.putInt64(l);
}
else if (value is string s) {
buffer.putUint8(_valueString);
byte[] bytes = Encoding.UTF8.GetBytes(s);
writeSize(buffer, bytes.Length);
buffer.putUint8List(bytes);
}
else if (value is byte[] bytes) {
buffer.putUint8(_valueUint8List);
writeSize(buffer, bytes.Length);
buffer.putUint8List(bytes);
}
else if (value is int[] ints) {
buffer.putUint8(_valueInt32List);
writeSize(buffer, ints.Length);
buffer.putInt32List(ints);
}
else if (value is long[] longs) {
buffer.putUint8(_valueInt64List);
writeSize(buffer, longs.Length);
buffer.putInt64List(longs);
}
else if (value is float[] floats) {
buffer.putUint8(_valueFloat32List);
writeSize(buffer, floats.Length);
buffer.putFloat32List(floats);
}
else if (value is IList list) {
buffer.putUint8(_valueList);
writeSize(buffer, list.Count);
foreach (object item in list) {
writeValue(buffer, item);
}
}
else if (value is IDictionary dict) {
buffer.putUint8(_valueMap);
writeSize(buffer, dict.Count);
foreach (DictionaryEntry entry in dict) {
writeValue(buffer, entry.Key);
writeValue(buffer, entry.Value);
}
}
else {
throw new ArgumentException(value.ToString());
}
}
public object readValue(ReadBuffer buffer) {
if (!buffer.hasRemaining)
throw new Exception("Message corrupted");
int type = buffer.getUint8();
return readValueOfType(type, buffer);
}
object readValueOfType(int type, ReadBuffer buffer) {
switch (type) {
case _valueNull:
return null;
case _valueTrue:
return true;
case _valueFalse:
return false;
case _valueInt32:
return buffer.getInt32();
case _valueInt64:
return buffer.getInt64();
case _valueFloat32:
return buffer.getFloat32();
case _valueString: {
int length = (int) readSize(buffer);
return Encoding.UTF8.GetString(buffer.getUint8List(length));
}
case _valueUint8List: {
int length = (int) readSize(buffer);
return buffer.getUint8List(length);
}
case _valueInt32List: {
int length = (int) readSize(buffer);
return buffer.getInt32List(length);
}
case _valueInt64List: {
int length = (int) readSize(buffer);
return buffer.getInt64List(length);
}
case _valueFloat32List: {
int length = (int) readSize(buffer);
return buffer.getFloat32List(length);
}
case _valueList: {
int length = (int) readSize(buffer);
var result = new ArrayList(length);
for (int i = 0; i < length; i++)
result.Add(readValue(buffer));
return result;
}
case _valueMap: {
int length = (int) readSize(buffer);
Hashtable result = new Hashtable();
for (int i = 0; i < length; i++)
result[readValue(buffer)] = readValue(buffer);
return result;
}
default:
throw new Exception("Message corrupted");
}
}
void writeSize(WriteBuffer buffer, long value) {
D.assert(0 <= value && value <= 0x7fffffff);
if (value < 254) {
buffer.putUint8((byte) value);
}
else if (value <= 0xffff) {
buffer.putUint8(254);
buffer.putUint16((ushort) value);
}
else {
buffer.putUint8(255);
buffer.putUint32((uint) value);
}
}
long readSize(ReadBuffer buffer) {
int value = buffer.getUint8();
switch (value) {
case 254:
return buffer.getUint16();
case 255:
return buffer.getUint32();
default:
return value;
}
}
}
public class StandardMethodCodec : MethodCodec {
public StandardMethodCodec(StandardMessageCodec messageCodec = null) {
this.messageCodec = messageCodec ?? StandardMessageCodec.instance;
}
readonly StandardMessageCodec messageCodec;
public byte[] encodeMethodCall(MethodCall call) {
WriteBuffer buffer = new WriteBuffer();
messageCodec.writeValue(buffer, call.method);
messageCodec.writeValue(buffer, call.arguments);
return buffer.done();
}
public MethodCall decodeMethodCall(byte[] methodCall) {
ReadBuffer buffer = new ReadBuffer(methodCall);
object methodRaw = messageCodec.readValue(buffer);
object arguments = messageCodec.readValue(buffer);
if (methodRaw is string method && !buffer.hasRemaining)
return new MethodCall(method, arguments);
else
throw new Exception("Invalid method call");
}
public byte[] encodeSuccessEnvelope(object result) {
WriteBuffer buffer = new WriteBuffer();
buffer.putUint8(0);
messageCodec.writeValue(buffer, result);
return buffer.done();
}
public byte[] encodeErrorEnvelope(string code, string message = null, object details = null) {
WriteBuffer buffer = new WriteBuffer();
buffer.putUint8(1);
messageCodec.writeValue(buffer, code);
messageCodec.writeValue(buffer, message);
messageCodec.writeValue(buffer, details);
return buffer.done();
}
public object decodeEnvelope(byte[] envelope) {
if (envelope.Length == 0)
throw new Exception("Expected envelope, got nothing");
ReadBuffer buffer = new ReadBuffer(envelope);
if (buffer.getUint8() == 0)
return messageCodec.readValue(buffer);
object errorCodeRaw = messageCodec.readValue(buffer);
object errorMessage = messageCodec.readValue(buffer);
object errorDetails = messageCodec.readValue(buffer);
if (errorCodeRaw is string errorCode && (errorMessage == null || errorMessage is string) &&
!buffer.hasRemaining)
throw new PlatformException(code: errorCode, message: errorMessage as string, details: errorDetails);
else
throw new Exception("Invalid envelope");
}
}