PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_ctypes/ArrayType.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 409 lines | 317 code | 66 blank | 26 comment | 58 complexity | 4c37ad7de7644ef61ce88019d58f75fe MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Reflection.Emit;
  20. using System.Runtime.InteropServices;
  21. using System.Text;
  22. using Microsoft.Scripting;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. using IronPython.Runtime;
  26. using IronPython.Runtime.Operations;
  27. using IronPython.Runtime.Types;
  28. #if CLR2
  29. using Microsoft.Scripting.Math;
  30. #else
  31. using System.Numerics;
  32. #endif
  33. #if !SILVERLIGHT
  34. namespace IronPython.Modules {
  35. /// <summary>
  36. /// Provides support for interop with native code from Python code.
  37. /// </summary>
  38. public static partial class CTypes {
  39. private static WeakDictionary<PythonType, Dictionary<int, ArrayType>> _arrayTypes = new WeakDictionary<PythonType, Dictionary<int, ArrayType>>();
  40. /// <summary>
  41. /// The meta class for ctypes array instances.
  42. /// </summary>
  43. [PythonType, PythonHidden]
  44. public class ArrayType : PythonType, INativeType {
  45. private int _length;
  46. private INativeType _type;
  47. public ArrayType(CodeContext/*!*/ context, string name, PythonTuple bases, PythonDictionary dict)
  48. : base(context, name, bases, dict) {
  49. object len;
  50. int iLen;
  51. if (!dict.TryGetValue("_length_", out len) || !(len is int) || (iLen = (int)len) < 0) {
  52. throw PythonOps.AttributeError("arrays must have _length_ attribute and it must be a positive integer");
  53. }
  54. object type;
  55. if (!dict.TryGetValue("_type_", out type)) {
  56. throw PythonOps.AttributeError("class must define a '_type_' attribute");
  57. }
  58. _length = iLen;
  59. _type = (INativeType)type;
  60. if (_type is SimpleType) {
  61. SimpleType st = (SimpleType)_type;
  62. if (st._type == SimpleTypeKind.Char) {
  63. // TODO: (c_int * 2).value isn't working
  64. SetCustomMember(context,
  65. "value",
  66. new ReflectedExtensionProperty(
  67. new ExtensionPropertyInfo(this, typeof(CTypes).GetMethod("GetCharArrayValue")),
  68. NameType.Property | NameType.Python
  69. )
  70. );
  71. SetCustomMember(context,
  72. "raw",
  73. new ReflectedExtensionProperty(
  74. new ExtensionPropertyInfo(this, typeof(CTypes).GetMethod("GetWCharArrayRaw")),
  75. NameType.Property | NameType.Python
  76. )
  77. );
  78. } else if (st._type == SimpleTypeKind.WChar) {
  79. SetCustomMember(context,
  80. "value",
  81. new ReflectedExtensionProperty(
  82. new ExtensionPropertyInfo(this, typeof(CTypes).GetMethod("GetWCharArrayValue")),
  83. NameType.Property | NameType.Python
  84. )
  85. );
  86. SetCustomMember(context,
  87. "raw",
  88. new ReflectedExtensionProperty(
  89. new ExtensionPropertyInfo(this, typeof(CTypes).GetMethod("GetWCharArrayRaw")),
  90. NameType.Property | NameType.Python
  91. )
  92. );
  93. }
  94. }
  95. }
  96. private ArrayType(Type underlyingSystemType)
  97. : base(underlyingSystemType) {
  98. }
  99. public _Array from_address(CodeContext/*!*/ context, int ptr) {
  100. _Array res = (_Array)CreateInstance(context);
  101. res.SetAddress(new IntPtr(ptr));
  102. return res;
  103. }
  104. public _Array from_address(CodeContext/*!*/ context, BigInteger ptr) {
  105. _Array res = (_Array)CreateInstance(context);
  106. res.SetAddress(new IntPtr((long)ptr));
  107. return res;
  108. }
  109. public _Array from_buffer(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  110. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  111. _Array res = (_Array)CreateInstance(Context.SharedContext);
  112. IntPtr addr = array.GetArrayAddress();
  113. res._memHolder = new MemoryHolder(addr.Add(offset), ((INativeType)this).Size);
  114. res._memHolder.AddObject("ffffffff", array);
  115. return res;
  116. }
  117. public _Array from_buffer_copy(ArrayModule.array array, [DefaultParameterValue(0)]int offset) {
  118. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  119. _Array res = (_Array)CreateInstance(Context.SharedContext);
  120. res._memHolder = new MemoryHolder(((INativeType)this).Size);
  121. res._memHolder.CopyFrom(array.GetArrayAddress().Add(offset), new IntPtr(((INativeType)this).Size));
  122. GC.KeepAlive(array);
  123. return res;
  124. }
  125. public _Array from_buffer_copy(Bytes array, [DefaultParameterValue(0)]int offset) {
  126. ValidateArraySizes(array, offset, ((INativeType)this).Size);
  127. _Array res = (_Array)CreateInstance(Context.SharedContext);
  128. res._memHolder = new MemoryHolder(((INativeType)this).Size);
  129. for (int i = 0; i < ((INativeType)this).Size; i++) {
  130. res._memHolder.WriteByte(i, array._bytes[i]);
  131. }
  132. return res;
  133. }
  134. /// <summary>
  135. /// Converts an object into a function call parameter.
  136. /// </summary>
  137. public object from_param(object obj) {
  138. return null;
  139. }
  140. internal static PythonType MakeSystemType(Type underlyingSystemType) {
  141. return PythonType.SetPythonType(underlyingSystemType, new ArrayType(underlyingSystemType));
  142. }
  143. public static ArrayType/*!*/ operator *(ArrayType type, int count) {
  144. return MakeArrayType(type, count);
  145. }
  146. public static ArrayType/*!*/ operator *(int count, ArrayType type) {
  147. return MakeArrayType(type, count);
  148. }
  149. #region INativeType Members
  150. int INativeType.Size {
  151. get {
  152. return GetSize();
  153. }
  154. }
  155. private int GetSize() {
  156. return _length * _type.Size;
  157. }
  158. int INativeType.Alignment {
  159. get {
  160. return _type.Alignment;
  161. }
  162. }
  163. object INativeType.GetValue(MemoryHolder owner, object readingFrom, int offset, bool raw) {
  164. if (IsStringType) {
  165. SimpleType st = (SimpleType)_type;
  166. string str;
  167. if (st._type == SimpleTypeKind.Char) {
  168. str = owner.ReadAnsiString(offset, _length);
  169. } else {
  170. str = owner.ReadUnicodeString(offset, _length);
  171. }
  172. // remove any trailing nulls
  173. for (int i = 0; i < str.Length; i++) {
  174. if (str[i] == '\x00') {
  175. return str.Substring(0, i);
  176. }
  177. }
  178. return str;
  179. }
  180. _Array arr = (_Array)CreateInstance(Context.SharedContext);
  181. arr._memHolder = new MemoryHolder(owner.UnsafeAddress.Add(offset), ((INativeType)this).Size, owner);
  182. return arr;
  183. }
  184. internal string GetRawValue(MemoryHolder owner, int offset) {
  185. Debug.Assert(IsStringType);
  186. SimpleType st = (SimpleType)_type;
  187. string str;
  188. if (st._type == SimpleTypeKind.Char) {
  189. str = owner.ReadAnsiString(offset, _length);
  190. } else {
  191. str = owner.ReadUnicodeString(offset, _length);
  192. }
  193. return str;
  194. }
  195. private bool IsStringType {
  196. get {
  197. SimpleType st = _type as SimpleType;
  198. if (st != null) {
  199. return st._type == SimpleTypeKind.WChar || st._type == SimpleTypeKind.Char;
  200. }
  201. return false;
  202. }
  203. }
  204. object INativeType.SetValue(MemoryHolder address, int offset, object value) {
  205. string str = value as string;
  206. if (str != null) {
  207. if (!IsStringType) {
  208. throw PythonOps.TypeError("expected {0} instance, got str", Name);
  209. } else if (str.Length > _length) {
  210. throw PythonOps.ValueError("string too long ({0}, maximum length {1})", str.Length, _length);
  211. }
  212. WriteString(address, offset, str);
  213. return null;
  214. } else if (IsStringType) {
  215. IList<object> objList = value as IList<object>;
  216. if (objList != null) {
  217. StringBuilder res = new StringBuilder(objList.Count);
  218. foreach (object o in objList) {
  219. res.Append(Converter.ConvertToChar(o));
  220. }
  221. WriteString(address, offset, res.ToString());
  222. return null;
  223. }
  224. throw PythonOps.TypeError("expected string or Unicode object, {0} found", DynamicHelpers.GetPythonType(value).Name);
  225. }
  226. object[] arrArgs = value as object[];
  227. if (arrArgs == null) {
  228. PythonTuple pt = value as PythonTuple;
  229. if (pt != null) {
  230. arrArgs = pt._data;
  231. }
  232. }
  233. if (arrArgs != null) {
  234. if (arrArgs.Length > _length) {
  235. throw PythonOps.RuntimeError("invalid index");
  236. }
  237. for (int i = 0; i < arrArgs.Length; i++) {
  238. _type.SetValue(address, checked(offset + i * _type.Size), arrArgs[i]);
  239. }
  240. } else {
  241. _Array arr = value as _Array;
  242. if (arr != null && arr.NativeType == this) {
  243. arr._memHolder.CopyTo(address, offset, ((INativeType)this).Size);
  244. return arr._memHolder.EnsureObjects();
  245. }
  246. throw PythonOps.TypeError("unexpected {0} instance, got {1}", Name, DynamicHelpers.GetPythonType(value).Name);
  247. }
  248. return null;
  249. }
  250. private void WriteString(MemoryHolder address, int offset, string str) {
  251. SimpleType st = (SimpleType)_type;
  252. if (str.Length < _length) {
  253. str = str + '\x00';
  254. }
  255. if (st._type == SimpleTypeKind.Char) {
  256. address.WriteAnsiString(offset, str);
  257. } else {
  258. address.WriteUnicodeString(offset, str);
  259. }
  260. }
  261. Type/*!*/ INativeType.GetNativeType() {
  262. return typeof(IntPtr);
  263. }
  264. MarshalCleanup INativeType.EmitMarshalling(ILGenerator/*!*/ method, LocalOrArg argIndex, List<object>/*!*/ constantPool, int constantPoolArgument) {
  265. Type argumentType = argIndex.Type;
  266. Label done = method.DefineLabel();
  267. if (!argumentType.IsValueType) {
  268. Label next = method.DefineLabel();
  269. argIndex.Emit(method);
  270. method.Emit(OpCodes.Ldnull);
  271. method.Emit(OpCodes.Bne_Un, next);
  272. method.Emit(OpCodes.Ldc_I4_0);
  273. method.Emit(OpCodes.Conv_I);
  274. method.Emit(OpCodes.Br, done);
  275. method.MarkLabel(next);
  276. }
  277. argIndex.Emit(method);
  278. if (argumentType.IsValueType) {
  279. method.Emit(OpCodes.Box, argumentType);
  280. }
  281. constantPool.Add(this);
  282. method.Emit(OpCodes.Ldarg, constantPoolArgument);
  283. method.Emit(OpCodes.Ldc_I4, constantPool.Count - 1);
  284. method.Emit(OpCodes.Ldelem_Ref);
  285. method.Emit(OpCodes.Call, typeof(ModuleOps).GetMethod("CheckCDataType"));
  286. method.Emit(OpCodes.Call, typeof(CData).GetMethod("get_UnsafeAddress"));
  287. method.MarkLabel(done);
  288. return null;
  289. }
  290. Type/*!*/ INativeType.GetPythonType() {
  291. return ((INativeType)this).GetNativeType();
  292. }
  293. void INativeType.EmitReverseMarshalling(ILGenerator method, LocalOrArg value, List<object> constantPool, int constantPoolArgument) {
  294. // TODO: Implement me
  295. value.Emit(method);
  296. }
  297. #endregion
  298. internal int Length {
  299. get {
  300. return _length;
  301. }
  302. }
  303. internal INativeType ElementType {
  304. get {
  305. return _type;
  306. }
  307. }
  308. string INativeType.TypeFormat {
  309. get {
  310. string size = "(" + Length;
  311. INativeType elemType = ElementType;
  312. while (elemType is ArrayType) {
  313. size += "," + ((ArrayType)elemType).Length;
  314. elemType = ((ArrayType)elemType).ElementType;
  315. }
  316. size += ")";
  317. return size + elemType.TypeFormat;
  318. }
  319. }
  320. }
  321. private static ArrayType/*!*/ MakeArrayType(PythonType type, int count) {
  322. if (count < 0) {
  323. throw PythonOps.ValueError("cannot multiply ctype by negative number");
  324. }
  325. lock (_arrayTypes) {
  326. ArrayType res;
  327. Dictionary<int, ArrayType> countDict;
  328. if (!_arrayTypes.TryGetValue(type, out countDict)) {
  329. _arrayTypes[type] = countDict = new Dictionary<int, ArrayType>();
  330. }
  331. if (!countDict.TryGetValue(count, out res)) {
  332. res = countDict[count] = new ArrayType(type.Context.SharedContext,
  333. type.Name + "_Array_" + count,
  334. PythonTuple.MakeTuple(Array),
  335. PythonOps.MakeDictFromItems(new object[] { type, "_type_", count, "_length_" })
  336. );
  337. }
  338. return res;
  339. }
  340. }
  341. }
  342. }
  343. #endif