<commit_before>﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Vanara.Extensions;

namespace Vanara.InteropServices
{
	/// <summary>Functions to safely convert a memory pointer to a type.</summary>
	public static class IntPtrConverter
	{
		/// <summary>Converts the specified pointer to <typeparamref name="T" />.</summary>
		/// <typeparam name="T">The destination type.</typeparam>
		/// <param name="ptr">The pointer to a block of memory.</param>
		/// <param name="sz">The size of the allocated memory block.</param>
		/// <param name="charSet">The character set.</param>
		/// <returns>A value of the type specified.</returns>
		public static T Convert<T>(this IntPtr ptr, uint sz, CharSet charSet = CharSet.Auto) => (T)Convert(ptr, sz, typeof(T), charSet);

		/// <summary>Converts the specified pointer to type specified in <paramref name="destType" />.</summary>
		/// <param name="ptr">The pointer to a block of memory.</param>
		/// <param name="sz">The size of the allocated memory block.</param>
		/// <param name="destType">The destination type.</param>
		/// <param name="charSet">The character set.</param>
		/// <returns>A value of the type specified.</returns>
		/// <exception cref="ArgumentException">
		/// Cannot convert a null pointer. - ptr
		/// or
		/// Cannot convert a pointer with no Size. - sz
		/// </exception>
		/// <exception cref="NotSupportedException">Thrown if type cannot be converted from memory.</exception>
		/// <exception cref="OutOfMemoryException"></exception>
		public static object Convert(this IntPtr ptr, uint sz, Type destType, CharSet charSet = CharSet.Auto)
		{
			if (ptr == IntPtr.Zero) throw new ArgumentException("Cannot convert a null pointer.", nameof(ptr));
			if (sz == 0) throw new ArgumentException("Cannot convert a pointer with no Size.", nameof(sz));

			// Handle byte array and pointer as special cases
			if (destType.IsArray && destType.GetElementType() == typeof(byte))
				return ptr.ToArray<byte>((int)sz);
			if (destType == typeof(IntPtr))
				return Marshal.ReadIntPtr(ptr);

			var typeCode = Type.GetTypeCode(destType);
			switch (typeCode)
			{
				case TypeCode.Object:
					if (typeof(ISerializable).IsAssignableFrom(destType))
					{
						using (var mem = new MemoryStream(ptr.ToArray<byte>((int)sz)))
							return new BinaryFormatter().Deserialize(mem);
					}
					try
					{
						return GetBlittable(destType);
					}
					catch (ArgumentOutOfRangeException e)
					{
						throw e;
					}
					catch
					{
						throw new NotSupportedException("Unsupported type parameter.");
					}
				case TypeCode.Boolean:
					object boolVal;
					if (sz == 1)
						boolVal = GetBlittable(typeof(byte));
					else if (sz == 2)
						boolVal = GetBlittable(typeof(ushort));
					else if (sz == 4)
						boolVal = GetBlittable(typeof(uint));
					else if (sz == 8)
						boolVal = GetBlittable(typeof(ulong));
					else
						throw SizeExc();
					return System.Convert.ChangeType(boolVal, typeCode);

				case TypeCode.Char:<commit_msg>Fixes for handling null pointer and bool<commit_after>﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Vanara.Extensions;

namespace Vanara.InteropServices
{
	/// <summary>Functions to safely convert a memory pointer to a type.</summary>
	public static class IntPtrConverter
	{
		/// <summary>Converts the specified pointer to <typeparamref name="T" />.</summary>
		/// <typeparam name="T">The destination type.</typeparam>
		/// <param name="ptr">The pointer to a block of memory.</param>
		/// <param name="sz">The size of the allocated memory block.</param>
		/// <param name="charSet">The character set.</param>
		/// <returns>A value of the type specified.</returns>
		public static T Convert<T>(this IntPtr ptr, uint sz, CharSet charSet = CharSet.Auto) => (T)Convert(ptr, sz, typeof(T), charSet);

		/// <summary>Converts the specified pointer to type specified in <paramref name="destType" />.</summary>
		/// <param name="ptr">The pointer to a block of memory.</param>
		/// <param name="sz">The size of the allocated memory block.</param>
		/// <param name="destType">The destination type.</param>
		/// <param name="charSet">The character set.</param>
		/// <returns>A value of the type specified.</returns>
		/// <exception cref="ArgumentException">
		/// Cannot convert a null pointer. - ptr
		/// or
		/// Cannot convert a pointer with no Size. - sz
		/// </exception>
		/// <exception cref="NotSupportedException">Thrown if type cannot be converted from memory.</exception>
		/// <exception cref="OutOfMemoryException"></exception>
		public static object Convert(this IntPtr ptr, uint sz, Type destType, CharSet charSet = CharSet.Auto)
		{
			if (ptr == IntPtr.Zero)
			{
				if (!destType.IsValueType) return null;
				throw new ArgumentException("Cannot convert a null pointer.", nameof(ptr));
			}
			if (sz == 0) throw new ArgumentException("Cannot convert a pointer with no Size.", nameof(sz));

			// Handle byte array and pointer as special cases
			if (destType.IsArray && destType.GetElementType() == typeof(byte))
				return ptr.ToArray<byte>((int)sz);
			if (destType == typeof(IntPtr))
				return Marshal.ReadIntPtr(ptr);

			var typeCode = Type.GetTypeCode(destType);
			switch (typeCode)
			{
				case TypeCode.Object:
					if (typeof(ISerializable).IsAssignableFrom(destType))
					{
						using (var mem = new MemoryStream(ptr.ToArray<byte>((int)sz)))
							return new BinaryFormatter().Deserialize(mem);
					}
					try
					{
						return GetBlittable(destType);
					}
					catch (ArgumentOutOfRangeException e)
					{
						throw e;
					}
					catch
					{
						throw new NotSupportedException("Unsupported type parameter.");
					}
				case TypeCode.Boolean:
					return System.Convert.ChangeType(GetBlittable(typeof(uint)), typeCode);

				case TypeCode.Char:
{'fraction_non_alphanumeric': 0.1341382732385048, 'fraction_numerical': 0.0009923916639100231, 'mean_word_length': 3.505961251862891, 'pattern_counts': {'":': 0, '<': 77, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2257673', 'n_tokens_mistral': 2062, 'n_tokens_neox': 1724, 'n_words': 533}