Merge pull request #1471 from ousttrue/fix/glb_parse_check

glb parse の throw を更新
This commit is contained in:
ousttrue 2022-01-18 21:33:07 +09:00 committed by GitHub
commit 3e8a2e7ee0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 107 deletions

View File

@ -24,30 +24,6 @@ namespace UniGLTF
s.Write(GLB_VERSION, 0, GLB_VERSION.Length);
}
public static int TryParse(ArraySegment<Byte> 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<byte>(bytes));
}
public static Glb Parse(ArraySegment<Byte> 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<byte>(bytes), out glb, out ex);
}
public static bool TryParse(ArraySegment<Byte> 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<GlbChunk>();
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;
}
}
}
}

View File

@ -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<GlbChunk> 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<GlbChunk>();

View File

@ -14,4 +14,12 @@ namespace UniGLTF
public UniGLTFNotSupportedException(string fmt, params object[] args) : this(string.Format(fmt, args)) { }
public UniGLTFNotSupportedException(string msg) : base(msg) { }
}
/// <summary>
/// Exception in parse the glb header
/// </summary>
public class GlbParseException : UniGLTFException
{
public GlbParseException(string msg) : base(msg) { }
}
}

View File

@ -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);
}
/// <summary>
/// ヘッダが正しいが、後ろが切れている場合に throw する
/// </summary>
[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<GlbParseException>(() =>
{
// 再パース
var data2 = new GlbBinaryParser(mod, Path.GetFileNameWithoutExtension(path)).Parse();
});
}
}
}
}

View File

@ -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,