Added NightAlert project for travel kit
This commit is contained in:
41
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Buffer.cs
vendored
Normal file
41
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Buffer.cs
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
internal class Buffer
|
||||
{
|
||||
|
||||
private Buffer()
|
||||
{
|
||||
}
|
||||
|
||||
public static byte[] Concat(byte[][] list)
|
||||
{
|
||||
int length = 0;
|
||||
foreach (var buf in list)
|
||||
{
|
||||
length += buf.Length;
|
||||
}
|
||||
|
||||
return Concat(list, length);
|
||||
}
|
||||
|
||||
public static byte[] Concat(byte[][] list, int length)
|
||||
{
|
||||
if (list.Length == 0)
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
if (list.Length == 1)
|
||||
{
|
||||
return list[0];
|
||||
}
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.Allocate(length);
|
||||
foreach (var buf in list)
|
||||
{
|
||||
buffer.Put(buf);
|
||||
}
|
||||
|
||||
return buffer.Array();
|
||||
}
|
||||
}
|
||||
}
|
||||
162
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/ByteBuffer.cs
vendored
Normal file
162
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/ByteBuffer.cs
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
public class ByteBuffer
|
||||
{
|
||||
private readonly MemoryStream _memoryStream;
|
||||
|
||||
private long _limit = 0;
|
||||
|
||||
|
||||
public ByteBuffer(int length)
|
||||
{
|
||||
this._memoryStream = new MemoryStream();
|
||||
_memoryStream.SetLength(length);
|
||||
_memoryStream.Capacity = length;
|
||||
_limit = length;
|
||||
}
|
||||
|
||||
|
||||
public static ByteBuffer Allocate(int length)
|
||||
{
|
||||
return new ByteBuffer(length);
|
||||
}
|
||||
|
||||
internal void Put(byte[] buf)
|
||||
{
|
||||
_memoryStream.Write(buf,0,buf.Length);
|
||||
}
|
||||
|
||||
internal byte[] Array()
|
||||
{
|
||||
return _memoryStream.ToArray();
|
||||
}
|
||||
|
||||
internal static ByteBuffer Wrap(byte[] data)
|
||||
{
|
||||
var result = new ByteBuffer(data.Length);
|
||||
result.Put(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A buffer's capacity is the number of elements it contains. The capacity of a
|
||||
/// buffer is never negative and never changes.
|
||||
/// </summary>
|
||||
public int Capacity
|
||||
{
|
||||
get { return _memoryStream.Capacity; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Absolute get method. Reads the byte at the given index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index from which the byte will be read</param>
|
||||
/// <returns>The byte at the given index</returns>
|
||||
internal byte Get(long index)
|
||||
{
|
||||
if (index > Capacity)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
_memoryStream.Position = index;
|
||||
return (byte) _memoryStream.ReadByte();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Relative bulk get method.
|
||||
///
|
||||
/// This method transfers bytes from this buffer into the given destination array. If there are fewer bytes
|
||||
/// remaining in the buffer than are required to satisfy the request, that is, if length > remaining(), then
|
||||
/// no bytes are transferred and a BufferUnderflowException is thrown.
|
||||
///
|
||||
/// Otherwise, this method copies length bytes from this buffer into the given array, starting at the current
|
||||
/// position of this buffer and at the given offset in the array. The position of this buffer is then
|
||||
/// incremented by length.
|
||||
///
|
||||
/// In other words, an invocation of this method of the form src.get(dst, off, len) has exactly the same effect as the loop
|
||||
/// <code>
|
||||
/// for (int i = off; i < off + len; i++)
|
||||
/// dst[i] = src.get();
|
||||
/// </code>
|
||||
/// except that it first checks that there are sufficient bytes in this buffer and it is potentially much more efficient.
|
||||
/// </summary>
|
||||
/// <param name="dst"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <returns>This buffer</returns>
|
||||
internal ByteBuffer Get(byte[] dst, int offset, int length)
|
||||
{
|
||||
_memoryStream.Read(dst, offset, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Relative bulk get method.
|
||||
///
|
||||
/// This method transfers bytes from this buffer into the given destination array.
|
||||
/// An invocation of this method of the form src.get(a) behaves in exactly the same
|
||||
/// way as the invocation src.get(a, 0, a.length)
|
||||
/// </summary>
|
||||
/// <param name="dst"></param>
|
||||
/// <returns>This buffer</returns>
|
||||
internal ByteBuffer Get(byte[] dst)
|
||||
{
|
||||
return Get(dst, 0, dst.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets this buffer's position. If the mark is defined and larger than the new
|
||||
/// position then it is discarded.
|
||||
/// </summary>
|
||||
/// <param name="newPosition">The new position value; must be non-negative and no larger than the current limit</param>
|
||||
internal void Position(long newPosition)
|
||||
{
|
||||
_memoryStream.Position = newPosition;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets this buffer's limit. If the position is larger than the new limit then it is set to the new limit.
|
||||
/// If the mark is defined and larger than the new limit then it is discarded.
|
||||
///
|
||||
/// A buffer's limit is the index of the first element that should not be read or written. A buffer's limit is never negative and is never greater than its capacity.
|
||||
/// </summary>
|
||||
/// <param name="newLimit">The new limit value; must be non-negative and no larger than this buffer's capacity</param>
|
||||
internal void Limit(long newLimit)
|
||||
{
|
||||
_limit = newLimit;
|
||||
if (_memoryStream.Position > newLimit)
|
||||
{
|
||||
_memoryStream.Position = newLimit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of elements between the current position and the limit.
|
||||
/// </summary>
|
||||
/// <returns>The number of elements remaining in this buffer</returns>
|
||||
internal long Remaining()
|
||||
{
|
||||
return (_limit - _memoryStream.Position);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears this buffer. The position is set to zero, the limit is set to the capacity, and the mark is discarded.
|
||||
///
|
||||
/// This method does not actually erase the data in the buffer, but it is named as if
|
||||
/// it did because it will most often be used in situations in which that might as well be the case.
|
||||
/// </summary>
|
||||
internal void Clear()
|
||||
{
|
||||
Position(0);
|
||||
Limit(Capacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
|
||||
public interface IDecodePayloadCallback
|
||||
{
|
||||
bool Call(Packet packet, int index, int total);
|
||||
}
|
||||
}
|
||||
9
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/IEncodeCallback.cs
vendored
Normal file
9
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/IEncodeCallback.cs
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
public interface IEncodeCallback
|
||||
{
|
||||
void Call(object data);
|
||||
}
|
||||
|
||||
}
|
||||
408
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Packet.cs
vendored
Normal file
408
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Packet.cs
vendored
Normal file
@@ -0,0 +1,408 @@
|
||||
using Quobject.EngineIoClientDotNet.Modules;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
/// <remarks>
|
||||
/// Packet type which is ported from the JavaScript module.
|
||||
/// This is the JavaScript parser for the engine.io protocol encoding,
|
||||
/// shared by both engine.io-client and engine.io.
|
||||
/// <see href="https://github.com/Automattic/engine.io-parser">https://github.com/Automattic/engine.io-parser</see>
|
||||
/// </remarks>
|
||||
public class Packet
|
||||
{
|
||||
public static readonly string OPEN = "open";
|
||||
public static readonly string CLOSE = "close";
|
||||
public static readonly string PING = "ping";
|
||||
public static readonly string PONG = "pong";
|
||||
public static readonly string UPGRADE = "upgrade";
|
||||
public static readonly string MESSAGE = "message";
|
||||
public static readonly string NOOP = "noop";
|
||||
public static readonly string ERROR = "error";
|
||||
|
||||
private static readonly int MAX_INT_CHAR_LENGTH = int.MaxValue.ToString().Length;
|
||||
|
||||
//TODO: suport binary?
|
||||
private bool SupportsBinary = false;
|
||||
|
||||
private static readonly Dictionary<string, byte> _packets = new Dictionary<string, byte>()
|
||||
{
|
||||
{Packet.OPEN, 0},
|
||||
{Packet.CLOSE, 1},
|
||||
{Packet.PING, 2},
|
||||
{Packet.PONG, 3},
|
||||
{Packet.MESSAGE, 4},
|
||||
{Packet.UPGRADE, 5},
|
||||
{Packet.NOOP, 6}
|
||||
};
|
||||
|
||||
private static readonly Dictionary<byte, string> _packetsList = new Dictionary<byte, string>();
|
||||
|
||||
static Packet()
|
||||
{
|
||||
foreach (var entry in _packets)
|
||||
{
|
||||
_packetsList.Add(entry.Value,entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Packet _err = new Packet(Packet.ERROR,"parser error");
|
||||
|
||||
public string Type { get; set; }
|
||||
public object Data { get; set; }
|
||||
|
||||
|
||||
public Packet(string type, object data)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
public Packet(string type)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Data = null;
|
||||
}
|
||||
|
||||
internal void Encode(IEncodeCallback callback,bool utf8encode = false)
|
||||
{
|
||||
if ( Data is byte[])
|
||||
{
|
||||
if (!SupportsBinary)
|
||||
{
|
||||
EncodeBase64Packet(callback);
|
||||
return;
|
||||
}
|
||||
EncodeByteArray(callback);
|
||||
return;
|
||||
}
|
||||
var encodedStringBuilder = new StringBuilder();
|
||||
encodedStringBuilder.Append(_packets[Type]);
|
||||
|
||||
if (Data != null)
|
||||
{
|
||||
encodedStringBuilder.Append( utf8encode ? UTF8.Encode((string) Data): (string)Data);
|
||||
}
|
||||
|
||||
callback.Call(encodedStringBuilder.ToString());
|
||||
}
|
||||
|
||||
private void EncodeBase64Packet(IEncodeCallback callback)
|
||||
{
|
||||
var byteData = Data as byte[];
|
||||
if (byteData != null)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
result.Append("b");
|
||||
result.Append(_packets[Type]);
|
||||
result.Append(Convert.ToBase64String(byteData));
|
||||
callback.Call(result.ToString());
|
||||
return;
|
||||
}
|
||||
throw new Exception("byteData == null");
|
||||
}
|
||||
|
||||
private void EncodeByteArray(IEncodeCallback callback)
|
||||
{
|
||||
var byteData = Data as byte[];
|
||||
if (byteData != null)
|
||||
{
|
||||
var resultArray = new byte[1 + byteData.Length];
|
||||
resultArray[0] = _packets[Type];
|
||||
Array.Copy(byteData, 0, resultArray, 1, byteData.Length);
|
||||
callback.Call(resultArray);
|
||||
return;
|
||||
}
|
||||
throw new Exception("byteData == null");
|
||||
}
|
||||
|
||||
internal static Packet DecodePacket(string data, bool utf8decode = false)
|
||||
{
|
||||
if (data.StartsWith("b"))
|
||||
{
|
||||
return DecodeBase64Packet(data.Substring(1));
|
||||
}
|
||||
|
||||
int type;
|
||||
var s = data.Substring(0, 1);
|
||||
if (!int.TryParse(s, out type))
|
||||
{
|
||||
type = -1;
|
||||
}
|
||||
|
||||
if (utf8decode)
|
||||
{
|
||||
try
|
||||
{
|
||||
data = UTF8.Decode(data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
return _err;
|
||||
}
|
||||
}
|
||||
|
||||
if (type < 0 || type >= _packetsList.Count)
|
||||
{
|
||||
return _err;
|
||||
}
|
||||
|
||||
if (data.Length > 1)
|
||||
{
|
||||
return new Packet(_packetsList[(byte) type], data.Substring(1));
|
||||
}
|
||||
return new Packet(_packetsList[(byte) type], null);
|
||||
}
|
||||
|
||||
private static Packet DecodeBase64Packet(string msg)
|
||||
{
|
||||
int type;
|
||||
var s = msg.Substring(0, 1);
|
||||
if (!int.TryParse(s, out type))
|
||||
{
|
||||
type = -1;
|
||||
}
|
||||
if (type < 0 || type >= _packetsList.Count)
|
||||
{
|
||||
return _err;
|
||||
}
|
||||
msg = msg.Substring(1);
|
||||
byte[] decodedFromBase64 = Convert.FromBase64String(msg);
|
||||
return new Packet(_packetsList[(byte)type], decodedFromBase64);
|
||||
}
|
||||
|
||||
internal static Packet DecodePacket(byte[] data)
|
||||
{
|
||||
int type = data[0];
|
||||
var byteArray = new byte[data.Length - 1];
|
||||
Array.Copy(data,1,byteArray,0, byteArray.Length);
|
||||
return new Packet(_packetsList[(byte)type], byteArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static void EncodePayload(Packet[] packets, IEncodeCallback callback)
|
||||
{
|
||||
if (packets.Length == 0)
|
||||
{
|
||||
callback.Call(new byte[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var results = new List<byte[]>(packets.Length);
|
||||
var encodePayloadCallback = new EncodePayloadCallback(results);
|
||||
foreach (var packet in packets)
|
||||
{
|
||||
packet.Encode(encodePayloadCallback, true);
|
||||
}
|
||||
|
||||
callback.Call(Buffer.Concat(results.ToArray()));//new byte[results.Count][]
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes data when a payload is maybe expected.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="callback"></param>
|
||||
public static void DecodePayload(string data, IDecodePayloadCallback callback)
|
||||
{
|
||||
if (String.IsNullOrEmpty(data))
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var length = new StringBuilder();
|
||||
for (int i = 0, l = data.Length; i < l; i++)
|
||||
{
|
||||
var chr = Convert.ToChar(data.Substring(i, 1));
|
||||
|
||||
if (chr != ':')
|
||||
{
|
||||
length.Append(chr);
|
||||
}
|
||||
else
|
||||
{
|
||||
int n;
|
||||
if (!int.TryParse(length.ToString(), out n))
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
string msg;
|
||||
try
|
||||
{
|
||||
msg = data.Substring(i + 1, n);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.Length != 0)
|
||||
{
|
||||
Packet packet = DecodePacket(msg, true);
|
||||
if (_err.Type == packet.Type && _err.Data == packet.Data)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ret = callback.Call(packet, i + n, l);
|
||||
if (!ret)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i += n;
|
||||
length = new StringBuilder();
|
||||
}
|
||||
}
|
||||
if (length.Length > 0)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes data when a payload is maybe expected.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="callback"></param>
|
||||
public static void DecodePayload(byte[] data, IDecodePayloadCallback callback)
|
||||
{
|
||||
var bufferTail = ByteBuffer.Wrap(data);
|
||||
|
||||
var buffers = new List<object>();
|
||||
int bufferTail_offset = 0;
|
||||
while (bufferTail.Capacity - bufferTail_offset > 0)
|
||||
{
|
||||
var strLen = new StringBuilder();
|
||||
var isString = (bufferTail.Get(0 + bufferTail_offset) & 0xFF) == 0;
|
||||
var numberTooLong = false;
|
||||
for (int i = 1;; i++)
|
||||
{
|
||||
int b = bufferTail.Get(i + bufferTail_offset) & 0xFF;
|
||||
if (b == 255)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// support only integer
|
||||
if (strLen.Length > MAX_INT_CHAR_LENGTH)
|
||||
{
|
||||
numberTooLong = true;
|
||||
break;
|
||||
}
|
||||
strLen.Append(b);
|
||||
}
|
||||
if (numberTooLong)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
bufferTail_offset += strLen.Length + 1;
|
||||
|
||||
int msgLength = int.Parse(strLen.ToString());
|
||||
|
||||
bufferTail.Position(1 + bufferTail_offset);
|
||||
bufferTail.Limit(msgLength + 1 + bufferTail_offset);
|
||||
var msg = new byte[bufferTail.Remaining()];
|
||||
bufferTail.Get(msg, 0, msg.Length);
|
||||
|
||||
if (isString)
|
||||
{
|
||||
buffers.Add(ByteArrayToString(msg));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffers.Add(msg);
|
||||
}
|
||||
bufferTail.Clear();
|
||||
bufferTail.Position(msgLength + 1 + bufferTail_offset);
|
||||
bufferTail_offset += msgLength + 1;
|
||||
}
|
||||
|
||||
var total = buffers.Count;
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
var buffer = buffers[i];
|
||||
if (buffer is string)
|
||||
{
|
||||
callback.Call(DecodePacket((string) buffer, true), i, total);
|
||||
}
|
||||
else if (buffer is byte[])
|
||||
{
|
||||
callback.Call(DecodePacket((byte[])buffer), i, total);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal static byte[] StringToByteArray(string str)
|
||||
{
|
||||
int len = str.Length;
|
||||
var bytes = new byte[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
bytes[i] = (byte)str[i];
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
internal static string ByteArrayToString(byte[] bytes)
|
||||
{
|
||||
//return Encoding.ASCII.GetString(bytes);
|
||||
//http://stackoverflow.com/questions/7750850/encoding-ascii-getstring-in-windows-phone-platform
|
||||
return string.Concat(bytes.Select(b => b <= 0x7f ? (char)b : '?'));
|
||||
}
|
||||
|
||||
private class EncodePayloadCallback : IEncodeCallback
|
||||
{
|
||||
private readonly List<byte[]> _results;
|
||||
|
||||
public EncodePayloadCallback(List<byte[]> results)
|
||||
{
|
||||
this._results = results;
|
||||
}
|
||||
|
||||
public void Call(object data)
|
||||
{
|
||||
if (data is string)
|
||||
{
|
||||
var packet = (string) data;
|
||||
var encodingLength = packet.Length.ToString();
|
||||
var sizeBuffer = new byte[encodingLength.Length + 2];
|
||||
sizeBuffer[0] = (byte) 0; // is a string
|
||||
for (var i = 0; i < encodingLength.Length; i++)
|
||||
{
|
||||
sizeBuffer[i + 1] = byte.Parse(encodingLength.Substring(i,1));
|
||||
}
|
||||
sizeBuffer[sizeBuffer.Length - 1] = (byte) 255;
|
||||
_results.Add(Buffer.Concat(new byte[][] { sizeBuffer, StringToByteArray(packet) }));
|
||||
return;
|
||||
}
|
||||
|
||||
var packet1 = (byte[]) data;
|
||||
var encodingLength1 = packet1.Length.ToString();
|
||||
var sizeBuffer1 = new byte[encodingLength1.Length + 2];
|
||||
sizeBuffer1[0] = (byte)1; // is binary
|
||||
for (var i = 0; i < encodingLength1.Length; i++)
|
||||
{
|
||||
sizeBuffer1[i + 1] = byte.Parse(encodingLength1.Substring(i, 1));
|
||||
}
|
||||
sizeBuffer1[sizeBuffer1.Length - 1] = (byte)255;
|
||||
_results.Add(Buffer.Concat(new byte[][] { sizeBuffer1, packet1 }));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
412
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Packet_net35.cs
vendored
Normal file
412
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Packet_net35.cs
vendored
Normal file
@@ -0,0 +1,412 @@
|
||||
using Quobject.EngineIoClientDotNet.Modules;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
/// <remarks>
|
||||
/// Packet type which is ported from the JavaScript module.
|
||||
/// This is the JavaScript parser for the engine.io protocol encoding,
|
||||
/// shared by both engine.io-client and engine.io.
|
||||
/// <see href="https://github.com/Automattic/engine.io-parser">https://github.com/Automattic/engine.io-parser</see>
|
||||
/// </remarks>
|
||||
public class Packet
|
||||
{
|
||||
public static readonly string OPEN = "open";
|
||||
public static readonly string CLOSE = "close";
|
||||
public static readonly string PING = "ping";
|
||||
public static readonly string PONG = "pong";
|
||||
public static readonly string UPGRADE = "upgrade";
|
||||
public static readonly string MESSAGE = "message";
|
||||
public static readonly string NOOP = "noop";
|
||||
public static readonly string ERROR = "error";
|
||||
|
||||
private static readonly int MAX_INT_CHAR_LENGTH = int.MaxValue.ToString().Length;
|
||||
|
||||
//TODO: suport binary?
|
||||
private bool SupportsBinary = false;
|
||||
|
||||
private static readonly Dictionary<string, byte> _packets = new Dictionary<string, byte>()
|
||||
{
|
||||
{Packet.OPEN, 0},
|
||||
{Packet.CLOSE, 1},
|
||||
{Packet.PING, 2},
|
||||
{Packet.PONG, 3},
|
||||
{Packet.MESSAGE, 4},
|
||||
{Packet.UPGRADE, 5},
|
||||
{Packet.NOOP, 6}
|
||||
};
|
||||
|
||||
private static readonly Dictionary<byte, string> _packetsList = new Dictionary<byte, string>();
|
||||
|
||||
static Packet()
|
||||
{
|
||||
foreach (var entry in _packets)
|
||||
{
|
||||
_packetsList.Add(entry.Value,entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Packet _err = new Packet(Packet.ERROR,"parser error");
|
||||
|
||||
public string Type { get; set; }
|
||||
public object Data { get; set; }
|
||||
|
||||
|
||||
public Packet(string type, object data)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
public Packet(string type)
|
||||
{
|
||||
this.Type = type;
|
||||
this.Data = null;
|
||||
}
|
||||
|
||||
internal void Encode(IEncodeCallback callback,bool utf8encode = false)
|
||||
{
|
||||
if ( Data is byte[])
|
||||
{
|
||||
if (!SupportsBinary)
|
||||
{
|
||||
EncodeBase64Packet(callback);
|
||||
return;
|
||||
}
|
||||
EncodeByteArray(callback);
|
||||
return;
|
||||
}
|
||||
var encodedStringBuilder = new StringBuilder();
|
||||
encodedStringBuilder.Append(_packets[Type]);
|
||||
|
||||
if (Data != null)
|
||||
{
|
||||
encodedStringBuilder.Append( utf8encode ? UTF8.Encode((string) Data): (string)Data);
|
||||
}
|
||||
|
||||
callback.Call(encodedStringBuilder.ToString());
|
||||
}
|
||||
|
||||
private void EncodeBase64Packet(IEncodeCallback callback)
|
||||
{
|
||||
var byteData = Data as byte[];
|
||||
if (byteData != null)
|
||||
{
|
||||
var result = new StringBuilder();
|
||||
result.Append("b");
|
||||
result.Append(_packets[Type]);
|
||||
result.Append(Convert.ToBase64String(byteData));
|
||||
callback.Call(result.ToString());
|
||||
return;
|
||||
}
|
||||
throw new Exception("byteData == null");
|
||||
}
|
||||
|
||||
private void EncodeByteArray(IEncodeCallback callback)
|
||||
{
|
||||
var byteData = Data as byte[];
|
||||
if (byteData != null)
|
||||
{
|
||||
var resultArray = new byte[1 + byteData.Length];
|
||||
resultArray[0] = _packets[Type];
|
||||
Array.Copy(byteData, 0, resultArray, 1, byteData.Length);
|
||||
callback.Call(resultArray);
|
||||
return;
|
||||
}
|
||||
throw new Exception("byteData == null");
|
||||
}
|
||||
|
||||
internal static Packet DecodePacket(string data, bool utf8decode = false)
|
||||
{
|
||||
if (data.StartsWith("b"))
|
||||
{
|
||||
return DecodeBase64Packet(data.Substring(1));
|
||||
}
|
||||
|
||||
int type;
|
||||
var s = data.Substring(0, 1);
|
||||
if (!int.TryParse(s, out type))
|
||||
{
|
||||
type = -1;
|
||||
}
|
||||
|
||||
if (utf8decode)
|
||||
{
|
||||
try
|
||||
{
|
||||
data = UTF8.Decode(data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
return _err;
|
||||
}
|
||||
}
|
||||
|
||||
if (type < 0 || type >= _packetsList.Count)
|
||||
{
|
||||
return _err;
|
||||
}
|
||||
|
||||
if (data.Length > 1)
|
||||
{
|
||||
return new Packet(_packetsList[(byte) type], data.Substring(1));
|
||||
}
|
||||
return new Packet(_packetsList[(byte) type], null);
|
||||
}
|
||||
|
||||
private static Packet DecodeBase64Packet(string msg)
|
||||
{
|
||||
int type;
|
||||
var s = msg.Substring(0, 1);
|
||||
if (!int.TryParse(s, out type))
|
||||
{
|
||||
type = -1;
|
||||
}
|
||||
if (type < 0 || type >= _packetsList.Count)
|
||||
{
|
||||
return _err;
|
||||
}
|
||||
msg = msg.Substring(1);
|
||||
byte[] decodedFromBase64 = Convert.FromBase64String(msg);
|
||||
return new Packet(_packetsList[(byte)type], decodedFromBase64);
|
||||
}
|
||||
|
||||
internal static Packet DecodePacket(byte[] data)
|
||||
{
|
||||
int type = data[0];
|
||||
var byteArray = new byte[data.Length - 1];
|
||||
Array.Copy(data,1,byteArray,0, byteArray.Length);
|
||||
return new Packet(_packetsList[(byte)type], byteArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal static void EncodePayload(Packet[] packets, IEncodeCallback callback)
|
||||
{
|
||||
if (packets.Length == 0)
|
||||
{
|
||||
callback.Call(new byte[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var results = new List<byte[]>(packets.Length);
|
||||
var encodePayloadCallback = new EncodePayloadCallback(results);
|
||||
foreach (var packet in packets)
|
||||
{
|
||||
packet.Encode(encodePayloadCallback, true);
|
||||
}
|
||||
|
||||
callback.Call(Buffer.Concat(results.ToArray()));//new byte[results.Count][]
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes data when a payload is maybe expected.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="callback"></param>
|
||||
public static void DecodePayload(string data, IDecodePayloadCallback callback)
|
||||
{
|
||||
if (String.IsNullOrEmpty(data))
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var length = new StringBuilder();
|
||||
for (int i = 0, l = data.Length; i < l; i++)
|
||||
{
|
||||
var chr = Convert.ToChar(data.Substring(i, 1));
|
||||
|
||||
if (chr != ':')
|
||||
{
|
||||
length.Append(chr);
|
||||
}
|
||||
else
|
||||
{
|
||||
int n;
|
||||
if (!int.TryParse(length.ToString(), out n))
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
string msg;
|
||||
try
|
||||
{
|
||||
msg = data.Substring(i + 1, n);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.Length != 0)
|
||||
{
|
||||
Packet packet = DecodePacket(msg, true);
|
||||
if (_err.Type == packet.Type && _err.Data == packet.Data)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
bool ret = callback.Call(packet, i + n, l);
|
||||
if (!ret)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i += n;
|
||||
length = new StringBuilder();
|
||||
}
|
||||
}
|
||||
if (length.Length > 0)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes data when a payload is maybe expected.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="callback"></param>
|
||||
public static void DecodePayload(byte[] data, IDecodePayloadCallback callback)
|
||||
{
|
||||
var bufferTail = ByteBuffer.Wrap(data);
|
||||
|
||||
var buffers = new List<object>();
|
||||
int bufferTail_offset = 0;
|
||||
while (bufferTail.Capacity - bufferTail_offset > 0)
|
||||
{
|
||||
var strLen = new StringBuilder();
|
||||
var isString = (bufferTail.Get(0 + bufferTail_offset) & 0xFF) == 0;
|
||||
var numberTooLong = false;
|
||||
for (int i = 1;; i++)
|
||||
{
|
||||
int b = bufferTail.Get(i + bufferTail_offset) & 0xFF;
|
||||
if (b == 255)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// support only integer
|
||||
if (strLen.Length > MAX_INT_CHAR_LENGTH)
|
||||
{
|
||||
numberTooLong = true;
|
||||
break;
|
||||
}
|
||||
strLen.Append(b);
|
||||
}
|
||||
if (numberTooLong)
|
||||
{
|
||||
callback.Call(_err, 0, 1);
|
||||
return;
|
||||
}
|
||||
bufferTail_offset += strLen.Length + 1;
|
||||
|
||||
int msgLength = int.Parse(strLen.ToString());
|
||||
|
||||
bufferTail.Position(1 + bufferTail_offset);
|
||||
bufferTail.Limit(msgLength + 1 + bufferTail_offset);
|
||||
var msg = new byte[bufferTail.Remaining()];
|
||||
bufferTail.Get(msg, 0, msg.Length);
|
||||
|
||||
if (isString)
|
||||
{
|
||||
buffers.Add(ByteArrayToString(msg));
|
||||
}
|
||||
else
|
||||
{
|
||||
buffers.Add(msg);
|
||||
}
|
||||
bufferTail.Clear();
|
||||
bufferTail.Position(msgLength + 1 + bufferTail_offset);
|
||||
bufferTail_offset += msgLength + 1;
|
||||
}
|
||||
|
||||
var total = buffers.Count;
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
var buffer = buffers[i];
|
||||
if (buffer is string)
|
||||
{
|
||||
callback.Call(DecodePacket((string) buffer, true), i, total);
|
||||
}
|
||||
else if (buffer is byte[])
|
||||
{
|
||||
callback.Call(DecodePacket((byte[])buffer), i, total);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal static byte[] StringToByteArray(string str)
|
||||
{
|
||||
int len = str.Length;
|
||||
var bytes = new byte[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
bytes[i] = (byte)str[i];
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
internal static string ByteArrayToString(byte[] bytes)
|
||||
{
|
||||
//return Encoding.ASCII.GetString(bytes);
|
||||
//http://stackoverflow.com/questions/7750850/encoding-ascii-getstring-in-windows-phone-platform
|
||||
// return string.Concat(bytes.Select(b => b <= 0x7f ? (char)b : '?')); //.net 4.0 only
|
||||
return string.Concat(
|
||||
(bytes.Select(b => (b <= 0x7f ? (char) b : '?').ToString()))
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
private class EncodePayloadCallback : IEncodeCallback
|
||||
{
|
||||
private readonly List<byte[]> _results;
|
||||
|
||||
public EncodePayloadCallback(List<byte[]> results)
|
||||
{
|
||||
this._results = results;
|
||||
}
|
||||
|
||||
public void Call(object data)
|
||||
{
|
||||
if (data is string)
|
||||
{
|
||||
var packet = (string) data;
|
||||
var encodingLength = packet.Length.ToString();
|
||||
var sizeBuffer = new byte[encodingLength.Length + 2];
|
||||
sizeBuffer[0] = (byte) 0; // is a string
|
||||
for (var i = 0; i < encodingLength.Length; i++)
|
||||
{
|
||||
sizeBuffer[i + 1] = byte.Parse(encodingLength.Substring(i,1));
|
||||
}
|
||||
sizeBuffer[sizeBuffer.Length - 1] = (byte) 255;
|
||||
_results.Add(Buffer.Concat(new byte[][] { sizeBuffer, StringToByteArray(packet) }));
|
||||
return;
|
||||
}
|
||||
|
||||
var packet1 = (byte[]) data;
|
||||
var encodingLength1 = packet1.Length.ToString();
|
||||
var sizeBuffer1 = new byte[encodingLength1.Length + 2];
|
||||
sizeBuffer1[0] = (byte)1; // is binary
|
||||
for (var i = 0; i < encodingLength1.Length; i++)
|
||||
{
|
||||
sizeBuffer1[i + 1] = byte.Parse(encodingLength1.Substring(i, 1));
|
||||
}
|
||||
sizeBuffer1[sizeBuffer1.Length - 1] = (byte)255;
|
||||
_results.Add(Buffer.Concat(new byte[][] { sizeBuffer1, packet1 }));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
51
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Parser.cs
vendored
Normal file
51
ThirdParty/EngineIoClientDotNet/Src/EngineIoClientDotNet.mono/Parser/Parser.cs
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
namespace Quobject.EngineIoClientDotNet.Parser
|
||||
{
|
||||
/// <remarks>
|
||||
/// This is the JavaScript parser for the engine.io protocol encoding,
|
||||
/// shared by both engine.io-client and engine.io.
|
||||
/// <see href="https://github.com/Automattic/engine.io-parser">https://github.com/Automattic/engine.io-parser</see>
|
||||
/// </remarks>
|
||||
public class Parser
|
||||
{
|
||||
|
||||
public static readonly int Protocol = 3;
|
||||
|
||||
|
||||
private Parser()
|
||||
{
|
||||
}
|
||||
|
||||
public static void EncodePacket(Packet packet, IEncodeCallback callback)
|
||||
{
|
||||
packet.Encode(callback);
|
||||
}
|
||||
|
||||
public static Packet DecodePacket(string data, bool utf8decode = false)
|
||||
{
|
||||
return Packet.DecodePacket(data, utf8decode);
|
||||
}
|
||||
|
||||
public static Packet DecodePacket(byte[] data)
|
||||
{
|
||||
return Packet.DecodePacket(data);
|
||||
}
|
||||
|
||||
public static void EncodePayload(Packet[] packets, IEncodeCallback callback)
|
||||
{
|
||||
Packet.EncodePayload(packets, callback);
|
||||
}
|
||||
|
||||
|
||||
public static void DecodePayload(string data, IDecodePayloadCallback callback)
|
||||
{
|
||||
Packet.DecodePayload(data, callback);
|
||||
}
|
||||
|
||||
public static void DecodePayload(byte[] data, IDecodePayloadCallback callback)
|
||||
{
|
||||
Packet.DecodePayload(data, callback);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user