diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index a3c2e5202..32003468b 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -124,6 +124,7 @@ + diff --git a/ClassicalSharp/Map/MapCw.cs b/ClassicalSharp/Map/MapCw.cs new file mode 100644 index 000000000..205e0833d --- /dev/null +++ b/ClassicalSharp/Map/MapCw.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Net; + +namespace ClassicalSharp { + + public sealed class MapCw : IMapFile { + + public override bool SupportsLoading { + get { return true; } + } + + public override bool SupportsSaving { + get { return true; } + } + + BinaryReader reader; + NbtTag invalid = default( NbtTag ); + public override byte[] Load( Stream stream, Game game, out int width, out int height, out int length ) { + using( GZipStream wrapper = new GZipStream( stream, CompressionMode.Decompress ) ) { + reader = new BinaryReader( wrapper ); + if( reader.ReadByte() != (byte)NbtTagType.Compound ) + throw new InvalidDataException( "Nbt file must start with Tag_Compound" ); + + invalid.TagId = NbtTagType.Invalid; + NbtTag root = ReadTag( (byte)NbtTagType.Compound, true ); + } + length = width = height = 0; + return null; + } + + unsafe NbtTag ReadTag( byte typeId, bool readTagName ) { + if( typeId == 0 ) return invalid; + + NbtTag tag = default( NbtTag ); + 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 ); + } + tag.Value = list; break; + + case NbtTagType.Compound: + Dictionary children = new Dictionary(); + 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; + } + + struct NbtTag { + public string Name; + public object Value; + public NbtTagType TagId; + } + + class NbtList { + public NbtTagType ChildTagId; + public object[] ChildrenValues; + } + + + enum NbtTagType : byte { + End = 0, + Int8 = 1, + Int16 = 2, + Int32 = 3, + Int64 = 4, + Real32 = 5, + Real64 = 6, + Int8Array = 7, + String = 8, + List = 9, + Compound = 10, + Int32Array = 11, + Invalid = 255, + } + + long ReadInt64() { return IPAddress.HostToNetworkOrder( reader.ReadInt64() ); } + int ReadInt32() { return IPAddress.HostToNetworkOrder( reader.ReadInt32() ); } + short ReadInt16() { return IPAddress.HostToNetworkOrder( reader.ReadInt16() ); } + string ReadString() { return Encoding.UTF8.GetString( reader.ReadBytes( (ushort)ReadInt16() ) ); } + + public override void Save( Stream stream, Game game ) { + } + } +} \ No newline at end of file