Skip to content

Commit

Permalink
Temporary fix for unescaped URI characters.
Browse files Browse the repository at this point in the history
  • Loading branch information
vpenades committed Apr 14, 2020
1 parent bcec338 commit f7fafa8
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 49 deletions.
12 changes: 8 additions & 4 deletions src/Shared/Guard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ public static void IsFalse(bool target, string parameterName, string message = "

#region specialised

private static readonly IReadOnlyList<Char> _InvalidRelativePathChars =
System.IO.Path.GetInvalidFileNameChars()
.Where(c => c != '/' && c != '\\')
.ToArray();

public static void IsValidURI(string parameterName, string gltfURI, params string[] validHeaders)
{
if (string.IsNullOrEmpty(gltfURI)) return;
Expand All @@ -206,12 +211,11 @@ public static void IsValidURI(string parameterName, string gltfURI, params strin
}
}

if (gltfURI.StartsWith("data:")) throw new ArgumentException($"Invalid URI '{gltfURI}'.");
if (gltfURI.Any(c => _InvalidRelativePathChars.Contains(c))) throw new ArgumentException($"Invalid URI '{gltfURI}'.");

gltfURI = Uri.EscapeUriString(gltfURI);
if (gltfURI.Any(chr => char.IsWhiteSpace(chr))) gltfURI = Uri.EscapeUriString(gltfURI);

if (!Uri.IsWellFormedUriString(gltfURI, UriKind.RelativeOrAbsolute)) throw new ArgumentException($"Invalid URI '{gltfURI}'.");
if (!Uri.TryCreate(gltfURI, UriKind.RelativeOrAbsolute, out Uri xuri)) throw new ArgumentException($"Invalid URI '{gltfURI}'.");
if (!Uri.TryCreate(gltfURI, UriKind.Relative, out Uri xuri)) throw new ArgumentException($"Invalid URI '{gltfURI}'.");

return;
}
Expand Down
7 changes: 7 additions & 0 deletions src/Shared/_Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,13 @@ private static bool _IsDegenerated(uint a, uint b, uint c)

#region serialization

public static Byte[] ToUnderlayingArray(this ArraySegment<Byte> segment)
{
if (segment.Offset == 0 && segment.Count == segment.Array.Length) return segment.Array;

return segment.ToArray();
}

public static ArraySegment<Byte> ToArraySegment(this System.IO.MemoryStream m)
{
if (m.TryGetBuffer(out ArraySegment<Byte> data)) return data;
Expand Down
14 changes: 12 additions & 2 deletions src/SharpGLTF.Core/IO/ReadContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,22 @@ public static ReadContext CreateFromFile(string filePath)

public static ReadContext CreateFromDirectory(string directoryPath)
{
return new ReadContext(assetFileName => new BYTES(File.ReadAllBytes(Path.Combine(directoryPath, assetFileName))));
BYTES _loadFile(string rawUri)
{
var path = Uri.UnescapeDataString(rawUri);
path = Path.Combine(directoryPath, path);

var content = File.ReadAllBytes(path);

return new BYTES(content);
}

return new ReadContext(_loadFile);
}

public static ReadContext CreateFromDictionary(IReadOnlyDictionary<string, BYTES> dictionary)
{
return new ReadContext(fn => dictionary[fn]);
return new ReadContext(rawUri => dictionary[rawUri]);
}

private ReadContext(FileReaderCallback reader)
Expand Down
16 changes: 12 additions & 4 deletions src/SharpGLTF.Core/IO/WriteContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,19 @@ public static WriteContext CreateFromFile(string filePath)
return CreateFromDirectory(dir);
}

public static WriteContext CreateFromDirectory(string dirPath)
public static WriteContext CreateFromDirectory(string directoryPath)
{
Guard.DirectoryPathMustExist(dirPath, nameof(dirPath));
Guard.DirectoryPathMustExist(directoryPath, nameof(directoryPath));

var context = Create((fn, d) => File.WriteAllBytes(Path.Combine(dirPath, fn), d.ToArray()));
void _saveFile(string rawUri, BYTES data)
{
var path = Uri.UnescapeDataString(rawUri);
path = Path.Combine(directoryPath, path);

File.WriteAllBytes(path, data.ToUnderlayingArray());
}

var context = Create(_saveFile);
context.ImageWriting = ResourceWriteMode.SatelliteFile;
context.JsonIndented = true;
return context;
Expand All @@ -60,7 +68,7 @@ public static WriteContext CreateFromDictionary(IDictionary<string, BYTES> dict)
{
Guard.NotNull(dict, nameof(dict));

var context = Create((fn, buff) => dict[fn] = buff);
var context = Create((rawUri, data) => dict[rawUri] = data);
context.ImageWriting = ResourceWriteMode.SatelliteFile;
context.MergeBuffers = false;
context.JsonIndented = false;
Expand Down
15 changes: 9 additions & 6 deletions src/SharpGLTF.Core/Schema2/gltf.Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ internal void _ResolveUri(IO.ReadContext context)
{
_Content = _LoadBinaryBufferUnchecked(_uri, context);

// if (_uri == null) _byteLength = _Content.Length; // fixes "valid_placeholder.glb" case

_uri = null; // When _Data is not empty, clear URI
}

private static Byte[] _LoadBinaryBufferUnchecked(string uri, IO.ReadContext context)
{
return uri.TryParseBase64Unchecked(EMBEDDEDGLTFBUFFER, EMBEDDEDOCTETSTREAM) ?? context.ReadAllBytesToEnd(uri).ToArray();
var data = uri.TryParseBase64Unchecked(EMBEDDEDGLTFBUFFER, EMBEDDEDOCTETSTREAM);
if (data != null) return data;

return context
.ReadAllBytesToEnd(uri)
.ToUnderlayingArray();
}

#endregion
Expand All @@ -69,10 +72,10 @@ private static Byte[] _LoadBinaryBufferUnchecked(string uri, IO.ReadContext cont
/// <param name="satelliteUri">A local satellite URI</param>
internal void _WriteToSatellite(IO.WriteContext writer, string satelliteUri)
{
this._uri = satelliteUri;
this._byteLength = _Content.Length;
writer.WriteAllBytesToEnd(satelliteUri, new ArraySegment<byte>(_Content.GetPaddedContent()));

writer.WriteAllBytesToEnd(satelliteUri, new ArraySegment<byte>(_Content.GetPaddedContent()) );
this._uri = Uri.EscapeDataString(satelliteUri);
this._byteLength = _Content.Length;
}

/// <summary>
Expand Down
36 changes: 15 additions & 21 deletions src/SharpGLTF.Core/Schema2/gltf.Images.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,17 @@ internal void _ResolveUri(IO.ReadContext context)
{
if (String.IsNullOrWhiteSpace(_uri)) return;

byte[] data = null;

try
{
data = Memory.MemoryImage.TryParseBytes(_uri);
}
catch (ArgumentException argex)
{
throw new Validation.DataException(this, argex.Message);
}
var data = Memory.MemoryImage.TryParseBytes(_uri);

if (data == null)
{
var bytes = context.ReadAllBytesToEnd(_uri);

// let's try to avoid making a copy if it's not neccesary.
if (bytes.Offset == 0 && bytes.Array.Length == bytes.Count) data = bytes.Array;
else data = bytes.ToArray();
data = context
.ReadAllBytesToEnd(_uri)
.ToUnderlayingArray();
}

_SatelliteImageContent = data;

_uri = null;
_mimeType = null;
}
Expand All @@ -226,8 +216,9 @@ internal void _WriteToInternal()
if (_SatelliteImageContent == null) { _WriteAsBufferView(); return; }

var imimg = new Memory.MemoryImage(_SatelliteImageContent);
_mimeType = imimg.MimeType;

_uri = imimg.ToMime64();
_mimeType = imimg.MimeType;
}

/// <summary>
Expand All @@ -243,13 +234,15 @@ internal void _WriteToSatellite(IO.WriteContext writer, string satelliteUri)
return;
}

_mimeType = null;

var imimg = new Memory.MemoryImage(_SatelliteImageContent);
if (!imimg.IsValid) throw new InvalidOperationException();

_uri = System.IO.Path.ChangeExtension(satelliteUri, imimg.FileExtension);
writer.WriteAllBytesToEnd(_uri, imimg.GetBuffer());
satelliteUri = System.IO.Path.ChangeExtension(satelliteUri, imimg.FileExtension);

writer.WriteAllBytesToEnd(satelliteUri, imimg.GetBuffer());

_uri = Uri.EscapeDataString(satelliteUri);
_mimeType = null;
}

private void _WriteAsBufferView()
Expand All @@ -259,6 +252,7 @@ private void _WriteAsBufferView()
var imimg = this.MemoryImage;
if (!imimg.IsValid) throw new InvalidOperationException();

_uri = null;
_mimeType = imimg.MimeType;
}

Expand All @@ -269,8 +263,8 @@ private void _WriteAsBufferView()
/// </summary>
internal void _ClearAfterWrite()
{
_mimeType = null;
_uri = null;
_mimeType = null;
}

#endregion
Expand Down
4 changes: 3 additions & 1 deletion src/SharpGLTF.Toolkit/IO/Zip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ private ModelRoot _LoadSchema2(string gltfFile, ReadSettings settings = null)
}
}

private ArraySegment<Byte> _ReadAsset(string filePath)
private ArraySegment<Byte> _ReadAsset(string rawUri)
{
var filePath = Uri.UnescapeDataString(rawUri);

System.IO.Compression.ZipArchiveEntry entry = _FindEntry(filePath);

using (var s = entry.Open())
Expand Down
4 changes: 2 additions & 2 deletions src/SharpGLTF.Toolkit/Scenes/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ and how you want to render it, so every AddMesh method adds an mesh instance to

```c#
scene = new SceneBuilder();
scene.AddMesh(...);
scene.AddMesh(...);
scene.AddRigidMesh(...);
scene.AddRigidMesh(...);
scene.AddSkinnedMesh(...);
scene.SaveGLB("scene.glb");
```
Expand Down
3 changes: 3 additions & 0 deletions tests/Assets/white space.gltf
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
"images": [
{
"uri": "white space.jpg"
},
{
"uri": "white%20space.jpg"
}
]
}
2 changes: 1 addition & 1 deletion tests/SharpGLTF.NUnit/gltf_validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ internal ValidationReport(string srcPath, string rawReport)
public bool HasWarnings => Warnings.Count > 0;
public bool HasErrors => Errors.Count > 0;

public string ToString()
public override string ToString()
{
return RawReport;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void CreateSceneWithWithLightsExtension()
.PunctualLight = root.CreatePunctualLight(PunctualLightType.Directional)
.WithColor(Vector3.UnitX, 2);

var node2 = scene.CreateNode()
scene.CreateNode()
.PunctualLight = root.CreatePunctualLight(PunctualLightType.Spot)
.WithColor(Vector3.UnitY, 3, 10)
.WithSpotCone(0.2f, 0.3f);
Expand Down Expand Up @@ -79,7 +79,7 @@ public void CreateSceneWithSpecularGlossinessExtension()
);

var scene = new Scenes.SceneBuilder();
scene.AddMesh(mesh, Matrix4x4.Identity);
scene.AddRigidMesh(mesh, Matrix4x4.Identity);

scene.AttachToCurrentTest("result.glb");
scene.AttachToCurrentTest("result.gltf");
Expand Down Expand Up @@ -115,7 +115,7 @@ public void CreateSceneWithClearCoatExtension()
);

var scene = new Scenes.SceneBuilder();
scene.AddMesh(mesh, Matrix4x4.Identity);
scene.AddRigidMesh(mesh, Matrix4x4.Identity);

scene.AttachToCurrentTest("result.glb");
scene.AttachToCurrentTest("result.gltf");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public void Setup()
#endregion

[Test]
public void LoadWithWhiteSpaceTexture()
public void LoadEscapedUriModel()
{
TestContext.CurrentContext.AttachShowDirLink();

Expand Down
5 changes: 2 additions & 3 deletions tests/SharpGLTF.Tests/Validation/InvalidFilesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void CheckInvalidFiles()

foreach (var f in files)
{
// System.Diagnostics.Debug.Assert(!f.EndsWith("unresolved_source.gltf"));
// System.Diagnostics.Debug.Assert(!f.EndsWith("invalid_uri_scheme.gltf"));

var gltfJson = f.EndsWith(".gltf") ? System.IO.File.ReadAllText(f) : string.Empty;

Expand All @@ -76,7 +76,6 @@ public void CheckInvalidFiles()

Assert.AreEqual(report.Issues.NumErrors > 0, result.HasErrors);
}
}

}
}
}
2 changes: 1 addition & 1 deletion tests/SharpGLTF.Toolkit.Tests/Scenes/SceneBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ public void TestCreateEmptyMesh()
// create a scenebuilder with an empty mesh
var sb = new SceneBuilder();

sb.AddMesh(VPOSNRM.CreateCompatibleMesh("Empty"), Matrix4x4.Identity);
sb.AddRigidMesh(VPOSNRM.CreateCompatibleMesh("Empty"), Matrix4x4.Identity);

var schema = sb.ToGltf2();

Expand Down

0 comments on commit f7fafa8

Please sign in to comment.