X Tutup
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. #if FEATURE_CTYPES using System; using System.Collections.Generic; using System.Diagnostics; using System.Numerics; using System.Runtime.InteropServices; using Microsoft.Scripting; using Microsoft.Scripting.Utils; using IronPython.Runtime; using IronPython.Runtime.Exceptions; using IronPython.Runtime.Operations; using IronPython.Runtime.Types; namespace IronPython.Modules { /// /// Provides helper functions which need to be called from generated code to implement various /// portions of modules. /// public static partial class ModuleOps { public static IntPtr StringToHGlobalAnsi(string str) { if (str == null) { return IntPtr.Zero; } return Marshal.StringToHGlobalAnsi(str); } public static IntPtr StringToHGlobalUni(string str) { if (str == null) { return IntPtr.Zero; } return Marshal.StringToHGlobalUni(str); } public static object DoErrorCheck(object errCheckFunc, object result, object func, object[] arguments) { return PythonCalls.Call(errCheckFunc, result, func, PythonTuple.Make(arguments)); } public static object CreateMemoryHolder(IntPtr data, int size) { var res = new MemoryHolder(size); res.CopyFrom(data, new IntPtr(size)); return res; } public static object CreateNativeWrapper(PythonType type, object holder) { Debug.Assert(holder is MemoryHolder); CTypes.CData data = (CTypes.CData)type.CreateInstance(type.Context.SharedContext); data.MemHolder = (MemoryHolder)holder; return data; } public static object CreateCData(IntPtr dataAddress, PythonType type) { CTypes.INativeType nativeType = (CTypes.INativeType)type; CTypes.CData data = (CTypes.CData)type.CreateInstance(type.Context.SharedContext); data.MemHolder = new MemoryHolder(nativeType.Size); data.MemHolder.CopyFrom(dataAddress, new IntPtr(nativeType.Size)); return data; } public static object CreateCFunction(IntPtr address, PythonType type) { return type.CreateInstance(type.Context.SharedContext, address); } public static CTypes.CData CheckSimpleCDataType(object o, object type) { CTypes.SimpleCData res = o as CTypes.SimpleCData; if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) { res = asParam as CTypes.SimpleCData; } if (res != null && res.NativeType != type) { throw PythonOps.TypeErrorForTypeMismatch(((PythonType)type).Name, o); } return res; } public static CTypes.CData/*!*/ CheckCDataType(object o, object type) { CTypes.CData res = o as CTypes.CData; if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) { res = asParam as CTypes.CData; } bool valid = true; // if we have an array, we can also send a pointer as long as the element types // for the pointer and array are the same if(res != null && res.NativeType is CTypes.ArrayType at) { valid = ((type is CTypes.ArrayType t) && (t.ElementType == at.ElementType)) || ((type is CTypes.PointerType p) && (p._type == at.ElementType)); } if (res == null || !valid) { throw ArgumentError(type, ((PythonType)type).Name, o); } return res; } public static IntPtr/*!*/ GetFunctionPointerValue(object o, object type) { CTypes._CFuncPtr res = o as CTypes._CFuncPtr; if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) { res = asParam as CTypes._CFuncPtr; } if (res == null || res.NativeType != type) { throw ArgumentError(type, ((PythonType)type).Name, o); } return res.addr; } public static CTypes.CData TryCheckCDataPointerType(object o, object type) { CTypes.CData res = o as CTypes.CData; if (res == null && PythonOps.TryGetBoundAttr(o, "_as_parameter_", out object asParam)) { res = asParam as CTypes.CData; } bool valid = true; // if we have an array, we can also send a pointer as long as the element types // for the pointer and array are the same if (res != null && res.NativeType is CTypes.ArrayType at) { valid = ((type is CTypes.ArrayType t) && (t.ElementType == at.ElementType)) || ((type is CTypes.PointerType p) && (p._type == at.ElementType)); } if (res != null && !valid) { throw ArgumentError(type, ((PythonType)((CTypes.PointerType)type)._type).Name, o); } return res; } public static CTypes._Array TryCheckCharArray(object o) { if (o is CTypes._Array array) { if (((CTypes.ArrayType)array.NativeType).ElementType is CTypes.SimpleType elemType && elemType._type == CTypes.SimpleTypeKind.Char) { return array; } } return null; } private static readonly byte[] FakeZeroLength = { 42 }; public static byte[] TryCheckBytes(object o) { if (o is Bytes bytes) { if (bytes.Count == 0) { // OpCodes.Ldelema refuses to get address of empty array // So we feed it with a fake one (cp34892) return FakeZeroLength; } return bytes.UnsafeByteArray; } return null; } public static byte[] GetBytes(Bytes bytes) { return bytes.UnsafeByteArray; } public static CTypes._Array TryCheckWCharArray(object o) { if (o is CTypes._Array array) { if (((CTypes.ArrayType)array.NativeType).ElementType is CTypes.SimpleType elemType && elemType._type == CTypes.SimpleTypeKind.WChar) { return array; } } return null; } public static object CreateSubclassInstance(object type, object instance) { return PythonCalls.Call(type, instance); } public static void CallbackException(Exception e, CodeContext/*!*/ context) { PythonContext pc = context.LanguageContext; object stderr = pc.SystemStandardError; PythonOps.PrintWithDest(context, stderr, pc.FormatException(e)); } private static Exception ArgumentError(object type, string expected, object got) { PythonContext pc = ((PythonType)type).Context; return PythonExceptions.CreateThrowable( (PythonType)pc.GetModuleState("ArgumentError"), string.Format("expected {0}, got {1}", expected, PythonOps.GetPythonTypeName(got)) ); } public static CTypes.CData CheckNativeArgument(object o, object type) { if (o is CTypes.NativeArgument arg) { if (((CTypes.PointerType)type)._type != DynamicHelpers.GetPythonType(arg._obj)) { throw ArgumentError(type, ((PythonType)type).Name, o); } return arg._obj; } return null; } public static Bytes CharToBytes(byte c) { return Bytes.FromByte(c); } public static string WCharToString(char c) { return new string(c, 1); } public static char StringToChar(string s) { return s[0]; } public static string EnsureString(object o) { if (!(o is string res)) { throw PythonOps.TypeErrorForTypeMismatch("str", o); } return res; } public static bool CheckFunctionId(CTypes._CFuncPtr func, int id) { return func.Id == id; } public static IntPtr GetWCharPointer(object value) { if (value is string strVal) { return Marshal.StringToCoTaskMemUni(strVal); } if (value == null) { return IntPtr.Zero; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetWCharPointer(asParam); } throw PythonOps.TypeErrorForTypeMismatch("wchar pointer", value); } public static IntPtr GetBSTR(object value) { if (value is string strVal) { return Marshal.StringToBSTR(strVal); } if (value == null) { return IntPtr.Zero; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetBSTR(asParam); } throw PythonOps.TypeErrorForTypeMismatch("BSTR", value); } public static IntPtr GetCharPointer(object value) { if (value is Bytes bytes) { var data = bytes.UnsafeByteArray; var ptr = Marshal.AllocCoTaskMem(data.Length + 1); Marshal.Copy(data, 0, ptr, data.Length); Marshal.WriteByte(ptr, data.Length, 0); return ptr; } if (value == null) { return IntPtr.Zero; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetCharPointer(asParam); } throw PythonOps.TypeErrorForTypeMismatch("char pointer", value); } public static Bytes IntPtrToBytes(IntPtr ptr) { // TODO: optimize this? var str = Marshal.PtrToStringAnsi(ptr); if (str is null) return null; return Bytes.Make(str.MakeByteArray()); } public static IntPtr GetPointer(object value) { if (value == null) { return IntPtr.Zero; } if (value is int iVal) { if(iVal > int.MaxValue) { iVal = -1; } return new IntPtr(iVal); } if (value is BigInteger bigVal) { if(bigVal > long.MaxValue) { bigVal = -1; } return new IntPtr((long)bigVal); } if (value is long lVal) { return new IntPtr(lVal); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetPointer(asParam); } if (value is CTypes.SimpleCData sd) { CTypes.SimpleType simpType = (CTypes.SimpleType)sd.NativeType; if (simpType._type == CTypes.SimpleTypeKind.WCharPointer || simpType._type == CTypes.SimpleTypeKind.CharPointer) { return sd.UnsafeAddress; } else if (simpType._type == CTypes.SimpleTypeKind.Pointer) { return sd.MemHolder.ReadIntPtr(0); } } if (value is CTypes._Array arr) { return arr.UnsafeAddress; } if (value is CTypes._CFuncPtr func) { return func.UnsafeAddress; } if (value is CTypes.Pointer pointer) { return pointer.UnsafeAddress; } throw PythonOps.TypeErrorForTypeMismatch("pointer", value); } public static IntPtr GetInterfacePointer(IntPtr self, int offset) { var vtable = Marshal.ReadIntPtr(self); return Marshal.ReadIntPtr(vtable, offset * IntPtr.Size); } public static IntPtr GetObject(object value) { GCHandle handle = GCHandle.Alloc(value); // TODO: Need to free the handle at some point return GCHandle.ToIntPtr(handle); } public static long GetSignedLongLong(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { return res.Value; } if (value is BigInteger) { return (long)(BigInteger)value; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSignedLongLong(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("signed long long ", value); } public static long GetUnsignedLongLong(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null && res.Value >= 0) { return res.Value; } if (value is BigInteger) { return (long)(ulong)(BigInteger)value; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetUnsignedLongLong(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("unsigned long long", value); } public static double GetDouble(object value, object type) { if (value is double) { return (double)value; } else if (value is float) { return (float)value; } else if (value is int) { return (double)(int)value; } else if (value is BigInteger) { return (double)((BigInteger)value).ToFloat64(); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetDouble(asParam, type); } return Converter.ConvertToDouble(value); } public static float GetSingle(object value, object type) { if (value is double) { return (float)(double)value; } else if (value is float) { return (float)value; } else if (value is int) { return (float)(int)value; } else if (value is BigInteger) { return (float)((BigInteger)value).ToFloat64(); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSingle(asParam, type); } return (float)Converter.ConvertToDouble(value); } public static long GetDoubleBits(object value) { if (value is double) { return BitConverter.ToInt64(BitConverter.GetBytes((double)value), 0); } else if (value is float) { return BitConverter.ToInt64(BitConverter.GetBytes((float)value), 0); } else if (value is int) { return BitConverter.ToInt64(BitConverter.GetBytes((double)(int)value), 0); } else if (value is BigInteger) { return BitConverter.ToInt64(BitConverter.GetBytes((double)((BigInteger)value).ToFloat64()), 0); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetDoubleBits(asParam); } return BitConverter.ToInt64(BitConverter.GetBytes(Converter.ConvertToDouble(value)), 0); } public static int GetSingleBits(object value) { if (value is double) { return BitConverter.ToInt32(BitConverter.GetBytes((float)(double)value), 0); } else if (value is float) { return BitConverter.ToInt32(BitConverter.GetBytes((float)value), 0); } else if (value is int) { return BitConverter.ToInt32(BitConverter.GetBytes((float)(int)value), 0); } else if (value is BigInteger) { return BitConverter.ToInt32(BitConverter.GetBytes((float)((BigInteger)value).ToFloat64()), 0); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSingleBits(asParam); } return BitConverter.ToInt32(BitConverter.GetBytes((float)Converter.ConvertToDouble(value)), 0); } public static int GetSignedLong(object value, object type) { if (value is int) { return (int)value; } int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { return res.Value; } if (value is BigInteger && ((BigInteger)value).AsUInt32(out uint unsigned)) { return (int)unsigned; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSignedLong(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("signed long", value); } public static int GetUnsignedLong(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { return res.Value; } if (value is BigInteger) { if (((BigInteger)value).AsUInt32(out uint ures)) { return (int)ures; } } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetUnsignedLong(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("unsigned long", value); } public static int GetUnsignedInt(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null && res.Value >= 0) { return res.Value; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetUnsignedInt(type, asParam); } throw PythonOps.TypeErrorForTypeMismatch("unsigned int", value); } public static int GetSignedInt(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { return res.Value; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSignedInt(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("signed int", value); } public static short GetUnsignedShort(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { int iVal = res.Value; if (iVal >= ushort.MinValue && iVal <= ushort.MaxValue) { return (short)(ushort)iVal; } } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetUnsignedShort(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("unsigned short", value); } public static short GetSignedShort(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { int iVal = res.Value; return (short)iVal; } else if (value is BigInteger bigInt) { return (short)(int)(bigInt & 0xffff); } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSignedShort(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("signed short", value); } public static int GetVariantBool(object value, object type) { return Converter.ConvertToBoolean(value) ? 1 : 0; } public static byte GetUnsignedByte(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { return (byte)res.Value; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetUnsignedByte(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("unsigned byte", value); } public static byte GetSignedByte(object value, object type) { int? res = Converter.ImplicitConvertToInt32(value); if (res != null) { int iVal = res.Value; if (iVal >= sbyte.MinValue && iVal <= sbyte.MaxValue) { return (byte)(sbyte)iVal; } } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetSignedByte(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("signed byte", value); } public static byte GetBoolean(object value, object type) { if (value is bool) { return ((bool)value) ? (byte)1 : (byte)0; } else if (value is int) { return ((int)value) != 0 ? (byte)1 : (byte)0; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetBoolean(asParam, type); } throw PythonOps.TypeErrorForTypeMismatch("bool", value); } public static byte GetChar(object value, object type) { // TODO: .NET interop? if (value is Bytes bytes && bytes.Count == 1) { return ((IList)bytes)[0]; } if (value is ByteArray bytearray && bytearray.Count == 1) { return ((IList)bytearray)[0]; } if (value is int i) { try { return checked((byte)i); } catch (OverflowException) { throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); } } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetChar(asParam, type); } throw PythonOps.TypeError("one character bytes, bytearray or integer expected"); } public static char GetWChar(object value, object type) { if (value is string strVal) { if (strVal.Length != 1) throw PythonOps.TypeError("one character unicode string expected"); return strVal[0]; } if (PythonOps.TryGetBoundAttr(value, "_as_parameter_", out object asParam)) { return GetWChar(asParam, type); } throw PythonOps.TypeError("unicode string expected instead of {0} instance", PythonOps.GetPythonTypeName(value)); } public static object IntPtrToObject(IntPtr address) { GCHandle handle = GCHandle.FromIntPtr(address); object res = handle.Target; handle.Free(); return res; } } } #endif
X Tutup