static NbtVersion DetectVersion([NotNull] Stream stream) { NbtVersion version = NbtVersion.Legacy; if (!stream.CanSeek) { throw new NotSupportedException("Cannot detect file version on a stream that's not seekable."); } int firstByte = stream.ReadByte(); switch (firstByte) { case -1: throw new EndOfStreamException(); case 0x07: version = NbtVersion.V7; break; case 0x08: version = NbtVersion.V8; break; default: version = NbtVersion.Legacy; break; } stream.Seek(-1, SeekOrigin.Current); return(version); }
/// <summary> Loads NBT data from a stream. Existing <c>RootTag</c> will be replaced </summary> /// <param name="stream"> Stream from which data will be loaded. If compression is set to AutoDetect, this stream must support seeking. </param> /// <param name="compression"> Compression method to use for loading/saving this file. </param> /// <param name="version"> Version of the file. </param> /// <returns> Number of bytes read from the stream. </returns> /// <exception cref="ArgumentNullException"> <paramref name="stream"/> is <c>null</c>. </exception> /// <exception cref="ArgumentOutOfRangeException"> If an unrecognized/unsupported value was given for <paramref name="compression"/>. </exception> /// <exception cref="NotSupportedException"> If <paramref name="compression"/> or <paramref name="version"/> is set to AutoDetect, but the stream is not seekable. </exception> /// <exception cref="EndOfStreamException"> If file ended earlier than expected. </exception> /// <exception cref="InvalidDataException"> If file compression could not be detected, decompressing failed, or given stream does not support reading. </exception> /// <exception cref="NbtFormatException"> If an error occurred while parsing data in NBT format. </exception> public long LoadFromStream([NotNull] Stream stream, NbtCompression compression, NbtVersion version) { return(LoadFromStream(stream, compression, version, null)); }
/// <summary> Loads NBT data from a stream. Existing <c>RootTag</c> will be replaced </summary> /// <param name="stream"> Stream from which data will be loaded. If compression or file version is set to AutoDetect, this stream must support seeking. </param> /// <param name="compression"> Compression method to use for loading/saving this file. </param> /// <param name="version"> Version of the file. </param> /// <param name="selector"> Optional callback to select which tags to load into memory. Root may not be skipped. /// No reference is stored to this callback after loading (don't worry about implicitly captured closures). May be <c>null</c>. </param> /// <returns> Number of bytes read from the stream. </returns> /// <exception cref="ArgumentNullException"> <paramref name="stream"/> is <c>null</c>. </exception> /// <exception cref="ArgumentOutOfRangeException"> If an unrecognized/unsupported value was given for <paramref name="compression"/>. </exception> /// <exception cref="NotSupportedException"> If <paramref name="compression"/> or <paramref name="fileVersion"/> is set to AutoDetect, but the stream is not seekable. </exception> /// <exception cref="EndOfStreamException"> If file ended earlier than expected. </exception> /// <exception cref="InvalidDataException"> If file compression could not be detected, decompressing failed, or given stream does not support reading. </exception> /// <exception cref="NbtFormatException"> If an error occurred while parsing data in NBT format. </exception> public long LoadFromStream([NotNull] Stream stream, NbtCompression compression, NbtVersion version, [CanBeNull] TagSelector selector) { if (stream == null) { throw new ArgumentNullException("stream"); } FileName = null; if (version == NbtVersion.AutoDetect) { FileVersion = DetectVersion(stream); } else { FileVersion = version; } if (FileVersion == NbtVersion.Legacy) { // detect compression, based on the first byte if (compression == NbtCompression.AutoDetect) { FileCompression = DetectCompression(stream); } else { FileCompression = compression; } } else { FileCompression = NbtCompression.None; BigEndian = false; } // prepare to count bytes read long startOffset = 0; if (stream.CanSeek) { startOffset = stream.Position; } else { stream = new ByteCountingStream(stream); } switch (FileCompression) { case NbtCompression.GZip: using (var decStream = new GZipStream(stream, CompressionMode.Decompress, true)) { if (bufferSize > 0) { LoadFromStreamInternal(new BufferedStream(decStream, bufferSize), selector); } else { LoadFromStreamInternal(decStream, selector); } } break; case NbtCompression.None: LoadFromStreamInternal(stream, selector); break; case NbtCompression.ZLib: if (stream.ReadByte() != 0x78) { throw new InvalidDataException(WrongZLibHeaderMessage); } stream.ReadByte(); using (var decStream = new DeflateStream(stream, CompressionMode.Decompress, true)) { if (bufferSize > 0) { LoadFromStreamInternal(new BufferedStream(decStream, bufferSize), selector); } else { LoadFromStreamInternal(decStream, selector); } } break; default: throw new ArgumentOutOfRangeException("compression"); } // report bytes read if (stream.CanSeek) { return(stream.Position - startOffset); } else { return(((ByteCountingStream)stream).BytesRead); } }