|
|
@@ -1,7 +1,9 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Runtime.InteropServices;
|
|
|
+using System.Linq;
|
|
|
using System.Text;
|
|
|
+using System.Text.Json;
|
|
|
|
|
|
namespace SharpGLTF
|
|
|
{
|
|
|
@@ -42,83 +44,141 @@ namespace SharpGLTF
|
|
|
if (!System.IO.Path.IsPathRooted(gltfFilePath)) gltfFilePath = System.IO.Path.GetFullPath(gltfFilePath);
|
|
|
|
|
|
var psi = new System.Diagnostics.ProcessStartInfo(ValidatorExePath);
|
|
|
- psi.Arguments = $"-p -r -a \"{gltfFilePath}\"";
|
|
|
- psi.UseShellExecute = false;
|
|
|
- psi.RedirectStandardError = true;
|
|
|
+ psi.Arguments = $"-p -r -a --stdout \"{gltfFilePath}\"";
|
|
|
+ psi.UseShellExecute = false;
|
|
|
+ psi.RedirectStandardOutput = true;
|
|
|
|
|
|
using (var p = System.Diagnostics.Process.Start(psi))
|
|
|
{
|
|
|
- if (!p.WaitForExit(1000 * 10))
|
|
|
+ if (!p.WaitForExit(1000 * 10)) // wait for a reasonable timeout
|
|
|
{
|
|
|
- try { p.Kill(); } catch { }
|
|
|
+ try { p.Kill(); } catch { return null; }
|
|
|
}
|
|
|
|
|
|
- var rawReport = p.StandardError.ReadToEnd();
|
|
|
+ var mainReport = p.StandardOutput.ReadToEnd();
|
|
|
+ if (string.IsNullOrWhiteSpace(mainReport)) return null;
|
|
|
+ var report = ValidationReport.Parse(mainReport);
|
|
|
+
|
|
|
+ if (report.Messages.Any(item => item.Code == "UNSUPPORTED_EXTENSION")) return null;
|
|
|
|
|
|
- if (string.IsNullOrWhiteSpace(rawReport)) return null;
|
|
|
-
|
|
|
- return new ValidationReport(gltfFilePath, rawReport);
|
|
|
+ return report;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Represents the report generated by glTF validator
|
|
|
+ /// </summary>
|
|
|
+ /// <see href="https://github.com/KhronosGroup/glTF-Validator/blob/898f53944b40650aacef550c4977de04c46990ab/docs/validation.schema.json"/>
|
|
|
public sealed class ValidationReport
|
|
|
{
|
|
|
- internal ValidationReport(string srcPath, string rawReport)
|
|
|
+ public static ValidationReport Parse(string json)
|
|
|
{
|
|
|
- var lines = rawReport.Split('\n');
|
|
|
-
|
|
|
- var status = 0;
|
|
|
+ var options = new JsonSerializerOptions();
|
|
|
+ options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
|
|
|
|
|
- var www = new List<string>();
|
|
|
- var eee = new List<string>();
|
|
|
+ return JsonSerializer.Deserialize<ValidationReport>(json, options);
|
|
|
+ }
|
|
|
|
|
|
- foreach (var l in lines)
|
|
|
- {
|
|
|
- if (l == "\tWarnings:") { status = 1; continue; }
|
|
|
- if (l == "\tErrors:") { status = 2; continue; }
|
|
|
+ public string Uri { get; set; }
|
|
|
+ public string MimeType { get; set; }
|
|
|
+ public string ValidatorVersion { get; set; }
|
|
|
+ public string ValidatedAt { get; set; }
|
|
|
+ public ValidationIssues Issues { get; set; }
|
|
|
+ public ValidationInfo Info { get; set; }
|
|
|
|
|
|
- if (status == 1) www.Add(l.Trim());
|
|
|
- if (status == 2) eee.Add(l.Trim());
|
|
|
- }
|
|
|
+ public bool HasWarnings => Issues.NumWarnings > 0;
|
|
|
+ public bool HasErrors => Issues.NumErrors > 0;
|
|
|
|
|
|
- FilePath = srcPath;
|
|
|
- RawReport = rawReport;
|
|
|
- Warnings = www;
|
|
|
- Errors = eee;
|
|
|
- }
|
|
|
+ public IEnumerable<ValidationMessage> Messages => Issues.Messages == null
|
|
|
+ ? Enumerable.Empty<ValidationMessage>()
|
|
|
+ : Issues.Messages;
|
|
|
|
|
|
- public string RawReport { get; private set; }
|
|
|
+ public IEnumerable<String> Hints => Messages
|
|
|
+ .Where(item => item.Severity == 3)
|
|
|
+ .Select(item => item.Message);
|
|
|
|
|
|
- public readonly IReadOnlyList<String> Warnings;
|
|
|
- public readonly IReadOnlyList<String> Errors;
|
|
|
+ public IEnumerable<String> Infos => Messages
|
|
|
+ .Where(item => item.Severity == 2)
|
|
|
+ .Select(item => item.Message);
|
|
|
|
|
|
- public string FilePath { get; private set; }
|
|
|
+ public IEnumerable<String> Warnings => Messages
|
|
|
+ .Where(item => item.Severity == 1)
|
|
|
+ .Select(item => item.Message);
|
|
|
|
|
|
- public bool HasWarnings => Warnings.Count > 0;
|
|
|
- public bool HasErrors => Errors.Count > 0;
|
|
|
+ public IEnumerable<String> Errors => Messages
|
|
|
+ .Where(item => item.Severity == 0)
|
|
|
+ .Select(item => item.Message);
|
|
|
|
|
|
public override string ToString()
|
|
|
{
|
|
|
- return RawReport;
|
|
|
+ var options = new JsonSerializerOptions();
|
|
|
+ options.WriteIndented = true;
|
|
|
+ options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
|
|
+ return JsonSerializer.Serialize(this, options);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- var sb = new StringBuilder();
|
|
|
+ public sealed class ValidationIssues
|
|
|
+ {
|
|
|
+ public int NumErrors { get; set; }
|
|
|
+ public int NumWarnings { get; set; }
|
|
|
+ public int NumInfos { get; set; }
|
|
|
+ public int NumHints { get; set; }
|
|
|
+ public ValidationMessage[] Messages { get; set; }
|
|
|
+ public bool Truncated { get; set; }
|
|
|
+ }
|
|
|
|
|
|
- sb.AppendLine(FilePath);
|
|
|
+ public sealed class ValidationMessage
|
|
|
+ {
|
|
|
+ public string Code { get; set; }
|
|
|
+ public string Message { get; set; }
|
|
|
+ public int Severity { get; set; }
|
|
|
+ public string Pointer { get; set; }
|
|
|
+ public int? Offset { get; set; }
|
|
|
+ }
|
|
|
|
|
|
- if (HasWarnings)
|
|
|
- {
|
|
|
- sb.AppendLine("\tWarnings:");
|
|
|
- foreach (var w in Warnings) sb.AppendLine($"\t\t{w}");
|
|
|
- }
|
|
|
+ public sealed class ValidationInfo
|
|
|
+ {
|
|
|
+ public string Version { get; set; }
|
|
|
+ public string MinVersion { get; set; }
|
|
|
+ public string Generator { get; set; }
|
|
|
+ public string[] ExtensionsUsed { get; set; }
|
|
|
+ public string[] ExtensionsRequired { get; set; }
|
|
|
+ public ValidationResources[] Resources { get; set; }
|
|
|
+ public int AnimationCount { get; set; }
|
|
|
+ public int MaterialCount { get; set; }
|
|
|
+ public bool HasMorphTargets { get; set; }
|
|
|
+ public bool HasSkins { get; set; }
|
|
|
+ public bool HasTextures { get; set; }
|
|
|
+ public bool HasDefaultScene { get; set; }
|
|
|
+ public int DrawCallCount { get; set; }
|
|
|
+ public int TotalVertexCount { get; set; }
|
|
|
+ public int TotalTriangleCount { get; set; }
|
|
|
+ public int MaxUVs { get; set; }
|
|
|
+ public int MaxInfluences { get; set; }
|
|
|
+ public int MaxAttributes { get; set; }
|
|
|
+ }
|
|
|
|
|
|
- if (HasErrors)
|
|
|
- {
|
|
|
- sb.AppendLine("\tErrors:");
|
|
|
- foreach (var e in Errors) sb.AppendLine($"\t\t{e}");
|
|
|
- }
|
|
|
+ public sealed class ValidationResources
|
|
|
+ {
|
|
|
+ public string Pointer { get; set; }
|
|
|
+ public string Storage { get; set; }
|
|
|
+ public string MimeType { get; set; }
|
|
|
+ public string Uri { get; set; }
|
|
|
+ public int ByteLength { get; set; }
|
|
|
+ public ValidationImage Image { get; set; }
|
|
|
+ }
|
|
|
|
|
|
- return sb.ToString();
|
|
|
- }
|
|
|
+ public sealed class ValidationImage
|
|
|
+ {
|
|
|
+ public int Width { get; set; }
|
|
|
+ public int Height { get; set; }
|
|
|
+ public string Format { get; set; }
|
|
|
+ public string Primaries { get; set; }
|
|
|
+ public string Transfer { get; set; }
|
|
|
+ public int Bits { get; set; }
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
}
|