Compare commits
3 Commits
e9d7960409
...
a83d6d82f5
| Author | SHA1 | Date | |
|---|---|---|---|
| a83d6d82f5 | |||
| ccbfcc09b2 | |||
| 4ac54c3c96 |
@@ -70,8 +70,6 @@ namespace ReFuel.Gltf
|
|||||||
case JsonValueKind.Undefined: break;
|
case JsonValueKind.Undefined: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,11 +145,11 @@ namespace ReFuel.Gltf
|
|||||||
|
|
||||||
while (GlbChunk.Read(str, out GlbChunk chunk))
|
while (GlbChunk.Read(str, out GlbChunk chunk))
|
||||||
{
|
{
|
||||||
using StreamWrapper substream = str.ForkAbs(str.Position, chunk.Size, true);
|
using StreamWrapper substream = str.ForkAbs(str.Position, str.Position + chunk.Size, true);
|
||||||
|
|
||||||
if (chunk.Type == GlbChunkType.Json)
|
if (chunk.Type == GlbChunkType.Json)
|
||||||
{
|
{
|
||||||
document = JsonDocument.Parse(substream);
|
document = JsonDocument.Parse(substream.Fork(keepOpen:true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace ReFuel.Gltf
|
|||||||
|
|
||||||
if (element.TryGetProperty("rotation", out JsonElement rotationElement))
|
if (element.TryGetProperty("rotation", out JsonElement rotationElement))
|
||||||
{
|
{
|
||||||
transform.Rotation = scaleElement.ToSingleVector(4, Quaternion.Identity);
|
transform.Rotation = rotationElement.ToSingleVector(4, Quaternion.Identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.TryGetProperty("translation", out JsonElement translationElement))
|
if (element.TryGetProperty("translation", out JsonElement translationElement))
|
||||||
|
|||||||
@@ -1,86 +1,216 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace ReFuel.Gltf.IO
|
namespace ReFuel.Gltf.IO
|
||||||
{
|
{
|
||||||
public class StreamWrapper : Stream
|
public class StreamWrapper : Stream
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The private synchronized proxy for the stream.
|
||||||
|
/// </summary>
|
||||||
private readonly Stream _proxy;
|
private readonly Stream _proxy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Head pointer for stream r/w operations.
|
||||||
|
/// </summary>
|
||||||
|
public long Head { get; private init; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tail pointer for stream r/w operations. -1 signifies unbound.
|
||||||
|
/// </summary>
|
||||||
|
public long Tail { get; private init; } = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The number of bytes in the stream if there is a limit set.
|
||||||
|
/// </summary>
|
||||||
|
public long Limit
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Tail <= 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CanWrite)
|
||||||
|
{
|
||||||
|
return Tail - Head;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the limit size or however many bytes are available.
|
||||||
|
return Math.Min(Tail - Head, _proxy.Length - Head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The base stream for this wrapper.
|
||||||
|
/// </summary>
|
||||||
public Stream BaseStream { get; }
|
public Stream BaseStream { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the stream has been set to be read only.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly { get; private init; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the base stream should be kept open.
|
||||||
|
/// </summary>
|
||||||
public bool KeepOpen { get; }
|
public bool KeepOpen { get; }
|
||||||
public long Offset { get; private init; } = 0;
|
|
||||||
public long Limit { get; private init; } = -1;
|
|
||||||
|
|
||||||
public override bool CanRead => _proxy.CanRead;
|
public override bool CanRead => _proxy.CanRead;
|
||||||
public override bool CanSeek => _proxy.CanSeek;
|
public override bool CanSeek => _proxy.CanSeek;
|
||||||
public override bool CanWrite => _proxy.CanWrite;
|
public override bool CanWrite => !IsReadOnly || _proxy.CanWrite;
|
||||||
public override long Length => Limit < 0 ? _proxy.Length : Math.Min(Limit, Length - Offset);
|
public override long Length => Tail < 0 ? _proxy.Length - Head : Math.Min(Tail - Head, _proxy.Length - Head);
|
||||||
|
|
||||||
public override long Position
|
public override long Position
|
||||||
{
|
{
|
||||||
get => ToRelOffset(_proxy.Position);
|
get => ToRelOffset(_proxy.Position);
|
||||||
set => _proxy.Position = ToAbsOffset(value);
|
set => _proxy.Position = ToAbsOffset(value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamWrapper(Stream baseStream, bool keepOpen = false)
|
public StreamWrapper(Stream baseStream, bool keepOpen = false, bool isReadOnly = false)
|
||||||
{
|
{
|
||||||
BaseStream = baseStream;
|
BaseStream = baseStream;
|
||||||
KeepOpen = keepOpen;
|
KeepOpen = keepOpen;
|
||||||
|
IsReadOnly = isReadOnly;
|
||||||
|
|
||||||
_proxy = Synchronized(baseStream);
|
_proxy = Synchronized(baseStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Flush() => _proxy.Flush();
|
public override void Flush() => _proxy.Flush();
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count) => _proxy.Read(buffer, offset, count);
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin) => _proxy.Seek(offset, origin);
|
|
||||||
|
|
||||||
public override void SetLength(long value) => _proxy.SetLength(value);
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count) => _proxy.Write(buffer, offset, count);
|
|
||||||
|
|
||||||
public StreamWrapper Fork(long offset = 0, long limit = -1, bool keepOpen = false)
|
|
||||||
{
|
{
|
||||||
if (limit < 0)
|
int clamped = ClampReadLength();
|
||||||
limit = Limit;
|
int rc =_proxy.Read(buffer, offset, clamped);
|
||||||
|
Debug.Assert(Tail < 0 || _proxy.Position <= Tail);
|
||||||
|
return rc;
|
||||||
|
|
||||||
if (offset < 0 || offset > Length)
|
int ClampReadLength()
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset), "Offset out of range.");
|
{
|
||||||
|
if (Tail > 0)
|
||||||
if (limit >= 0 && offset + limit > Length)
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(limit), "Limit too large for the given offset.");
|
return Math.Min(count, (int)Math.Min(int.MaxValue, Math.Max(0, Tail - _proxy.Position)));
|
||||||
|
}
|
||||||
return ForkAbs(ToAbsOffset(offset), limit, keepOpen);
|
else
|
||||||
|
{
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public StreamWrapper ForkAbs(long offset = 0, long limit = -1, bool keepOpen = false)
|
|
||||||
{
|
|
||||||
if (offset < 0 || offset > BaseStream.Length)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset), "Offset out of range.");
|
|
||||||
|
|
||||||
if (limit >= 0 && offset + limit > BaseStream.Length)
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
throw new ArgumentOutOfRangeException(nameof(limit), "Limit too large for the given offset.");
|
{
|
||||||
|
long absOffset = 0;
|
||||||
|
switch (origin)
|
||||||
|
{
|
||||||
|
case SeekOrigin.Begin:
|
||||||
|
absOffset = ToAbsOffset(offset, true);
|
||||||
|
break;
|
||||||
|
case SeekOrigin.End:
|
||||||
|
if (Tail < 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ToRelOffset(_proxy.Seek(offset, origin), true);
|
||||||
|
}
|
||||||
|
catch (ArgumentOutOfRangeException)
|
||||||
|
{
|
||||||
|
// Set the stream back to a known state.
|
||||||
|
_proxy.Seek(Tail, SeekOrigin.Begin);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
absOffset = Math.Max(Head, Math.Min(Tail, Tail + offset));
|
||||||
|
break;
|
||||||
|
case SeekOrigin.Current:
|
||||||
|
absOffset = Math.Max(Head, Math.Min(_proxy.Position + offset, Tail));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ToRelOffset(_proxy.Seek(absOffset, SeekOrigin.Begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
if (IsReadOnly)
|
||||||
|
throw new Exception("This stream is read only.");
|
||||||
|
|
||||||
|
if (Tail < 0)
|
||||||
|
throw new NotSupportedException("Cannot expand the stream at this point.");
|
||||||
|
|
||||||
|
if (Tail != _proxy.Length)
|
||||||
|
throw new NotSupportedException("Cannot resize the stream at this point.");
|
||||||
|
|
||||||
|
_proxy.SetLength(Head + value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (IsReadOnly)
|
||||||
|
throw new Exception("This stream is read only.");
|
||||||
|
|
||||||
|
if (Tail > 0 && _proxy.Position + count >= Tail)
|
||||||
|
throw new Exception("Source array will overrun the current limit.");
|
||||||
|
|
||||||
|
_proxy.Write(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamWrapper Fork(long head = 0, long tail = -1, bool keepOpen = false, bool isReadOnly = false)
|
||||||
|
{
|
||||||
|
return ForkAbs(ToAbsOffset(head, true), tail < 0 ? Tail : ToAbsOffset(tail, true), keepOpen, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StreamWrapper ForkAbs(long head = 0, long tail = -1, bool keepOpen = false, bool isReadOnly = false)
|
||||||
|
{
|
||||||
|
if (head < 0 || head > BaseStream.Length)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(head), "Head pointer out of range.");
|
||||||
|
|
||||||
|
if (tail >= 0 && tail > BaseStream.Length)
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(tail), "Tail pointer is too large for the given offset.");
|
||||||
|
|
||||||
return new StreamWrapper(BaseStream, keepOpen)
|
return new StreamWrapper(BaseStream, keepOpen)
|
||||||
{
|
{
|
||||||
Offset = offset,
|
Head = head,
|
||||||
Limit = limit,
|
Tail = tail,
|
||||||
|
IsReadOnly = IsReadOnly || isReadOnly,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ToAbsOffset(long offset)
|
private long ToAbsOffset(long relOffset, bool safe = false)
|
||||||
{
|
{
|
||||||
if (offset < 0)
|
if (relOffset < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The relative offset cannot be less than zero.");
|
throw new ArgumentOutOfRangeException(nameof(relOffset), relOffset, "The relative offset cannot be less than zero.");
|
||||||
|
|
||||||
if (Limit >= 0 && offset > Limit)
|
if (Limit >= 0 && relOffset > Limit)
|
||||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, "The relative offset cannot be greater than the limit.");
|
throw new ArgumentOutOfRangeException(nameof(relOffset), relOffset, "The relative offset cannot be greater than the limit.");
|
||||||
|
|
||||||
return offset + Offset;
|
long value = relOffset + Head;
|
||||||
|
|
||||||
|
if (safe)
|
||||||
|
{
|
||||||
|
if ((Tail > 0 && value >= Tail) || value < Head)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(relOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ToRelOffset(long offset)
|
private long ToRelOffset(long absOffset, bool safe = false)
|
||||||
{
|
{
|
||||||
return offset - Offset;
|
long value = absOffset - Head;
|
||||||
|
|
||||||
|
if (safe)
|
||||||
|
{
|
||||||
|
if ((Tail > 0 && value > Length) || value < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(absOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
@@ -90,9 +220,8 @@ namespace ReFuel.Gltf.IO
|
|||||||
if (!disposing)
|
if (!disposing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_proxy.Dispose();
|
|
||||||
if (!KeepOpen)
|
if (!KeepOpen)
|
||||||
BaseStream.Dispose();
|
_proxy.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user