Implemented data: ser/des.
This commit is contained in:
parent
10d912d302
commit
e196d5f50f
@ -37,7 +37,7 @@ namespace ReFuel.Gltf
|
|||||||
return File.OpenRead(path);
|
return File.OpenRead(path);
|
||||||
}
|
}
|
||||||
case "data":
|
case "data":
|
||||||
return new GltfUriReader(Uri);
|
return DataUriStream.FromUri(Uri.OriginalString);
|
||||||
default:
|
default:
|
||||||
if (provider != null)
|
if (provider != null)
|
||||||
return provider.OpenFile(pwd, Uri) ?? throw new FileNotFoundException(Uri.ToString());
|
return provider.OpenFile(pwd, Uri) ?? throw new FileNotFoundException(Uri.ToString());
|
||||||
|
@ -56,7 +56,7 @@ namespace ReFuel.Gltf
|
|||||||
return File.OpenRead(path);
|
return File.OpenRead(path);
|
||||||
}
|
}
|
||||||
case "data":
|
case "data":
|
||||||
return new GltfUriReader(Uri);
|
return DataUriStream.FromUri(Uri.OriginalString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
ReFuel.Gltf/IO/DataUriStream.cs
Executable file
99
ReFuel.Gltf/IO/DataUriStream.cs
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ReFuel.Gltf.IO
|
||||||
|
{
|
||||||
|
public class DataUriStream : MemoryStream
|
||||||
|
{
|
||||||
|
public string? MediaType { get; set; }
|
||||||
|
|
||||||
|
public DataUriStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataUriStream(byte[] array) : base(array, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataUriStream(int capacity) : base(capacity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToUri(Encoding? encoding = null)
|
||||||
|
{
|
||||||
|
// Not the most efficient implementation here but it works.
|
||||||
|
StringBuilder builder = new StringBuilder((int)Length * 4 / 3);
|
||||||
|
ReadOnlySpan<byte> buffer = GetBuffer().AsSpan()[..(int)Length];
|
||||||
|
|
||||||
|
if (MediaType != null)
|
||||||
|
{
|
||||||
|
builder.Append(MediaType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoding == null)
|
||||||
|
{
|
||||||
|
builder.Append(";base64,");
|
||||||
|
builder.Append(Convert.ToBase64String(buffer));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append(';');
|
||||||
|
builder.Append(encoding.WebName);
|
||||||
|
builder.Append(',');
|
||||||
|
builder.Append(Uri.EscapeDataString(encoding.GetString(buffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataUriStream FromUri(ReadOnlySpan<char> uri)
|
||||||
|
{
|
||||||
|
if (uri.CompareTo("data:", StringComparison.InvariantCulture) != 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Expected a data uri.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int commaIndex = uri.IndexOf(',');
|
||||||
|
|
||||||
|
string? mediaType = null;
|
||||||
|
string dataType = "base64";
|
||||||
|
ReadOnlySpan<char> data;
|
||||||
|
|
||||||
|
if (commaIndex != -1)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> header = uri[5..commaIndex];
|
||||||
|
int lastSemicolon = header.LastIndexOf(';');
|
||||||
|
ReadOnlySpan<char> mediaTypeSpan = header[..lastSemicolon];
|
||||||
|
ReadOnlySpan<char> dataTypeSpan = header[(lastSemicolon + 1)..];
|
||||||
|
|
||||||
|
mediaType = mediaTypeSpan.ToString();
|
||||||
|
dataType = dataTypeSpan.ToString();
|
||||||
|
data = uri[(commaIndex + 1)..];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = uri[5..];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DataUriStream stream;
|
||||||
|
if (dataType == "base64")
|
||||||
|
{
|
||||||
|
stream = new DataUriStream(data.Length * 3 / 4 + 1) { MediaType = mediaType };
|
||||||
|
|
||||||
|
if (!Convert.TryFromBase64Chars(data, stream.GetBuffer(), out int bytesWritten))
|
||||||
|
{
|
||||||
|
throw new Exception("Base64 conversion failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.SetLength(bytesWritten);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Encoding encoding = Encoding.GetEncoding(dataType);
|
||||||
|
stream = new DataUriStream(encoding.GetBytes(Uri.UnescapeDataString(data.ToString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
namespace ReFuel.Gltf.IO
|
|
||||||
{
|
|
||||||
public class GltfUriReader : Stream
|
|
||||||
{
|
|
||||||
public Uri Uri { get; }
|
|
||||||
public string Type { get; }
|
|
||||||
public string Encoding { get; }
|
|
||||||
|
|
||||||
private string data;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
public GltfUriReader(Uri uri)
|
|
||||||
{
|
|
||||||
if (uri.Scheme != "data")
|
|
||||||
throw new Exception("Expected a URI with 'data:' scheme.");
|
|
||||||
|
|
||||||
Uri = uri;
|
|
||||||
data = uri.AbsolutePath;
|
|
||||||
index = data.IndexOf(',') + 1;
|
|
||||||
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
throw new Exception("No data string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanRead => true;
|
|
||||||
|
|
||||||
public override bool CanSeek => true;
|
|
||||||
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
public override long Length => throw new NotImplementedException();
|
|
||||||
|
|
||||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user