-
-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
32 changed files
with
5,559 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
using System.Diagnostics; | ||
using System.IO; | ||
using JetBrains.Annotations; | ||
|
||
namespace fNbt { | ||
// Class used to count bytes read-from/written-to non-seekable streams. | ||
internal class ByteCountingStream : Stream { | ||
readonly Stream baseStream; | ||
|
||
// These are necessary to avoid counting bytes twice if ReadByte/WriteByte call Read/Write internally. | ||
bool readingOneByte, writingOneByte; | ||
|
||
// These are necessary to avoid counting bytes twice if Read/Write call ReadByte/WriteByte internally. | ||
bool readingManyBytes, writingManyBytes; | ||
|
||
|
||
public ByteCountingStream([NotNull] Stream stream) { | ||
Debug.Assert(stream != null); | ||
baseStream = stream; | ||
} | ||
|
||
|
||
public override void Flush() { | ||
baseStream.Flush(); | ||
} | ||
|
||
|
||
public override long Seek(long offset, SeekOrigin origin) { | ||
return baseStream.Seek(offset, origin); | ||
} | ||
|
||
|
||
public override void SetLength(long value) { | ||
baseStream.SetLength(value); | ||
} | ||
|
||
|
||
public override int Read(byte[] buffer, int offset, int count) { | ||
readingManyBytes = true; | ||
int bytesActuallyRead = baseStream.Read(buffer, offset, count); | ||
readingManyBytes = false; | ||
if (!readingOneByte) BytesRead += bytesActuallyRead; | ||
return bytesActuallyRead; | ||
} | ||
|
||
|
||
public override void Write(byte[] buffer, int offset, int count) { | ||
writingManyBytes = true; | ||
baseStream.Write(buffer, offset, count); | ||
writingManyBytes = false; | ||
if (!writingOneByte) BytesWritten += count; | ||
} | ||
|
||
|
||
public override int ReadByte() { | ||
readingOneByte = true; | ||
int value = base.ReadByte(); | ||
readingOneByte = false; | ||
if (value >= 0 && !readingManyBytes) BytesRead++; | ||
return value; | ||
} | ||
|
||
|
||
public override void WriteByte(byte value) { | ||
writingOneByte = true; | ||
base.WriteByte(value); | ||
writingOneByte = false; | ||
if (!writingManyBytes) BytesWritten++; | ||
} | ||
|
||
|
||
public override bool CanRead { | ||
get { return baseStream.CanRead; } | ||
} | ||
|
||
public override bool CanSeek { | ||
get { return baseStream.CanSeek; } | ||
} | ||
|
||
public override bool CanWrite { | ||
get { return baseStream.CanWrite; } | ||
} | ||
|
||
public override long Length { | ||
get { return baseStream.Length; } | ||
} | ||
|
||
public override long Position { | ||
get { return baseStream.Position; } | ||
set { baseStream.Position = value; } | ||
} | ||
|
||
public long BytesRead { get; private set; } | ||
public long BytesWritten { get; private set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
using JetBrains.Annotations; | ||
|
||
namespace fNbt { | ||
/// <summary> Exception thrown when an operation is attempted on an NbtReader that | ||
/// cannot recover from a previous parsing error. </summary> | ||
[Serializable] | ||
public sealed class InvalidReaderStateException : InvalidOperationException { | ||
internal InvalidReaderStateException([NotNull] string message) | ||
: base(message) {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* Copyright 2007-2012 JetBrains s.r.o. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
using System; | ||
|
||
namespace JetBrains.Annotations { | ||
/// <summary> Indicates that the value of marked element could be <c>null</c> sometimes, | ||
/// so the check for <c>null</c> is necessary before its usage. </summary> | ||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | | ||
AttributeTargets.Property | AttributeTargets.Delegate | AttributeTargets.Field)] | ||
public sealed class CanBeNullAttribute : Attribute {} | ||
|
||
|
||
/// <summary> Indicates that the value of marked element could never be <c>null</c>. </summary> | ||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter | | ||
AttributeTargets.Property | AttributeTargets.Delegate | AttributeTargets.Field)] | ||
public sealed class NotNullAttribute : Attribute {} | ||
|
||
|
||
/// <summary> Indicates that method doesn't contain observable side effects. </summary> | ||
[AttributeUsage(AttributeTargets.Method)] | ||
public sealed class PureAttribute : Attribute {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
using System; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Text; | ||
using JetBrains.Annotations; | ||
|
||
namespace fNbt { | ||
/// <summary> BinaryReader wrapper that takes care of reading primitives from an NBT stream, | ||
/// while taking care of endianness, string encoding, and skipping. </summary> | ||
internal sealed class NbtBinaryReader : BinaryReader { | ||
readonly byte[] buffer = new byte[sizeof(double)]; | ||
|
||
byte[] seekBuffer; | ||
const int SeekBufferSize = 8*1024; | ||
readonly bool swapNeeded; | ||
readonly byte[] stringConversionBuffer = new byte[64]; | ||
|
||
|
||
public NbtBinaryReader([NotNull] Stream input, bool bigEndian) | ||
: base(input) { | ||
swapNeeded = (BitConverter.IsLittleEndian == bigEndian); | ||
} | ||
|
||
|
||
public NbtTagType ReadTagType() { | ||
int type = ReadByte(); | ||
if (type < 0) { | ||
throw new EndOfStreamException(); | ||
} else if (type > (int)NbtTagType.IntArray) { | ||
throw new NbtFormatException("NBT tag type out of range: " + type); | ||
} | ||
return (NbtTagType)type; | ||
} | ||
|
||
|
||
public override short ReadInt16() { | ||
if (swapNeeded) { | ||
return Swap(base.ReadInt16()); | ||
} else { | ||
return base.ReadInt16(); | ||
} | ||
} | ||
|
||
|
||
public override int ReadInt32() { | ||
if (swapNeeded) { | ||
return Swap(base.ReadInt32()); | ||
} else { | ||
return base.ReadInt32(); | ||
} | ||
} | ||
|
||
|
||
public override long ReadInt64() { | ||
if (swapNeeded) { | ||
return Swap(base.ReadInt64()); | ||
} else { | ||
return base.ReadInt64(); | ||
} | ||
} | ||
|
||
|
||
public override float ReadSingle() { | ||
if (swapNeeded) { | ||
FillBuffer(sizeof(float)); | ||
Array.Reverse(buffer, 0, sizeof(float)); | ||
return BitConverter.ToSingle(buffer, 0); | ||
} else { | ||
return base.ReadSingle(); | ||
} | ||
} | ||
|
||
|
||
public override double ReadDouble() { | ||
if (swapNeeded) { | ||
FillBuffer(sizeof(double)); | ||
Array.Reverse(buffer); | ||
return BitConverter.ToDouble(buffer, 0); | ||
} | ||
return base.ReadDouble(); | ||
} | ||
|
||
|
||
public override string ReadString() { | ||
short length = ReadInt16(); | ||
if (length < 0) { | ||
throw new NbtFormatException("Negative string length given!"); | ||
} | ||
if (length < stringConversionBuffer.Length) { | ||
int stringBytesRead = 0; | ||
while (stringBytesRead < length) { | ||
int bytesToRead = length - stringBytesRead; | ||
int bytesReadThisTime = BaseStream.Read(stringConversionBuffer, stringBytesRead, bytesToRead); | ||
if (bytesReadThisTime == 0) { | ||
throw new EndOfStreamException(); | ||
} | ||
stringBytesRead += bytesReadThisTime; | ||
} | ||
return Encoding.UTF8.GetString(stringConversionBuffer, 0, length); | ||
} else { | ||
byte[] stringData = ReadBytes(length); | ||
if (stringData.Length < length) { | ||
throw new EndOfStreamException(); | ||
} | ||
return Encoding.UTF8.GetString(stringData); | ||
} | ||
} | ||
|
||
|
||
public void Skip(int bytesToSkip) { | ||
if (bytesToSkip < 0) { | ||
throw new ArgumentOutOfRangeException("bytesToSkip"); | ||
} else if (BaseStream.CanSeek) { | ||
BaseStream.Position += bytesToSkip; | ||
} else if (bytesToSkip != 0) { | ||
if (seekBuffer == null) seekBuffer = new byte[SeekBufferSize]; | ||
int bytesSkipped = 0; | ||
while (bytesSkipped < bytesToSkip) { | ||
int bytesToRead = Math.Min(SeekBufferSize, bytesToSkip - bytesSkipped); | ||
int bytesReadThisTime = BaseStream.Read(seekBuffer, 0, bytesToRead); | ||
if (bytesReadThisTime == 0) { | ||
throw new EndOfStreamException(); | ||
} | ||
bytesSkipped += bytesReadThisTime; | ||
} | ||
} | ||
} | ||
|
||
|
||
new void FillBuffer(int numBytes) { | ||
int offset = 0; | ||
do { | ||
int num = BaseStream.Read(buffer, offset, numBytes - offset); | ||
if (num == 0) throw new EndOfStreamException(); | ||
offset += num; | ||
} while (offset < numBytes); | ||
} | ||
|
||
|
||
public void SkipString() { | ||
short length = ReadInt16(); | ||
if (length < 0) { | ||
throw new NbtFormatException("Negative string length given!"); | ||
} | ||
Skip(length); | ||
} | ||
|
||
|
||
[DebuggerStepThrough] | ||
static short Swap(short v) { | ||
unchecked { | ||
return (short)((v >> 8) & 0x00FF | | ||
(v << 8) & 0xFF00); | ||
} | ||
} | ||
|
||
|
||
[DebuggerStepThrough] | ||
static int Swap(int v) { | ||
unchecked { | ||
var v2 = (uint)v; | ||
return (int)((v2 >> 24) & 0x000000FF | | ||
(v2 >> 8) & 0x0000FF00 | | ||
(v2 << 8) & 0x00FF0000 | | ||
(v2 << 24) & 0xFF000000); | ||
} | ||
} | ||
|
||
|
||
[DebuggerStepThrough] | ||
static long Swap(long v) { | ||
unchecked { | ||
return (Swap((int)v) & uint.MaxValue) << 32 | | ||
Swap((int)(v >> 32)) & uint.MaxValue; | ||
} | ||
} | ||
|
||
|
||
[CanBeNull] | ||
public TagSelector Selector { get; set; } | ||
} | ||
} |
Oops, something went wrong.