2016-12-02 15:31:34 +11:00

142 lines
4.0 KiB
C#

// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace ClassicalSharp.Map {
public struct NbtTag {
public string Name;
public object Value;
public NbtTagType TagId;
}
public class NbtList {
public NbtTagType ChildTagId;
public object[] ChildrenValues;
}
public enum NbtTagType : byte {
End, Int8, Int16, Int32, Int64,
Real32, Real64, Int8Array, String,
List, Compound, Int32Array,
Invalid = 255,
}
public sealed class NbtFile {
readonly BinaryReader reader;
readonly BinaryWriter writer;
public NbtFile(BinaryReader reader) {
this.reader = reader;
}
public NbtFile(BinaryWriter writer) {
this.writer = writer;
}
public void Write(NbtTagType v) { writer.Write((byte)v); }
public void WriteInt64(long v) { writer.Write(IPAddress.HostToNetworkOrder(v)); }
public void WriteInt32(int v) { writer.Write(IPAddress.HostToNetworkOrder(v)); }
public void WriteInt16(short v) { writer.Write(IPAddress.HostToNetworkOrder(v)); }
public void WriteInt8(sbyte v) { writer.Write((byte)v); }
public void WriteUInt8(int v) { writer.Write((byte)v); }
public void WriteUInt8(byte v) { writer.Write(v); }
public void WriteBytes(byte[] v) { writer.Write(v); }
public void WriteBytes(byte[] v, int index, int count) { writer.Write(v, index, count); }
public void Write(string value) {
ushort len = (ushort)value.Length;
byte[] data = Encoding.UTF8.GetBytes(value);
WriteInt16((short)len);
writer.Write(data);
}
public void WriteCpeExtCompound(string name, int version) {
Write(NbtTagType.Compound); Write(name);
Write(NbtTagType.Int32);
Write("ExtensionVersion"); WriteInt32(version);
}
public long ReadInt64() { return IPAddress.HostToNetworkOrder(reader.ReadInt64()); }
public int ReadInt32() { return IPAddress.HostToNetworkOrder(reader.ReadInt32()); }
public short ReadInt16() { return IPAddress.HostToNetworkOrder(reader.ReadInt16()); }
public string ReadString() {
int len = (ushort)ReadInt16();
byte[] data = reader.ReadBytes(len);
return Encoding.UTF8.GetString(data);
}
public unsafe NbtTag ReadTag(byte typeId, bool readTagName) {
NbtTag tag = default(NbtTag);
if (typeId == 0) {
tag.TagId = NbtTagType.Invalid; return tag;
}
tag.Name = readTagName ? ReadString() : null;
tag.TagId = (NbtTagType)typeId;
switch ((NbtTagType)typeId) {
case NbtTagType.Int8:
tag.Value = reader.ReadByte(); break;
case NbtTagType.Int16:
tag.Value = ReadInt16(); break;
case NbtTagType.Int32:
tag.Value = ReadInt32(); break;
case NbtTagType.Int64:
tag.Value = ReadInt64(); break;
case NbtTagType.Real32:
int temp32 = ReadInt32();
tag.Value = *((float*)&temp32); break;
case NbtTagType.Real64:
long temp64 = ReadInt64();
tag.Value = *((double*)&temp64); break;
case NbtTagType.Int8Array:
tag.Value = reader.ReadBytes(ReadInt32()); break;
case NbtTagType.String:
tag.Value = ReadString(); break;
case NbtTagType.List:
NbtList list = new NbtList();
list.ChildTagId = (NbtTagType)reader.ReadByte();
list.ChildrenValues = new object[ReadInt32()];
for (int i = 0; i < list.ChildrenValues.Length; i++)
list.ChildrenValues[i] = ReadTag((byte)list.ChildTagId, false).Value;
tag.Value = list; break;
case NbtTagType.Compound:
Dictionary<string, NbtTag> children = new Dictionary<string, NbtTag>();
NbtTag child;
while ((child = ReadTag(reader.ReadByte(), true)).TagId != NbtTagType.Invalid)
children[child.Name] = child;
tag.Value = children; break;
case NbtTagType.Int32Array:
int[] array = new int[ReadInt32()];
for (int i = 0; i < array.Length; i++)
array[i] = ReadInt32();
tag.Value = array; break;
default:
throw new InvalidDataException("Unrecognised tag id: " + typeId);
}
return tag;
}
}
}