3using System.Collections;
4using System.Collections.Generic;
21 public abstract object Clone(
object o);
40 var list =
new List<T>(size);
41 for (
int i = 0; i < size; i++)
53 public override object Clone(
object o) => o;
55 public virtual IList
CloneList(IList<T> list) =>
new List<T>(list);
57 public override object Default() =>
default(T);
67 base(reader, writer) {
73 public override IList
CloneList(IList<T> list) => list.Select(
clone).ToList();
86 r => r.ReadBytes(r.ReadInt32()),
91 v => (
byte[]) v.Clone(),
94 r => Encoding.UTF8.GetString(r.ReadBytes(r.ReadInt16())),
96 var b = Encoding.UTF8.GetBytes(v);
97 w.Write((short)b.Length);
107 id = GetPayloadId(v.GetType().GetGenericArguments()[0]);
110 throw new IOException(
"Invalid NBT list type: "+v.GetType());
121 throw new ArgumentException(
"Invalid NBT list type: "+v.GetType());
124 new ClassPayloadHandler<TagCompound>(
126 var compound =
new TagCompound();
129 while ((tag =
ReadTag(r, out name)) !=
null)
130 compound.Set(name, tag);
135 foreach (var entry
in v)
136 if (entry.Value !=
null)
137 WriteTag(entry.Key, entry.Value, w);
141 v => (TagCompound) v.Clone(),
142 () =>
new TagCompound()),
143 new ClassPayloadHandler<
int[]>(
145 var ia =
new int[r.ReadInt32()];
146 for (
int i = 0; i < ia.Length; i++)
147 ia[i] = r.ReadInt32();
155 v => (
int[]) v.Clone(),
159 private static readonly Dictionary<Type, int> PayloadIDs =
160 Enumerable.Range(1, PayloadHandlers.Length - 1).ToDictionary(i => PayloadHandlers[i].PayloadType);
165 if (id < 1 || id >= PayloadHandlers.Length)
166 throw new IOException(
"Invalid NBT payload id: " +
id);
168 return PayloadHandlers[id];
173 if (PayloadIDs.TryGetValue(t, out
id))
176 if (typeof(IList).IsAssignableFrom(t))
179 throw new IOException($
"Invalid NBT payload type '{t}'");
183 var type = value.GetType();
190 if (GetPayloadId(type) != 9)
193 var elemType = type.GetGenericArguments()[0];
197 if (GetPayloadId(elemType) != 9)
201 var list = value as IList<IList> ?? ((IList)value).Cast<IList>().ToList();
202 for (
int i = 0; i < list.Count; i++)
203 list[i] = (IList)Serialize(list[i]);
208 public static T Deserialize<T>(
object tag) {
209 if (tag is T)
return (T)tag;
210 return (T)Deserialize(typeof(T), tag);
214 if (type.IsInstanceOfType(tag))
220 tag = Deserialize(serializer.
TagType,
null);
227 if (type.GetGenericArguments().Length == 0)
228 return GetHandler(GetPayloadId(type)).Default();
230 if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
235 if ((tag ==
null || tag is IList) &&
236 type.GetGenericArguments().Length == 1) {
237 var elemType = type.GetGenericArguments()[0];
238 var newListType = typeof(List<>).MakeGenericType(elemType);
239 if (type.IsAssignableFrom(newListType)) {
241 return newListType.GetConstructor(
new Type[0]).Invoke(
new object[0]);
244 return serializer.DeserializeList((IList)tag);
247 var oldList = (IList)tag;
248 var newList = (IList)newListType.GetConstructor(
new[] { typeof(
int) }).Invoke(
new object[] { oldList.Count });
249 foreach (var elem
in oldList)
250 newList.Add(Deserialize(elemType, elem));
257 throw new IOException($
"Invalid NBT payload type '{type}'");
259 throw new InvalidCastException($
"Unable to cast object of type '{tag.GetType()}' to type '{type}'");
262 public static T Clone<T>(T o) => (T)GetHandler(GetPayloadId(o.GetType())).Clone(o);
265 int id = r.ReadByte();
271 name = StringHandler.reader(r);
272 return PayloadHandlers[id].Read(r);
276 int id = GetPayloadId(tag.GetType());
278 StringHandler.writer(w, name);
279 PayloadHandlers[id].Write(w, tag);
284 using (Stream fs =
new FileStream(path, FileMode.Open, FileAccess.Read))
285 return FromStream(fs, compressed);
288 throw new IOException(
"Failed to read NBT file: " + path, e);
293 if (compressed) stream =
new GZipStream(stream, CompressionMode.Decompress);
299 var tag = ReadTag(reader, out name);
301 throw new IOException(
"Root tag not a TagCompound");
308 using (Stream fs =
new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
309 ToStream(root, fs, compress);
312 throw new IOException(
"Failed to read NBT file: " + path, e);
317 if (compress) stream =
new GZipStream(stream, CompressionMode.Compress,
true);
319 if (compress) stream.Close();
override object Clone(object o)
override object Default()
ClassPayloadHandler(Func< BinaryReader, T > reader, Action< BinaryWriter, T > writer, Func< T, T > clone, Func< T > makeDefault=null)
override IList CloneList(IList< T > list)
override void Write(BinaryWriter w, object v)
override object Clone(object o)
override IList ReadList(BinaryReader r, int size)
virtual IList CloneList(IList< T > list)
abstract object Clone(object o)
abstract void Write(BinaryWriter w, object v)
override void WriteList(BinaryWriter w, IList list)
abstract IList ReadList(BinaryReader r, int size)
abstract object Default()
override object Read(BinaryReader r)
override IList CloneList(IList list)
void WriteList(BinaryWriter w, IList< T > list)
PayloadHandler(Func< BinaryReader, T > reader, Action< BinaryWriter, T > writer)
abstract void WriteList(BinaryWriter w, IList list)
abstract Type PayloadType
abstract IList CloneList(IList list)
abstract object Read(BinaryReader r)
override object Default()
static readonly PayloadHandler[] PayloadHandlers
static int GetPayloadId(Type t)
static void Write(TagCompound root, BinaryWriter writer)
static void WriteTag(string name, object tag, BinaryWriter w)
static object Deserialize(Type type, object tag)
static void ToStream(TagCompound root, Stream stream, bool compress=true)
static TagCompound FromStream(Stream stream, bool compressed=true)
static PayloadHandler GetHandler(int id)
static object ReadTag(BinaryReader r, out string name)
static TagCompound Read(BinaryReader reader)
static object Serialize(object value)
static TagCompound FromFile(string path, bool compressed=true)
static void ToFile(TagCompound root, string path, bool compress=true)
abstract object Serialize(object value)
static bool TryGetSerializer(Type type, out TagSerializer serializer)
abstract IList SerializeList(IList value)
abstract object Deserialize(object tag)