/// <summary> /// Opens an existing NBT file from a stream. /// </summary> /// <param name="stream">The stream to get the NBT file from.</param> /// <param name="version">The compression version of the NBT, specify '1' for the original gzip compression, '2' for the mcregion zlib compression.</param> /// <returns>An opened NBT file.</returns> public static NBTFile OpenFile(Stream stream, int version) { NBTFile file = new NBTFile(); Stream compressStream; if (version == 1) { compressStream = new GZipStream(stream, CompressionMode.Decompress); } else { stream.ReadByte(); stream.ReadByte(); compressStream = new DeflateStream(stream, CompressionMode.Decompress); } BinaryReader reader = new BinaryReader(compressStream); { Encoding textEncoding = Encoding.UTF8; file.NamedNBT = reader.ReadByte() == 10; file.RootName = textEncoding.GetString(reader.ReadBytes(EndiannessConverter.ToInt16(reader.ReadInt16()))); if (file.NamedNBT) { byte type; while ((type = reader.ReadByte()) != 0) { string name = textEncoding.GetString(reader.ReadBytes(EndiannessConverter.ToInt16(reader.ReadInt16()))); file.InsertTag(new NBTTag(name, type, file.ReadPayload(ref reader, type))); } } else { byte type = reader.ReadByte(); int size = EndiannessConverter.ToInt32(reader.ReadInt32()); for (int i = 0; i < size; i++) { file.InsertTag(new NBTTag("", type, file.ReadPayload(ref reader, type))); } } } reader.Dispose(); compressStream.Dispose(); return(file); }
/// <summary> /// Opens the region file from a stream. /// </summary> /// <param name="stream">The stream the region file will read from.</param> /// <returns>The parsed region file.</returns> public static RegionFile OpenRegion(Stream stream) { #if DEBUG DateTime wStart; #endif RegionFile region = new RegionFile(); using (BinaryReader reader = new BinaryReader(stream)) { int[] sectors = new int[1024]; int[] tstamps = new int[1024]; for (int i = 0; i < 1024; i++) { sectors[i] = reader.ReadInt32(); } for (int i = 0; i < 1024; i++) { tstamps[i] = reader.ReadInt32(); } Thread offsetThread = new Thread(new ThreadStart(() => { int sector = 0; lock (sectors) for (int i = 0; i < 1024; i++) { sector = EndiannessConverter.ToInt32(sectors[i]); region.offsets[i] = new McrOffset() { SectorSize = (byte)(sector & 0xFF), SectorOffset = sector >> 8, }; } sectors = null; })); offsetThread.Name = "offset calculator thread"; offsetThread.Start(); offsetThread.Join(); Thread tstampThread = new Thread(() => { int tstamp = 0; lock (tstamps) for (int i = 0; i < 1024; i++) { tstamp = EndiannessConverter.ToInt32(tstamps[i]); region.tstamps[i] = new McrtStamp { Timestamp = tstamp, }; } tstamps = null; }) { Name = "timestamp calculator thread" }; tstampThread.Start(); tstampThread.Join(); #if DEBUG wStart = DateTime.Now; #endif byte[][] chunkBuffer = new byte[1024][]; { int length; McrOffset offset; for (int i = 0; i < 1024; i++) { offset = region.offsets[i]; if (offset.SectorOffset != 0) { stream.Seek(offset.SectorOffset * 4096, SeekOrigin.Begin); length = EndiannessConverter.ToInt32(reader.ReadInt32()); reader.ReadByte(); chunkBuffer[i] = reader.ReadBytes(length - 1); } } } int chunkSlice = 1024 / MaxTHREADS; Thread[] workerThreads = new Thread[MaxTHREADS]; { for (int i = 0; i < MaxTHREADS; i++) { byte[][] chunkWorkerBuffer = new byte[chunkSlice][]; Array.Copy(chunkBuffer, i * chunkSlice, chunkWorkerBuffer, 0, chunkSlice); int index = i; workerThreads[i] = new Thread(new ThreadStart(() => { #if DEBUG DateTime start = DateTime.Now; #endif int offset = index * (1024 / MaxTHREADS); MemoryStream mmStream = null; for (int n = 0; n < chunkWorkerBuffer.Length; n++) { byte[] chunk = chunkWorkerBuffer[n]; if (chunk == null) { continue; } mmStream = new MemoryStream(chunk); region.chunks[n + offset] = NBTFile.OpenFile(mmStream, 2); mmStream.Dispose(); } chunkWorkerBuffer = null; #if DEBUG Console.WriteLine("Thread worker " + (index + 1) + " is complete! Took " + (int)(DateTime.Now - start).TotalMilliseconds + "ms to process."); })); workerThreads[i].Name = "chunk worker thread " + (index + 1); #else }));
private void SavePayload(ref BinaryWriter writer, byte type, dynamic payload) { switch (type) { case 0: writer.Write((byte)0); break; case 1: writer.Write((byte)payload); break; case 2: writer.Write(EndiannessConverter.ToInt16(payload)); break; case 3: writer.Write(EndiannessConverter.ToInt32(payload)); break; case 4: writer.Write(EndiannessConverter.ToInt64(payload)); break; case 5: writer.Write(EndiannessConverter.ToSingle(payload)); break; case 6: writer.Write(EndiannessConverter.ToDouble(payload)); break; case 7: writer.Write(EndiannessConverter.ToInt32(payload.Length)); for (int i = 0; i < payload.Length; i++) { writer.Write(payload[i]); } break; case 8: writer.Write(EndiannessConverter.ToInt16((short)payload.Length)); byte[] oString = Encoding.UTF8.GetBytes(payload); for (int i = 0; i < oString.Length; i++) { writer.Write(oString[i]); } break; case 9: writer.Write(payload[0].Type); writer.Write(EndiannessConverter.ToInt32(payload.Count)); foreach (NBTTag tag in payload) { SavePayload(ref writer, tag.Type, tag.Payload); } break; case 10: foreach (KeyValuePair <string, NBTTag> tag in payload) { writer.Write(tag.Value.Type); writer.Write(EndiannessConverter.ToInt16((short)tag.Key.Length)); byte[] cString = Encoding.UTF8.GetBytes(tag.Key); for (int i = 0; i < cString.Length; i++) { writer.Write(cString[i]); } SavePayload(ref writer, tag.Value.Type, tag.Value.Payload); } writer.Write((byte)0); break; } }
private dynamic ReadPayload(ref BinaryReader reader, byte type) { switch (type) { case 0: return(0); case 1: return(reader.ReadByte()); case 2: return(EndiannessConverter.ToInt16(reader.ReadInt16())); case 3: return(EndiannessConverter.ToInt32(reader.ReadInt32())); case 4: return(EndiannessConverter.ToInt64(reader.ReadInt64())); case 5: return(EndiannessConverter.ToSingle(reader.ReadSingle())); case 6: return(EndiannessConverter.ToDouble(reader.ReadDouble())); case 7: return(reader.ReadBytes(EndiannessConverter.ToInt32(reader.ReadInt32()))); case 8: return(Encoding.UTF8.GetString(reader.ReadBytes(EndiannessConverter.ToInt16(reader.ReadInt16())))); case 9: { List <NBTTag> ret = new List <NBTTag>(); { byte containerType = reader.ReadByte(); int containerSize = EndiannessConverter.ToInt32(reader.ReadInt32()); for (int i = 0; i < containerSize; i++) { ret.Add(new NBTTag("", containerType, ReadPayload(ref reader, containerType))); } } return(ret); } case 10: { Dictionary <string, NBTTag> dic = new Dictionary <string, NBTTag>(); { byte containerType; while ((containerType = reader.ReadByte()) != 0) { string containerName = Encoding.UTF8.GetString(reader.ReadBytes(EndiannessConverter.ToInt16(reader.ReadInt16()))); dic.Add(containerName, new NBTTag(containerName, containerType, ReadPayload(ref reader, containerType))); } } return(dic); } default: throw new NotSupportedException("Tag type is invalid!"); } }
/// <summary> /// Saves this NBT file in a stream. /// </summary> /// <param name="stream">The output stream this NBT file will write onto.</param> /// <param name="version">The compression version of the NBT, specify '1' for the original gzip compression, '2' for the mcregion zlib compression.</param> public void SaveTag(Stream stream, int version) { Stream compressStream; if (version == 1) { compressStream = new GZipStream(stream, CompressionMode.Compress); } else { stream.WriteByte(0); stream.WriteByte(0); compressStream = new DeflateStream(stream, CompressionMode.Compress); } BinaryWriter writer = new BinaryWriter(compressStream); { writer.Write((byte)(NamedNBT ? 10 : 9)); writer.Write(EndiannessConverter.ToInt16((short)RootName.Length)); byte[] oString = Encoding.UTF8.GetBytes(RootName); for (int i = 0; i < oString.Length; i++) { writer.Write(oString[i]); } if (this.NamedNBT) { foreach (KeyValuePair <string, NBTTag> tag in _dict) { writer.Write(tag.Value.Type); writer.Write(EndiannessConverter.ToInt16((short)tag.Value.Name.Length)); oString = Encoding.UTF8.GetBytes(tag.Value.Name); for (int i = 0; i < oString.Length; i++) { writer.Write(oString[i]); } SavePayload(ref writer, tag.Value.Type, tag.Value.Payload); } writer.Write((byte)0); } else { writer.Write(_list[0].Type); writer.Write(EndiannessConverter.ToInt32(_list.Count)); for (int i = 0; i < _list.Count; i++) { SavePayload(ref writer, _list[0].Type, _list[i].Payload); } } } writer.Dispose(); compressStream.Dispose(); }