-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
Copy pathMsgPackSerializer.cs
189 lines (155 loc) · 5.5 KB
/
MsgPackSerializer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using MsgPack;
using MsgPack.Serialization;
using System.Security;
namespace CitizenFX.Core
{
static class MsgPackSerializer
{
//private static SerializationContext ms_context = new SerializationContext();
static MsgPackSerializer()
{
//SerializationContext.Default.CompatibilityOptions.PackerCompatibilityOptions = MsgPack.PackerCompatibilityOptions.None; // we want to use ext types, as our unpackers aren't retarded
//SerializationContext.Default.Serializers.RegisterOverride(new DelegateSerializer());
}
private static readonly Type[] WriteTypes = new[] {
typeof(string), typeof(DateTime), typeof(Enum),
typeof(decimal), typeof(Guid),
};
public static bool IsSimpleType(this Type type)
{
return type.IsPrimitive || WriteTypes.Contains(type);
}
public static byte[] Serialize(object obj)
{
/*if (obj == null)
{
return new byte[] { 0xC0 };
}
var serializer = MessagePackSerializer.Get(obj.GetType());
return serializer.PackSingleObject(obj);*/
if (obj == null)
{
return new byte[] { 0xC0 };
}
var stream = new MemoryStream();
using (var packer = Packer.Create(stream, PackerCompatibilityOptions.None))
{
Serialize(obj, packer);
return stream.ToArray();
}
}
private static void Serialize(object obj, Packer packer)
{
if (obj == null)
{
packer.PackNull();
return;
}
var type = obj.GetType();
if (type.IsSimpleType())
{
packer.Pack(obj);
}
else if (obj is IDictionary)
{
var dict = (IDictionary)obj;
packer.PackMapHeader(dict.Count);
foreach (var key in dict.Keys)
{
Serialize(key, packer);
Serialize(dict[key], packer);
}
}
else if (obj is IDictionary<string, object>) // special case for ExpandoObject
{
var dict = (IDictionary<string, object>)obj;
packer.PackMapHeader(dict.Count);
foreach (var kvp in dict)
{
Serialize(kvp.Key, packer);
Serialize(kvp.Value, packer);
}
}
else if (obj is IList)
{
var list = (IList)obj;
packer.PackArrayHeader(list.Count);
foreach (var item in list)
{
Serialize(item, packer);
}
}
else if (obj is IEnumerable enu)
{
var list = new List<object>();
foreach (var item in enu)
{
list.Add(item);
}
packer.PackArrayHeader(list.Count);
list.ForEach(a => Serialize(a, packer));
}
else if (obj is IPackable packable)
{
packable.PackToMessage(packer, null);
}
else if (obj is Delegate deleg)
{
var serializer = new DelegateSerializer();
serializer.PackTo(packer, deleg);
}
else
{
var properties = type.GetProperties();
var dict = new Dictionary<string, object>();
foreach (var property in properties)
{
dict[property.Name] = property.GetValue(obj, null);
}
Serialize(dict, packer);
}
}
}
class DelegateSerializer : MessagePackSerializer<Delegate>
{
public DelegateSerializer()
: base(SerializationContext.Default)
{
}
[SecuritySafeCritical]
protected override void PackToCore(Packer packer, Delegate objectTree)
{
if (objectTree is CallbackDelegate)
{
var funcRef = objectTree.Method.DeclaringType?.GetFields(BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.Static).FirstOrDefault(a => a.FieldType == typeof(RemoteFunctionReference));
if (funcRef == null)
{
throw new ArgumentException("The CallbackDelegate does not contain a RemoteFunctionReference capture.");
}
var fr = (RemoteFunctionReference)funcRef.GetValue(objectTree.Target);
packer.PackExtendedTypeValue(10, fr.Duplicate());
}
else
{
var funcRefDetails = FunctionReference.Create(objectTree);
var refType = InternalManager.CanonicalizeRef(funcRefDetails.Identifier);
packer.PackExtendedTypeValue(10, Encoding.UTF8.GetBytes(refType));
}
}
protected override Delegate UnpackFromCore(Unpacker unpacker)
{
throw new NotImplementedException();
}
}
}