Last active
August 29, 2015 14:05
-
-
Save dimzon/2b1d22b6d5d0589cdca6 to your computer and use it in GitHub Desktop.
MeaasagePack for JSON.NET
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.IO; | |
using System.Text; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Utilities; | |
namespace Newtonsoft.Json.MessagePack | |
{ | |
public static class MessagePack | |
{ | |
private static class MessagePackConstants | |
{ | |
public const sbyte ExtTypeDateTime = 21; | |
public const sbyte ExtTypeTimeStamp = 22; | |
public const byte TagNil = 0xc0; | |
public const byte TagFalse = 0xc2; | |
public const byte TagTrue = 0xc3; | |
public const byte TagBin8 = 0xc4; | |
public const byte TagBin16 = 0xc5; | |
public const byte TagBin32 = 0xc6; | |
public const byte TagFloat32 = 0xca; | |
public const byte TagFloat64 = 0xcb; | |
public const byte TagUint8 = 0xcc; | |
public const byte TagUint16 = 0xcd; | |
public const byte TagUint32 = 0xce; | |
public const byte TagUint64 = 0xcf; | |
public const byte TagInt8 = 0xd0; | |
public const byte TagInt16 = 0xd1; | |
public const byte TagInt32 = 0xd2; | |
public const byte TagInt64 = 0xd3; | |
public const byte TagFixExt1 = 0xd4; | |
public const byte TagFixExt2 = 0xd5; | |
public const byte TagFixExt4 = 0xd6; | |
public const byte TagFixExt8 = 0xd7; | |
public const byte TagFixExt16 = 0xd8; | |
public const byte TagStr8 = 0xd9; | |
public const byte TagStr16 = 0xda; | |
public const byte TagStr32 = 0xdb; | |
public const byte TagArr16 = 0xdc; | |
public const byte TagArr32 = 0xdd; | |
public const byte TagMap16 = 0xde; | |
public const byte TagMap32 = 0xdf; | |
} | |
public class MessagePackWriter : JsonWriter | |
{ | |
private class Container | |
{ | |
public readonly Stream Out; | |
public ulong Counter; | |
public Container(Stream str) | |
{ | |
Out = str; | |
} | |
protected Container() : this(new MemoryStream()) { } | |
public virtual void OnObjectProperty() | |
{ | |
} | |
public virtual void OnArrayItem() | |
{ | |
} | |
} | |
private class ObjectContainer : Container | |
{ | |
public override void OnObjectProperty() | |
{ | |
++Counter; | |
} | |
} | |
private class ArrayContainer : Container | |
{ | |
public override void OnArrayItem() | |
{ | |
++Counter; | |
} | |
} | |
private readonly Stack<Container> _containers = new Stack<Container>(); | |
private readonly Stream _outputStream; | |
private Container _peekContainer; | |
public MessagePackWriter(Stream outputStream) | |
{ | |
_outputStream = outputStream; | |
_peekContainer = new Container(outputStream); | |
_containers.Push(_peekContainer); | |
} | |
public override void WriteNull() | |
{ | |
//!! base.WriteNull(); | |
_ints[0] = MessagePackConstants.TagNil; | |
_peekContainer.Out.Write(_ints, 0, 1); | |
_peekContainer.OnArrayItem(); | |
} | |
public override void WriteUndefined() | |
{ | |
WriteNull(); | |
} | |
public override void Close() | |
{ | |
//!! base.Close(); | |
// foreach (var container in _containers) | |
// { | |
// container.Out.Close(); | |
// } | |
_outputStream.Close(); | |
} | |
public override void WriteStartObject() | |
{ | |
//!! base.WriteStartObject(); | |
_peekContainer = new ObjectContainer(); | |
_containers.Push(_peekContainer); | |
} | |
public override void WriteEndObject() | |
{ | |
//!! base.WriteEndObject(); | |
var objectContainer = _containers.Pop(); | |
_peekContainer = _containers.Peek(); | |
_peekContainer.OnArrayItem(); | |
var mapSize = objectContainer.Counter; | |
var stream = _peekContainer.Out; | |
if (mapSize < 16) | |
{ | |
_ints[0] = (byte)(0x80 | mapSize); | |
stream.Write(_ints, 0, 1); | |
} | |
else if (mapSize <= 0xFFFF) | |
{ | |
Write16(stream, MessagePackConstants.TagMap16, mapSize); | |
} | |
else | |
{ | |
Write32(stream, MessagePackConstants.TagMap32, mapSize); | |
} | |
using (var memoryStream = ((MemoryStream)objectContainer.Out)) | |
{ | |
var buff = memoryStream.GetBuffer(); | |
stream.Write(buff, 0, (int)memoryStream.Length); | |
} | |
} | |
private void Write08(Stream stream, byte prefix, ulong l2) | |
{ | |
_ints[0] = prefix; | |
_ints[1] = (byte)(l2 & 0xff); | |
stream.Write(_ints, 0, 2); | |
} | |
private void Write16(Stream stream, byte prefix, ulong l2) | |
{ | |
_ints[0] = prefix; | |
_ints[1] = (byte)((l2 & 0xff00) >> 8); | |
_ints[2] = (byte)(l2 & 0xff); | |
stream.Write(_ints, 0, 3); | |
} | |
private void Write32(Stream stream, byte prefix, ulong l2) | |
{ | |
_ints[0] = prefix; | |
_ints[1] = (byte)((l2 & 0xff000000) >> 24); | |
_ints[2] = (byte)((l2 & 0xff0000) >> 16); | |
_ints[3] = (byte)((l2 & 0xff00) >> 8); | |
_ints[4] = (byte)(l2 & 0xff); | |
stream.Write(_ints, 0, 5); | |
} | |
private readonly byte[] _ints = new byte[9]; | |
private void Write64(Stream stream, byte prefix, ulong l2) | |
{ | |
_ints[0] = prefix; | |
_ints[1] = (byte)((l2 & 0xff00000000000000) >> 56); | |
_ints[2] = (byte)((l2 & 0xff000000000000) >> 48); | |
_ints[3] = (byte)((l2 & 0xff0000000000) >> 40); | |
_ints[4] = (byte)((l2 & 0xff00000000) >> 32); | |
_ints[5] = (byte)((l2 & 0xff000000) >> 24); | |
_ints[6] = (byte)((l2 & 0xff0000) >> 16); | |
_ints[7] = (byte)((l2 & 0xff00) >> 8); | |
_ints[8] = (byte)(l2 & 0xff); | |
stream.Write(_ints, 0, 9); | |
} | |
public override void WriteStartArray() | |
{ | |
//!! base.WriteStartArray(); | |
_peekContainer = new ArrayContainer(); | |
_containers.Push(_peekContainer); | |
} | |
public override void WriteEndArray() | |
{ | |
//!! base.WriteEndArray(); | |
var arrayContainer = _containers.Pop(); | |
_peekContainer = _containers.Peek(); | |
_peekContainer.OnArrayItem(); | |
var arraySize = arrayContainer.Counter; | |
var stream = _peekContainer.Out; | |
if (arraySize < 16) | |
{ | |
_ints[0] = ((byte)(0x90 | arraySize)); | |
stream.Write(_ints, 0, 1); | |
} | |
else if (arraySize <= 0xFFFF) | |
{ | |
Write16(stream, MessagePackConstants.TagArr16, arraySize); | |
} | |
else | |
{ | |
Write32(stream, MessagePackConstants.TagArr32, arraySize); | |
} | |
using (var memoryStream = ((MemoryStream)arrayContainer.Out)) | |
{ | |
var buff = memoryStream.GetBuffer(); | |
stream.Write(buff, 0, (int)memoryStream.Length); | |
} | |
} | |
public override void WriteStartConstructor(string name) | |
{ | |
throw new JsonWriterException("Cannot write JSON constructor as MsgPack."); | |
} | |
public override void WritePropertyName(string name) | |
{ | |
//!! base.WritePropertyName(name); | |
_peekContainer.OnObjectProperty(); | |
if (name == null) | |
{ | |
_ints[0] = MessagePackConstants.TagNil; | |
_peekContainer.Out.Write(_ints, 0, 1); | |
} | |
else | |
PutString(name); | |
} | |
public override void WritePropertyName(string name, bool escape) | |
{ | |
WritePropertyName(name); | |
} | |
protected override void WriteIndent() | |
{ | |
} | |
protected override void WriteValueDelimiter() | |
{ | |
} | |
protected override void WriteIndentSpace() | |
{ | |
} | |
public override void WriteRaw(string json) | |
{ | |
throw new JsonWriterException("Cannot write raw as MsgPack."); | |
} | |
public override void WriteRawValue(string json) | |
{ | |
throw new JsonWriterException("Cannot write raw as MsgPack."); | |
} | |
internal static readonly UTF8Encoding Utf8 = new UTF8Encoding(false); | |
public override void WriteValue(string value) | |
{ | |
if (value == null) | |
{ | |
WriteNull(); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
PutString(value); | |
} | |
private int _buffSize = 256; | |
private byte[] _buffBytes = new byte[256]; | |
private void PutString(string value) | |
{ | |
unchecked | |
{ | |
var charCount = value.Length; | |
var maxCount = 4 * charCount + 16; //Utf8.GetMaxByteCount(charCount); | |
if (_buffSize < maxCount) | |
{ | |
_buffSize = maxCount; | |
_buffBytes = new byte[maxCount]; | |
} | |
var len = (ulong)Utf8.GetBytes(value, 0, charCount, _buffBytes, 1); | |
var @out = _peekContainer.Out; | |
if (len < 0x20) | |
{ | |
_buffBytes[0] = ((byte)(0xA0 | len)); | |
@out.Write(_buffBytes, 0, (int)len + 1); | |
return; | |
} | |
if (len < 0x100) | |
{ | |
Write08(@out, MessagePackConstants.TagStr8, len); | |
} | |
else if (len < 0x10000) | |
{ | |
Write16(@out, MessagePackConstants.TagStr16, len); | |
} | |
else | |
{ | |
Write32(@out, MessagePackConstants.TagStr32, len); | |
} | |
@out.Write(_buffBytes, 1, (int)len); | |
} | |
} | |
public override void WriteValue(byte[] value) | |
{ | |
if (value == null) | |
{ | |
WriteNull(); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
var str = _peekContainer.Out; | |
unchecked | |
{ | |
var len = (ulong)value.Length; | |
if (len < 0x100) | |
{ | |
Write08(str, MessagePackConstants.TagBin8, len); | |
} | |
else if (len < 0x10000) | |
{ | |
Write16(str, MessagePackConstants.TagBin16, len); | |
} | |
else | |
{ | |
Write32(str, MessagePackConstants.TagBin32, len); | |
} | |
} | |
str.Write(value, 0, value.Length); | |
} | |
public override void WriteValue(char value) | |
{ | |
WriteValue((ulong)value); | |
} | |
public override void WriteValue(sbyte value) | |
{ | |
unchecked | |
{ | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
if (value >= -32) | |
{ | |
// -32..+127 | |
// 111YYYYY .. 0XXXXXXX | |
// positive fixnum stores 7-bit positive integer | |
// negative fixnum stores 5-bit negative integer | |
_ints[0] = (byte)value; | |
_peekContainer.Out.Write(_ints, 0, 1); | |
return; | |
} | |
Write08(_peekContainer.Out, MessagePackConstants.TagInt8, (ulong)value); | |
} | |
} | |
public override void WriteValue(byte value) | |
{ | |
unchecked | |
{ | |
if (value <= SByte.MaxValue) | |
{ | |
WriteValue((sbyte)value); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write16(_peekContainer.Out, MessagePackConstants.TagUint8, value); | |
} | |
} | |
public override void WriteValue(short value) | |
{ | |
unchecked | |
{ | |
if (value >= 0) | |
{ | |
if (value <= Byte.MaxValue) | |
{ | |
WriteValue((byte)value); | |
return; | |
} | |
} | |
else | |
{ | |
if (value >= SByte.MinValue) | |
{ | |
WriteValue((sbyte)value); | |
return; | |
} | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write16(_peekContainer.Out, MessagePackConstants.TagInt16, (ulong)value); | |
} | |
} | |
public override void WriteValue(ushort value) | |
{ | |
unchecked | |
{ | |
if (value <= Int16.MaxValue) | |
{ | |
WriteValue((short)value); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write16(_peekContainer.Out, MessagePackConstants.TagUint16, value); | |
} | |
} | |
public override void WriteValue(int value) | |
{ | |
unchecked | |
{ | |
if (value >= 0) | |
{ | |
if (value <= UInt16.MaxValue) | |
{ | |
WriteValue((ushort)value); | |
return; | |
} | |
} | |
else | |
{ | |
if (value >= Int16.MinValue) | |
{ | |
WriteValue((short)value); | |
return; | |
} | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write32(_peekContainer.Out, MessagePackConstants.TagInt32, (ulong)value); | |
} | |
} | |
public override void WriteValue(uint value) | |
{ | |
unchecked | |
{ | |
if (value <= Int32.MaxValue) | |
{ | |
WriteValue((int)value); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write32(_peekContainer.Out, MessagePackConstants.TagUint32, value); | |
} | |
} | |
public override void WriteValue(long value) | |
{ | |
unchecked | |
{ | |
if (value >= 0) | |
{ | |
if (value <= UInt32.MaxValue) | |
{ | |
WriteValue((uint)value); | |
return; | |
} | |
} | |
else | |
{ | |
if (value >= Int32.MinValue) | |
{ | |
WriteValue((int)value); | |
return; | |
} | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write64(_peekContainer.Out, MessagePackConstants.TagInt64, (ulong)value); | |
} | |
} | |
public override void WriteValue(ulong value) | |
{ | |
unchecked | |
{ | |
if (value <= Int64.MaxValue) | |
{ | |
WriteValue((long)value); | |
return; | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
Write64(_peekContainer.Out, MessagePackConstants.TagUint64, value); | |
} | |
} | |
private static readonly byte[] FloatTag = { MessagePackConstants.TagFloat32 }; | |
public override void WriteValue(float value) | |
{ | |
var bytes = BitConverter.GetBytes(value); | |
if (BitConverter.IsLittleEndian) | |
{ | |
Array.Reverse(bytes); | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
_peekContainer.Out.Write(FloatTag, 0, 1); | |
_peekContainer.Out.Write(bytes, 0, 4); | |
} | |
private static readonly byte[] DoubleTag = { MessagePackConstants.TagFloat64 }; | |
public override void WriteValue(double value) | |
{ | |
var bytes = BitConverter.GetBytes(value); | |
if (BitConverter.IsLittleEndian) | |
{ | |
Array.Reverse(bytes); | |
} | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
_peekContainer.Out.Write(DoubleTag, 0, 1); | |
_peekContainer.Out.Write(bytes, 0, 8); | |
} | |
public override void WriteValue(bool value) | |
{ | |
//!! base.WriteValue(value); | |
_peekContainer.OnArrayItem(); | |
_ints[0] = value ? MessagePackConstants.TagTrue : MessagePackConstants.TagFalse; | |
_peekContainer.Out.Write(_ints, 0, 1); | |
} | |
public override void WriteValue(decimal value) | |
{ | |
WriteValue(value.ToString(Culture)); | |
} | |
private void WriteFixExt8(sbyte type, ulong value) | |
{ | |
unchecked | |
{ | |
_ints[0] = MessagePackConstants.TagFixExt8; | |
var @out = _peekContainer.Out; | |
@out.Write(_ints, 0, 1); | |
Write64(@out, (byte)type, value); | |
} | |
} | |
public override void WriteValue(DateTime value) | |
{ | |
unchecked | |
{ | |
WriteFixExt8(MessagePackConstants.ExtTypeDateTime,(ulong) value.ToBinary()); | |
} | |
} | |
public override void WriteValue(DateTimeOffset value) | |
{ | |
WriteValue(value.UtcDateTime); | |
} | |
public override void WriteValue(Guid value) | |
{ | |
WriteValue(value.ToByteArray()); | |
} | |
public override void WriteValue(TimeSpan value) | |
{ | |
unchecked | |
{ | |
WriteFixExt8(MessagePackConstants.ExtTypeTimeStamp, (ulong)value.Ticks); | |
} | |
} | |
public override void WriteValue(int? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(uint? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(long? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(ulong? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(float? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(double? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(bool? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(short? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(ushort? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(char? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(byte? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(sbyte? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(decimal? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(DateTime? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(DateTimeOffset? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(Guid? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(TimeSpan? value) | |
{ | |
if (value.HasValue) | |
WriteValue(value.Value); | |
else | |
WriteNull(); | |
} | |
public override void WriteValue(Uri value) | |
{ | |
WriteValue(value.ToString()); | |
} | |
public override void WriteComment(string text) | |
{ | |
} | |
public override void WriteWhitespace(string ws) | |
{ | |
} | |
public override void Flush() | |
{ | |
_outputStream.Flush(); | |
} | |
} | |
public class MessagePackReader : JsonReader | |
{ | |
private readonly Stream _inputStream; | |
private readonly Stack<Container> _ctxs = new Stack<Container>(); | |
private Container _topCtx; | |
private void PushCtx(Container ctx) | |
{ | |
_ctxs.Push(ctx); | |
_topCtx = ctx; | |
} | |
private void PopCtx() | |
{ | |
_ctxs.Pop(); | |
_topCtx = _ctxs.Peek(); | |
} | |
public MessagePackReader(Stream inputStream) | |
{ | |
_inputStream = inputStream; | |
PushCtx(new RootContainer(this)); | |
} | |
public override void Close() | |
{ | |
base.Close(); | |
_inputStream.Close(); | |
} | |
public override bool Read() | |
{ | |
return _topCtx.Read(); | |
} | |
private abstract class Container | |
{ | |
protected readonly MessagePackReader Reader; | |
protected Container(MessagePackReader reader) | |
{ | |
Reader = reader; | |
} | |
public virtual bool Read() | |
{ | |
return Reader.ReadValue(Reader.SetToken); | |
} | |
} | |
private class RootContainer : Container | |
{ | |
public RootContainer(MessagePackReader reader) | |
: base(reader) | |
{ | |
} | |
} | |
private class ArrayContainer : Container | |
{ | |
private uint _size; | |
public ArrayContainer(MessagePackReader reader, uint size) | |
: base(reader) | |
{ | |
_size = size; | |
} | |
public override bool Read() | |
{ | |
if (_size == 0) | |
{ | |
Reader.SetToken(JsonToken.EndArray); | |
Reader.PopCtx(); | |
return true; | |
} | |
--_size; | |
return base.Read(); | |
} | |
} | |
private class ObjectContainer : Container | |
{ | |
private uint _size; | |
private bool _prop = true; | |
public ObjectContainer(MessagePackReader reader, uint size) | |
: base(reader) | |
{ | |
_size = size; | |
} | |
public override bool Read() | |
{ | |
if (_size == 0) | |
{ | |
Reader.SetToken(JsonToken.EndObject); | |
Reader.PopCtx(); | |
return true; | |
} | |
if (_prop) | |
{ | |
_prop = false; | |
Reader.ReadValue((token, o) => | |
{ | |
switch (token) | |
{ | |
case JsonToken.String: | |
Reader.SetToken(JsonToken.PropertyName, o); | |
break; | |
case JsonToken.Date: | |
case JsonToken.Float: | |
case JsonToken.Integer: | |
Reader.SetToken(JsonToken.PropertyName, o.ToString()); | |
break; | |
default: | |
throw new Exception("TODO: unknownToken" + token); | |
} | |
}); | |
return true; | |
} | |
_prop = true; | |
--_size; | |
return base.Read(); | |
} | |
} | |
private static readonly object TrueBox = true; | |
private static readonly object FalseBox = false; | |
private byte[] ReadBytes(int n) | |
{ | |
var bytes = new byte[n]; | |
if(n!=_inputStream.Read(bytes,0,n)) throw new Exception("TODO:EOF"); | |
return bytes; | |
} | |
private bool ReadValue(Action<JsonToken,Object> setToken) | |
{ | |
unchecked | |
{ | |
if (1 != _inputStream.Read(_buff, 0, 1)) return false; | |
var type = _buff[0]; | |
switch (type) | |
{ | |
case MessagePackConstants.TagNil: | |
setToken(JsonToken.Null, null); | |
return true; | |
case MessagePackConstants.TagFalse: | |
setToken(JsonToken.Boolean, FalseBox); | |
return true; | |
case MessagePackConstants.TagTrue: | |
setToken(JsonToken.Boolean, TrueBox); | |
return true; | |
case MessagePackConstants.TagBin8: | |
setToken(JsonToken.Bytes, ReadBytes(ReadByte())); | |
return true; | |
case MessagePackConstants.TagBin16: | |
setToken(JsonToken.Bytes, ReadBytes(ReadUshort())); | |
return true; | |
case MessagePackConstants.TagBin32: | |
setToken(JsonToken.Bytes, ReadBytes((int) ReadUint())); | |
return true; | |
case MessagePackConstants.TagFloat32: | |
setToken(JsonToken.Float, ReadFloat32()); | |
return true; | |
case MessagePackConstants.TagFloat64: | |
setToken(JsonToken.Float, ReadFloat64()); | |
return true; | |
case MessagePackConstants.TagUint8: | |
setToken(JsonToken.Integer, ReadByte()); | |
return true; | |
case MessagePackConstants.TagUint16: | |
setToken(JsonToken.Integer, ReadUshort()); | |
return true; | |
case MessagePackConstants.TagUint32: | |
setToken(JsonToken.Integer, ReadUint()); | |
return true; | |
case MessagePackConstants.TagUint64: | |
setToken(JsonToken.Integer, ReadUlong()); | |
return true; | |
case MessagePackConstants.TagInt8: | |
setToken(JsonToken.Integer, (sbyte)ReadByte()); | |
return true; | |
case MessagePackConstants.TagInt16: | |
setToken(JsonToken.Integer, (short)ReadUshort()); | |
return true; | |
case MessagePackConstants.TagInt32: | |
setToken(JsonToken.Integer, (int)ReadUint()); | |
return true; | |
case MessagePackConstants.TagInt64: | |
setToken(JsonToken.Integer, (long)ReadUlong()); | |
return true; | |
case MessagePackConstants.TagFixExt1: | |
ProcessFixExt1((sbyte) ReadByte(), setToken); | |
return true; | |
case MessagePackConstants.TagFixExt2: | |
ProcessFixExt2((sbyte)ReadByte(), setToken); | |
return true; | |
case MessagePackConstants.TagFixExt4: | |
ProcessFixExt4((sbyte) ReadByte(), setToken); | |
return true; | |
case MessagePackConstants.TagFixExt8: | |
ProcessFixExt8((sbyte) ReadByte(),setToken); | |
return true; | |
case MessagePackConstants.TagFixExt16: | |
ProcessFixExt16((sbyte) ReadByte(),setToken); | |
return true; | |
case MessagePackConstants.TagStr8: | |
setToken(JsonToken.String, GetStr(ReadByte())); | |
return true; | |
case MessagePackConstants.TagStr16: | |
setToken(JsonToken.String, GetStr(ReadUshort())); | |
return true; | |
case MessagePackConstants.TagStr32: | |
setToken(JsonToken.String, GetStr((int)ReadUint())); | |
return true; | |
case MessagePackConstants.TagArr16: | |
PushCtx(new ArrayContainer(this, ReadUshort())); | |
setToken(JsonToken.StartArray, null); | |
return true; | |
case MessagePackConstants.TagArr32: | |
PushCtx(new ArrayContainer(this, ReadUint())); | |
setToken(JsonToken.StartArray, null); | |
return true; | |
case MessagePackConstants.TagMap16: | |
PushCtx(new ObjectContainer(this, ReadUshort())); | |
setToken(JsonToken.StartObject, null); | |
return true; | |
case MessagePackConstants.TagMap32: | |
PushCtx(new ObjectContainer(this, ReadUint())); | |
setToken(JsonToken.StartObject, null); | |
return true; | |
default: | |
if ( /*type >=0 &&*/ type <= 0x7f) | |
{ | |
setToken(JsonToken.Integer, type); | |
return true; | |
} | |
if (type >= 0xe0 && type <= 0xff) | |
{ | |
setToken(JsonToken.Integer, (sbyte)type); | |
return true; | |
} | |
if (type >= 0x80 && type <= 0x8f) | |
{ | |
PushCtx(new ObjectContainer(this, (uint)(type & 0x0f))); | |
setToken(JsonToken.StartObject, null); | |
return true; | |
} | |
if (type >= 0x90 && type <= 0x9f) | |
{ | |
PushCtx(new ArrayContainer(this, (uint)(type & 0x0f))); | |
setToken(JsonToken.StartArray, null); | |
return true; | |
} | |
if (type >= 0xa0 && type <= 0xbf) | |
{ | |
setToken(JsonToken.String, GetStr(type & 0x1f)); | |
return true; | |
} | |
throw new Exception("TODO:Unknown type=" + type); | |
} | |
} | |
} | |
private class UnknownExtensionContainer: Container | |
{ | |
private readonly sbyte _type; | |
private readonly byte _tag; | |
private readonly object _dataBytes; | |
private readonly JsonToken _valueToken; | |
private int _step; | |
public UnknownExtensionContainer(MessagePackReader reader, byte tag, sbyte type, object dataBytes, JsonToken valueToken) : base(reader) | |
{ | |
_tag = tag; | |
_type = type; | |
_dataBytes = dataBytes; | |
_valueToken = valueToken; | |
} | |
public override bool Read() | |
{ | |
switch (++_step) | |
{ | |
case 1: | |
Reader.SetToken(JsonToken.PropertyName,String.Format("$ext:{0:x}:{1:x}",_tag,_type)); | |
return true; | |
case 2: | |
Reader.SetToken(_valueToken,_dataBytes); | |
return true; | |
default: | |
Reader.PopCtx(); | |
Reader.SetToken(JsonToken.EndObject); | |
return true; | |
} | |
} | |
} | |
private void ProcessFixExt1(sbyte type, Action<JsonToken, object> setToken) | |
{ | |
PushCtx(new UnknownExtensionContainer(this, MessagePackConstants.TagFixExt1,type,ReadByte(),JsonToken.Integer)); | |
setToken(JsonToken.StartObject, null); | |
} | |
private void ProcessFixExt2(sbyte type, Action<JsonToken, object> setToken) | |
{ | |
PushCtx(new UnknownExtensionContainer(this, MessagePackConstants.TagFixExt2, type, ReadUshort(),JsonToken.Integer)); | |
setToken(JsonToken.StartObject, null); | |
} | |
private void ProcessFixExt4(sbyte type, Action<JsonToken, object> setToken) | |
{ | |
PushCtx(new UnknownExtensionContainer(this, MessagePackConstants.TagFixExt4, type, ReadUint(),JsonToken.Integer)); | |
setToken(JsonToken.StartObject, null); | |
} | |
private void ProcessFixExt8(sbyte type, Action<JsonToken, object> setToken) | |
{ | |
unchecked | |
{ | |
switch (type) | |
{ | |
case MessagePackConstants.ExtTypeDateTime: | |
setToken(JsonToken.Date, DateTime.FromBinary((long) ReadUlong())); | |
return; | |
case MessagePackConstants.ExtTypeTimeStamp: | |
setToken(JsonToken.Date, new TimeSpan((long) ReadUlong())); | |
return; | |
default: | |
PushCtx(new UnknownExtensionContainer(this, MessagePackConstants.TagFixExt8, type, (long)ReadUlong(),JsonToken.Integer)); | |
setToken(JsonToken.StartObject,null); | |
return; | |
} | |
} | |
} | |
private void ProcessFixExt16(sbyte type, Action<JsonToken, object> setToken) | |
{ | |
PushCtx(new UnknownExtensionContainer(this, MessagePackConstants.TagFixExt16, type, ReadBytes(16),JsonToken.Bytes)); | |
setToken(JsonToken.StartObject,null); | |
} | |
public override int? ReadAsInt32() | |
{ | |
throw new NotImplementedException(); | |
} | |
public override string ReadAsString() | |
{ | |
throw new NotImplementedException(); | |
} | |
public override byte[] ReadAsBytes() | |
{ | |
throw new NotImplementedException(); | |
} | |
public override decimal? ReadAsDecimal() | |
{ | |
while (Read()) | |
{ | |
var tokenType = TokenType; | |
switch (tokenType) | |
{ | |
case JsonToken.Comment: | |
continue; | |
case JsonToken.Integer: | |
case JsonToken.Float: | |
return !(Value is Decimal) | |
? Convert.ToDecimal(Value, CultureInfo.InvariantCulture) | |
: (Decimal) Value; | |
case JsonToken.Null: | |
return null; | |
case JsonToken.String: | |
var s = (string) Value; | |
if (string.IsNullOrEmpty(s)) | |
{ | |
return null; | |
} | |
Decimal result; | |
if (!Decimal.TryParse(s, NumberStyles.Number, Culture, out result)) | |
throw new JsonReaderException(String.Format(CultureInfo.InvariantCulture, | |
"Could not convert string to decimal: {0}.", Value)); | |
return result; | |
case JsonToken.EndArray: | |
return null; | |
default: | |
throw new JsonReaderException(String.Format(CultureInfo.InvariantCulture, | |
"Error reading decimal. Unexpected token: {0}.", tokenType)); | |
} | |
} | |
return null; | |
} | |
private readonly byte[] _buff = new byte[256]; | |
private void ReadToBuffer(int bytes) | |
{ | |
if (bytes != _inputStream.Read(_buff, 0, bytes)) | |
throw new Exception("TODO:EOF"); | |
} | |
private byte ReadByte() | |
{ | |
ReadToBuffer(1); | |
return _buff[0]; | |
} | |
private ushort ReadUshort() | |
{ | |
ReadToBuffer(2); | |
return (ushort)(_buff[0] << 8 | _buff[1]); | |
} | |
private uint ReadUint() | |
{ | |
ReadToBuffer(4); | |
return ((uint)_buff[0] << 24 | (uint)_buff[1] << 16 | (uint)_buff[2] << 8 | _buff[3]); | |
} | |
private ulong ReadUlong() | |
{ | |
ReadToBuffer(8); | |
return (ulong)_buff[0] << 56 | (ulong)_buff[1] << 48 | (ulong)_buff[2] << 40 | (ulong)_buff[3] << 32 | (ulong)_buff[4] << 24 | (ulong)_buff[5] << 16 | (ulong)_buff[6] << 8 | _buff[7]; | |
} | |
private float ReadFloat32() | |
{ | |
ReadToBuffer(4); | |
if (BitConverter.IsLittleEndian) Array.Reverse(_buff, 0, 4); | |
return BitConverter.ToSingle(_buff, 0); | |
} | |
private double ReadFloat64() | |
{ | |
ReadToBuffer(8); | |
if (BitConverter.IsLittleEndian) Array.Reverse(_buff, 0, 8); | |
return BitConverter.ToDouble(_buff, 0); | |
} | |
private string GetStr(int len) | |
{ | |
var buff = len > _buff.Length ? new byte[len] : _buff; | |
if (len != _inputStream.Read(buff, 0, len)) | |
throw new Exception("TODO:EOF"); | |
return MessagePackWriter.Utf8.GetString(buff, 0, len); | |
} | |
public override DateTime? ReadAsDateTime() | |
{ | |
throw new NotImplementedException(); | |
} | |
public override DateTimeOffset? ReadAsDateTimeOffset() | |
{ | |
throw new NotImplementedException(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment