PageRenderTime 61ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 1ms

/Languages/IronPython/IronPython/Runtime/Operations/MarshalOps.cs

http://github.com/IronLanguages/main
C# | 714 lines | 573 code | 90 blank | 51 comment | 157 complexity | f612e4f16dd18310277f61dea282b904 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using IronPython.Runtime;
  5. using IronPython.Runtime.Exceptions;
  6. using IronPython.Runtime.Operations;
  7. using IronPython.Runtime.Types;
  8. using Microsoft.Scripting.Runtime;
  9. using Microsoft.Scripting.Utils;
  10. #if FEATURE_NUMERICS
  11. using System.Numerics;
  12. #else
  13. using Microsoft.Scripting.Math;
  14. using Complex = Microsoft.Scripting.Math.Complex64;
  15. #endif
  16. namespace IronPython.Runtime.Operations {
  17. public class MarshalOps {
  18. public static byte[] GetBytes (object o, int version) {
  19. MarshalWriter mw = new MarshalWriter (version);
  20. mw.WriteObject (o);
  21. return mw.GetBytes ();
  22. }
  23. public static object GetObject (IEnumerator<byte> bytes) {
  24. MarshalReader mr = new MarshalReader (bytes);
  25. return mr.ReadObject ();
  26. }
  27. //
  28. // Format
  29. //
  30. // Tuple: '(',int cnt,tuple items
  31. // List: '[',int cnt, list items
  32. // Dict: '{',key item, value item, '0' terminator
  33. // Int : 'i',4 bytes
  34. // float: 'f', 1 byte len, float in string
  35. // float: 'g', 8 bytes - float in binary form
  36. // BigInt: 'l', int encodingSize
  37. // if the value is negative then the size is negative
  38. // and needs to be subtracted from int.MaxValue
  39. //
  40. // the bytes are encoded in 15 bit multiples, a size of
  41. // 0 represents a value of zero.
  42. //
  43. // True: 'T'
  44. // False: 'F'
  45. // Float: 'f', str len, float in str
  46. // string: 't', int len, bytes (ascii)
  47. // string: 'u', int len, bytes (unicode)
  48. // string: 'R' <id> - refer to interned string
  49. // StopIteration: 'S'
  50. // None: 'N'
  51. // Long: 'I' followed by 8 bytes (little endian 64-bit value)
  52. // complex: 'x', byte len, real str, byte len, imag str
  53. // Buffer (array.array too, but they don't round trip): 's', int len, buffer bytes
  54. // code: 'c', more stuff...
  55. //
  56. private class MarshalWriter {
  57. private readonly List<byte> _bytes;
  58. private readonly int _version;
  59. private readonly Dictionary<string, int> _strings;
  60. public MarshalWriter (int version) {
  61. _bytes = new List<byte> ();
  62. _version = version;
  63. if (_version > 0) {
  64. _strings = new Dictionary<string, int> ();
  65. }
  66. }
  67. public void WriteObject (object o) {
  68. List<object> infinite = PythonOps.GetReprInfinite ();
  69. if (infinite.Contains (o)) throw PythonOps.ValueError ("Marshaled data contains infinite cycle");
  70. int index = infinite.Count;
  71. infinite.Add (o);
  72. try {
  73. if (o == null) _bytes.Add ((byte)'N');
  74. else if (o == ScriptingRuntimeHelpers.True) _bytes.Add ((byte)'T');
  75. else if (o == ScriptingRuntimeHelpers.False) _bytes.Add ((byte)'F');
  76. else if (o is string) WriteString (o as string);
  77. else if (o is int) WriteInt ((int)o);
  78. else if (o is float) WriteFloat ((float)o);
  79. else if (o is double) WriteFloat ((double)o);
  80. else if (o is long) WriteLong ((long)o);
  81. else if (o.GetType () == typeof (List)) WriteList (o);
  82. else if (o.GetType () == typeof (PythonDictionary)) WriteDict (o);
  83. else if (o.GetType () == typeof (PythonTuple)) WriteTuple (o);
  84. else if (o.GetType () == typeof (SetCollection)) WriteSet (o);
  85. else if (o.GetType () == typeof (FrozenSetCollection)) WriteFrozenSet (o);
  86. else if (o is BigInteger) WriteInteger ((BigInteger)o);
  87. else if (o is Complex) WriteComplex ((Complex)o);
  88. else if (o is PythonBuffer) WriteBuffer ((PythonBuffer)o);
  89. else if (o == PythonExceptions.StopIteration) WriteStopIteration ();
  90. else throw PythonOps.ValueError ("unmarshallable object");
  91. } finally {
  92. infinite.RemoveAt (index);
  93. }
  94. }
  95. private void WriteFloat (float f) {
  96. if (_version > 1) {
  97. _bytes.Add ((byte)'g');
  98. _bytes.AddRange (BitConverter.GetBytes ((double)f));
  99. } else {
  100. _bytes.Add ((byte)'f');
  101. WriteDoubleString (f);
  102. }
  103. }
  104. private void WriteFloat (double f) {
  105. if (_version > 1) {
  106. _bytes.Add ((byte)'g');
  107. _bytes.AddRange (BitConverter.GetBytes (f));
  108. } else {
  109. _bytes.Add ((byte)'f');
  110. WriteDoubleString (f);
  111. }
  112. }
  113. private void WriteDoubleString (double d) {
  114. string s = DoubleOps.__repr__ (DefaultContext.Default, d);
  115. _bytes.Add ((byte)s.Length);
  116. for (int i = 0; i < s.Length; i++) {
  117. _bytes.Add ((byte)s[i]);
  118. }
  119. }
  120. private void WriteInteger (BigInteger val) {
  121. _bytes.Add ((byte)'l');
  122. int wordCount = 0, dir;
  123. if (val < BigInteger.Zero) {
  124. val *= -1;
  125. dir = -1;
  126. } else {
  127. dir = 1;
  128. }
  129. List<byte> bytes = new List<byte> ();
  130. while (val != BigInteger.Zero) {
  131. int word = (int)(val & 0x7FFF);
  132. val = val >> 15;
  133. bytes.Add ((byte)(word & 0xFF));
  134. bytes.Add ((byte)((word >> 8) & 0xFF));
  135. wordCount += dir;
  136. }
  137. WriteInt32 (wordCount);
  138. _bytes.AddRange (bytes);
  139. }
  140. private void WriteBuffer (PythonBuffer b) {
  141. _bytes.Add ((byte)'s');
  142. List<byte> newBytes = new List<byte> ();
  143. for (int i = 0; i < b.Size; i++) {
  144. if (b[i] is string) {
  145. string str = b[i] as string;
  146. byte[] utfBytes = Encoding.UTF8.GetBytes (str);
  147. if (utfBytes.Length != str.Length) {
  148. newBytes.AddRange (utfBytes);
  149. } else {
  150. byte[] strBytes = PythonAsciiEncoding.Instance.GetBytes (str);
  151. newBytes.AddRange (strBytes);
  152. }
  153. } else {
  154. newBytes.Add ((byte)b[i]);
  155. }
  156. }
  157. WriteInt32 (newBytes.Count);
  158. _bytes.AddRange (newBytes);
  159. }
  160. private void WriteLong (long l) {
  161. _bytes.Add ((byte)'I');
  162. for (int i = 0; i < 8; i++) {
  163. _bytes.Add ((byte)(l & 0xff));
  164. l = l >> 8;
  165. }
  166. }
  167. private void WriteComplex (Complex val) {
  168. _bytes.Add ((byte)'x');
  169. WriteDoubleString (val.Real);
  170. WriteDoubleString (val.Imaginary ());
  171. }
  172. private void WriteStopIteration () {
  173. _bytes.Add ((byte)'S');
  174. }
  175. private void WriteInt (int val) {
  176. _bytes.Add ((byte)'i');
  177. WriteInt32 (val);
  178. }
  179. private void WriteInt32 (int val) {
  180. _bytes.Add ((byte)(val & 0xff));
  181. _bytes.Add ((byte)((val >> 8) & 0xff));
  182. _bytes.Add ((byte)((val >> 16) & 0xff));
  183. _bytes.Add ((byte)((val >> 24) & 0xff));
  184. }
  185. private void WriteString (string s) {
  186. byte[] utfBytes = Encoding.UTF8.GetBytes (s);
  187. if (utfBytes.Length != s.Length) {
  188. _bytes.Add ((byte)'u');
  189. WriteInt32 (utfBytes.Length);
  190. for (int i = 0; i < utfBytes.Length; i++) {
  191. _bytes.Add (utfBytes[i]);
  192. }
  193. } else {
  194. int index;
  195. if (_strings != null && _strings.TryGetValue (s, out index)) {
  196. _bytes.Add ((byte)'R');
  197. WriteInt32 (index);
  198. } else {
  199. byte[] strBytes = PythonAsciiEncoding.Instance.GetBytes (s);
  200. if (_strings != null) {
  201. _bytes.Add ((byte)'t');
  202. } else {
  203. _bytes.Add ((byte)'s');
  204. }
  205. WriteInt32 (strBytes.Length);
  206. for (int i = 0; i < strBytes.Length; i++) {
  207. _bytes.Add (strBytes[i]);
  208. }
  209. if (_strings != null) {
  210. _strings[s] = _strings.Count;
  211. }
  212. }
  213. }
  214. }
  215. private void WriteList (object o) {
  216. List l = o as List;
  217. _bytes.Add ((byte)'[');
  218. WriteInt32 (l.__len__ ());
  219. for (int i = 0; i < l.__len__ (); i++) {
  220. WriteObject (l[i]);
  221. }
  222. }
  223. private void WriteDict (object o) {
  224. PythonDictionary d = o as PythonDictionary;
  225. _bytes.Add ((byte)'{');
  226. IEnumerator<KeyValuePair<object, object>> ie = ((IEnumerable<KeyValuePair<object, object>>)d).GetEnumerator ();
  227. while (ie.MoveNext ()) {
  228. WriteObject (ie.Current.Key);
  229. WriteObject (ie.Current.Value);
  230. }
  231. _bytes.Add ((byte)'0');
  232. }
  233. private void WriteTuple (object o) {
  234. PythonTuple t = o as PythonTuple;
  235. _bytes.Add ((byte)'(');
  236. WriteInt32 (t.__len__ ());
  237. for (int i = 0; i < t.__len__ (); i++) {
  238. WriteObject (t[i]);
  239. }
  240. }
  241. private void WriteSet (object set) {
  242. SetCollection s = set as SetCollection;
  243. _bytes.Add ((byte)'<');
  244. WriteInt32 (s.__len__ ());
  245. foreach (object o in s) {
  246. WriteObject (o);
  247. }
  248. }
  249. private void WriteFrozenSet (object set) {
  250. FrozenSetCollection s = set as FrozenSetCollection;
  251. _bytes.Add ((byte)'>');
  252. WriteInt32 (s.__len__ ());
  253. foreach (object o in s) {
  254. WriteObject (o);
  255. }
  256. }
  257. public byte[] GetBytes () {
  258. return _bytes.ToArray ();
  259. }
  260. }
  261. private class MarshalReader {
  262. private IEnumerator<byte> _myBytes;
  263. private Stack<ProcStack> _stack;
  264. private readonly Dictionary<int, string> _strings;
  265. private object _result;
  266. public MarshalReader (IEnumerator<byte> bytes) {
  267. _myBytes = bytes;
  268. _strings = new Dictionary<int, string> ();
  269. }
  270. public object ReadObject () {
  271. while (_myBytes.MoveNext ()) {
  272. byte cur = _myBytes.Current;
  273. object res;
  274. switch ((char)cur) {
  275. case '(': PushStack (StackType.Tuple); break;
  276. case '[': PushStack (StackType.List); break;
  277. case '{': PushStack (StackType.Dict); break;
  278. case '<': PushStack (StackType.Set); break;
  279. case '>': PushStack (StackType.FrozenSet); break;
  280. case '0':
  281. // end of dictionary
  282. if (_stack == null || _stack.Count == 0) {
  283. throw PythonOps.ValueError ("bad marshal data");
  284. }
  285. _stack.Peek ().StackCount = 0;
  286. break;
  287. // case 'c': break;
  288. default:
  289. res = YieldSimple ();
  290. if (_stack == null) {
  291. return res;
  292. }
  293. do {
  294. res = UpdateStack (res);
  295. } while (res != null && _stack.Count > 0);
  296. if (_stack.Count == 0) {
  297. return _result;
  298. }
  299. continue;
  300. }
  301. // handle empty lists/tuples...
  302. if (_stack != null && _stack.Count > 0 && _stack.Peek ().StackCount == 0) {
  303. ProcStack ps = _stack.Pop ();
  304. res = ps.StackObj;
  305. if (ps.StackType == StackType.Tuple) {
  306. res = PythonTuple.Make (res);
  307. } else if (ps.StackType == StackType.FrozenSet) {
  308. res = FrozenSetCollection.Make (TypeCache.FrozenSet, res);
  309. }
  310. if (_stack.Count > 0) {
  311. // empty list/tuple
  312. do {
  313. res = UpdateStack (res);
  314. } while (res != null && _stack.Count > 0);
  315. if (_stack.Count == 0) break;
  316. } else {
  317. _result = res;
  318. break;
  319. }
  320. }
  321. }
  322. return _result;
  323. }
  324. private void PushStack (StackType type) {
  325. ProcStack newStack = new ProcStack ();
  326. newStack.StackType = type;
  327. switch (type) {
  328. case StackType.Dict:
  329. newStack.StackObj = new PythonDictionary ();
  330. newStack.StackCount = -1;
  331. break;
  332. case StackType.List:
  333. newStack.StackObj = new List ();
  334. newStack.StackCount = ReadInt32 ();
  335. break;
  336. case StackType.Tuple:
  337. newStack.StackCount = ReadInt32 ();
  338. newStack.StackObj = new List<object> (newStack.StackCount);
  339. break;
  340. case StackType.Set:
  341. newStack.StackObj = new SetCollection ();
  342. newStack.StackCount = ReadInt32 ();
  343. break;
  344. case StackType.FrozenSet:
  345. newStack.StackCount = ReadInt32 ();
  346. newStack.StackObj = new List<object> (newStack.StackCount);
  347. break;
  348. }
  349. if (_stack == null) _stack = new Stack<ProcStack> ();
  350. _stack.Push (newStack);
  351. }
  352. private object UpdateStack (object res) {
  353. ProcStack curStack = _stack.Peek ();
  354. switch (curStack.StackType) {
  355. case StackType.Dict:
  356. PythonDictionary od = curStack.StackObj as PythonDictionary;
  357. if (curStack.HaveKey) {
  358. od[curStack.Key] = res;
  359. curStack.HaveKey = false;
  360. } else {
  361. curStack.HaveKey = true;
  362. curStack.Key = res;
  363. }
  364. break;
  365. case StackType.Tuple:
  366. List<object> objs = curStack.StackObj as List<object>;
  367. objs.Add (res);
  368. curStack.StackCount--;
  369. if (curStack.StackCount == 0) {
  370. _stack.Pop ();
  371. object tuple = PythonTuple.Make (objs);
  372. if (_stack.Count == 0) {
  373. _result = tuple;
  374. }
  375. return tuple;
  376. }
  377. break;
  378. case StackType.List:
  379. List ol = curStack.StackObj as List;
  380. ol.AddNoLock (res);
  381. curStack.StackCount--;
  382. if (curStack.StackCount == 0) {
  383. _stack.Pop ();
  384. if (_stack.Count == 0) {
  385. _result = ol;
  386. }
  387. return ol;
  388. }
  389. break;
  390. case StackType.Set:
  391. SetCollection os = curStack.StackObj as SetCollection;
  392. os.add (res);
  393. curStack.StackCount--;
  394. if (curStack.StackCount == 0) {
  395. _stack.Pop ();
  396. if (_stack.Count == 0) {
  397. _result = os;
  398. }
  399. return os;
  400. }
  401. break;
  402. case StackType.FrozenSet:
  403. List<object> ofs = curStack.StackObj as List<object>;
  404. ofs.Add (res);
  405. curStack.StackCount--;
  406. if (curStack.StackCount == 0) {
  407. _stack.Pop ();
  408. object frozenSet = FrozenSetCollection.Make (TypeCache.FrozenSet, ofs);
  409. if (_stack.Count == 0) {
  410. _result = frozenSet;
  411. }
  412. return frozenSet;
  413. }
  414. break;
  415. }
  416. return null;
  417. }
  418. private enum StackType {
  419. Tuple,
  420. Dict,
  421. List,
  422. Set,
  423. FrozenSet
  424. }
  425. private class ProcStack {
  426. public StackType StackType;
  427. public object StackObj;
  428. public int StackCount;
  429. public bool HaveKey;
  430. public object Key;
  431. }
  432. private object YieldSimple () {
  433. object res;
  434. switch ((char)_myBytes.Current) {
  435. // simple ops to be read in
  436. case 'i': res = ReadInt (); break;
  437. case 'l': res = ReadBigInteger (); break;
  438. case 'T': res = ScriptingRuntimeHelpers.True; break;
  439. case 'F': res = ScriptingRuntimeHelpers.False; break;
  440. case 'f': res = ReadFloat (); break;
  441. case 't': res = ReadAsciiString (); break;
  442. case 'u': res = ReadUnicodeString (); break;
  443. case 'S': res = PythonExceptions.StopIteration; break;
  444. case 'N': res = null; break;
  445. case 'x': res = ReadComplex (); break;
  446. case 's': res = ReadBuffer (); break;
  447. case 'I': res = ReadLong (); break;
  448. case 'R': res = _strings[ReadInt32 ()]; break;
  449. case 'g': res = ReadBinaryFloat (); break;
  450. default: throw PythonOps.ValueError ("bad marshal data");
  451. }
  452. return res;
  453. }
  454. private byte[] ReadBytes (int len) {
  455. byte[] bytes = new byte[len];
  456. for (int i = 0; i < len; i++) {
  457. if (!_myBytes.MoveNext ()) {
  458. throw PythonOps.ValueError ("bad marshal data");
  459. }
  460. bytes[i] = _myBytes.Current;
  461. }
  462. return bytes;
  463. }
  464. private int ReadInt32 () {
  465. byte[] intBytes = ReadBytes (4);
  466. int res = intBytes[0] |
  467. (intBytes[1] << 8) |
  468. (intBytes[2] << 16) |
  469. (intBytes[3] << 24);
  470. return res;
  471. }
  472. private double ReadFloatStr () {
  473. MoveNext ();
  474. string str = DecodeString (PythonAsciiEncoding.Instance, ReadBytes (_myBytes.Current));
  475. double res = 0;
  476. if (double.TryParse (str, out res)) {
  477. return res;
  478. }
  479. return 0;
  480. }
  481. private void MoveNext () {
  482. if (!_myBytes.MoveNext ()) {
  483. throw PythonOps.EofError ("EOF read where object expected");
  484. }
  485. }
  486. private string DecodeString (Encoding enc, byte[] bytes) {
  487. return enc.GetString (bytes, 0, bytes.Length);
  488. }
  489. object ReadInt () {
  490. // bytes not present are treated as being -1
  491. byte b1, b2, b3, b4;
  492. b1 = ReadIntPart ();
  493. b2 = ReadIntPart ();
  494. b3 = ReadIntPart ();
  495. b4 = ReadIntPart ();
  496. byte[] bytes = new byte[] { b1, b2, b3, b4 };
  497. return ScriptingRuntimeHelpers.Int32ToObject (BitConverter.ToInt32 (bytes, 0));
  498. //return Ops.int2object(b1 | (b2 << 8) | (b3 << 16) | (b4 << 24));
  499. }
  500. private byte ReadIntPart () {
  501. byte b;
  502. if (_myBytes.MoveNext ()) {
  503. b = _myBytes.Current;
  504. } else {
  505. b = 255;
  506. }
  507. return b;
  508. }
  509. object ReadFloat () {
  510. return ReadFloatStr ();
  511. }
  512. private object ReadBinaryFloat () {
  513. return BitConverter.ToDouble (ReadBytes (8), 0);
  514. }
  515. private object ReadAsciiString () {
  516. string res = DecodeString (PythonAsciiEncoding.Instance, ReadBytes (ReadInt32 ()));
  517. _strings[_strings.Count] = res;
  518. return res;
  519. }
  520. private object ReadUnicodeString () {
  521. return DecodeString (Encoding.UTF8, ReadBytes (ReadInt32 ()));
  522. }
  523. private object ReadComplex () {
  524. double real = ReadFloatStr ();
  525. double imag = ReadFloatStr ();
  526. return new Complex (real, imag);
  527. }
  528. private object ReadBuffer () {
  529. return DecodeString (Encoding.UTF8, ReadBytes (ReadInt32 ()));
  530. }
  531. private object ReadLong () {
  532. byte[] bytes = ReadBytes (8);
  533. long res = 0;
  534. for (int i = 0; i < 8; i++) {
  535. res |= (((long)bytes[i]) << (i * 8));
  536. }
  537. return res;
  538. }
  539. private object ReadBigInteger () {
  540. int encodingSize = ReadInt32 ();
  541. if (encodingSize == 0) {
  542. return BigInteger.Zero;
  543. }
  544. int sign = 1;
  545. if (encodingSize < 0) {
  546. sign = -1;
  547. encodingSize *= -1;
  548. }
  549. int len = encodingSize * 2;
  550. byte[] bytes = ReadBytes (len);
  551. #if CLR2
  552. // first read the values in shorts so we can work
  553. // with them as 15-bit bytes easier...
  554. short[] shData = new short[encodingSize];
  555. for (int i = 0; i < shData.Length; i++) {
  556. shData[i] = (short)(bytes[i * 2] | (bytes[1 + i * 2] << 8));
  557. }
  558. // then convert the short's into BigInteger's 32-bit
  559. // format.
  560. uint[] numData = new uint[(shData.Length + 1) / 2];
  561. int bitWriteIndex = 0, shortIndex = 0, bitReadIndex = 0;
  562. while (shortIndex < shData.Length) {
  563. short val = shData[shortIndex];
  564. int shift = bitWriteIndex % 32;
  565. if (bitReadIndex != 0) {
  566. // we're read some bits, mask them off
  567. // and adjust the shift.
  568. int maskOff = ~((1 << bitReadIndex) - 1);
  569. val = (short)(val & maskOff);
  570. shift -= bitReadIndex;
  571. }
  572. // write the value into numData
  573. if (shift < 0) {
  574. numData[bitWriteIndex / 32] |= (uint)(val >> (shift * -1));
  575. } else {
  576. numData[bitWriteIndex / 32] |= (uint)(val << shift);
  577. }
  578. // and advance our indices
  579. if ((bitWriteIndex % 32) <= 16) {
  580. bitWriteIndex += (15 - bitReadIndex);
  581. bitReadIndex = 0;
  582. shortIndex++;
  583. } else {
  584. bitReadIndex = (32 - (bitWriteIndex % 32));
  585. bitWriteIndex += bitReadIndex;
  586. }
  587. }
  588. // and finally pass the data onto the big integer.
  589. return new BigInteger(sign, numData);
  590. #else
  591. // re-pack our 15-bit values into bytes
  592. byte[] data = new byte[bytes.Length];
  593. for (int bytesIndex = 0, dataIndex = 0, shift = 0; bytesIndex < len; bytesIndex++) {
  594. // write 8 bits
  595. if (shift == 0) {
  596. data[dataIndex] = bytes[bytesIndex];
  597. } else {
  598. data[dataIndex] = (byte)((bytes[bytesIndex] >> shift) | (bytes[bytesIndex + 1] << (8 - shift)));
  599. }
  600. //done
  601. dataIndex++;
  602. bytesIndex++;
  603. if (shift == 7) {
  604. shift = 0;
  605. continue;
  606. }
  607. // write 7 bits
  608. if (bytesIndex < len - 1) {
  609. data[dataIndex] = (byte)((bytes[bytesIndex] >> shift) | (bytes[bytesIndex + 1] << (7 - shift)));
  610. } else {
  611. data[dataIndex] = (byte)(bytes[bytesIndex] >> shift);
  612. }
  613. //done
  614. dataIndex++;
  615. shift++;
  616. }
  617. // and finally pass the data onto the big integer.
  618. BigInteger res = new BigInteger (data);
  619. return sign < 0 ? -res : res;
  620. #endif
  621. }
  622. }
  623. }
  624. }