|
@@ -51,6 +51,33 @@ namespace SharpGLTF.Schema2
|
|
|
|
|
|
|
|
partial class ModelRoot
|
|
partial class ModelRoot
|
|
|
{
|
|
{
|
|
|
|
|
+ #region validate
|
|
|
|
|
+
|
|
|
|
|
+ public static Validation.ValidationResult Validate(string filePath)
|
|
|
|
|
+ {
|
|
|
|
|
+ Guard.FilePathMustExist(filePath, nameof(filePath));
|
|
|
|
|
+
|
|
|
|
|
+ var settings = new ReadSettings(filePath);
|
|
|
|
|
+
|
|
|
|
|
+ using (var stream = File.OpenRead(filePath))
|
|
|
|
|
+ {
|
|
|
|
|
+ bool binaryFile = glb._Identify(stream);
|
|
|
|
|
+
|
|
|
|
|
+ if (binaryFile) return _ReadGLB(stream, settings).Item2;
|
|
|
|
|
+
|
|
|
|
|
+ string content = null;
|
|
|
|
|
+
|
|
|
|
|
+ using (var streamReader = new StreamReader(stream))
|
|
|
|
|
+ {
|
|
|
|
|
+ content = streamReader.ReadToEnd();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return _ParseGLTF(content, settings).Item2;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #endregion
|
|
|
|
|
+
|
|
|
#region read / load methods
|
|
#region read / load methods
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -130,27 +157,11 @@ namespace SharpGLTF.Schema2
|
|
|
/// <returns>A <see cref="MODEL"/> instance.</returns>
|
|
/// <returns>A <see cref="MODEL"/> instance.</returns>
|
|
|
public static MODEL ReadGLB(Stream stream, ReadSettings settings)
|
|
public static MODEL ReadGLB(Stream stream, ReadSettings settings)
|
|
|
{
|
|
{
|
|
|
- Guard.NotNull(stream, nameof(stream));
|
|
|
|
|
- Guard.NotNull(settings, nameof(settings));
|
|
|
|
|
-
|
|
|
|
|
- var chunks = glb.ReadBinaryFile(stream);
|
|
|
|
|
-
|
|
|
|
|
- var dom = Encoding.UTF8.GetString(chunks[glb.CHUNKJSON]);
|
|
|
|
|
|
|
+ var mv = _ReadGLB(stream, settings);
|
|
|
|
|
|
|
|
- if (chunks.ContainsKey(glb.CHUNKBIN))
|
|
|
|
|
- {
|
|
|
|
|
- var sourceReader = settings.FileReader;
|
|
|
|
|
|
|
+ if (mv.Item2.HasErrors) throw mv.Item2.Errors.FirstOrDefault();
|
|
|
|
|
|
|
|
- settings.FileReader =
|
|
|
|
|
- key =>
|
|
|
|
|
- string.IsNullOrEmpty(key)
|
|
|
|
|
- ?
|
|
|
|
|
- new BYTES(chunks[glb.CHUNKBIN])
|
|
|
|
|
- :
|
|
|
|
|
- sourceReader.Invoke(key);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return ParseGLTF(dom, settings);
|
|
|
|
|
|
|
+ return mv.Item1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
@@ -161,13 +172,11 @@ namespace SharpGLTF.Schema2
|
|
|
/// <returns>A <see cref="MODEL"/> instance.</returns>
|
|
/// <returns>A <see cref="MODEL"/> instance.</returns>
|
|
|
public static MODEL ParseGLTF(String jsonContent, ReadSettings settings)
|
|
public static MODEL ParseGLTF(String jsonContent, ReadSettings settings)
|
|
|
{
|
|
{
|
|
|
- Guard.NotNullOrEmpty(jsonContent, nameof(jsonContent));
|
|
|
|
|
- Guard.NotNull(settings, nameof(settings));
|
|
|
|
|
|
|
+ var mv = _ParseGLTF(jsonContent, settings);
|
|
|
|
|
|
|
|
- using (var tr = new StringReader(jsonContent))
|
|
|
|
|
- {
|
|
|
|
|
- return _Read(tr, settings);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (mv.Item2.HasErrors) throw mv.Item2.Errors.FirstOrDefault();
|
|
|
|
|
+
|
|
|
|
|
+ return mv.Item1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static MODEL ReadFromDictionary(Dictionary<string, BYTES> files, string fileName)
|
|
public static MODEL ReadFromDictionary(Dictionary<string, BYTES> files, string fileName)
|
|
@@ -180,9 +189,13 @@ namespace SharpGLTF.Schema2
|
|
|
|
|
|
|
|
using (var m = new MemoryStream(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count))
|
|
using (var m = new MemoryStream(jsonBytes.Array, jsonBytes.Offset, jsonBytes.Count))
|
|
|
{
|
|
{
|
|
|
- using (var s = new StreamReader(m))
|
|
|
|
|
|
|
+ using (var tr = new StreamReader(m))
|
|
|
{
|
|
{
|
|
|
- return _Read(s, settings);
|
|
|
|
|
|
|
+ var mv = _Read(tr, settings);
|
|
|
|
|
+
|
|
|
|
|
+ if (mv.Item2.HasErrors) throw mv.Item2.Errors.FirstOrDefault();
|
|
|
|
|
+
|
|
|
|
|
+ return mv.Item1;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -191,7 +204,43 @@ namespace SharpGLTF.Schema2
|
|
|
|
|
|
|
|
#region reading core
|
|
#region reading core
|
|
|
|
|
|
|
|
- private static MODEL _Read(TextReader textReader, ReadSettings settings)
|
|
|
|
|
|
|
+ private static (MODEL, Validation.ValidationResult) _ReadGLB(Stream stream, ReadSettings settings)
|
|
|
|
|
+ {
|
|
|
|
|
+ Guard.NotNull(stream, nameof(stream));
|
|
|
|
|
+ Guard.NotNull(settings, nameof(settings));
|
|
|
|
|
+
|
|
|
|
|
+ var chunks = glb.ReadBinaryFile(stream);
|
|
|
|
|
+
|
|
|
|
|
+ var dom = Encoding.UTF8.GetString(chunks[glb.CHUNKJSON]);
|
|
|
|
|
+
|
|
|
|
|
+ if (chunks.ContainsKey(glb.CHUNKBIN))
|
|
|
|
|
+ {
|
|
|
|
|
+ var sourceReader = settings.FileReader;
|
|
|
|
|
+
|
|
|
|
|
+ settings.FileReader =
|
|
|
|
|
+ key =>
|
|
|
|
|
+ string.IsNullOrEmpty(key)
|
|
|
|
|
+ ?
|
|
|
|
|
+ new BYTES(chunks[glb.CHUNKBIN])
|
|
|
|
|
+ :
|
|
|
|
|
+ sourceReader.Invoke(key);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return _ParseGLTF(dom, settings);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static (MODEL, Validation.ValidationResult) _ParseGLTF(String jsonContent, ReadSettings settings)
|
|
|
|
|
+ {
|
|
|
|
|
+ Guard.NotNullOrEmpty(jsonContent, nameof(jsonContent));
|
|
|
|
|
+ Guard.NotNull(settings, nameof(settings));
|
|
|
|
|
+
|
|
|
|
|
+ using (var tr = new StringReader(jsonContent))
|
|
|
|
|
+ {
|
|
|
|
|
+ return _Read(tr, settings);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static (MODEL, Validation.ValidationResult) _Read(TextReader textReader, ReadSettings settings)
|
|
|
{
|
|
{
|
|
|
Guard.NotNull(textReader, nameof(textReader));
|
|
Guard.NotNull(textReader, nameof(textReader));
|
|
|
Guard.NotNull(settings, nameof(settings));
|
|
Guard.NotNull(settings, nameof(settings));
|
|
@@ -199,22 +248,31 @@ namespace SharpGLTF.Schema2
|
|
|
using (var reader = new JsonTextReader(textReader))
|
|
using (var reader = new JsonTextReader(textReader))
|
|
|
{
|
|
{
|
|
|
var root = new MODEL();
|
|
var root = new MODEL();
|
|
|
|
|
+ var vcontext = new Validation.ValidationResult(root);
|
|
|
|
|
+
|
|
|
|
|
+ if (!reader.Read())
|
|
|
|
|
+ {
|
|
|
|
|
+ vcontext.AddError(new Validation.ModelException(root, "Json is empty"));
|
|
|
|
|
+ return (null, vcontext);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
- reader.Read();
|
|
|
|
|
root.Deserialize(reader);
|
|
root.Deserialize(reader);
|
|
|
}
|
|
}
|
|
|
catch (JsonReaderException rex)
|
|
catch (JsonReaderException rex)
|
|
|
{
|
|
{
|
|
|
- throw new Validation.SchemaException(root, rex);
|
|
|
|
|
|
|
+ vcontext.AddError(new Validation.SchemaException(root, rex));
|
|
|
|
|
+ return (null, vcontext);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // reference checking is mandatory and cannot be skipped
|
|
|
|
|
- var result = new Validation.ValidationResult(root);
|
|
|
|
|
- root.ValidateReferences(result.GetContext(root));
|
|
|
|
|
- var ex = result.Errors.FirstOrDefault();
|
|
|
|
|
- if (ex != null) throw ex;
|
|
|
|
|
|
|
+ // schema validation
|
|
|
|
|
+
|
|
|
|
|
+ root.ValidateReferences(vcontext.GetContext(root));
|
|
|
|
|
+ var ex = vcontext.Errors.FirstOrDefault();
|
|
|
|
|
+ if (ex != null) return (null, vcontext);
|
|
|
|
|
+
|
|
|
|
|
+ // resolve external references
|
|
|
|
|
|
|
|
foreach (var buffer in root._buffers)
|
|
foreach (var buffer in root._buffers)
|
|
|
{
|
|
{
|
|
@@ -226,15 +284,16 @@ namespace SharpGLTF.Schema2
|
|
|
image._ResolveUri(settings.FileReader);
|
|
image._ResolveUri(settings.FileReader);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // full validation
|
|
|
|
|
+
|
|
|
if (!settings.SkipValidation)
|
|
if (!settings.SkipValidation)
|
|
|
{
|
|
{
|
|
|
- result = new Validation.ValidationResult(root);
|
|
|
|
|
- root.Validate(result.GetContext(root));
|
|
|
|
|
- ex = result.Errors.FirstOrDefault();
|
|
|
|
|
- if (ex != null) throw ex;
|
|
|
|
|
|
|
+ root.Validate(vcontext.GetContext(root));
|
|
|
|
|
+ ex = vcontext.Errors.FirstOrDefault();
|
|
|
|
|
+ if (ex != null) return (null, vcontext);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return root;
|
|
|
|
|
|
|
+ return (root, vcontext);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|