259 lines
7.3 KiB
C#
259 lines
7.3 KiB
C#
|
//
|
|||
|
// Copyright 2011 Kazuki Oikawa
|
|||
|
//
|
|||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
// you may not use this file except in compliance with the License.
|
|||
|
// You may obtain a copy of the License at
|
|||
|
//
|
|||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
//
|
|||
|
// Unless required by applicable law or agreed to in writing, software
|
|||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
// See the License for the specific language governing permissions and
|
|||
|
// limitations under the License.
|
|||
|
//
|
|||
|
|
|||
|
using System;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
|
|||
|
namespace MsgPack
|
|||
|
{
|
|||
|
public class MsgPackReader
|
|||
|
{
|
|||
|
Stream _strm;
|
|||
|
byte[] _tmp0 = new byte[8];
|
|||
|
byte[] _tmp1 = new byte[8];
|
|||
|
|
|||
|
Encoding _encoding = Encoding.UTF8;
|
|||
|
//Decoder _decoder = Encoding.UTF8.GetDecoder ();
|
|||
|
byte[] _buf = new byte[64];
|
|||
|
|
|||
|
public MsgPackReader (Stream strm)
|
|||
|
{
|
|||
|
_strm = strm;
|
|||
|
}
|
|||
|
|
|||
|
public TypePrefixes Type { get; private set; }
|
|||
|
|
|||
|
public bool ValueBoolean { get; private set; }
|
|||
|
public uint Length { get; private set; }
|
|||
|
|
|||
|
public uint ValueUnsigned { get; private set; }
|
|||
|
public ulong ValueUnsigned64 { get; private set; }
|
|||
|
|
|||
|
public int ValueSigned { get; private set; }
|
|||
|
public long ValueSigned64 { get; private set; }
|
|||
|
|
|||
|
public float ValueFloat { get; private set; }
|
|||
|
public double ValueDouble { get; private set; }
|
|||
|
|
|||
|
public bool IsSigned ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.NegativeFixNum ||
|
|||
|
this.Type == TypePrefixes.PositiveFixNum ||
|
|||
|
this.Type == TypePrefixes.Int8 ||
|
|||
|
this.Type == TypePrefixes.Int16 ||
|
|||
|
this.Type == TypePrefixes.Int32;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsBoolean ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsSigned64 ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.Int64;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsUnsigned ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.PositiveFixNum ||
|
|||
|
this.Type == TypePrefixes.UInt8 ||
|
|||
|
this.Type == TypePrefixes.UInt16 ||
|
|||
|
this.Type == TypePrefixes.UInt32;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsUnsigned64 ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.UInt64;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsRaw ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.FixRaw || this.Type == TypePrefixes.Raw16 || this.Type == TypePrefixes.Raw32;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsArray ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.FixArray || this.Type == TypePrefixes.Array16 || this.Type == TypePrefixes.Array32;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsMap ()
|
|||
|
{
|
|||
|
return this.Type == TypePrefixes.FixMap || this.Type == TypePrefixes.Map16 || this.Type == TypePrefixes.Map32;
|
|||
|
}
|
|||
|
|
|||
|
public bool Read ()
|
|||
|
{
|
|||
|
byte[] tmp0 = _tmp0, tmp1 = _tmp1;
|
|||
|
int x = _strm.ReadByte ();
|
|||
|
if (x < 0)
|
|||
|
return false; // EOS
|
|||
|
|
|||
|
if (x >= 0x00 && x <= 0x7f) {
|
|||
|
this.Type = TypePrefixes.PositiveFixNum;
|
|||
|
} else if (x >= 0xe0 && x <= 0xff) {
|
|||
|
this.Type = TypePrefixes.NegativeFixNum;
|
|||
|
} else if (x >= 0xa0 && x <= 0xbf) {
|
|||
|
this.Type = TypePrefixes.FixRaw;
|
|||
|
} else if (x >= 0x90 && x <= 0x9f) {
|
|||
|
this.Type = TypePrefixes.FixArray;
|
|||
|
} else if (x >= 0x80 && x <= 0x8f) {
|
|||
|
this.Type = TypePrefixes.FixMap;
|
|||
|
} else {
|
|||
|
this.Type = (TypePrefixes)x;
|
|||
|
}
|
|||
|
|
|||
|
switch (this.Type) {
|
|||
|
case TypePrefixes.Nil:
|
|||
|
break;
|
|||
|
case TypePrefixes.False:
|
|||
|
ValueBoolean = false;
|
|||
|
break;
|
|||
|
case TypePrefixes.True:
|
|||
|
ValueBoolean = true;
|
|||
|
break;
|
|||
|
case TypePrefixes.Float:
|
|||
|
_strm.Read (tmp0, 0, 4);
|
|||
|
if (BitConverter.IsLittleEndian) {
|
|||
|
tmp1[0] = tmp0[3];
|
|||
|
tmp1[1] = tmp0[2];
|
|||
|
tmp1[2] = tmp0[1];
|
|||
|
tmp1[3] = tmp0[0];
|
|||
|
ValueFloat = BitConverter.ToSingle (tmp1, 0);
|
|||
|
} else {
|
|||
|
ValueFloat = BitConverter.ToSingle (tmp0, 0);
|
|||
|
}
|
|||
|
break;
|
|||
|
case TypePrefixes.Double:
|
|||
|
_strm.Read (tmp0, 0, 8);
|
|||
|
if (BitConverter.IsLittleEndian) {
|
|||
|
tmp1[0] = tmp0[7];
|
|||
|
tmp1[1] = tmp0[6];
|
|||
|
tmp1[2] = tmp0[5];
|
|||
|
tmp1[3] = tmp0[4];
|
|||
|
tmp1[4] = tmp0[3];
|
|||
|
tmp1[5] = tmp0[2];
|
|||
|
tmp1[6] = tmp0[1];
|
|||
|
tmp1[7] = tmp0[0];
|
|||
|
ValueDouble = BitConverter.ToDouble (tmp1, 0);
|
|||
|
} else {
|
|||
|
ValueDouble = BitConverter.ToDouble (tmp0, 0);
|
|||
|
}
|
|||
|
break;
|
|||
|
case TypePrefixes.NegativeFixNum:
|
|||
|
ValueSigned = (x & 0x1f) - 0x20;
|
|||
|
break;
|
|||
|
case TypePrefixes.PositiveFixNum:
|
|||
|
ValueSigned = x & 0x7f;
|
|||
|
ValueUnsigned = (uint)ValueSigned;
|
|||
|
break;
|
|||
|
case TypePrefixes.UInt8:
|
|||
|
x = _strm.ReadByte ();
|
|||
|
if (x < 0)
|
|||
|
throw new FormatException ();
|
|||
|
ValueUnsigned = (uint)x;
|
|||
|
break;
|
|||
|
case TypePrefixes.UInt16:
|
|||
|
if (_strm.Read (tmp0, 0, 2) != 2)
|
|||
|
throw new FormatException ();
|
|||
|
ValueUnsigned = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
|
|||
|
break;
|
|||
|
case TypePrefixes.UInt32:
|
|||
|
if (_strm.Read (tmp0, 0, 4) != 4)
|
|||
|
throw new FormatException ();
|
|||
|
ValueUnsigned = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
|
|||
|
break;
|
|||
|
case TypePrefixes.UInt64:
|
|||
|
if (_strm.Read (tmp0, 0, 8) != 8)
|
|||
|
throw new FormatException ();
|
|||
|
ValueUnsigned64 = ((ulong)tmp0[0] << 56) | ((ulong)tmp0[1] << 48) | ((ulong)tmp0[2] << 40) | ((ulong)tmp0[3] << 32) | ((ulong)tmp0[4] << 24) | ((ulong)tmp0[5] << 16) | ((ulong)tmp0[6] << 8) | (ulong)tmp0[7];
|
|||
|
break;
|
|||
|
case TypePrefixes.Int8:
|
|||
|
x = _strm.ReadByte ();
|
|||
|
if (x < 0)
|
|||
|
throw new FormatException ();
|
|||
|
ValueSigned = (sbyte)x;
|
|||
|
break;
|
|||
|
case TypePrefixes.Int16:
|
|||
|
if (_strm.Read (tmp0, 0, 2) != 2)
|
|||
|
throw new FormatException ();
|
|||
|
ValueSigned = (short)((tmp0[0] << 8) | tmp0[1]);
|
|||
|
break;
|
|||
|
case TypePrefixes.Int32:
|
|||
|
if (_strm.Read (tmp0, 0, 4) != 4)
|
|||
|
throw new FormatException ();
|
|||
|
ValueSigned = (tmp0[0] << 24) | (tmp0[1] << 16) | (tmp0[2] << 8) | tmp0[3];
|
|||
|
break;
|
|||
|
case TypePrefixes.Int64:
|
|||
|
if (_strm.Read (tmp0, 0, 8) != 8)
|
|||
|
throw new FormatException ();
|
|||
|
ValueSigned64 = ((long)tmp0[0] << 56) | ((long)tmp0[1] << 48) | ((long)tmp0[2] << 40) | ((long)tmp0[3] << 32) | ((long)tmp0[4] << 24) | ((long)tmp0[5] << 16) | ((long)tmp0[6] << 8) | (long)tmp0[7];
|
|||
|
break;
|
|||
|
case TypePrefixes.FixRaw:
|
|||
|
Length = (uint)(x & 0x1f);
|
|||
|
break;
|
|||
|
case TypePrefixes.FixArray:
|
|||
|
case TypePrefixes.FixMap:
|
|||
|
Length = (uint)(x & 0xf);
|
|||
|
break;
|
|||
|
case TypePrefixes.Raw16:
|
|||
|
case TypePrefixes.Array16:
|
|||
|
case TypePrefixes.Map16:
|
|||
|
if (_strm.Read (tmp0, 0, 2) != 2)
|
|||
|
throw new FormatException ();
|
|||
|
Length = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
|
|||
|
break;
|
|||
|
case TypePrefixes.Raw32:
|
|||
|
case TypePrefixes.Array32:
|
|||
|
case TypePrefixes.Map32:
|
|||
|
if (_strm.Read (tmp0, 0, 4) != 4)
|
|||
|
throw new FormatException ();
|
|||
|
Length = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new FormatException ();
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
public int ReadValueRaw (byte[] buf, int offset, int count)
|
|||
|
{
|
|||
|
return _strm.Read (buf, offset, count);
|
|||
|
}
|
|||
|
|
|||
|
public string ReadRawString ()
|
|||
|
{
|
|||
|
return ReadRawString (_buf);
|
|||
|
}
|
|||
|
|
|||
|
public string ReadRawString (byte[] buf)
|
|||
|
{
|
|||
|
if (this.Length < buf.Length) {
|
|||
|
if (ReadValueRaw (buf, 0, (int)this.Length) != this.Length)
|
|||
|
throw new FormatException ();
|
|||
|
return _encoding.GetString (buf, 0, (int)this.Length);
|
|||
|
}
|
|||
|
|
|||
|
// Poor implementation
|
|||
|
byte[] tmp = new byte[(int)this.Length];
|
|||
|
if (ReadValueRaw (tmp, 0, tmp.Length) != tmp.Length)
|
|||
|
throw new FormatException ();
|
|||
|
return _encoding.GetString (tmp);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|