mirror of https://github.com/dahall/Vanara.git
Added ToStructure method with boundary checking. Cleaned and optimized code.
parent
0644bcedfb
commit
427de28a0e
|
@ -23,7 +23,7 @@ namespace Vanara.Extensions
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero || length <= 0) return;
|
if (ptr == IntPtr.Zero || length <= 0) return;
|
||||||
// Write multiples of 8 bytes first
|
// Write multiples of 8 bytes first
|
||||||
var lval = value == 0 ? 0L : BitConverter.ToInt64(new byte[] { value, value, value, value, value, value, value, value }, 0);
|
var lval = value == 0 ? 0L : BitConverter.ToInt64(new[] { value, value, value, value, value, value, value, value }, 0);
|
||||||
for (var ofs = 0L; ofs < length / 8; ofs++)
|
for (var ofs = 0L; ofs < length / 8; ofs++)
|
||||||
Marshal.WriteInt64(ptr.Offset(ofs * 8), 0, lval);
|
Marshal.WriteInt64(ptr.Offset(ofs * 8), 0, lval);
|
||||||
// Write remaining bytes
|
// Write remaining bytes
|
||||||
|
@ -43,7 +43,8 @@ namespace Vanara.Extensions
|
||||||
{
|
{
|
||||||
if (lptr == IntPtr.Zero) return 0;
|
if (lptr == IntPtr.Zero) return 0;
|
||||||
var c = 0;
|
var c = 0;
|
||||||
while (Marshal.ReadIntPtr(lptr, IntPtr.Size * c++) != IntPtr.Zero) ;
|
while (Marshal.ReadIntPtr(lptr, IntPtr.Size * c++) != IntPtr.Zero) { }
|
||||||
|
|
||||||
return c - 1;
|
return c - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +53,8 @@ namespace Vanara.Extensions
|
||||||
/// <returns><c>true</c> if the specified type is blittable; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified type is blittable; otherwise, <c>false</c>.</returns>
|
||||||
public static bool IsBlittable(this Type T)
|
public static bool IsBlittable(this Type T)
|
||||||
{
|
{
|
||||||
|
if (T is null) return false;
|
||||||
|
|
||||||
// if (T.IsArray && T.GetArrayRank() > 1) return false; // Need to find a way to exclude jagged arrays
|
// if (T.IsArray && T.GetArrayRank() > 1) return false; // Need to find a way to exclude jagged arrays
|
||||||
while (T.IsArray)
|
while (T.IsArray)
|
||||||
T = T.GetElementType();
|
T = T.GetElementType();
|
||||||
|
@ -89,7 +92,6 @@ namespace Vanara.Extensions
|
||||||
yield return ret;
|
yield return ret;
|
||||||
pCurrent = next(ret);
|
pCurrent = next(ret);
|
||||||
}
|
}
|
||||||
yield break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.</summary>
|
/// <summary>Marshals data from a managed list of specified type to a pre-allocated unmanaged block of memory.</summary>
|
||||||
|
@ -132,7 +134,7 @@ namespace Vanara.Extensions
|
||||||
if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
|
if (!typeof(T).IsBlittable()) throw new ArgumentException(@"Structure layout is not sequential or explicit.");
|
||||||
|
|
||||||
bytesAllocated = prefixBytes;
|
bytesAllocated = prefixBytes;
|
||||||
var count = (items as IList<T>)?.Count ?? (items as T[])?.Length ?? items?.Count() ?? 0;
|
var count = items?.Count() ?? 0;
|
||||||
if (count == 0) return memAlloc(bytesAllocated);
|
if (count == 0) return memAlloc(bytesAllocated);
|
||||||
|
|
||||||
var sz = Marshal.SizeOf(typeof(T));
|
var sz = Marshal.SizeOf(typeof(T));
|
||||||
|
@ -168,7 +170,7 @@ namespace Vanara.Extensions
|
||||||
var list = values as IList<string> ?? (values != null ? new List<string>(values) : null);
|
var list = values as IList<string> ?? (values != null ? new List<string>(values) : null);
|
||||||
|
|
||||||
// Look at count and bail early if 0
|
// Look at count and bail early if 0
|
||||||
var count = values?.Count() ?? 0;
|
var count = list?.Count ?? 0;
|
||||||
var chSz = StringHelper.GetCharSize(charSet);
|
var chSz = StringHelper.GetCharSize(charSet);
|
||||||
bytesAllocated = prefixBytes + (packing == StringListPackMethod.Concatenated ? chSz : IntPtr.Size);
|
bytesAllocated = prefixBytes + (packing == StringListPackMethod.Concatenated ? chSz : IntPtr.Size);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
|
@ -179,11 +181,11 @@ namespace Vanara.Extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for empty and/or null strings
|
// Check for empty and/or null strings
|
||||||
if (packing == StringListPackMethod.Concatenated && list.Any(s => string.IsNullOrEmpty(s)))
|
if (packing == StringListPackMethod.Concatenated && list.Any(string.IsNullOrEmpty))
|
||||||
throw new ArgumentException("Concatenated string arrays cannot contain empty or null strings.");
|
throw new ArgumentException("Concatenated string arrays cannot contain empty or null strings.");
|
||||||
|
|
||||||
// Get size of output
|
// Get size of output
|
||||||
var sumStrLen = list.Sum(s => s == null ? 0 : s.Length + 1);
|
var sumStrLen = list.Sum(s => s?.Length + 1 ?? 0);
|
||||||
bytesAllocated += sumStrLen * chSz;
|
bytesAllocated += sumStrLen * chSz;
|
||||||
if (packing == StringListPackMethod.Packed) bytesAllocated += (IntPtr.Size * count);
|
if (packing == StringListPackMethod.Packed) bytesAllocated += (IntPtr.Size * count);
|
||||||
|
|
||||||
|
@ -231,7 +233,7 @@ namespace Vanara.Extensions
|
||||||
var list = values as IList<object> ?? (values != null ? new List<object>(values) : null);
|
var list = values as IList<object> ?? (values != null ? new List<object>(values) : null);
|
||||||
|
|
||||||
// Look at count and bail early if 0
|
// Look at count and bail early if 0
|
||||||
var count = values?.Count() ?? 0;
|
var count = list?.Count ?? 0;
|
||||||
bytesAllocated = prefixBytes + IntPtr.Size;
|
bytesAllocated = prefixBytes + IntPtr.Size;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
|
@ -495,7 +497,7 @@ namespace Vanara.Extensions
|
||||||
var i = prefixBytes;
|
var i = prefixBytes;
|
||||||
for (var ptr = lptr.Offset(i); i + charLength <= allocatedBytes && GetCh(ptr) != 0; i += charLength, ptr = lptr.Offset(i))
|
for (var ptr = lptr.Offset(i); i + charLength <= allocatedBytes && GetCh(ptr) != 0; i += charLength, ptr = lptr.Offset(i))
|
||||||
{
|
{
|
||||||
for (var cptr = ptr; i + charLength <= allocatedBytes && GetCh(cptr) != 0; cptr = cptr.Offset(charLength), i += charLength) ;
|
for (var cptr = ptr; i + charLength <= allocatedBytes && GetCh(cptr) != 0; cptr = cptr.Offset(charLength), i += charLength) { }
|
||||||
if (i + charLength > allocatedBytes) throw new InsufficientMemoryException();
|
if (i + charLength > allocatedBytes) throw new InsufficientMemoryException();
|
||||||
yield return StringHelper.GetString(ptr, charSet);
|
yield return StringHelper.GetString(ptr, charSet);
|
||||||
//ptr = ptr.Offset(((s?.Length ?? 0) + 1) * charLength);
|
//ptr = ptr.Offset(((s?.Length ?? 0) + 1) * charLength);
|
||||||
|
@ -508,9 +510,17 @@ namespace Vanara.Extensions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
|
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a structure.</typeparam>
|
||||||
/// <param name="ptr">A pointer to an unmanaged block of memory.</param>
|
/// <param name="ptr">A pointer to an unmanaged block of memory.</param>
|
||||||
/// <returns>A managed object that contains the data that the <paramref name="ptr"/> parameter points to.</returns>
|
/// <param name="allocatedBytes">If known, the total number of bytes allocated to the native memory in <paramref name="ptr"/>.</param>
|
||||||
|
/// <returns>A managed object that contains the data that the <paramref name="ptr" /> parameter points to.</returns>
|
||||||
|
/// <exception cref="InsufficientMemoryException"></exception>
|
||||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||||
public static T ToStructure<T>(this IntPtr ptr) => (T)Marshal.PtrToStructure(ptr, typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T));
|
public static T ToStructure<T>(this IntPtr ptr, long allocatedBytes = -1)
|
||||||
|
{
|
||||||
|
var t = typeof(T).IsEnum ? Enum.GetUnderlyingType(typeof(T)) : typeof(T);
|
||||||
|
if (allocatedBytes >= 0 && allocatedBytes < Marshal.SizeOf(t))
|
||||||
|
throw new InsufficientMemoryException();
|
||||||
|
return (T)Marshal.PtrToStructure(ptr, t);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Marshals data from an unmanaged block of memory to a managed object.</summary>
|
/// <summary>Marshals data from an unmanaged block of memory to a managed object.</summary>
|
||||||
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a formatted class.</typeparam>
|
/// <typeparam name="T">The type of the object to which the data is to be copied. This must be a formatted class.</typeparam>
|
||||||
|
|
Loading…
Reference in New Issue