mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-05-19 17:27:56 -05:00
Merge pull request #1436 from ousttrue/fix/safe_marshal_copy
Marshal.Copy で問題が発生する前に throw する
This commit is contained in:
commit
4b61b3e5e8
|
|
@ -89,15 +89,6 @@ namespace UniGLTF
|
|||
|
||||
public static class ArrayExtensions
|
||||
{
|
||||
public static int MarshalCopyTo<T>(this ArraySegment<byte> src, T[] dst) where T : struct
|
||||
{
|
||||
var size = dst.Length * Marshal.SizeOf(typeof(T));
|
||||
using (var pin = Pin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(src.Array, src.Offset, pin.Ptr, size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static T[] SelectInplace<T>(this T[] src, Func<T, T> pred)
|
||||
{
|
||||
|
|
@ -107,21 +98,6 @@ namespace UniGLTF
|
|||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
public static void Copy<TFrom, TTo>(ArraySegment<TFrom> src, ArraySegment<TTo> dst)
|
||||
where TFrom : struct
|
||||
where TTo : struct
|
||||
{
|
||||
var bytes = new byte[src.Count * Marshal.SizeOf(typeof(TFrom))];
|
||||
using (var pin = Pin.Create(src))
|
||||
{
|
||||
Marshal.Copy(pin.Ptr, bytes, 0, bytes.Length);
|
||||
};
|
||||
using (var pin = Pin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(bytes, 0, pin.Ptr, bytes.Length);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListExtensions
|
||||
|
|
@ -134,7 +110,7 @@ namespace UniGLTF
|
|||
}
|
||||
|
||||
public static class ArraySegmentExtensions
|
||||
{
|
||||
{
|
||||
public static ArraySegment<T> Slice<T>(this ArraySegment<T> self, int start, int length)
|
||||
{
|
||||
if (start + length > self.Count)
|
||||
|
|
@ -156,6 +132,6 @@ namespace UniGLTF
|
|||
}
|
||||
return self.Slice(start, self.Count - start);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,30 +89,14 @@ namespace UniGLTF
|
|||
{
|
||||
public static int FromBytes<T>(this ArraySegment<byte> src, T[] dst) where T : struct
|
||||
{
|
||||
var dstSize = dst.Length * Marshal.SizeOf(typeof(T));
|
||||
if (src.Count > dstSize)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
using (var pin = ArrayPin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(src.Array, src.Offset, pin.Ptr, src.Count);
|
||||
}
|
||||
SafeMarshalCopy.CopyBytesToArray(src, dst);
|
||||
return src.Count;
|
||||
}
|
||||
|
||||
public static int ToBytes<T>(this T[] src, ArraySegment<byte> dst) where T : struct
|
||||
{
|
||||
var srcSize = src.Length * Marshal.SizeOf(typeof(T));
|
||||
if (srcSize > dst.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
using (var pin = ArrayPin.Create(src))
|
||||
{
|
||||
Marshal.Copy(pin.Ptr, dst.Array, dst.Offset, srcSize);
|
||||
}
|
||||
return srcSize;
|
||||
SafeMarshalCopy.CopyArrayToToBytes(src, dst);
|
||||
return dst.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace UniGLTF
|
|||
Byte[] m_bytes;
|
||||
int m_pos;
|
||||
|
||||
public BytesReader(Byte[] bytes, int pos=0)
|
||||
public BytesReader(Byte[] bytes, int pos = 0)
|
||||
{
|
||||
m_bytes = bytes;
|
||||
m_pos = pos;
|
||||
|
|
@ -63,8 +63,9 @@ namespace UniGLTF
|
|||
|
||||
public void ReadToArray<T>(T[] dst) where T : struct
|
||||
{
|
||||
var size = new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos).MarshalCopyTo(dst);
|
||||
m_pos += size;
|
||||
var bytes = new ArraySegment<Byte>(m_bytes, m_pos, m_bytes.Length - m_pos);
|
||||
SafeMarshalCopy.CopyBytesToArray(bytes, dst);
|
||||
m_pos += bytes.Count;
|
||||
}
|
||||
|
||||
public T ReadStruct<T>() where T : struct
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
|
|
@ -156,8 +157,8 @@ namespace UniGLTF
|
|||
{
|
||||
var segment = GetBytesFromBuffer(view.buffer);
|
||||
var attrib = new T[count];
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + byteOffset, count * view.byteStride);
|
||||
bytes.MarshalCopyTo(attrib);
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + byteOffset, count * Marshal.SizeOf<T>());
|
||||
SafeMarshalCopy.CopyBytesToArray(bytes, attrib);
|
||||
return attrib;
|
||||
}
|
||||
|
||||
|
|
@ -288,8 +289,8 @@ namespace UniGLTF
|
|||
var attrib = new float[vertexAccessor.count * vertexAccessor.TypeCount];
|
||||
var view = GLTF.bufferViews[vertexAccessor.bufferView];
|
||||
var segment = GetBytesFromBuffer(view.buffer);
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * view.byteStride);
|
||||
bytes.MarshalCopyTo(attrib);
|
||||
var bytes = new ArraySegment<Byte>(segment.Array, segment.Offset + view.byteOffset + vertexAccessor.byteOffset, vertexAccessor.count * 4 * vertexAccessor.TypeCount);
|
||||
SafeMarshalCopy.CopyBytesToArray(bytes, attrib);
|
||||
result = attrib;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
77
Assets/UniGLTF/Runtime/UniGLTF/IO/SafeMarshalCopy.cs
Normal file
77
Assets/UniGLTF/Runtime/UniGLTF/IO/SafeMarshalCopy.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UniGLTF
|
||||
{
|
||||
/// <summary>
|
||||
/// Marshal.Copy
|
||||
/// * ptr to bytes
|
||||
/// * bytes to ptr
|
||||
/// の両方向がある。
|
||||
/// ptr になったら範囲は分からん。
|
||||
/// ptr にする前に範囲チェックするのを明確にするのがこの Utility の意図である。
|
||||
///
|
||||
/// Marshal.Copy を使わずにこの関数を使うべし
|
||||
///
|
||||
/// </summary>
|
||||
public static class SafeMarshalCopy
|
||||
{
|
||||
/// <summary>
|
||||
/// bytes から T[] へのコピー
|
||||
/// </summary>
|
||||
public static void CopyBytesToArray<T>(ArraySegment<byte> src, T[] dst) where T : struct
|
||||
{
|
||||
if (src.Array == null || dst == null || src.Count == 0)
|
||||
{
|
||||
throw new System.ArgumentNullException();
|
||||
}
|
||||
if (src.Offset < 0)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyBytesToArray: ArraySegment: negative offset");
|
||||
}
|
||||
if ((src.Offset + src.Count) > src.Array.Length)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyBytesToArray: ArraySegment: exceed");
|
||||
}
|
||||
var dstByteSize = dst.Length * Marshal.SizeOf(typeof(T));
|
||||
if (src.Count > dstByteSize)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyBytesToArray: src > dst");
|
||||
}
|
||||
|
||||
using (var pin = Pin.Create(dst))
|
||||
{
|
||||
Marshal.Copy(src.Array, src.Offset, pin.Ptr, src.Count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// T[] から bytes へのコピー
|
||||
/// </summary>
|
||||
public static void CopyArrayToToBytes<T>(T[] src, ArraySegment<byte> dst) where T : struct
|
||||
{
|
||||
if (dst.Array == null || src == null || dst.Count == 0)
|
||||
{
|
||||
throw new System.ArgumentNullException();
|
||||
}
|
||||
if (dst.Offset < 0)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyArrayToToBytes: ArraySegment: negative offset");
|
||||
}
|
||||
if (dst.Offset + dst.Count > dst.Array.Length)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyArrayToToBytes: ArraySegment: exceed");
|
||||
}
|
||||
var srcByteSize = src.Length * Marshal.SizeOf(typeof(T));
|
||||
if (srcByteSize > dst.Count)
|
||||
{
|
||||
throw new System.AccessViolationException("CopyArrayToToBytes: src > dst");
|
||||
}
|
||||
|
||||
using (var pin = Pin.Create(src))
|
||||
{
|
||||
Marshal.Copy(pin.Ptr, dst.Array, dst.Offset, srcByteSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/UniGLTF/Runtime/UniGLTF/IO/SafeMarshalCopy.cs.meta
Normal file
11
Assets/UniGLTF/Runtime/UniGLTF/IO/SafeMarshalCopy.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 234ebccfeacecfe4da0351a092c985af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -32,8 +32,8 @@ TextureImporter:
|
|||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 0
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ TextureImporter:
|
|||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 0
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ TextureImporter:
|
|||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 0
|
||||
aniso: -1
|
||||
mipBias: -100
|
||||
wrapU: -1
|
||||
wrapV: -1
|
||||
wrapW: -1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 0
|
||||
wrapV: 0
|
||||
wrapW: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
|
|
|
|||
|
|
@ -121,10 +121,7 @@ namespace UniVRM10
|
|||
u.m33 = 15;
|
||||
Assert.AreEqual(new UnityEngine.Vector4(0, 1, 2, 3), u.GetRow(0));
|
||||
var bytes = new Byte[64];
|
||||
using (var pin = Pin.Create(new[] { u }))
|
||||
{
|
||||
Marshal.Copy(pin.Ptr, bytes, 0, 64);
|
||||
}
|
||||
SafeMarshalCopy.CopyArrayToToBytes(new[] { u }, new ArraySegment<byte>(bytes));
|
||||
Assert.AreEqual(1.0f, BitConverter.ToSingle(bytes, 16));
|
||||
}
|
||||
|
||||
|
|
@ -149,10 +146,7 @@ namespace UniVRM10
|
|||
u.M43 = 14;
|
||||
u.M44 = 15;
|
||||
var bytes = new Byte[64];
|
||||
using (var pin = Pin.Create(new[] { u }))
|
||||
{
|
||||
Marshal.Copy(pin.Ptr, bytes, 0, 64);
|
||||
}
|
||||
SafeMarshalCopy.CopyArrayToToBytes(new[] { u }, new ArraySegment<byte>(bytes));
|
||||
Assert.AreEqual(1.0f, BitConverter.ToSingle(bytes, 4));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user