mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-10-10 14:48:48 -04:00
142 lines
4.0 KiB
C#
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;
|
|
}
|
|
}
|
|
} |