PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_struct.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1257 lines | 1072 code | 159 blank | 26 comment | 166 complexity | 1af45a482294e1fdcbacbca2ad414d56 MD5 | raw file

Large files files are truncated, but you can click here to view the full 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. * ironpy@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.Generic;
  17. using System.IO;
  18. using System.Runtime.CompilerServices;
  19. using System.Runtime.InteropServices;
  20. using System.Text;
  21. using System.Threading;
  22. using Microsoft.Scripting;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. using IronPython.Runtime;
  26. using IronPython.Runtime.Exceptions;
  27. using IronPython.Runtime.Operations;
  28. using IronPython.Runtime.Types;
  29. using IronPython.Runtime.Binding;
  30. #if CLR2
  31. using Microsoft.Scripting.Math;
  32. #else
  33. using System.Numerics;
  34. #endif
  35. [assembly: PythonModule("_struct", typeof(IronPython.Modules.PythonStruct))]
  36. namespace IronPython.Modules {
  37. public static class PythonStruct {
  38. [SpecialName]
  39. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  40. context.EnsureModuleException("structerror", dict, "error", "struct");
  41. }
  42. #region Public API
  43. public const string __doc__ = null;
  44. public const string __version__ = "0.2";
  45. public const int _PY_STRUCT_FLOAT_COERCE = 0;
  46. public const int _PY_STRUCT_OVERFLOW_MASKING = 0;
  47. public const int _PY_STRUCT_RANGE_CHECKING = 0;
  48. [PythonType, Documentation("Represents a compiled struct pattern")]
  49. public class Struct : IWeakReferenceable {
  50. private string _formatString; // the last format string passed to __init__
  51. private Format[] _formats; // the various formatting options for the compiled struct
  52. private bool _isStandardized; // true if the format is in standardized mode
  53. private bool _isLittleEndian; // true if the format is in little endian mode
  54. private int _encodingCount = -1; // the number of objects consumed/produced by the format
  55. private int _encodingSize = -1; // the number of bytes read/produced by the format
  56. private WeakRefTracker _tracker; // storage for weak proxy's
  57. private void Initialize(Struct s) {
  58. _formatString = s._formatString;
  59. _formats = s._formats;
  60. _isStandardized = s._isStandardized;
  61. _isLittleEndian = s._isLittleEndian;
  62. _encodingCount = s._encodingCount;
  63. _encodingSize = s._encodingSize;
  64. _tracker = s._tracker;
  65. }
  66. internal Struct(CodeContext/*!*/ context, [NotNull]string/*!*/ fmt) {
  67. __init__(context, fmt);
  68. }
  69. #region Python construction
  70. [Documentation("creates a new uninitialized struct object - all arguments are ignored")]
  71. public Struct(params object[] args) {
  72. }
  73. [Documentation("creates a new uninitialized struct object - all arguments are ignored")]
  74. public Struct([ParamDictionary]IDictionary<object, object> kwArgs, params object[] args) {
  75. }
  76. [Documentation("initializes or re-initializes the compiled struct object with a new format")]
  77. public void __init__(CodeContext/*!*/ context, [NotNull]string/*!*/ fmt) {
  78. ContractUtils.RequiresNotNull(fmt, "fmt");
  79. _formatString = fmt;
  80. Struct s;
  81. if (_cache.TryGetValue(_formatString, out s)) {
  82. Initialize(s);
  83. } else {
  84. Compile(context, fmt);
  85. }
  86. }
  87. #endregion
  88. #region Public API
  89. [Documentation("gets the current format string for the compiled Struct")]
  90. public string format {
  91. get {
  92. return _formatString;
  93. }
  94. }
  95. [Documentation("returns a string consisting of the values serialized according to the format of the struct object")]
  96. public string/*!*/ pack(CodeContext/*!*/ context, params object[] values) {
  97. if (values.Length != _encodingCount) {
  98. throw Error(context, String.Format("pack requires exactly {0} arguments", _encodingCount));
  99. }
  100. int curObj = 0;
  101. StringBuilder res = new StringBuilder(_encodingSize);
  102. for (int i = 0; i < _formats.Length; i++) {
  103. Format curFormat = _formats[i];
  104. if (!_isStandardized) {
  105. // In native mode, align to {size}-byte boundaries
  106. int nativeSize = curFormat.NativeSize;
  107. int alignLength = Align(res.Length, nativeSize);
  108. int padLength = alignLength - res.Length;
  109. for (int j = 0; j < padLength; j++) {
  110. res.Append('\0');
  111. }
  112. }
  113. switch (curFormat.Type) {
  114. case FormatType.PadByte:
  115. res.Append('\0', curFormat.Count);
  116. break;
  117. case FormatType.Bool:
  118. res.Append(GetBoolValue(context, curObj++, values) ? (char)1 : '\0');
  119. break;
  120. case FormatType.Char:
  121. for (int j = 0; j < curFormat.Count; j++) {
  122. res.Append(GetCharValue(context, curObj++, values));
  123. }
  124. break;
  125. case FormatType.SignedChar:
  126. for (int j = 0; j < curFormat.Count; j++) {
  127. res.Append((char)(byte)GetSByteValue(context, curObj++, values));
  128. }
  129. break;
  130. case FormatType.UnsignedChar:
  131. for (int j = 0; j < curFormat.Count; j++) {
  132. res.Append((char)GetByteValue(context, curObj++, values));
  133. }
  134. break;
  135. case FormatType.Short:
  136. for (int j = 0; j < curFormat.Count; j++) {
  137. WriteShort(res, _isLittleEndian, GetShortValue(context, curObj++, values));
  138. }
  139. break;
  140. case FormatType.UnsignedShort:
  141. for (int j = 0; j < curFormat.Count; j++) {
  142. WriteUShort(res, _isLittleEndian, GetUShortValue(context, curObj++, values));
  143. }
  144. break;
  145. case FormatType.Int:
  146. for (int j = 0; j < curFormat.Count; j++) {
  147. WriteInt(res, _isLittleEndian, GetIntValue(context, curObj++, values));
  148. }
  149. break;
  150. case FormatType.UnsignedInt:
  151. for (int j = 0; j < curFormat.Count; j++) {
  152. WriteUInt(res, _isLittleEndian, GetULongValue(context, _isStandardized, curObj++, values, "unsigned int"));
  153. }
  154. break;
  155. case FormatType.UnsignedLong:
  156. for (int j = 0; j < curFormat.Count; j++) {
  157. WriteUInt(res, _isLittleEndian, GetULongValue(context, _isStandardized, curObj++, values, "unsigned long"));
  158. }
  159. break;
  160. case FormatType.Pointer:
  161. for (int j = 0; j < curFormat.Count; j++) {
  162. WritePointer(res, _isLittleEndian, GetPointer(context, curObj++, values));
  163. }
  164. break;
  165. case FormatType.LongLong:
  166. for (int j = 0; j < curFormat.Count; j++) {
  167. WriteLong(res, _isLittleEndian, GetLongValue(context, curObj++, values));
  168. }
  169. break;
  170. case FormatType.UnsignedLongLong:
  171. for (int j = 0; j < curFormat.Count; j++) {
  172. WriteULong(res, _isLittleEndian, GetULongLongValue(context, curObj++, values));
  173. }
  174. break;
  175. case FormatType.Double:
  176. for (int j = 0; j < curFormat.Count; j++) {
  177. WriteDouble(res, _isLittleEndian, GetDoubleValue(context, curObj++, values));
  178. }
  179. break;
  180. case FormatType.Float:
  181. for (int j = 0; j < curFormat.Count; j++) {
  182. WriteFloat(res, _isLittleEndian, (float)GetDoubleValue(context, curObj++, values));
  183. }
  184. break;
  185. case FormatType.CString:
  186. WriteString(res, curFormat.Count, GetStringValue(context, curObj++, values));
  187. break;
  188. case FormatType.PascalString:
  189. WritePascalString(res, curFormat.Count - 1, GetStringValue(context, curObj++, values));
  190. break;
  191. default:
  192. throw Error(context, "bad format string");
  193. }
  194. }
  195. return res.ToString();
  196. }
  197. [Documentation("Stores the deserialized data into the provided array")]
  198. public void pack_into(CodeContext/*!*/ context, [NotNull]ArrayModule.array/*!*/ buffer, int offset, params object[] args) {
  199. byte[] existing = buffer.ToByteArray();
  200. if (offset + size > existing.Length) {
  201. throw Error(context, String.Format("pack_into requires a buffer of at least {0} bytes", size));
  202. }
  203. string data = pack(context, args);
  204. for (int i = 0; i < data.Length; i++) {
  205. existing[i + offset] = (byte)data[i];
  206. }
  207. buffer.Clear();
  208. buffer.FromStream(new MemoryStream(existing));
  209. }
  210. [Documentation("deserializes the string using the structs specified format")]
  211. public PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]string @string) {
  212. if (@string.Length != size) {
  213. throw Error(context, String.Format("unpack requires a string argument of length {0}", size));
  214. }
  215. string data = @string;
  216. int curIndex = 0;
  217. List<object> res = new List<object>(_encodingCount);
  218. for (int i = 0; i < _formats.Length; i++) {
  219. Format curFormat = _formats[i];
  220. if (!_isStandardized) {
  221. // In native mode, align to {size}-byte boundaries
  222. int nativeSize = curFormat.NativeSize;
  223. if (nativeSize > 0) {
  224. curIndex = Align(curIndex, nativeSize);
  225. }
  226. }
  227. switch (curFormat.Type) {
  228. case FormatType.PadByte:
  229. curIndex += curFormat.Count;
  230. break;
  231. case FormatType.Bool:
  232. for (int j = 0; j < curFormat.Count; j++) {
  233. res.Add(CreateBoolValue(context, ref curIndex, data));
  234. }
  235. break;
  236. case FormatType.Char:
  237. for (int j = 0; j < curFormat.Count; j++) {
  238. res.Add(CreateCharValue(context, ref curIndex, data).ToString());
  239. }
  240. break;
  241. case FormatType.SignedChar:
  242. for (int j = 0; j < curFormat.Count; j++) {
  243. res.Add((int)(sbyte)CreateCharValue(context, ref curIndex, data));
  244. }
  245. break;
  246. case FormatType.UnsignedChar:
  247. for (int j = 0; j < curFormat.Count; j++) {
  248. res.Add((int)CreateCharValue(context, ref curIndex, data));
  249. }
  250. break;
  251. case FormatType.Short:
  252. for (int j = 0; j < curFormat.Count; j++) {
  253. res.Add((int)CreateShortValue(context, ref curIndex, _isLittleEndian, data));
  254. }
  255. break;
  256. case FormatType.UnsignedShort:
  257. for (int j = 0; j < curFormat.Count; j++) {
  258. res.Add((int)CreateUShortValue(context, ref curIndex, _isLittleEndian, data));
  259. }
  260. break;
  261. case FormatType.Int:
  262. for (int j = 0; j < curFormat.Count; j++) {
  263. res.Add(CreateIntValue(context, ref curIndex, _isLittleEndian, data));
  264. }
  265. break;
  266. case FormatType.UnsignedInt:
  267. case FormatType.UnsignedLong:
  268. for (int j = 0; j < curFormat.Count; j++) {
  269. res.Add(BigIntegerOps.__int__((BigInteger)CreateUIntValue(context, ref curIndex, _isLittleEndian, data)));
  270. }
  271. break;
  272. case FormatType.Pointer:
  273. for (int j = 0; j < curFormat.Count; j++) {
  274. if (IntPtr.Size == 4) {
  275. res.Add(CreateIntValue(context, ref curIndex, _isLittleEndian, data));
  276. } else {
  277. res.Add(BigIntegerOps.__int__((BigInteger)CreateLongValue(context, ref curIndex, _isLittleEndian, data)));
  278. }
  279. }
  280. break;
  281. case FormatType.LongLong:
  282. for (int j = 0; j < curFormat.Count; j++) {
  283. res.Add(BigIntegerOps.__int__((BigInteger)CreateLongValue(context, ref curIndex, _isLittleEndian, data)));
  284. }
  285. break;
  286. case FormatType.UnsignedLongLong:
  287. for (int j = 0; j < curFormat.Count; j++) {
  288. res.Add(BigIntegerOps.__int__((BigInteger)CreateULongValue(context, ref curIndex, _isLittleEndian, data)));
  289. }
  290. break;
  291. case FormatType.Float:
  292. for (int j = 0; j < curFormat.Count; j++) {
  293. res.Add((double)CreateFloatValue(context, ref curIndex, _isLittleEndian, data));
  294. }
  295. break;
  296. case FormatType.Double:
  297. for (int j = 0; j < curFormat.Count; j++) {
  298. res.Add(CreateDoubleValue(context, ref curIndex, _isLittleEndian, data));
  299. }
  300. break;
  301. case FormatType.CString:
  302. res.Add(CreateString(context, ref curIndex, curFormat.Count, data));
  303. break;
  304. case FormatType.PascalString:
  305. res.Add(CreatePascalString(context, ref curIndex, curFormat.Count - 1, data));
  306. break;
  307. }
  308. }
  309. return new PythonTuple(res);
  310. }
  311. public PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]ArrayModule.array/*!*/ buffer) {
  312. return unpack_from(context, buffer, 0);
  313. }
  314. public PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]PythonBuffer/*!*/ buffer) {
  315. return unpack_from(context, buffer, 0);
  316. }
  317. [Documentation("reads the current format from the specified array")]
  318. public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]ArrayModule.array/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  319. return unpack_from(context, buffer.ToByteArray().MakeString(), offset);
  320. }
  321. [Documentation("reads the current format from the specified string")]
  322. public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]string/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  323. int bytesAvail = buffer.Length - offset;
  324. if (bytesAvail < size) {
  325. throw Error(context, String.Format("unpack_from requires a buffer of at least {0} bytes", size));
  326. }
  327. return unpack(context, buffer.Substring(offset, size));
  328. }
  329. [Documentation("reads the current format from the specified buffer object")]
  330. public PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]PythonBuffer/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  331. return unpack_from(context, buffer.ToString(), offset);
  332. }
  333. [Documentation("gets the number of bytes that the serialized string will occupy or are required to deserialize the data")]
  334. public int size {
  335. get {
  336. return _encodingSize;
  337. }
  338. }
  339. #endregion
  340. #region IWeakReferenceable Members
  341. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  342. return _tracker;
  343. }
  344. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  345. return Interlocked.CompareExchange(ref _tracker, value, null) == null;
  346. }
  347. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  348. _tracker = value;
  349. }
  350. #endregion
  351. #region Implementation Details
  352. private void Compile(CodeContext/*!*/ context, string/*!*/ fmt) {
  353. List<Format> res = new List<Format>();
  354. int count = 1;
  355. bool fLittleEndian = BitConverter.IsLittleEndian;
  356. bool fStandardized = false;
  357. for (int i = 0; i < fmt.Length; i++) {
  358. switch (fmt[i]) {
  359. case 'x': // pad byte
  360. res.Add(new Format(FormatType.PadByte, count));
  361. count = 1;
  362. break;
  363. case '?': // bool
  364. res.Add(new Format(FormatType.Bool, count));
  365. count = 1;
  366. break;
  367. case 'c': // char
  368. res.Add(new Format(FormatType.Char, count));
  369. count = 1;
  370. break;
  371. case 'b': // signed char
  372. res.Add(new Format(FormatType.SignedChar, count));
  373. count = 1;
  374. break;
  375. case 'B': // unsigned char
  376. res.Add(new Format(FormatType.UnsignedChar, count));
  377. count = 1;
  378. break;
  379. case 'h': // short
  380. res.Add(new Format(FormatType.Short, count));
  381. count = 1;
  382. break;
  383. case 'H': // unsigned short
  384. res.Add(new Format(FormatType.UnsignedShort, count));
  385. count = 1;
  386. break;
  387. case 'i': // int
  388. case 'l': // long
  389. res.Add(new Format(FormatType.Int, count));
  390. count = 1;
  391. break;
  392. case 'I': // unsigned int
  393. res.Add(new Format(FormatType.UnsignedInt, count));
  394. count = 1;
  395. break;
  396. case 'L': // unsigned long
  397. res.Add(new Format(FormatType.UnsignedLong, count));
  398. count = 1;
  399. break;
  400. case 'q': // long long
  401. res.Add(new Format(FormatType.LongLong, count));
  402. count = 1;
  403. break;
  404. case 'Q': // unsigned long long
  405. res.Add(new Format(FormatType.UnsignedLongLong, count));
  406. count = 1;
  407. break;
  408. case 'f': // float
  409. res.Add(new Format(FormatType.Float, count));
  410. count = 1;
  411. break;
  412. case 'd': // double
  413. res.Add(new Format(FormatType.Double, count));
  414. count = 1;
  415. break;
  416. case 's': // char[]
  417. res.Add(new Format(FormatType.CString, count));
  418. count = 1;
  419. break;
  420. case 'p': // pascal char[]
  421. res.Add(new Format(FormatType.PascalString, count));
  422. count = 1;
  423. break;
  424. case 'P': // void *
  425. res.Add(new Format(FormatType.Pointer, count));
  426. count = 1;
  427. break;
  428. case ' ': // white space, ignore
  429. case '\t':
  430. break;
  431. case '=': // native
  432. if (i != 0) throw Error(context, "unexpected byte order");
  433. fStandardized = true;
  434. break;
  435. case '@': // native
  436. if (i != 0) throw Error(context, "unexpected byte order");
  437. break;
  438. case '<': // little endian
  439. if (i != 0) throw Error(context, "unexpected byte order");
  440. fLittleEndian = true;
  441. fStandardized = true;
  442. break;
  443. case '>': // big endian
  444. case '!': // big endian
  445. if (i != 0) throw Error(context, "unexpected byte order");
  446. fLittleEndian = false;
  447. fStandardized = true;
  448. break;
  449. default:
  450. if (Char.IsDigit(fmt[i])) {
  451. count = 0;
  452. while (Char.IsDigit(fmt[i])) {
  453. count = count * 10 + (fmt[i] - '0');
  454. i++;
  455. }
  456. if (Char.IsWhiteSpace(fmt[i])) Error(context, "white space not allowed between count and format");
  457. i--;
  458. break;
  459. }
  460. throw Error(context, "bad format string");
  461. }
  462. }
  463. // store the new formats
  464. _formats = res.ToArray();
  465. _isStandardized = fStandardized;
  466. _isLittleEndian = fLittleEndian;
  467. _encodingSize = _encodingCount = 0;
  468. for (int i = 0; i < _formats.Length; i++) {
  469. if (_formats[i].Type != FormatType.PadByte) {
  470. if (_formats[i].Type != FormatType.CString && _formats[i].Type != FormatType.PascalString) {
  471. _encodingCount += _formats[i].Count;
  472. } else {
  473. _encodingCount++;
  474. }
  475. }
  476. if (!_isStandardized) {
  477. // In native mode, align to {size}-byte boundaries
  478. _encodingSize = Align(_encodingSize, _formats[i].NativeSize);
  479. }
  480. _encodingSize += GetNativeSize(_formats[i].Type) * _formats[i].Count;
  481. }
  482. _cache.Add(fmt, this);
  483. }
  484. #endregion
  485. #region Internal helpers
  486. internal static Struct Create(string/*!*/ format) {
  487. Struct res = new Struct();
  488. res.__init__(DefaultContext.Default, format); // default context is only used for errors, this better be an error free format.
  489. return res;
  490. }
  491. #endregion
  492. }
  493. #endregion
  494. #region Compiled Format
  495. /// <summary>
  496. /// Enum which specifies the format type for a compiled struct
  497. /// </summary>
  498. private enum FormatType {
  499. None,
  500. PadByte,
  501. Bool,
  502. Char,
  503. SignedChar,
  504. UnsignedChar,
  505. Short,
  506. UnsignedShort,
  507. Int,
  508. UnsignedInt,
  509. UnsignedLong,
  510. Float,
  511. LongLong,
  512. UnsignedLongLong,
  513. Double,
  514. CString,
  515. PascalString,
  516. Pointer,
  517. }
  518. private static int GetNativeSize(FormatType c) {
  519. switch (c) {
  520. case FormatType.Char:
  521. case FormatType.SignedChar:
  522. case FormatType.UnsignedChar:
  523. case FormatType.PadByte:
  524. case FormatType.Bool:
  525. case FormatType.CString:
  526. case FormatType.PascalString:
  527. return 1;
  528. case FormatType.Short:
  529. case FormatType.UnsignedShort:
  530. return 2;
  531. case FormatType.Int:
  532. case FormatType.UnsignedInt:
  533. case FormatType.UnsignedLong:
  534. case FormatType.Float:
  535. return 4;
  536. case FormatType.LongLong:
  537. case FormatType.UnsignedLongLong:
  538. case FormatType.Double:
  539. return 8;
  540. case FormatType.Pointer:
  541. return IntPtr.Size;
  542. default:
  543. throw new InvalidOperationException(c.ToString());
  544. }
  545. }
  546. /// <summary>
  547. /// Struct used to store the format and the number of times it should be repeated.
  548. /// </summary>
  549. private struct Format {
  550. public FormatType Type;
  551. public int Count;
  552. public Format(FormatType type, int count) {
  553. Type = type;
  554. Count = count;
  555. }
  556. public int NativeSize {
  557. get {
  558. return GetNativeSize(Type);
  559. }
  560. }
  561. }
  562. #endregion
  563. #region Cache of compiled struct patterns
  564. private const int MAX_CACHE_SIZE = 1024;
  565. private static CacheDict<string, Struct> _cache = new CacheDict<string, Struct>(MAX_CACHE_SIZE);
  566. [Documentation("Clear the internal cache.")]
  567. public static void _clearcache() {
  568. _cache = new CacheDict<string, Struct>(MAX_CACHE_SIZE);
  569. }
  570. [Documentation("int(x[, base]) -> integer\n\nConvert a string or number to an integer, if possible. A floating point\nargument will be truncated towards zero (this does not include a string\nrepresentation of a floating point number!) When converting a string, use\nthe optional base. It is an error to supply a base when converting a\nnon-string. If base is zero, the proper base is guessed based on the\nstring content. If the argument is outside the integer range a\nlong object will be returned instead.")]
  571. public static int calcsize(CodeContext/*!*/ context, [NotNull]string fmt) {
  572. Struct s;
  573. if (!_cache.TryGetValue(fmt, out s)) {
  574. s = new Struct(context, fmt);
  575. }
  576. return s.size;
  577. }
  578. [Documentation("Return string containing values v1, v2, ... packed according to fmt.")]
  579. public static string/*!*/ pack(CodeContext/*!*/ context, [NotNull]string fmt/*!*/, params object[] values) {
  580. Struct s;
  581. if (!_cache.TryGetValue(fmt, out s)) {
  582. s = new Struct(context, fmt);
  583. }
  584. return s.pack(context, values);
  585. }
  586. [Documentation("Pack the values v1, v2, ... according to fmt.\nWrite the packed bytes into the writable buffer buf starting at offset.")]
  587. public static void pack_into(CodeContext/*!*/ context, [NotNull]string/*!*/ fmt, [NotNull]ArrayModule.array/*!*/ buffer, int offset, params object[] args) {
  588. Struct s;
  589. if (!_cache.TryGetValue(fmt, out s)) {
  590. s = new Struct(context, fmt);
  591. }
  592. s.pack_into(context, buffer, offset, args);
  593. }
  594. [Documentation("Unpack the string containing packed C structure data, according to fmt.\nRequires len(string) == calcsize(fmt).")]
  595. public static PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]string/*!*/ fmt, [NotNull]string/*!*/ @string) {
  596. Struct s;
  597. if (!_cache.TryGetValue(fmt, out s)) {
  598. s = new Struct(context, fmt);
  599. }
  600. return s.unpack(context, @string);
  601. }
  602. [Documentation("Unpack the string containing packed C structure data, according to fmt.\nRequires len(string) == calcsize(fmt).")]
  603. public static PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]string/*!*/ fmt, [NotNull]ArrayModule.array/*!*/ buffer) {
  604. Struct s;
  605. if (!_cache.TryGetValue(fmt, out s)) {
  606. s = new Struct(context, fmt);
  607. }
  608. return s.unpack(context, buffer);
  609. }
  610. [Documentation("Unpack the string containing packed C structure data, according to fmt.\nRequires len(string) == calcsize(fmt).")]
  611. public static PythonTuple/*!*/ unpack(CodeContext/*!*/ context, [NotNull]string fmt/*!*/, [NotNull]PythonBuffer/*!*/ buffer) {
  612. Struct s;
  613. if (!_cache.TryGetValue(fmt, out s)) {
  614. s = new Struct(context, fmt);
  615. }
  616. return s.unpack(context, buffer);
  617. }
  618. [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")]
  619. public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]string fmt/*!*/, [NotNull]ArrayModule.array/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  620. Struct s;
  621. if (!_cache.TryGetValue(fmt, out s)) {
  622. s = new Struct(context, fmt);
  623. }
  624. return s.unpack_from(context, buffer, offset);
  625. }
  626. [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")]
  627. public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]string fmt/*!*/, [NotNull]string/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  628. Struct s;
  629. if (!_cache.TryGetValue(fmt, out s)) {
  630. s = new Struct(context, fmt);
  631. }
  632. return s.unpack_from(context, buffer, offset);
  633. }
  634. [Documentation("Unpack the buffer, containing packed C structure data, according to\nfmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt).")]
  635. public static PythonTuple/*!*/ unpack_from(CodeContext/*!*/ context, [NotNull]string fmt/*!*/, [NotNull]PythonBuffer/*!*/ buffer, [DefaultParameterValue(0)] int offset) {
  636. Struct s;
  637. if (!_cache.TryGetValue(fmt, out s)) {
  638. s = new Struct(context, fmt);
  639. }
  640. return s.unpack_from(context, buffer, offset);
  641. }
  642. #endregion
  643. #region Write Helpers
  644. private static void WriteShort(StringBuilder res, bool fLittleEndian, short val) {
  645. if (fLittleEndian) {
  646. res.Append((char)(val & 0xff));
  647. res.Append((char)((val >> 8) & 0xff));
  648. } else {
  649. res.Append((char)((val >> 8) & 0xff));
  650. res.Append((char)(val & 0xff));
  651. }
  652. }
  653. private static void WriteUShort(StringBuilder res, bool fLittleEndian, ushort val) {
  654. if (fLittleEndian) {
  655. res.Append((char)(val & 0xff));
  656. res.Append((char)((val >> 8) & 0xff));
  657. } else {
  658. res.Append((char)((val >> 8) & 0xff));
  659. res.Append((char)(val & 0xff));
  660. }
  661. }
  662. private static void WriteInt(StringBuilder res, bool fLittleEndian, int val) {
  663. if (fLittleEndian) {
  664. res.Append((char)(val & 0xff));
  665. res.Append((char)((val >> 8) & 0xff));
  666. res.Append((char)((val >> 16) & 0xff));
  667. res.Append((char)((val >> 24) & 0xff));
  668. } else {
  669. res.Append((char)((val >> 24) & 0xff));
  670. res.Append((char)((val >> 16) & 0xff));
  671. res.Append((char)((val >> 8) & 0xff));
  672. res.Append((char)(val & 0xff));
  673. }
  674. }
  675. private static void WriteUInt(StringBuilder res, bool fLittleEndian, uint val) {
  676. if (fLittleEndian) {
  677. res.Append((char)(val & 0xff));
  678. res.Append((char)((val >> 8) & 0xff));
  679. res.Append((char)((val >> 16) & 0xff));
  680. res.Append((char)((val >> 24) & 0xff));
  681. } else {
  682. res.Append((char)((val >> 24) & 0xff));
  683. res.Append((char)((val >> 16) & 0xff));
  684. res.Append((char)((val >> 8) & 0xff));
  685. res.Append((char)(val & 0xff));
  686. }
  687. }
  688. private static void WritePointer(StringBuilder res, bool fLittleEndian, IntPtr val) {
  689. if (IntPtr.Size == 4) {
  690. WriteInt(res, fLittleEndian, val.ToInt32());
  691. } else {
  692. WriteLong(res, fLittleEndian, val.ToInt64());
  693. }
  694. }
  695. private static void WriteFloat(StringBuilder res, bool fLittleEndian, float val) {
  696. byte[] bytes = BitConverter.GetBytes(val);
  697. if (fLittleEndian) {
  698. res.Append((char)bytes[0]);
  699. res.Append((char)bytes[1]);
  700. res.Append((char)bytes[2]);
  701. res.Append((char)bytes[3]);
  702. } else {
  703. res.Append((char)bytes[3]);
  704. res.Append((char)bytes[2]);
  705. res.Append((char)bytes[1]);
  706. res.Append((char)bytes[0]);
  707. }
  708. }
  709. private static void WriteLong(StringBuilder res, bool fLittleEndian, long val) {
  710. if (fLittleEndian) {
  711. res.Append((char)(val & 0xff));
  712. res.Append((char)((val >> 8) & 0xff));
  713. res.Append((char)((val >> 16) & 0xff));
  714. res.Append((char)((val >> 24) & 0xff));
  715. res.Append((char)((val >> 32) & 0xff));
  716. res.Append((char)((val >> 40) & 0xff));
  717. res.Append((char)((val >> 48) & 0xff));
  718. res.Append((char)((val >> 56) & 0xff));
  719. } else {
  720. res.Append((char)((val >> 56) & 0xff));
  721. res.Append((char)((val >> 48) & 0xff));
  722. res.Append((char)((val >> 40) & 0xff));
  723. res.Append((char)((val >> 32) & 0xff));
  724. res.Append((char)((val >> 24) & 0xff));
  725. res.Append((char)((val >> 16) & 0xff));
  726. res.Append((char)((val >> 8) & 0xff));
  727. res.Append((char)(val & 0xff));
  728. }
  729. }
  730. private static void WriteULong(StringBuilder res, bool fLittleEndian, ulong val) {
  731. if (fLittleEndian) {
  732. res.Append((char)(val & 0xff));
  733. res.Append((char)((val >> 8) & 0xff));
  734. res.Append((char)((val >> 16) & 0xff));
  735. res.Append((char)((val >> 24) & 0xff));
  736. res.Append((char)((val >> 32) & 0xff));
  737. res.Append((char)((val >> 40) & 0xff));
  738. res.Append((char)((val >> 48) & 0xff));
  739. res.Append((char)((val >> 56) & 0xff));
  740. } else {
  741. res.Append((char)((val >> 56) & 0xff));
  742. res.Append((char)((val >> 48) & 0xff));
  743. res.Append((char)((val >> 40) & 0xff));
  744. res.Append((char)((val >> 32) & 0xff));
  745. res.Append((char)((val >> 24) & 0xff));
  746. res.Append((char)((val >> 16) & 0xff));
  747. res.Append((char)((val >> 8) & 0xff));
  748. res.Append((char)(val & 0xff));
  749. }
  750. }
  751. private static void WriteDouble(StringBuilder res, bool fLittleEndian, double val) {
  752. byte[] bytes = BitConverter.GetBytes(val);
  753. if (fLittleEndian) {
  754. res.Append((char)bytes[0]);
  755. res.Append((char)bytes[1]);
  756. res.Append((char)bytes[2]);
  757. res.Append((char)bytes[3]);
  758. res.Append((char)bytes[4]);
  759. res.Append((char)bytes[5]);
  760. res.Append((char)bytes[6]);
  761. res.Append((char)bytes[7]);
  762. } else {
  763. res.Append((char)bytes[7]);
  764. res.Append((char)bytes[6]);
  765. res.Append((char)bytes[5]);
  766. res.Append((char)bytes[4]);
  767. res.Append((char)bytes[3]);
  768. res.Append((char)bytes[2]);
  769. res.Append((char)bytes[1]);
  770. res.Append((char)bytes[0]);
  771. }
  772. }
  773. private static void WriteString(StringBuilder res, int len, string val) {
  774. for (int i = 0; i < val.Length && i < len; i++) {
  775. res.Append(val[i]);
  776. }
  777. for (int i = val.Length; i < len; i++) {
  778. res.Append('\0');
  779. }
  780. }
  781. private static void WritePascalString(StringBuilder res, int len, string val) {
  782. int lenByte = Math.Min(255, Math.Min(val.Length, len));
  783. res.Append((char)lenByte);
  784. for (int i = 0; i < val.Length && i < len; i++) {
  785. res.Append(val[i]);
  786. }
  787. for (int i = val.Length; i < len; i++) {
  788. res.Append('\0');
  789. }
  790. }
  791. #endregion
  792. #region Data getter helpers
  793. internal static bool GetBoolValue(CodeContext/*!*/ context, int index, object[] args) {
  794. object val = GetValue(context, index, args);
  795. object res;
  796. if (Converter.TryConvert(val, typeof(bool), out res)) {
  797. return (bool)res;
  798. }
  799. // Should never happen
  800. throw Error(context, "expected bool value got " + val.ToString());
  801. }
  802. internal static char GetCharValue(CodeContext/*!*/ context, int index, object[] args) {
  803. string val = GetValue(context, index, args) as string;
  804. if (val == null || val.Length != 1) throw Error(context, "char format requires string of length 1");
  805. return val[0];
  806. }
  807. internal static sbyte GetSByteValue(CodeContext/*!*/ context, int index, object[] args) {
  808. object val = GetValue(context, index, args);
  809. sbyte res;
  810. if (Converter.TryConvertToSByte(val, out res)) {
  811. return res;
  812. }
  813. throw Error(context, "expected sbyte value got " + val.ToString());
  814. }
  815. internal static byte GetByteValue(CodeContext/*!*/ context, int index, object[] args) {
  816. object val = GetValue(context, index, args);
  817. byte res;
  818. if (Converter.TryConvertToByte(val, out res)) return res;
  819. char cres;
  820. if (Converter.TryConvertToChar(val, out cres)) return (byte)cres;
  821. throw Error(context, "expected byte value got " + val.ToString());
  822. }
  823. internal static short GetShortValue(CodeContext/*!*/ context, int index, object[] args) {
  824. object val = GetValue(context, index, args);
  825. short res;
  826. if (Converter.TryConvertToInt16(val, out res)) return res;
  827. throw Error(context, "expected short value");
  828. }
  829. internal static ushort GetUShortValue(CodeContext/*!*/ context, int index, object[] args) {
  830. object val = GetValue(context, index, args);
  831. ushort res;
  832. if (Converter.TryConvertToUInt16(val, out res)) return res;
  833. throw Error(context, "expected ushort value");
  834. }
  835. internal static int GetIntValue(CodeContext/*!*/ context, int index, object[] args) {
  836. object val = GetValue(context, index, args);
  837. int res;
  838. if (Converter.TryConvertToInt32(val, out res)) return res;
  839. throw Error(context, "expected int value");
  840. }
  841. internal static uint GetUIntValue(CodeContext/*!*/ context, bool isStandardized, int index, object[] args) {
  842. object val = GetValue(context, index, args);
  843. uint res;
  844. if (Converter.TryConvertToUInt32(val, out res)) {
  845. return res;
  846. }
  847. if (isStandardized) {
  848. throw Error(context, "expected unsigned long value");
  849. }
  850. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "'I' format requires 0 <= number <= 4294967295");
  851. return 0;
  852. }
  853. internal static uint GetULongValue(CodeContext/*!*/ context, bool isStandardized, int index, object[] args, string type) {
  854. object val = GetValue(context, index, args);
  855. uint res;
  856. if (val is int) {
  857. res = (uint)(int)val;
  858. WarnRange(context, (int)val, isStandardized, type);
  859. } else if (val is BigInteger) {
  860. res = (uint)(((BigInteger)val) & 0xffffffff);
  861. WarnRange(context, (BigInteger)val, isStandardized, type);
  862. } else if (val is Extensible<int>) {
  863. res = (uint)((Extensible<int>)val).Value;
  864. WarnRange(context, ((Extensible<int>)val).Value, isStandardized, type);
  865. } else if (val is Extensible<BigInteger>) {
  866. res = (uint)(((Extensible<BigInteger>)val).Value & 0xffffffff);
  867. BigInteger bi = ((Extensible<BigInteger>)val).Value;
  868. WarnRange(context, bi, isStandardized, type);
  869. } else {
  870. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, "struct integer overflow masking is deprecated");
  871. object maskedValue = PythonContext.GetContext(context).Operation(PythonOperationKind.BitwiseAnd, val, (BigInteger)4294967295);
  872. if (!Converter.TryConvertToUInt32(maskedValue, out res)) {
  873. throw PythonOps.OverflowError("can't convert to " + type);
  874. }
  875. }
  876. return res;
  877. }
  878. private static void WarnRange(CodeContext context, int val, bool isStandardized, string type) {
  879. if (val < 0) {
  880. WarnRange(context, isStandardized, type);
  881. }
  882. }
  883. private static void WarnRange(CodeContext context, BigInteger bi, bool isStandardized, string type) {
  884. if (bi < 0 || bi > 4294967295) {
  885. WarnRange(context, isStandardized, type);
  886. }
  887. }
  888. private static void WarnRange(CodeContext context, bool isStandardized, string type) {
  889. if (isStandardized) {
  890. throw Error(context, "expected " + type + " value");
  891. }
  892. PythonOps.Warn(context, PythonExceptions.DeprecationWarning, (type == "unsigned long" ? "'L'" : "'I'") + " format requires 0 <= number <= 4294967295");
  893. }
  894. internal static IntPtr GetPointer(CodeContext/*!*/ context, int index, object[] args) {
  895. object val = GetValue(context, index, args);
  896. if (IntPtr.Size == 4) {
  897. uint res;
  898. if (Converter.TryConvertToUInt32(val, out res)) {
  899. return new IntPtr(res);
  900. }
  901. } else {
  902. long res;
  903. if (Converter.TryConvertToInt64(val, out res)) {
  904. return new IntPtr(res);
  905. }
  906. }
  907. throw Error(context, "expected pointer value");
  908. }
  909. internal static long GetLongValue(CodeContext/*!*/ context, int index, object[] args) {
  910. object val = GetValue(context, index, args);
  911. long res;
  912. if (Converter.TryConvertToInt64(val, out res)) return res;
  913. throw Error(context, "expected long value");
  914. }
  915. internal static ulong GetULongLongValue(CodeContext/*!*/ context, int index, object[] args) {
  916. object val = GetValue(context, index, args);
  917. ulong res;
  918. if (Converter.TryConvertToUInt64(val, out res)) return res;
  919. throw Error(context, "expected ulong value");
  920. }
  921. internal static double GetDoubleValue(CodeContext/*!*/ context, int index, object[] args) {
  922. object val = GetValue(context, index, args);
  923. double res;
  924. if (Converter.TryConvertToDouble(val, out res)) return res;
  925. throw Error(context, "expected double value");
  926. }
  927. internal static string GetStringValue(CodeContext/*!*/ context, int index, object[] args) {
  928. object val = GetValue(context, index, args);
  929. string res;
  930. if (Converter.TryConvertToString(val, out res)) return res;
  931. throw Error(context, "expected string value");
  932. }
  933. internal static object GetValue(CodeContext/*!*/ context, int index, object[] args) {
  934. if (index >= args.Length) throw Error(context, "not enough arguments");
  935. return args[index];
  936. }
  937. #endregion
  938. #region Data creater helpers
  939. internal static bool CreateBoolValue(CodeContext/*!*/ context, ref int index, string data) {
  940. return (int)ReadData(context, ref index, data) != 0;
  941. }
  942. internal static char CreateCharValue(CodeContext/*!*/ context, ref int index, string data) {
  943. return ReadData(context, ref index, data);
  944. }
  945. internal static short CreateShortValue(CodeContext/*!*/ context, ref int index, bool fLittleEndian, string data) {
  946. byte b1 = (byte)ReadData(context, ref index, data);
  947. byte b2 = (byte)ReadData(context, ref index, data);
  948. if (fLittleEndian) {
  949. return (short)((b2 << 8) | b1);
  950. } else {
  951. return (short)((b1 << 8) | b2);
  952. }
  953. }
  954. internal static ushort CreateUShor

Large files files are truncated, but you can click here to view the full file