diff --git a/Assets/UniGLTF/Runtime/UniGLTF/Format/glbTypes.cs b/Assets/UniGLTF/Runtime/UniGLTF/Format/glbTypes.cs index 59c352a4c..9628e9344 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/Format/glbTypes.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/Format/glbTypes.cs @@ -24,30 +24,6 @@ namespace UniGLTF s.Write(GLB_VERSION, 0, GLB_VERSION.Length); } - public static int TryParse(ArraySegment bytes, out int pos, out Exception message) - { - pos = 0; - - if (!bytes.Slice(0, 4).SequenceEqual(GLB_MAGIC)) - { - message = new FormatException("invalid magic"); - return 0; - } - pos += 4; - - if (!bytes.Slice(pos, 4).SequenceEqual(GLB_VERSION)) - { - message = new FormatException("invalid magic"); - return 0; - } - pos += 4; - - var totalLength = BitConverter.ToInt32(bytes.Array, bytes.Offset + pos); - pos += 4; - - message = null; - return totalLength; - } } public struct GlbChunk @@ -219,75 +195,5 @@ namespace UniGLTF throw new FormatException("unknown chunk type: " + src); } } - - public static Glb Parse(Byte[] bytes) - { - return Parse(new ArraySegment(bytes)); - } - - public static Glb Parse(ArraySegment bytes) - { - if (TryParse(bytes, out Glb glb, out Exception ex)) - { - return glb; - } - else - { - throw ex; - } - } - - public static bool TryParse(Byte[] bytes, out Glb glb, out Exception ex) - { - return TryParse(new ArraySegment(bytes), out glb, out ex); - } - - public static bool TryParse(ArraySegment bytes, out Glb glb, out Exception ex) - { - glb = default(Glb); - if (bytes.Count == 0) - { - ex = new Exception("empty bytes"); - return false; - } - - var length = GlbHeader.TryParse(bytes, out int pos, out ex); - if (length == 0) - { - return false; - } - bytes = bytes.Slice(0, length); - - try - { - var chunks = new List(); - while (pos < bytes.Count) - { - var chunkDataSize = BitConverter.ToInt32(bytes.Array, bytes.Offset + pos); - pos += 4; - - //var type = (GlbChunkType)BitConverter.ToUInt32(bytes, pos); - var chunkTypeBytes = bytes.Slice(pos, 4).Where(x => x != 0).ToArray(); - var chunkTypeStr = Encoding.ASCII.GetString(chunkTypeBytes); - pos += 4; - - chunks.Add(new GlbChunk - { - ChunkTypeString = chunkTypeStr, - Bytes = bytes.Slice(pos, chunkDataSize) - }); - - pos += chunkDataSize; - } - - glb = new Glb(chunks[0], chunks[1]); - return true; - } - catch (Exception _ex) - { - ex = _ex; - return false; - } - } } } diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/glbImporter.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/glbImporter.cs index d6415a0de..ac3eabf2d 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/glbImporter.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/glbImporter.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using UnityEngine; namespace UniGLTF @@ -14,7 +13,7 @@ namespace UniGLTF public static GlbChunkType ToChunkType(this string src) { - switch(src) + switch (src) { case "BIN": return GlbChunkType.BIN; @@ -48,27 +47,33 @@ namespace UniGLTF public static List ParseGlbChunks(Byte[] bytes) { - if (bytes.Length == 0) + // + // glb header(12byte) + // + if (bytes.Length < 12) { - throw new Exception("empty bytes"); + throw new GlbParseException("glb header not found"); } int pos = 0; if (Encoding.ASCII.GetString(bytes, 0, 4) != GLB_MAGIC) { - throw new Exception("invalid magic"); + throw new GlbParseException("invalid magic"); } pos += 4; var version = BitConverter.ToUInt32(bytes, pos); if (version != GLB_VERSION) { - Debug.LogWarningFormat("unknown version: {0}", version); - return null; + throw new GlbParseException($"unknown version: {version}"); } pos += 4; - //var totalLength = BitConverter.ToUInt32(bytes, pos); + var totalLength = BitConverter.ToUInt32(bytes, pos); + if (bytes.Length < totalLength) + { + throw new GlbParseException($"not enough size: {bytes.Length} < {totalLength}"); + } pos += 4; var chunks = new List(); diff --git a/Assets/UniGLTF/Runtime/UniGLTF/UniGLTFException.cs b/Assets/UniGLTF/Runtime/UniGLTF/UniGLTFException.cs index fde2faaf8..8522e2201 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/UniGLTFException.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/UniGLTFException.cs @@ -14,4 +14,12 @@ namespace UniGLTF public UniGLTFNotSupportedException(string fmt, params object[] args) : this(string.Format(fmt, args)) { } public UniGLTFNotSupportedException(string msg) : base(msg) { } } + + /// + /// Exception in parse the glb header + /// + public class GlbParseException : UniGLTFException + { + public GlbParseException(string msg) : base(msg) { } + } } diff --git a/Assets/UniGLTF/Tests/UniGLTF/GlbParserTests.cs b/Assets/UniGLTF/Tests/UniGLTF/GlbParserTests.cs index 3acbc4a65..9c36ec786 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/GlbParserTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/GlbParserTests.cs @@ -1,4 +1,6 @@ using System; +using System.IO; +using System.Linq; using NUnit.Framework; namespace UniGLTF @@ -37,5 +39,38 @@ namespace UniGLTF // NOTE: 大文字小文字が違うだけの名前は、同一としてみなされ、Suffix が付く。 Assert.AreEqual("foobar__UNIGLTF__DUPLICATED__2", parsed.GLTF.textures[1].name); } + + /// + /// ヘッダが正しいが、後ろが切れている場合に throw する + /// + [Test] + public void GlbLengthTest() + { + var env = System.Environment.GetEnvironmentVariable("GLTF_SAMPLE_MODELS"); + if (string.IsNullOrEmpty(env)) + { + return; + } + var root = new DirectoryInfo($"{env}/2.0"); + if (!root.Exists) + { + return; + } + + var path = Path.Combine(root.ToString(), "DamagedHelmet\\glTF-Binary\\DamagedHelmet.glb"); + Assert.True(File.Exists(path)); + + var bytes = File.ReadAllBytes(path); + var data = new GlbBinaryParser(bytes, Path.GetFileNameWithoutExtension(path)).Parse(); + + // glb header + 1st chunk only + var mod = bytes.Take(12 + 8 + data.Chunks[0].Bytes.Count).ToArray(); + + Assert.Throws(() => + { + // 再パース + var data2 = new GlbBinaryParser(mod, Path.GetFileNameWithoutExtension(path)).Parse(); + }); + } } -} \ No newline at end of file +} diff --git a/Assets/VRM10/Tests/MigrationTests.cs b/Assets/VRM10/Tests/MigrationTests.cs index 21ea537c2..d1c8f7763 100644 --- a/Assets/VRM10/Tests/MigrationTests.cs +++ b/Assets/VRM10/Tests/MigrationTests.cs @@ -22,8 +22,8 @@ namespace UniVRM10 static JsonNode GetVRM0(byte[] bytes) { - var glb = UniGLTF.Glb.Parse(bytes); - var json = glb.Json.Bytes.ParseAsJson(); + var glb = new GlbBinaryParser(bytes, "vrm0").Parse(); + var json = glb.Json.ParseAsJson(); return json["extensions"]["VRM"]; } @@ -50,8 +50,8 @@ namespace UniVRM10 var vrm0Json = GetVRM0(vrm0Bytes); var vrm1 = MigrationVrm.Migrate(vrm0Bytes); - var glb = UniGLTF.Glb.Parse(vrm1); - var json = glb.Json.Bytes.ParseAsJson(); + var glb = new GlbBinaryParser(vrm1, "vrm1").Parse(); + var json = glb.Json.ParseAsJson(); var gltf = UniGLTF.GltfDeserializer.Deserialize(json); MigrationVrm.Check(vrm0Json, GetExtension(gltf.extensions, UniGLTF.Extensions.VRMC_vrm.GltfDeserializer.ExtensionNameUtf8,