221 lines
5.0 KiB
C#
221 lines
5.0 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Runtime.Serialization;
|
|
using System.Xml;
|
|
using ProtoBuf.Meta;
|
|
|
|
namespace ProtoBuf.ServiceModel;
|
|
|
|
public sealed class XmlProtoSerializer : XmlObjectSerializer
|
|
{
|
|
private readonly TypeModel model;
|
|
|
|
private readonly int key;
|
|
|
|
private readonly bool isList;
|
|
|
|
private readonly bool isEnum;
|
|
|
|
private readonly Type type;
|
|
|
|
private const string PROTO_ELEMENT = "proto";
|
|
|
|
internal XmlProtoSerializer(TypeModel model, int key, Type type, bool isList)
|
|
{
|
|
if (key < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("key");
|
|
}
|
|
this.model = model ?? throw new ArgumentNullException("model");
|
|
this.key = key;
|
|
this.isList = isList;
|
|
this.type = type ?? throw new ArgumentOutOfRangeException("type");
|
|
isEnum = Helpers.IsEnum(type);
|
|
}
|
|
|
|
public static XmlProtoSerializer TryCreate(TypeModel model, Type type)
|
|
{
|
|
if (model == null)
|
|
{
|
|
throw new ArgumentNullException("model");
|
|
}
|
|
if ((object)type == null)
|
|
{
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
bool flag;
|
|
int num = GetKey(model, ref type, out flag);
|
|
if (num >= 0)
|
|
{
|
|
return new XmlProtoSerializer(model, num, type, flag);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public XmlProtoSerializer(TypeModel model, Type type)
|
|
{
|
|
if (model == null)
|
|
{
|
|
throw new ArgumentNullException("model");
|
|
}
|
|
if ((object)type == null)
|
|
{
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
key = GetKey(model, ref type, out isList);
|
|
this.model = model;
|
|
this.type = type;
|
|
isEnum = Helpers.IsEnum(type);
|
|
if (key < 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException("type", "Type not recognised by the model: " + type.FullName);
|
|
}
|
|
}
|
|
|
|
private static int GetKey(TypeModel model, ref Type type, out bool isList)
|
|
{
|
|
if (model != null && (object)type != null)
|
|
{
|
|
int num = model.GetKey(ref type);
|
|
if (num >= 0)
|
|
{
|
|
isList = false;
|
|
return num;
|
|
}
|
|
Type listItemType = TypeModel.GetListItemType(model, type);
|
|
if ((object)listItemType != null)
|
|
{
|
|
num = model.GetKey(ref listItemType);
|
|
if (num >= 0)
|
|
{
|
|
isList = true;
|
|
return num;
|
|
}
|
|
}
|
|
}
|
|
isList = false;
|
|
return -1;
|
|
}
|
|
|
|
public override void WriteEndObject(XmlDictionaryWriter writer)
|
|
{
|
|
if (writer == null)
|
|
{
|
|
throw new ArgumentNullException("writer");
|
|
}
|
|
((XmlWriter)writer).WriteEndElement();
|
|
}
|
|
|
|
public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
|
|
{
|
|
if (writer == null)
|
|
{
|
|
throw new ArgumentNullException("writer");
|
|
}
|
|
((XmlWriter)writer).WriteStartElement("proto");
|
|
}
|
|
|
|
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
|
|
{
|
|
if (writer == null)
|
|
{
|
|
throw new ArgumentNullException("writer");
|
|
}
|
|
if (graph == null)
|
|
{
|
|
((XmlWriter)writer).WriteAttributeString("nil", "true");
|
|
return;
|
|
}
|
|
using MemoryStream memoryStream = new MemoryStream();
|
|
if (isList)
|
|
{
|
|
model.Serialize(memoryStream, graph, null);
|
|
}
|
|
else
|
|
{
|
|
using ProtoWriter dest = ProtoWriter.Create(memoryStream, model);
|
|
model.Serialize(key, graph, dest);
|
|
}
|
|
byte[] buffer = memoryStream.GetBuffer();
|
|
((XmlWriter)writer).WriteBase64(buffer, 0, (int)memoryStream.Length);
|
|
}
|
|
|
|
public override bool IsStartObject(XmlDictionaryReader reader)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001f: Invalid comparison between Unknown and I4
|
|
if (reader == null)
|
|
{
|
|
throw new ArgumentNullException("reader");
|
|
}
|
|
((XmlReader)reader).MoveToContent();
|
|
if ((int)((XmlReader)reader).NodeType == 1)
|
|
{
|
|
return ((XmlReader)reader).Name == "proto";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
if (reader == null)
|
|
{
|
|
throw new ArgumentNullException("reader");
|
|
}
|
|
((XmlReader)reader).MoveToContent();
|
|
bool isEmptyElement = ((XmlReader)reader).IsEmptyElement;
|
|
bool flag = ((XmlReader)reader).GetAttribute("nil") == "true";
|
|
((XmlReader)reader).ReadStartElement("proto");
|
|
if (flag)
|
|
{
|
|
if (!isEmptyElement)
|
|
{
|
|
((XmlReader)reader).ReadEndElement();
|
|
}
|
|
return null;
|
|
}
|
|
if (isEmptyElement)
|
|
{
|
|
if (isList || isEnum)
|
|
{
|
|
return model.Deserialize(Stream.Null, null, type, null);
|
|
}
|
|
ProtoReader protoReader = null;
|
|
try
|
|
{
|
|
protoReader = ProtoReader.Create(Stream.Null, model, null, -1L);
|
|
return model.Deserialize(key, null, protoReader);
|
|
}
|
|
finally
|
|
{
|
|
ProtoReader.Recycle(protoReader);
|
|
}
|
|
}
|
|
object result;
|
|
using (MemoryStream source = new MemoryStream(reader.ReadContentAsBase64()))
|
|
{
|
|
if (isList || isEnum)
|
|
{
|
|
result = model.Deserialize(source, null, type, null);
|
|
}
|
|
else
|
|
{
|
|
ProtoReader protoReader2 = null;
|
|
try
|
|
{
|
|
protoReader2 = ProtoReader.Create(source, model, null, -1L);
|
|
result = model.Deserialize(key, null, protoReader2);
|
|
}
|
|
finally
|
|
{
|
|
ProtoReader.Recycle(protoReader2);
|
|
}
|
|
}
|
|
}
|
|
((XmlReader)reader).ReadEndElement();
|
|
return result;
|
|
}
|
|
}
|